diff options
author | Alexandre Marie <alexandre.marie@synchrotron-soleil.fr> | 2020-07-21 14:45:14 +0200 |
---|---|---|
committer | Alexandre Marie <alexandre.marie@synchrotron-soleil.fr> | 2020-07-21 14:45:14 +0200 |
commit | 328032e2317e3ac4859196bbf12bdb71795302fe (patch) | |
tree | 8cd13462beab109e3cb53410c42335b6d1e00ee6 /examples | |
parent | 33ed2a64c92b0311ae35456c016eb284e426afc2 (diff) |
New upstream version 0.13.0+dfsg
Diffstat (limited to 'examples')
-rw-r--r-- | examples/colormapDialog.py | 36 | ||||
-rw-r--r-- | examples/customSilxView.py | 88 | ||||
-rw-r--r-- | examples/dropZones.py | 113 | ||||
-rwxr-xr-x | examples/fftPlotAction.py | 4 | ||||
-rw-r--r-- | examples/findContours.py | 7 | ||||
-rwxr-xr-x | examples/hdf5widget.py | 2 | ||||
-rw-r--r-- | examples/icons.py | 2 | ||||
-rw-r--r-- | examples/imageStack.py | 143 | ||||
-rw-r--r-- | examples/plotCurveLegendWidget.py | 6 | ||||
-rw-r--r-- | examples/plotInteractiveImageROI.py | 8 | ||||
-rwxr-xr-x | examples/plotItemsSelector.py | 4 | ||||
-rw-r--r-- | examples/plotProfile.py | 207 | ||||
-rwxr-xr-x | examples/simplewidget.py | 24 | ||||
-rw-r--r-- | examples/viewer3DVolume.py | 4 |
14 files changed, 588 insertions, 60 deletions
diff --git a/examples/colormapDialog.py b/examples/colormapDialog.py index 08e3fe8..c9e7c35 100644 --- a/examples/colormapDialog.py +++ b/examples/colormapDialog.py @@ -101,43 +101,46 @@ class ColormapDialogExample(qt.QMainWindow): layout.addSpacing(10) - button = qt.QPushButton("Set no histogram") + button = qt.QPushButton("No histogram") button.clicked.connect(self.setNoHistogram) layout.addWidget(button) - button = qt.QPushButton("Set positive histogram") + button = qt.QPushButton("Positive histogram") button.clicked.connect(self.setPositiveHistogram) layout.addWidget(button) - button = qt.QPushButton("Set neg-pos histogram") + button = qt.QPushButton("Neg-pos histogram") button.clicked.connect(self.setNegPosHistogram) layout.addWidget(button) - button = qt.QPushButton("Set negative histogram") + button = qt.QPushButton("Negative histogram") button.clicked.connect(self.setNegativeHistogram) layout.addWidget(button) layout.addSpacing(10) - button = qt.QPushButton("Set no range") + button = qt.QPushButton("No range") button.clicked.connect(self.setNoRange) layout.addWidget(button) - button = qt.QPushButton("Set positive range") + button = qt.QPushButton("Positive range") button.clicked.connect(self.setPositiveRange) layout.addWidget(button) - button = qt.QPushButton("Set neg-pos range") + button = qt.QPushButton("Neg-pos range") button.clicked.connect(self.setNegPosRange) layout.addWidget(button) - button = qt.QPushButton("Set negative range") + button = qt.QPushButton("Negative range") button.clicked.connect(self.setNegativeRange) layout.addWidget(button) layout.addSpacing(10) - button = qt.QPushButton("Set no data") + button = qt.QPushButton("No data") button.clicked.connect(self.setNoData) layout.addWidget(button) - button = qt.QPushButton("Set shepp logan phantom") + button = qt.QPushButton("Zero to positive") button.clicked.connect(self.setSheppLoganPhantom) layout.addWidget(button) - button = qt.QPushButton("Set data with non finite") + button = qt.QPushButton("Negative to positive") + button.clicked.connect(self.setDataFromNegToPos) + layout.addWidget(button) + button = qt.QPushButton("Only non finite values") button.clicked.connect(self.setDataWithNonFinite) layout.addWidget(button) @@ -240,7 +243,14 @@ class ColormapDialogExample(qt.QMainWindow): data = numpy.random.poisson(data) self.data = data for dialog in self.colorDialogs: - dialog.setData(data) + dialog.setData(self.data) + + def setDataFromNegToPos(self): + data = numpy.ones((50,50)) + data = numpy.random.poisson(data) + self.data = data - 0.5 + for dialog in self.colorDialogs: + dialog.setData(self.data) def setDataWithNonFinite(self): from silx.image import phantomgenerator @@ -255,7 +265,7 @@ class ColormapDialogExample(qt.QMainWindow): data[100] = float("-inf") self.data = data for dialog in self.colorDialogs: - dialog.setData(data) + dialog.setData(self.data) def main(): diff --git a/examples/customSilxView.py b/examples/customSilxView.py new file mode 100644 index 0000000..c240280 --- /dev/null +++ b/examples/customSilxView.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2020 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ###########################################################################*/ +"""Sample code illustrating how to custom silx view into another application. +""" + +import sys +import numpy + + +def createWindow(parent, settings): + # Local import to avoid early import (like h5py) + # SOme libraries have to be configured first properly + from silx.gui.plot.actions import PlotAction + from silx.app.view.Viewer import Viewer + from silx.app.view.ApplicationContext import ApplicationContext + + class RandomColorAction(PlotAction): + def __init__(self, plot, parent=None): + super(RandomColorAction, self).__init__( + plot, icon="colormap", text='Color', + tooltip='Random plot background color', + triggered=self.__randomColor, + checkable=False, parent=parent) + + def __randomColor(self): + color = "#%06X" % numpy.random.randint(0xFFFFFF) + self.plot.setBackgroundColor(color) + + class MyApplicationContext(ApplicationContext): + """This class is shared to all the silx view application.""" + + def findPrintToolBar(self, plot): + # FIXME: It would be better to use the Qt API + return plot._outputToolBar + + def viewWidgetCreated(self, view, widget): + """Called when the widget of the view was created. + + So we can custom it. + """ + from silx.gui.plot import Plot1D + if isinstance(widget, Plot1D): + toolBar = self.findPrintToolBar(widget) + action = RandomColorAction(widget, widget) + toolBar.addAction(action) + + class MyViewer(Viewer): + def createApplicationContext(self, settings): + return MyApplicationContext(self, settings) + + window = MyViewer(parent=parent, settings=settings) + window.setWindowTitle(window.windowTitle() + " [custom]") + return window + + +def main(args): + from silx.app.view import main as silx_view_main + # Monkey patch the main window creation + silx_view_main.createWindow = createWindow + # Use the default launcher + silx_view_main.main(args) + + +if __name__ == '__main__': + main(sys.argv) diff --git a/examples/dropZones.py b/examples/dropZones.py index 27d9df8..68d0a57 100644 --- a/examples/dropZones.py +++ b/examples/dropZones.py @@ -2,7 +2,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2016-2019 European Synchrotron Radiation Facility +# Copyright (c) 2016-2020 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -24,7 +24,11 @@ # # ###########################################################################*/ """ -Example of drop zone supporting application/x-silx-uri +Example of drop zone supporting application/x-silx-uri. + +This example illustrates the support of drag&drop of silx URLs. +It provides 2 URLs (corresponding to 2 datasets) that can be dragged to +either a :class:`PlotWidget` or a QLable displaying the URL information. """ from __future__ import absolute_import @@ -34,6 +38,12 @@ __license__ = "MIT" __date__ = "25/01/2019" import logging +import os +import tempfile + +import h5py +import numpy + import silx.io from silx.gui import qt from silx.gui.plot.PlotWidget import PlotWidget @@ -43,6 +53,7 @@ logging.basicConfig() class DropPlotWidget(PlotWidget): + """PlotWidget accepting drop of silx URLs""" def __init__(self, parent=None, backend=None): PlotWidget.__init__(self, parent=parent, backend=backend) @@ -76,11 +87,30 @@ class DropPlotWidget(PlotWidget): class DropLabel(qt.QLabel): + """Label widget accepting drop of silx URLs""" - def __init__(self, parent=None, backend=None): - qt.QLabel.__init__(self) + DEFAULT_TEXT = "Drop an URL here to display information" + + def __init__(self, parent=None): + qt.QLabel.__init__(self, parent) self.setAcceptDrops(True) - self.setText("Drop something here") + self.setUrl(silx.io.url.DataUrl()) + + def setUrl(self, url): + template = ("<html>URL information (drop an URL here to parse its information):<ul>" + "<li><b>file_path</b>: {file_path}</li>" + "<li><b>data_path</b>: {data_path}</li>" + "<li><b>data_slice</b>: {data_slice}</li>" + "<li><b>scheme</b>: {scheme}</li>" + "</ul></html>" + ) + + text = template.format( + file_path=url.file_path(), + data_path=url.data_path(), + data_slice=url.data_slice(), + scheme=url.scheme()) + self.setText(text) def dragEnterEvent(self, event): if event.mimeData().hasFormat("application/x-silx-uri"): @@ -88,46 +118,67 @@ class DropLabel(qt.QLabel): def dropEvent(self, event): byteString = event.mimeData().data("application/x-silx-uri") - silxUrl = byteString.data().decode("utf-8") - url = silx.io.url.DataUrl(silxUrl) - self.setText(url.path()) - - toolTipTemplate = ("<html><ul>" - "<li><b>file_path</b>: {file_path}</li>" - "<li><b>data_path</b>: {data_path}</li>" - "<li><b>data_slice</b>: {data_slice}</li>" - "<li><b>scheme</b>: {scheme}</li>" - "</html>" - "</ul></html>" - ) - - toolTip = toolTipTemplate.format( - file_path=url.file_path(), - data_path=url.data_path(), - data_slice=url.data_slice(), - scheme=url.scheme()) - - self.setToolTip(toolTip) + url = silx.io.url.DataUrl(byteString.data().decode("utf-8")) + self.setUrl(url) event.acceptProposedAction() -class DropExample(qt.QMainWindow): +class DragLabel(qt.QLabel): + """Label widget providing a silx URL to drag""" - def __init__(self, parent=None): - super(DropExample, self).__init__(parent) + def __init__(self, parent=None, url=None): + self._url = url + qt.QLabel.__init__(self, parent) + self.setText('-' if url is None else "- " + self._url.path()) + + def mousePressEvent(self, event): + if event.button() == qt.Qt.LeftButton and self._url is not None: + mimeData = qt.QMimeData() + mimeData.setText(self._url.path()) + mimeData.setData( + "application/x-silx-uri", + self._url.path().encode(encoding='utf-8')) + drag = qt.QDrag(self) + drag.setMimeData(mimeData) + dropAction = drag.exec_() + + +class DragAndDropExample(qt.QMainWindow): + """Main window of the example""" + + def __init__(self, parent=None, urls=()): + super(DragAndDropExample, self).__init__(parent) centralWidget = qt.QWidget(self) layout = qt.QVBoxLayout() centralWidget.setLayout(layout) + layout.addWidget(qt.QLabel( + "Drag and drop one of the following URLs on the plot or on the URL information zone:", + self)) + for url in urls: + layout.addWidget(DragLabel(parent=self, url=url)) + layout.addWidget(DropPlotWidget(parent=self)) layout.addWidget(DropLabel(parent=self)) + self.setCentralWidget(centralWidget) def main(): app = qt.QApplication([]) - example = DropExample() - example.show() - app.exec_() + with tempfile.TemporaryDirectory() as tempdir: + # Create temporary file with datasets + filename = os.path.join(tempdir, "file.h5") + with h5py.File(filename, "w") as f: + f['image'] = numpy.arange(10000.).reshape(100, 100) + f['curve'] = numpy.sin(numpy.linspace(0, 2*numpy.pi, 1000)) + + # Create widgets + example = DragAndDropExample(urls=( + silx.io.url.DataUrl(file_path=filename, data_path='/image', scheme="silx"), + silx.io.url.DataUrl(file_path=filename, data_path='/curve', scheme="silx"))) + example.setWindowTitle("Drag&Drop URLs sample code") + example.show() + app.exec_() if __name__ == "__main__": diff --git a/examples/fftPlotAction.py b/examples/fftPlotAction.py index 877225f..bdea08d 100755 --- a/examples/fftPlotAction.py +++ b/examples/fftPlotAction.py @@ -2,7 +2,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2016-2018 European Synchrotron Radiation Facility +# Copyright (c) 2016-2020 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -110,7 +110,7 @@ class FftAction(PlotAction): for curve in allCurves: x = curve.getXData() y = curve.getYData() - legend = curve.getLegend() + legend = curve.getName() info = curve.getInfo() if info is None: info = {} diff --git a/examples/findContours.py b/examples/findContours.py index a7b5ac4..6199ba6 100644 --- a/examples/findContours.py +++ b/examples/findContours.py @@ -549,9 +549,10 @@ class FindContours(qt.QMainWindow): self.__customValue = value div = 12 delta = (self.__image.max() - self.__image.min()) / div - self.__value.setValue(value) - self.__value.setRange(self.__image.min() + delta, - self.__image.min() + delta * (div - 1)) + self.__value.setValue(int(numpy.round(value))) + minv = self.__image.min() + delta + maxv = self.__image.min() + delta * (div - 1) + self.__value.setRange(int(numpy.floor(minv)), int(numpy.ceil(maxv))) self.updateCustomContours() def generate(self): diff --git a/examples/hdf5widget.py b/examples/hdf5widget.py index 217eb7f..0d45b8f 100755 --- a/examples/hdf5widget.py +++ b/examples/hdf5widget.py @@ -488,7 +488,7 @@ def get_edf_with_100000_frames(): else: header = fabio.fabioimage.OrderedDict() header["frame_nb"] = framre_id - fabiofile.appendFrame(fabio.edfimage.Frame(data, header, framre_id)) + fabiofile.append_frame(fabio.edfimage.Frame(data, header, framre_id)) fabiofile.write(tmp.name) _file_cache[ID] = tmp diff --git a/examples/icons.py b/examples/icons.py index 673ca6f..ae77630 100644 --- a/examples/icons.py +++ b/examples/icons.py @@ -146,7 +146,7 @@ class IconPreview(qt.QMainWindow): for i, icon_info in enumerate(icons): icon_name, icon_kind = icon_info - col, line = i / 10, i % 10 + col, line = i // 10, i % 10 if icon_kind == "anim": tool = AnimatedToolButton(panel) try: diff --git a/examples/imageStack.py b/examples/imageStack.py new file mode 100644 index 0000000..0437a6e --- /dev/null +++ b/examples/imageStack.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2016-2018 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ###########################################################################*/ +""" +Simple example for using the ImageStack. + +In this example we want to display images from different source: .h5, .edf +and .npy files. + +To do so we simple reimplement the thread managing the loading of data. +""" + +import numpy +import h5py +import tempfile +import logging +import shutil +import os +import time +from silx.io.url import DataUrl +from silx.io.utils import get_data +from silx.gui import qt +from silx.gui.plot.ImageStack import ImageStack, UrlLoader +import fabio + + +logging.basicConfig() +_logger = logging.getLogger("hdf5widget") +"""Module logger""" + + +def create_random_image(): + """Create a simple image with random values""" + width = numpy.random.randint(100, 400) + height = numpy.random.randint(100, 400) + return numpy.random.random((width, height)) + + +def create_h5py_urls(n_url, file_name): + """ creates n urls based on h5py""" + res = [] + with h5py.File(file_name, 'w') as h5f: + for i in range(n_url): + h5f[str(i)] = create_random_image() + res.append(DataUrl(file_path=file_name, + data_path=str(i), + scheme='silx')) + return res + + +def create_numpy_url(file_name): + """ create a simple DataUrl with a .npy file """ + numpy.save(file=file_name, arr=create_random_image()) + return [DataUrl(file_path=file_name, + scheme='numpy'), ] + + +def create_edf_url(file_name): + """ create a simple DataUrl with a .edf file""" + dsc = fabio.edfimage.EdfImage(data=create_random_image(), header={}) + dsc.write(file_name) + return [DataUrl(file_path=file_name, + data_slice=(0,), + scheme='fabio'), ] + + +def create_datasets(folder): + """create a set of DataUrl containing each one image""" + urls = [] + file_ = os.path.join(folder, 'myh5file.h5') + urls.extend(create_h5py_urls(n_url=5, file_name=file_)) + file_ = os.path.join(folder, 'secondH5file.h5') + urls.extend(create_h5py_urls(n_url=2, file_name=file_)) + file_ = os.path.join(folder, 'firstnumpy_file.npy') + urls.extend(create_numpy_url(file_name=file_)) + file_ = os.path.join(folder, 'secondnumpy_file.npy') + urls.extend(create_numpy_url(file_name=file_)) + file_ = os.path.join(folder, 'single_edf_file.edf') + urls.extend(create_edf_url(file_name=file_)) + file_ = os.path.join(folder, 'single_edf_file_2.edf') + urls.extend(create_edf_url(file_name=file_)) + return urls + + +class MyOwnUrlLoader(UrlLoader): + """ + Thread use to load DataUrl + """ + def __init__(self, parent, url): + super(MyOwnUrlLoader, self).__init__(parent=parent, url=url) + self.url = url + self.data = None + + def run(self): + # just to see the waiting interface... + time.sleep(1.0) + if self.url.scheme() == 'numpy': + self.data = numpy.load(self.url.file_path()) + else: + self.data = get_data(self.url) + + +def main(): + dataset_folder = tempfile.mkdtemp() + + qapp = qt.QApplication([]) + widget = ImageStack() + widget.setUrlLoaderClass(MyOwnUrlLoader) + widget.setNPrefetch(1) + urls = create_datasets(folder=dataset_folder) + widget.setUrls(urls=urls) + widget.show() + qapp.exec_() + widget.close() + + shutil.rmtree(dataset_folder) + + +if __name__ == '__main__': + main() + exit(0) diff --git a/examples/plotCurveLegendWidget.py b/examples/plotCurveLegendWidget.py index 9209c58..97c516a 100644 --- a/examples/plotCurveLegendWidget.py +++ b/examples/plotCurveLegendWidget.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2018 European Synchrotron Radiation Facility +# Copyright (c) 2018-2020 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -71,7 +71,7 @@ class MyCurveLegendsWidget(CurveLegendsWidget): """ plot = curve.getPlot() plot.setActiveCurve( - curve.getLegend() if curve != plot.getActiveCurve() else None) + curve.getName() if curve != plot.getActiveCurve() else None) def _switchCurveVisibility(self, curve): """Toggle the visibility of a curve @@ -86,7 +86,7 @@ class MyCurveLegendsWidget(CurveLegendsWidget): :param silx.gui.plot.items.Curve curve: """ yaxis = curve.getYAxis() - curve.setYAxis('left' if yaxis is 'right' else 'right') + curve.setYAxis('left' if yaxis == 'right' else 'right') def _contextMenu(self, pos): """Create a show the context menu. diff --git a/examples/plotInteractiveImageROI.py b/examples/plotInteractiveImageROI.py index 8a4019f..c10bbf3 100644 --- a/examples/plotInteractiveImageROI.py +++ b/examples/plotInteractiveImageROI.py @@ -2,7 +2,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2018-2019 European Synchrotron Radiation Facility +# Copyright (c) 2018-2020 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -61,6 +61,7 @@ if "--opengl" in sys.argv: # Create the plot widget and add an image plot = Plot2D(backend=backend) plot.getDefaultColormap().setName('viridis') +plot.setKeepDataAspectRatio(True) plot.addImage(dummy_image()) # Create the object controlling the ROIs and set it up @@ -74,14 +75,17 @@ def updateAddedRegionOfInterest(roi): if roi.getName() == '': roi.setName('ROI %d' % len(roiManager.getRois())) if isinstance(roi, LineMixIn): - roi.setLineWidth(2) + roi.setLineWidth(1) roi.setLineStyle('--') if isinstance(roi, SymbolMixIn): roi.setSymbolSize(5) + roi.setSelectable(True) + roi.setEditable(True) roiManager.sigRoiAdded.connect(updateAddedRegionOfInterest) + # Add a rectangular region of interest roi = RectangleROI() roi.setGeometry(origin=(50, 50), size=(200, 200)) diff --git a/examples/plotItemsSelector.py b/examples/plotItemsSelector.py index 458bbeb..177489f 100755 --- a/examples/plotItemsSelector.py +++ b/examples/plotItemsSelector.py @@ -2,7 +2,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2017-2018 European Synchrotron Radiation Facility +# Copyright (c) 2017-2020 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -49,7 +49,7 @@ isd.setItemsSelectionMode(qt.QTableWidget.ExtendedSelection) result = isd.exec_() if result: for item in isd.getSelectedItems(): - print(item.getLegend(), type(item)) + print(item.getName(), type(item)) else: print("Selection cancelled") diff --git a/examples/plotProfile.py b/examples/plotProfile.py new file mode 100644 index 0000000..931f9b4 --- /dev/null +++ b/examples/plotProfile.py @@ -0,0 +1,207 @@ +#!/usr/bin/env python +# coding: utf-8 +# /*########################################################################## +# +# Copyright (c) 2020 European Synchrotron Radiation Facility +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# +# ###########################################################################*/ +"""Example illustrating the different profile tools. +""" + +import numpy +import scipy.signal + +from silx.gui import qt +from silx.gui.plot import Plot2D +from silx.gui.plot import ScatterView +from silx.gui.plot import StackView +from silx.gui.plot.tools.profile import toolbar + + +def createScatterData(): + nbPoints = 200 + nbX = int(numpy.sqrt(nbPoints)) + nbY = nbPoints // nbX + 1 + + # Motor position + yy = numpy.atleast_2d(numpy.ones(nbY)).T + xx = numpy.atleast_2d(numpy.ones(nbX)) + + positionX = numpy.linspace(10, 50, nbX) * yy + positionX = positionX.reshape(nbX * nbY) + positionX = positionX + numpy.random.rand(len(positionX)) - 0.5 + + positionY = numpy.atleast_2d(numpy.linspace(20, 60, nbY)).T * xx + positionY = positionY.reshape(nbX * nbY) + positionY = positionY + numpy.random.rand(len(positionY)) - 0.5 + + # Diodes position + lut = scipy.signal.gaussian(max(nbX, nbY), std=8) * 10 + yy, xx = numpy.ogrid[:nbY, :nbX] + signal = lut[yy] * lut[xx] + diode1 = numpy.random.poisson(signal * 10) + diode1 = diode1.reshape(nbX * nbY) + return positionX, positionY, diode1 + + +class Example(qt.QMainWindow): + def __init__(self, parent=None): + qt.QMainWindow.__init__(self, parent=parent) + self._createPlot2D() + self._createScatterView() + self._createStackView() + + dataWidget = qt.QWidget(self) + dataLayout = qt.QStackedLayout(dataWidget) + dataLayout.addWidget(self.plot) + dataLayout.addWidget(self.scatter) + dataLayout.addWidget(self.stack) + dataLayout.setCurrentWidget(self.plot) + self.dataLayout = dataLayout + + clearButton = qt.QPushButton(self) + clearButton.clicked.connect(self._clearData) + clearButton.setText("Clear") + + imageButton = qt.QPushButton(self) + imageButton.clicked.connect(self._updateImage) + imageButton.setText("Intensity image") + + imageRgbButton = qt.QPushButton(self) + imageRgbButton.clicked.connect(self._updateRgbImage) + imageRgbButton.setText("RGB image") + + scatterButton = qt.QPushButton(self) + scatterButton.clicked.connect(self._updateScatter) + scatterButton.setText("Scatter") + + stackButton = qt.QPushButton(self) + stackButton.clicked.connect(self._updateStack) + stackButton.setText("Stack") + + options = qt.QWidget(self) + layout = qt.QHBoxLayout(options) + layout.addStretch() + layout.addWidget(clearButton) + layout.addWidget(imageButton) + layout.addWidget(imageRgbButton) + layout.addWidget(scatterButton) + layout.addWidget(stackButton) + layout.addStretch() + + widget = qt.QWidget(self) + layout = qt.QVBoxLayout(widget) + layout.addWidget(dataWidget) + layout.addWidget(options) + self.setCentralWidget(widget) + + self._updateImage() + + def _createPlot2D(self): + plot = Plot2D(self) + self.plot = plot + + toolBar = toolbar.ProfileToolBar(plot, plot) + toolBar.setScheme("image") + plot.addToolBar(toolBar) + + toolBar = plot.getProfileToolbar() + toolBar.clear() + + def _createScatterView(self): + plot = ScatterView(self) + self.scatter = plot + + toolBar = toolbar.ProfileToolBar(plot, plot.getPlotWidget()) + toolBar.setScheme("scatter") + plot.addToolBar(toolBar) + + toolBar = plot.getScatterProfileToolBar() + toolBar.clear() + + def _createStackView(self): + plot = StackView(self) + self.stack = plot + + toolBar = toolbar.ProfileToolBar(plot, plot.getPlotWidget()) + toolBar.setScheme("imagestack") + plot.addToolBar(toolBar) + + toolBar = plot.getProfileToolbar() + toolBar.clear() + + def _clearData(self): + image = self.plot.getActiveImage() + if image is not None: + self.plot.removeItem(image) + self.scatter.setData(None, None, None) + self.stack.clear() + + def _updateImage(self): + x = numpy.outer(numpy.linspace(-10, 10, 200), + numpy.linspace(-5, 5, 150)) + image = numpy.sin(x) / x + image = image * 10 + numpy.random.rand(*image.shape) + + self.plot.addImage(image) + self.dataLayout.setCurrentWidget(self.plot) + + def _updateRgbImage(self): + image = numpy.empty(shape=(200, 150, 3), dtype=numpy.uint8) + x = numpy.outer(numpy.linspace(-10, 10, 200), + numpy.linspace(-5, 5, 150)) + r = numpy.sin(x) / x + g = numpy.cos(x/10) * numpy.sin(x/10) + b = x + image[..., 0] = 100 + 200 * (r / r.max()) + image[..., 1] = 100 + 200 * (g / g.max()) + image[..., 2] = 100 + 200 * (b / b.max()) + image[...] = image + numpy.random.randint(0, 20, size=image.shape) + + self.plot.addImage(image) + self.dataLayout.setCurrentWidget(self.plot) + + def _updateScatter(self): + xx, yy, value = createScatterData() + self.scatter.setData(xx, yy, value) + self.dataLayout.setCurrentWidget(self.scatter) + + def _updateStack(self): + a, b, c = numpy.meshgrid(numpy.linspace(-10, 10, 200), + numpy.linspace(-10, 5, 150), + numpy.linspace(-5, 10, 120), + indexing="ij") + raw = numpy.asarray(numpy.sin(a * b * c) / (a * b * c), + dtype='float32') + raw = numpy.abs(raw) + raw[numpy.isnan(raw)] = 0 + data = raw + numpy.random.poisson(raw * 10) + self.stack.setStack(data) + self.dataLayout.setCurrentWidget(self.stack) + +def main(): + app = qt.QApplication([]) + widget = Example() + widget.show() + app.exec_() + +if __name__ == "__main__": + main() diff --git a/examples/simplewidget.py b/examples/simplewidget.py index 88977b7..0e9038e 100755 --- a/examples/simplewidget.py +++ b/examples/simplewidget.py @@ -45,6 +45,7 @@ from silx.gui.widgets.WaitingPushButton import WaitingPushButton from silx.gui.widgets.ThreadPoolPushButton import ThreadPoolPushButton from silx.gui.widgets.RangeSlider import RangeSlider from silx.gui.widgets.LegendIconWidget import LegendIconWidget +from silx.gui.widgets.ElidedLabel import ElidedLabel class SimpleWidgetExample(qt.QMainWindow): @@ -74,6 +75,10 @@ class SimpleWidgetExample(qt.QMainWindow): layout.addWidget(qt.QLabel("LegendIconWidget")) layout.addWidget(panel) + panel = self.createElidedLabelPanel(self) + layout.addWidget(qt.QLabel("ElidedLabel")) + layout.addWidget(panel) + self.setCentralWidget(main_panel) def createWaitingPushButton(self): @@ -186,6 +191,25 @@ class SimpleWidgetExample(qt.QMainWindow): return panel + def createElidedLabelPanel(self, parent): + panel = qt.QWidget(parent) + layout = qt.QVBoxLayout(panel) + + label = ElidedLabel(parent) + label.setText("A very long text which is far too long.") + layout.addWidget(label) + + label = ElidedLabel(parent) + label.setText("A very long text which is far too long.") + label.setElideMode(qt.Qt.ElideMiddle) + layout.addWidget(label) + + label = ElidedLabel(parent) + label.setText("Basically nothing.") + layout.addWidget(label) + + return panel + def main(): """ diff --git a/examples/viewer3DVolume.py b/examples/viewer3DVolume.py index 4de04f6..2193402 100644 --- a/examples/viewer3DVolume.py +++ b/examples/viewer3DVolume.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2016-2017 European Synchrotron Radiation Facility +# Copyright (c) 2016-2020 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -74,7 +74,7 @@ def load(filename): filename, path = filename.split('::') path, indices = path.split('#')[0], path.split('#')[1:] - with h5py.File(filename) as f: + with h5py.File(filename, mode='r') as f: data = f[path] # Loop through indices along first dimensions |