summaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorAlexandre Marie <alexandre.marie@synchrotron-soleil.fr>2020-07-21 14:45:14 +0200
committerAlexandre Marie <alexandre.marie@synchrotron-soleil.fr>2020-07-21 14:45:14 +0200
commit328032e2317e3ac4859196bbf12bdb71795302fe (patch)
tree8cd13462beab109e3cb53410c42335b6d1e00ee6 /examples
parent33ed2a64c92b0311ae35456c016eb284e426afc2 (diff)
New upstream version 0.13.0+dfsg
Diffstat (limited to 'examples')
-rw-r--r--examples/colormapDialog.py36
-rw-r--r--examples/customSilxView.py88
-rw-r--r--examples/dropZones.py113
-rwxr-xr-xexamples/fftPlotAction.py4
-rw-r--r--examples/findContours.py7
-rwxr-xr-xexamples/hdf5widget.py2
-rw-r--r--examples/icons.py2
-rw-r--r--examples/imageStack.py143
-rw-r--r--examples/plotCurveLegendWidget.py6
-rw-r--r--examples/plotInteractiveImageROI.py8
-rwxr-xr-xexamples/plotItemsSelector.py4
-rw-r--r--examples/plotProfile.py207
-rwxr-xr-xexamples/simplewidget.py24
-rw-r--r--examples/viewer3DVolume.py4
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