Skip to content

Commit

Permalink
Merge branch 'master' into issue-1757
Browse files Browse the repository at this point in the history
  • Loading branch information
vallsv authored Apr 18, 2018
2 parents 749a2a9 + 511513c commit 9660f98
Show file tree
Hide file tree
Showing 44 changed files with 604 additions and 350,430 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ matrix:
- BUILD_COMMAND=sdist
- WITH_QT_TEST=True
- PYOPENCL_VERSION=2015.1

- python: 3.6
os: linux
env:
Expand Down Expand Up @@ -69,6 +69,7 @@ install:
# Install build dependencies
- pip install --upgrade wheel
- pip install --upgrade numpy
- pip install --upgrade cython

# Print Python info
- python ./ci/info_platform.py
Expand Down
1 change: 1 addition & 0 deletions ci/appveyor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ build_script:
# Install build dependencies
- "pip install --upgrade wheel"
- "pip install --upgrade numpy"
- "pip install --upgrade cython"

# Print Python info
- "python ci\\info_platform.py"
Expand Down
2 changes: 1 addition & 1 deletion doc/source/install.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ The GUI widgets depend on the following extra packages:
`PySide <https://pypi.python.org/pypi/PySide/>`_, or `PySide2 <https://wiki.qt.io/PySide2>`_
* `matplotlib <http://matplotlib.org/>`_
* `PyOpenGL <http://pyopengl.sourceforge.net/>`_
* `IPython <https://ipython.org/>`_ and `qt_console <https://pypi.python.org/pypi/qtconsole>`_
* `qt_console <https://pypi.python.org/pypi/qtconsole>`_
for the ``silx.gui.console`` widget.
* `dateutil <https://pypi.org/project/python-dateutil/>`_

Expand Down
1 change: 1 addition & 0 deletions doc/source/modules/gui/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ The ``silx.gui`` package provides a set of PyQt widgets.
plot/index.rst
plot3d/index.rst
qt.rst
utils.rst
widgets/index.rst


Expand Down
12 changes: 12 additions & 0 deletions doc/source/modules/gui/utils.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.. currentmodule:: silx.gui.utils

:mod:`~silx.gui.utils`: Qt helpers
==================================

.. automodule:: silx.gui.utils

:mod:`~silx.gui.utils.concurrent`
---------------------------------

.. automodule:: silx.gui.utils.concurrent
:members:
27 changes: 13 additions & 14 deletions doc/source/sample_code/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -254,28 +254,27 @@ Sample code that adds specific tools or functions to plot widgets.
- This script illustrates the update of a :mod:`silx.gui.plot` widget from a thread.

The problem is that plot and GUI methods should be called from the main thread.
To safely update the plot from another thread, one need to make the update
asynchronously from the main thread.
In this example, this is achieved through a Qt signal.

In this example we create a subclass of :class:`~silx.gui.plot.PlotWindow.Plot1D`
that adds a thread-safe method to add curves:
:meth:`ThreadSafePlot1D.addCurveThreadSafe`.
This thread-safe method is then called from a thread to update the plot.
To safely update the plot from another thread, one need to execute the update
asynchronously in the main thread.
In this example, this is achieved with
:func:`~silx.gui.utils.concurrent.submitToQtMainThread`.

In this example a thread calls submitToQtMainThread to update the curve
of a plot.
* - :download:`plotUpdateImageFromThread.py <../../../examples/plotUpdateImageFromThread.py>`
- .. image:: img/plotUpdateImageFromThread.png
:height: 150px
:align: center
- This script illustrates the update of a :mod:`silx.gui.plot` widget from a thread.

The problem is that plot and GUI methods should be called from the main thread.
To safely update the plot from another thread, one need to make the update
asynchronously from the main thread.
In this example, this is achieved through a Qt signal.
To safely update the plot from another thread, one need to execute the update
asynchronously in the main thread.
In this example, this is achieved with
:func:`~silx.gui.utils.concurrent.submitToQtMainThread`.

In this example we create a subclass of :class:`~silx.gui.plot.PlotWindow.Plot2D`
that adds a thread-safe method to add images: :meth:`ThreadSafePlot1D.addImageThreadSafe`.
This thread-safe method is then called from a thread to update the plot.
In this example a thread calls submitToQtMainThread to update the curve
of a plot.
* - :download:`printPreview.py <../../../examples/printPreview.py>`
- .. image:: img/printPreview.png
:height: 150px
Expand Down
64 changes: 20 additions & 44 deletions examples/plotUpdateCurveFromThread.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,13 @@
"""This script illustrates the update of a :mod:`silx.gui.plot` widget from a thread.
The problem is that plot and GUI methods should be called from the main thread.
To safely update the plot from another thread, one need to make the update
asynchronously from the main thread.
In this example, this is achieved through a Qt signal.
In this example we create a subclass of :class:`~silx.gui.plot.PlotWindow.Plot1D`
that adds a thread-safe method to add curves:
:meth:`ThreadSafePlot1D.addCurveThreadSafe`.
This thread-safe method is then called from a thread to update the plot.
To safely update the plot from another thread, one need to execute the update
asynchronously in the main thread.
In this example, this is achieved with
:func:`~silx.gui.utils.concurrent.submitToQtMainThread`.
In this example a thread calls submitToQtMainThread to update the curve
of a plot.
"""

__authors__ = ["T. Vincent"]
Expand All @@ -46,42 +45,15 @@
import numpy

from silx.gui import qt
from silx.gui.plot import Plot1D


class ThreadSafePlot1D(Plot1D):
"""Add a thread-safe :meth:`addCurveThreadSafe` method to Plot1D.
"""

_sigAddCurve = qt.Signal(tuple, dict)
"""Signal used to perform addCurve in the main thread.
It takes args and kwargs as arguments.
"""
from silx.gui.utils import concurrent

def __init__(self, parent=None):
super(ThreadSafePlot1D, self).__init__(parent)
# Connect the signal to the method actually calling addCurve
self._sigAddCurve.connect(self.__addCurve)

def __addCurve(self, args, kwargs):
"""Private method calling addCurve from _sigAddCurve"""
self.addCurve(*args, **kwargs)

def addCurveThreadSafe(self, *args, **kwargs):
"""Thread-safe version of :meth:`silx.gui.plot.Plot.addCurve`
This method takes the same arguments as Plot.addCurve.
WARNING: This method does not return a value as opposed to Plot.addCurve
"""
self._sigAddCurve.emit(args, kwargs)
from silx.gui.plot import Plot1D


class UpdateThread(threading.Thread):
"""Thread updating the curve of a :class:`ThreadSafePlot1D`
"""Thread updating the curve of a :class:`~silx.gui.plot.Plot1D`
:param plot1d: The ThreadSafePlot1D to update."""
:param plot1d: The Plot1D to update."""

def __init__(self, plot1d):
self.plot1d = plot1d
Expand All @@ -97,8 +69,12 @@ def run(self):
"""Method implementing thread loop that updates the plot"""
while self.running:
time.sleep(1)
self.plot1d.addCurveThreadSafe(
numpy.arange(1000), numpy.random.random(1000), resetzoom=False)
# Run plot update asynchronously
concurrent.submitToQtMainThread(
self.plot1d.addCurve,
numpy.arange(1000),
numpy.random.random(1000),
resetzoom=False)

def stop(self):
"""Stop the update thread"""
Expand All @@ -110,12 +86,12 @@ def main():
global app
app = qt.QApplication([])

# Create a ThreadSafePlot1D, set its limits and display it
plot1d = ThreadSafePlot1D()
# Create a Plot1D, set its limits and display it
plot1d = Plot1D()
plot1d.setLimits(0., 1000., 0., 1.)
plot1d.show()

# Create the thread that calls ThreadSafePlot1D.addCurveThreadSafe
# Create the thread that calls submitToQtMainThread
updateThread = UpdateThread(plot1d)
updateThread.start() # Start updating the plot

Expand Down
83 changes: 31 additions & 52 deletions examples/plotUpdateImageFromThread.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,17 @@
# THE SOFTWARE.
#
# ###########################################################################*/
"""This script illustrates the update of a :mod:`silx.gui.plot` widget from a
thread.
"""This script illustrates the update of a :class:`~silx.gui.plot.Plot2D`
widget from a thread.
The problem is that plot and GUI methods should be called from the main thread.
To safely update the plot from another thread, one need to make the update
asynchronously from the main thread.
In this example, this is achieved through a Qt signal.
To safely update the plot from another thread, one need to execute the update
asynchronously in the main thread.
In this example, this is achieved with
:func:`~silx.gui.utils.concurrent.submitToQtMainThread`.
In this example we create a subclass of
:class:`~silx.gui.plot.PlotWindow.Plot2D`
that adds a thread-safe method to add images:
:meth:`ThreadSafePlot1D.addImageThreadSafe`.
This thread-safe method is then called from a thread to update the plot.
In this example a thread calls submitToQtMainThread to update the image
of a plot.
Update from 1d to 2d example by Hans Fangohr, European XFEL GmbH, 26 Feb 2018.
"""
Expand All @@ -50,51 +48,23 @@
import numpy

from silx.gui import qt
from silx.gui.utils import concurrent
from silx.gui.plot import Plot2D


Nx = 150
Ny = 50


class ThreadSafePlot2D(Plot2D):
"""Add a thread-safe :meth:`addImageThreadSafe` method to Plot2D.
"""

_sigAddImage = qt.Signal(tuple, dict)
"""Signal used to perform addImage in the main thread.
It takes args and kwargs as arguments.
"""

def __init__(self, parent=None):
super(ThreadSafePlot2D, self).__init__(parent)
# Connect the signal to the method actually calling addImage
self._sigAddImage.connect(self.__addImage)

def __addImage(self, args, kwargs):
"""Private method calling addImage from _sigAddImage"""
self.addImage(*args, **kwargs)

def addImageThreadSafe(self, *args, **kwargs):
"""Thread-safe version of :meth:`silx.gui.plot.Plot.addImage`
This method takes the same arguments as Plot.addImage.
WARNING: This method does not return a value as opposed to
Plot.addImage
"""
self._sigAddImage.emit(args, kwargs)


class UpdateThread(threading.Thread):
"""Thread updating the image of a :class:`ThreadSafePlot2D`
"""Thread updating the image of a :class:`~sil.gui.plot.Plot2D`
:param plot2d: The ThreadSafePlot2D to update."""
:param plot2d: The Plot2D to update."""

def __init__(self, plot2d):
self.plot2d = plot2d
self.running = False
self.future_result = None
super(UpdateThread, self).__init__()

def start(self):
Expand All @@ -103,12 +73,15 @@ def start(self):
super(UpdateThread, self).start()

def run(self, pos={'x0': 0, 'y0': 0}):
"""Method implementing thread loop that updates the plot"""
"""Method implementing thread loop that updates the plot
It produces an image every 10 ms or so, and
either updates the plot or skip the image
"""
while self.running:
time.sleep(1)
# pixels in plot (defined at beginning of file)
# Nx = 70
# Ny = 50
time.sleep(0.01)

# Create image
# width of peak
sigma_x = 0.15
sigma_y = 0.25
Expand All @@ -123,8 +96,13 @@ def run(self, pos={'x0': 0, 'y0': 0}):
# random walk of center of peak ('drift')
pos['x0'] += 0.05 * (numpy.random.random() - 0.5)
pos['y0'] += 0.05 * (numpy.random.random() - 0.5)
# plot the data
self.plot2d.addImage(signal, replace=True, resetzoom=False)

# If previous frame was not added to the plot yet, skip this one
if self.future_result is None or self.future_result.done():
# plot the data asynchronously, and
# keep a reference to the `future` object
self.future_result = concurrent.submitToQtMainThread(
self.plot2d.addImage, signal, resetzoom=False)

def stop(self):
"""Stop the update thread"""
Expand All @@ -136,12 +114,13 @@ def main():
global app
app = qt.QApplication([])

# Create a ThreadSafePlot2D, set its limits and display it
plot2d = ThreadSafePlot2D()
# Create a Plot2D, set its limits and display it
plot2d = Plot2D()
plot2d.setLimits(0, Nx, 0, Ny)
plot2d.getDefaultColormap().setVRange(0., 1.5)
plot2d.show()

# Create the thread that calls ThreadSafePlot2D.addImageThreadSafe
# Create the thread that calls submitToQtMainThread
updateThread = UpdateThread(plot2d)
updateThread.start() # Start updating the plot

Expand Down
6 changes: 0 additions & 6 deletions package/debian8/control
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ Build-Depends: cython,
python-pyopencl,
python-pyopencl-dbg,
python-mako,
ipython,
python-matplotlib,
python-matplotlib-dbg,
python-dateutil,
Expand All @@ -50,7 +49,6 @@ Build-Depends: cython,
python3-pyopencl,
python3-pyopencl-dbg,
python3-mako,
ipython3,
python3-matplotlib,
python3-matplotlib-dbg,
python3-dateutil,
Expand Down Expand Up @@ -94,7 +92,6 @@ Depends: ${misc:Depends},
python-h5py,
python-pyopencl,
python-mako,
ipython,
python-matplotlib,
python-dateutil,
python-opengl,
Expand Down Expand Up @@ -124,7 +121,6 @@ Depends: ${misc:Depends},
python-h5py-dbg,
python-pyopencl-dbg,
python-mako,
ipython,
python-matplotlib-dbg,
python-dateutil,
python-opengl,
Expand All @@ -151,7 +147,6 @@ Depends: ${misc:Depends},
python3-h5py,
python3-pyopencl,
python3-mako,
ipython3,
python3-matplotlib,
python3-dateutil,
python3-opengl,
Expand Down Expand Up @@ -179,7 +174,6 @@ Depends: ${misc:Depends},
python3-h5py-dbg,
python3-pyopencl-dbg,
python3-mako,
ipython3,
python3-matplotlib-dbg,
python3-dateutil,
python3-opengl,
Expand Down
Loading

0 comments on commit 9660f98

Please sign in to comment.