From 8725dcca6831795de9548d209d2edf2a993211e7 Mon Sep 17 00:00:00 2001 From: edgar Date: Thu, 19 Sep 2024 19:30:45 +0200 Subject: [PATCH 01/21] support imageaggregate in _plot2d --- src/silx/gui/data/DataViews.py | 126 +++++++++++++++++++ src/silx/gui/plot/ImageView.py | 85 +------------ src/silx/gui/plot/PlotWindow.py | 12 ++ src/silx/gui/plot/actions/__init__.py | 1 + src/silx/gui/plot/actions/image.py | 131 ++++++++++++++++++++ src/silx/gui/plot/items/image_aggregated.py | 2 +- 6 files changed, 272 insertions(+), 85 deletions(-) create mode 100644 src/silx/gui/plot/actions/image.py diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index ed688b8e2e..b8c7198872 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -37,6 +37,8 @@ from silx.io.nxdata import get_attr_as_unicode from silx.gui.colors import Colormap from silx.gui.dialog.ColormapDialog import ColormapDialog +from silx.gui.plot.actions.image import ImageDataAggregated +from silx._utils import NP_OPTIONAL_COPY __authors__ = ["V. Valls", "P. Knobel"] __license__ = "MIT" @@ -1066,6 +1068,10 @@ def createWidget(self, parent): widget.setDefaultColormap(self.defaultColormap()) widget.getColormapAction().setColormapDialog(self.defaultColorDialog()) widget.getIntensityHistogramAction().setVisible(True) + widget.getAggregationModeAction().setVisible(True) + widget.getAggregationModeAction().sigAggregationModeChanged.connect( + self._aggregationModeChanged + ) widget.setKeepDataAspectRatio(True) widget.getXAxis().setLabel("X") widget.getYAxis().setLabel("Y") @@ -1073,6 +1079,117 @@ def createWidget(self, parent): maskToolsWidget.setItemMaskUpdated(True) return widget + def _aggregationModeChanged(self): + plot = self.getWidget() + item = plot._getItem("image") + if item is None: + return + + aggregationMode = plot.getAggregationModeAction().getAggregationMode() + if aggregationMode is not None and isinstance(item, ImageDataAggregated): + item.setAggregationMode(aggregationMode) + else: + image = item.getData(copy=False) + if image is None: + return + origin = item.getOrigin() + scale = item.getScale() + self.setAggregatedImage(image, origin, scale, copy=False, resetzoom=False) + + def setAggregatedImage( + self, + image, + origin=(0, 0), + scale=(1.0, 1.0), + copy=True, + reset=None, + resetzoom=True, + ): + """Set the image to display. + + :param image: A 2D array representing the image or None to empty plot. + :type image: numpy.ndarray-like with 2 dimensions or None. + :param origin: The (x, y) position of the origin of the image. + Default: (0, 0). + The origin is the lower left corner of the image when + the Y axis is not inverted. + :type origin: Tuple of 2 floats: (origin x, origin y). + :param scale: The scale factor to apply to the image on X and Y axes. + Default: (1, 1). + It is the size of a pixel in the coordinates of the axes. + Scales must be positive numbers. + :type scale: Tuple of 2 floats: (scale x, scale y). + :param bool copy: Whether to copy image data (default) or not. + :param bool reset: Deprecated. Alias for `resetzoom`. + :param bool resetzoom: Whether to reset zoom and ROI (default) or not. + """ + plot = self.getWidget() + legend = plot._getItem('image').getName() + + if reset is not None: + resetzoom = reset + + assert len(origin) == 2 + assert len(scale) == 2 + assert scale[0] > 0 + assert scale[1] > 0 + + + if image is None: + plot.remove(legend, kind="image") + return + + data = numpy.array(image, order="C", copy=copy or NP_OPTIONAL_COPY) + if data.size == 0: + plot.remove(legend, kind="image") + return + + assert data.ndim == 2 or (data.ndim == 3 and data.shape[2] in (3, 4)) + + aggregation = plot.getAggregationModeAction().getAggregationMode() + if data.ndim != 2 and aggregation is not None: + # RGB/A with aggregation is not supported + aggregation = ImageDataAggregated.Aggregation.NONE + + if aggregation is ImageDataAggregated.Aggregation.NONE: + self.addImage( + data, + legend=legend, + origin=origin, + scale=scale, + colormap=plot.getDefaultColormap(), + resetzoom=False, + ) + else: + item = plot._getItem("image", legend) + if isinstance(item, ImageDataAggregated): + item.setData(data) + item.setOrigin(origin) + item.setScale(scale) + else: + if isinstance(item, ImageDataAggregated): + print("holaaaa") + imageItem = item + wasCreated = False + else: + if item is not None: + plot.removeImage(legend) + imageItem = ImageDataAggregated() + imageItem.setName(legend) + imageItem.setColormap(plot.getDefaultColormap()) + wasCreated = True + imageItem.setData(data) + imageItem.setOrigin(origin) + imageItem.setScale(scale) + imageItem.setAggregationMode(aggregation) + if wasCreated: + print(f"adding: {type(imageItem)}") + plot.addItem(imageItem) + + plot.setActiveImage(legend) + if resetzoom: + plot.resetZoom() + def clear(self): self.getWidget().clear() self.__resetZoomNextTime = True @@ -1089,6 +1206,15 @@ def setData(self, data): ) self.__resetZoomNextTime = False + def setAggregatedData(self, data): + data = self.normalizeData(data) + self.getWidget().addImage( + legend="data", data=data, resetzoom=self.__resetZoomNextTime + ) + self.__resetZoomNextTime = False + + + def setDataSelection(self, selection): self.getWidget().setGraphTitle(self.titleForSelection(selection)) diff --git a/src/silx/gui/plot/ImageView.py b/src/silx/gui/plot/ImageView.py index 37710f03c5..31684c66d0 100644 --- a/src/silx/gui/plot/ImageView.py +++ b/src/silx/gui/plot/ImageView.py @@ -65,6 +65,7 @@ from . import _utils from .tools.profile import rois from .actions import PlotAction +from .actions.image import AggregationModeAction from silx._utils import NP_OPTIONAL_COPY _logger = logging.getLogger(__name__) @@ -353,90 +354,6 @@ def _actionTriggered(self, checked=False): self.plot.setSideHistogramDisplayed(checked) -class AggregationModeAction(qt.QWidgetAction): - """Action providing few filters to the image""" - - sigAggregationModeChanged = qt.Signal() - - def __init__(self, parent): - qt.QWidgetAction.__init__(self, parent) - - toolButton = qt.QToolButton(parent) - - filterAction = qt.QAction(self) - filterAction.setText("No filter") - filterAction.setCheckable(True) - filterAction.setChecked(True) - filterAction.setProperty( - "aggregation", items.ImageDataAggregated.Aggregation.NONE - ) - densityNoFilterAction = filterAction - - filterAction = qt.QAction(self) - filterAction.setText("Max filter") - filterAction.setCheckable(True) - filterAction.setProperty( - "aggregation", items.ImageDataAggregated.Aggregation.MAX - ) - densityMaxFilterAction = filterAction - - filterAction = qt.QAction(self) - filterAction.setText("Mean filter") - filterAction.setCheckable(True) - filterAction.setProperty( - "aggregation", items.ImageDataAggregated.Aggregation.MEAN - ) - densityMeanFilterAction = filterAction - - filterAction = qt.QAction(self) - filterAction.setText("Min filter") - filterAction.setCheckable(True) - filterAction.setProperty( - "aggregation", items.ImageDataAggregated.Aggregation.MIN - ) - densityMinFilterAction = filterAction - - densityGroup = qt.QActionGroup(self) - densityGroup.setExclusive(True) - densityGroup.addAction(densityNoFilterAction) - densityGroup.addAction(densityMaxFilterAction) - densityGroup.addAction(densityMeanFilterAction) - densityGroup.addAction(densityMinFilterAction) - densityGroup.triggered.connect(self._aggregationModeChanged) - self.__densityGroup = densityGroup - - filterMenu = qt.QMenu(toolButton) - filterMenu.addAction(densityNoFilterAction) - filterMenu.addAction(densityMaxFilterAction) - filterMenu.addAction(densityMeanFilterAction) - filterMenu.addAction(densityMinFilterAction) - - toolButton.setPopupMode(qt.QToolButton.InstantPopup) - toolButton.setMenu(filterMenu) - toolButton.setText("Data filters") - toolButton.setToolTip("Enable/disable filter on the image") - icon = icons.getQIcon("aggregation-mode") - toolButton.setIcon(icon) - toolButton.setText("Pixel aggregation filter") - - self.setDefaultWidget(toolButton) - - def _aggregationModeChanged(self): - self.sigAggregationModeChanged.emit() - - def setAggregationMode(self, mode): - """Set an Aggregated enum from ImageDataAggregated""" - for a in self.__densityGroup.actions(): - if a.property("aggregation") is mode: - a.setChecked(True) - - def getAggregationMode(self): - """Returns an Aggregated enum from ImageDataAggregated""" - densityAction = self.__densityGroup.checkedAction() - if densityAction is None: - return items.ImageDataAggregated.Aggregation.NONE - return densityAction.property("aggregation") - class ImageView(PlotWindow): """Display a single image with horizontal and vertical histograms. diff --git a/src/silx/gui/plot/PlotWindow.py b/src/silx/gui/plot/PlotWindow.py index 9aa8c78605..c896003c25 100644 --- a/src/silx/gui/plot/PlotWindow.py +++ b/src/silx/gui/plot/PlotWindow.py @@ -229,6 +229,11 @@ def __init__( ) self._intensityHistoAction.setVisible(False) + self.__aggregationModeAction = self.group.addAction( + actions.image.AggregationModeAction(parent=self) + ) + self.__aggregationModeAction.setVisible(False) + self._medianFilter2DAction = self.group.addAction( actions_medfilt.MedianFilter2DAction(self, parent=self) ) @@ -809,6 +814,13 @@ def getIntensityHistogramAction(self): :rtype: actions.PlotAction """ return self._intensityHistoAction + + def getAggregationModeAction(self): + """Action toggling the aggregation mode action + + :rtype: actions.PlotAction + """ + return self.__aggregationModeAction def getCopyAction(self): """Action to copy plot snapshot to clipboard diff --git a/src/silx/gui/plot/actions/__init__.py b/src/silx/gui/plot/actions/__init__.py index 3e606c6ec3..fd3072e6ed 100644 --- a/src/silx/gui/plot/actions/__init__.py +++ b/src/silx/gui/plot/actions/__init__.py @@ -39,3 +39,4 @@ from . import control from . import mode from . import io +from . import image diff --git a/src/silx/gui/plot/actions/image.py b/src/silx/gui/plot/actions/image.py new file mode 100644 index 0000000000..064921bac5 --- /dev/null +++ b/src/silx/gui/plot/actions/image.py @@ -0,0 +1,131 @@ +# /*########################################################################## +# +# Copyright (c) 2024 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. +# +# ###########################################################################*/ +""" +:mod:`silx.gui.plot.actions.image` provides a set of QAction relative to data processing +and outputs for a :class:`.PlotWidget`. + +The following QAction are available: + +- :class:`CopyAction` +- :class:`PrintAction` +- :class:`SaveAction` +""" + +__authors__ = ["T. Vincent"] +__license__ = "MIT" +__date__ = "19/09/2024" + + + + +import logging +from silx.gui import qt +from silx.gui import icons +from ..items.image_aggregated import ImageDataAggregated + +_logger = logging.getLogger(__name__) + +class AggregationModeAction(qt.QWidgetAction): + """Action providing few filters to the image""" + + sigAggregationModeChanged = qt.Signal() + + def __init__(self, parent): + qt.QWidgetAction.__init__(self, parent) + + toolButton = qt.QToolButton(parent) + + filterAction = qt.QAction(self) + filterAction.setText("No filter") + filterAction.setCheckable(True) + filterAction.setChecked(True) + filterAction.setProperty( + "aggregation", ImageDataAggregated.Aggregation.NONE + ) + densityNoFilterAction = filterAction + + filterAction = qt.QAction(self) + filterAction.setText("Max filter") + filterAction.setCheckable(True) + filterAction.setProperty( + "aggregation", ImageDataAggregated.Aggregation.MAX + ) + densityMaxFilterAction = filterAction + + filterAction = qt.QAction(self) + filterAction.setText("Mean filter") + filterAction.setCheckable(True) + filterAction.setProperty( + "aggregation", ImageDataAggregated.Aggregation.MEAN + ) + densityMeanFilterAction = filterAction + + filterAction = qt.QAction(self) + filterAction.setText("Min filter") + filterAction.setCheckable(True) + filterAction.setProperty( + "aggregation", ImageDataAggregated.Aggregation.MIN + ) + densityMinFilterAction = filterAction + + densityGroup = qt.QActionGroup(self) + densityGroup.setExclusive(True) + densityGroup.addAction(densityNoFilterAction) + densityGroup.addAction(densityMaxFilterAction) + densityGroup.addAction(densityMeanFilterAction) + densityGroup.addAction(densityMinFilterAction) + densityGroup.triggered.connect(self._aggregationModeChanged) + self.__densityGroup = densityGroup + + filterMenu = qt.QMenu(toolButton) + filterMenu.addAction(densityNoFilterAction) + filterMenu.addAction(densityMaxFilterAction) + filterMenu.addAction(densityMeanFilterAction) + filterMenu.addAction(densityMinFilterAction) + + toolButton.setPopupMode(qt.QToolButton.InstantPopup) + toolButton.setMenu(filterMenu) + toolButton.setText("Data filters") + toolButton.setToolTip("Enable/disable filter on the image") + icon = icons.getQIcon("aggregation-mode") + toolButton.setIcon(icon) + toolButton.setText("Pixel aggregation filter") + + self.setDefaultWidget(toolButton) + + def _aggregationModeChanged(self): + self.sigAggregationModeChanged.emit() + + def setAggregationMode(self, mode): + """Set an Aggregated enum from ImageDataAggregated""" + for a in self.__densityGroup.actions(): + if a.property("aggregation") is mode: + a.setChecked(True) + + def getAggregationMode(self): + """Returns an Aggregated enum from ImageDataAggregated""" + densityAction = self.__densityGroup.checkedAction() + if densityAction is None: + return ImageDataAggregated.Aggregation.NONE + return densityAction.property("aggregation") diff --git a/src/silx/gui/plot/items/image_aggregated.py b/src/silx/gui/plot/items/image_aggregated.py index c7c0f684d8..c75846d984 100644 --- a/src/silx/gui/plot/items/image_aggregated.py +++ b/src/silx/gui/plot/items/image_aggregated.py @@ -180,7 +180,7 @@ def _getLevelOfDetails(self) -> Tuple[int, int]: return lodx, lody @docstring(ImageDataBase) - def setData(self, data, copy=True): + def setData(self, data, copy=True, **kwargs): self.__cacheLODData = {} # Reset cache super().setData(data) From df68c578897898947042ce1d012edd17d8dde484 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Wed, 25 Sep 2024 17:10:59 +0200 Subject: [PATCH 02/21] add aggregation action in _Plot2dView --- src/silx/gui/data/DataViews.py | 17 +++++++++++++---- src/silx/gui/plot/PlotWindow.py | 12 ------------ 2 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index b8c7198872..98e0010d9b 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -38,6 +38,7 @@ from silx.gui.colors import Colormap from silx.gui.dialog.ColormapDialog import ColormapDialog from silx.gui.plot.actions.image import ImageDataAggregated +from silx.gui.plot.actions.image import AggregationModeAction from silx._utils import NP_OPTIONAL_COPY __authors__ = ["V. Valls", "P. Knobel"] @@ -1068,16 +1069,24 @@ def createWidget(self, parent): widget.setDefaultColormap(self.defaultColormap()) widget.getColormapAction().setColormapDialog(self.defaultColorDialog()) widget.getIntensityHistogramAction().setVisible(True) - widget.getAggregationModeAction().setVisible(True) - widget.getAggregationModeAction().sigAggregationModeChanged.connect( - self._aggregationModeChanged - ) + + self.__aggregationModeAction = AggregationModeAction(parent=widget) + widget.toolBar().addAction(self.__aggregationModeAction) + self.__aggregationModeAction.setVisible(True) + widget.setKeepDataAspectRatio(True) widget.getXAxis().setLabel("X") widget.getYAxis().setLabel("Y") maskToolsWidget = widget.getMaskToolsDockWidget().widget() maskToolsWidget.setItemMaskUpdated(True) return widget + + def getAggregationModeAction(self): + """Action toggling the aggregation mode action + + :rtype: actions.PlotAction + """ + return self.__aggregationModeAction def _aggregationModeChanged(self): plot = self.getWidget() diff --git a/src/silx/gui/plot/PlotWindow.py b/src/silx/gui/plot/PlotWindow.py index c896003c25..9aa8c78605 100644 --- a/src/silx/gui/plot/PlotWindow.py +++ b/src/silx/gui/plot/PlotWindow.py @@ -229,11 +229,6 @@ def __init__( ) self._intensityHistoAction.setVisible(False) - self.__aggregationModeAction = self.group.addAction( - actions.image.AggregationModeAction(parent=self) - ) - self.__aggregationModeAction.setVisible(False) - self._medianFilter2DAction = self.group.addAction( actions_medfilt.MedianFilter2DAction(self, parent=self) ) @@ -814,13 +809,6 @@ def getIntensityHistogramAction(self): :rtype: actions.PlotAction """ return self._intensityHistoAction - - def getAggregationModeAction(self): - """Action toggling the aggregation mode action - - :rtype: actions.PlotAction - """ - return self.__aggregationModeAction def getCopyAction(self): """Action to copy plot snapshot to clipboard From b07bc5375d59217157ac069b305380628ee2ab37 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Wed, 25 Sep 2024 18:41:47 +0200 Subject: [PATCH 03/21] imageaggregate by default --- src/silx/gui/data/DataViews.py | 51 +++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 98e0010d9b..27f33874e8 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1073,6 +1073,7 @@ def createWidget(self, parent): self.__aggregationModeAction = AggregationModeAction(parent=widget) widget.toolBar().addAction(self.__aggregationModeAction) self.__aggregationModeAction.setVisible(True) + self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) widget.setKeepDataAspectRatio(True) widget.getXAxis().setLabel("X") @@ -1091,19 +1092,27 @@ def getAggregationModeAction(self): def _aggregationModeChanged(self): plot = self.getWidget() item = plot._getItem("image") + legend = item.getName() + if item is None: return - - aggregationMode = plot.getAggregationModeAction().getAggregationMode() - if aggregationMode is not None and isinstance(item, ImageDataAggregated): - item.setAggregationMode(aggregationMode) - else: - image = item.getData(copy=False) - if image is None: - return + + if not isinstance(item, ImageDataAggregated): + data = item.getData() origin = item.getOrigin() scale = item.getScale() - self.setAggregatedImage(image, origin, scale, copy=False, resetzoom=False) + plot.removeImage(legend) + item = ImageDataAggregated() + item.setName(legend) + item.setColormap(plot.getDefaultColormap()) + item.setData(data) + item.setOrigin(origin) + item.setScale(scale) + plot.addItem(item) + plot.setActiveImage(legend) + + aggregationMode = self.getAggregationModeAction().getAggregationMode() + item.setAggregationMode(aggregationMode) def setAggregatedImage( self, @@ -1210,20 +1219,22 @@ def normalizeData(self, data): def setData(self, data): data = self.normalizeData(data) - self.getWidget().addImage( - legend="data", data=data, resetzoom=self.__resetZoomNextTime - ) - self.__resetZoomNextTime = False + plot = self.getWidget() + imageItem = plot._getItem("image") + + if imageItem is None: + imageItem = ImageDataAggregated() + imageItem.setData(data) + imageItem.setColormap(plot.getDefaultColormap()) + plot.addItem(imageItem) + plot.setActiveImage(imageItem.getName()) + plot.resetZoom() + else: + imageItem.setData(data) - def setAggregatedData(self, data): - data = self.normalizeData(data) - self.getWidget().addImage( - legend="data", data=data, resetzoom=self.__resetZoomNextTime - ) + imageItem.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) self.__resetZoomNextTime = False - - def setDataSelection(self, selection): self.getWidget().setGraphTitle(self.titleForSelection(selection)) From 14bf6d622bac572f5a94b247024c6f5a57bacf26 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Wed, 25 Sep 2024 18:44:50 +0200 Subject: [PATCH 04/21] no kwargs needed --- src/silx/gui/plot/items/image_aggregated.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/silx/gui/plot/items/image_aggregated.py b/src/silx/gui/plot/items/image_aggregated.py index c75846d984..c7c0f684d8 100644 --- a/src/silx/gui/plot/items/image_aggregated.py +++ b/src/silx/gui/plot/items/image_aggregated.py @@ -180,7 +180,7 @@ def _getLevelOfDetails(self) -> Tuple[int, int]: return lodx, lody @docstring(ImageDataBase) - def setData(self, data, copy=True, **kwargs): + def setData(self, data, copy=True): self.__cacheLODData = {} # Reset cache super().setData(data) From 044a912e104a3507cebd67d2180c71958e549a5b Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Thu, 26 Sep 2024 11:58:57 +0200 Subject: [PATCH 05/21] predefined imagedataaggregatd --- src/silx/gui/data/DataViews.py | 120 +------------------- src/silx/gui/plot/items/image_aggregated.py | 2 +- 2 files changed, 6 insertions(+), 116 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 27f33874e8..a869ec196a 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1092,122 +1092,13 @@ def getAggregationModeAction(self): def _aggregationModeChanged(self): plot = self.getWidget() item = plot._getItem("image") - legend = item.getName() if item is None: return - - if not isinstance(item, ImageDataAggregated): - data = item.getData() - origin = item.getOrigin() - scale = item.getScale() - plot.removeImage(legend) - item = ImageDataAggregated() - item.setName(legend) - item.setColormap(plot.getDefaultColormap()) - item.setData(data) - item.setOrigin(origin) - item.setScale(scale) - plot.addItem(item) - plot.setActiveImage(legend) aggregationMode = self.getAggregationModeAction().getAggregationMode() item.setAggregationMode(aggregationMode) - def setAggregatedImage( - self, - image, - origin=(0, 0), - scale=(1.0, 1.0), - copy=True, - reset=None, - resetzoom=True, - ): - """Set the image to display. - - :param image: A 2D array representing the image or None to empty plot. - :type image: numpy.ndarray-like with 2 dimensions or None. - :param origin: The (x, y) position of the origin of the image. - Default: (0, 0). - The origin is the lower left corner of the image when - the Y axis is not inverted. - :type origin: Tuple of 2 floats: (origin x, origin y). - :param scale: The scale factor to apply to the image on X and Y axes. - Default: (1, 1). - It is the size of a pixel in the coordinates of the axes. - Scales must be positive numbers. - :type scale: Tuple of 2 floats: (scale x, scale y). - :param bool copy: Whether to copy image data (default) or not. - :param bool reset: Deprecated. Alias for `resetzoom`. - :param bool resetzoom: Whether to reset zoom and ROI (default) or not. - """ - plot = self.getWidget() - legend = plot._getItem('image').getName() - - if reset is not None: - resetzoom = reset - - assert len(origin) == 2 - assert len(scale) == 2 - assert scale[0] > 0 - assert scale[1] > 0 - - - if image is None: - plot.remove(legend, kind="image") - return - - data = numpy.array(image, order="C", copy=copy or NP_OPTIONAL_COPY) - if data.size == 0: - plot.remove(legend, kind="image") - return - - assert data.ndim == 2 or (data.ndim == 3 and data.shape[2] in (3, 4)) - - aggregation = plot.getAggregationModeAction().getAggregationMode() - if data.ndim != 2 and aggregation is not None: - # RGB/A with aggregation is not supported - aggregation = ImageDataAggregated.Aggregation.NONE - - if aggregation is ImageDataAggregated.Aggregation.NONE: - self.addImage( - data, - legend=legend, - origin=origin, - scale=scale, - colormap=plot.getDefaultColormap(), - resetzoom=False, - ) - else: - item = plot._getItem("image", legend) - if isinstance(item, ImageDataAggregated): - item.setData(data) - item.setOrigin(origin) - item.setScale(scale) - else: - if isinstance(item, ImageDataAggregated): - print("holaaaa") - imageItem = item - wasCreated = False - else: - if item is not None: - plot.removeImage(legend) - imageItem = ImageDataAggregated() - imageItem.setName(legend) - imageItem.setColormap(plot.getDefaultColormap()) - wasCreated = True - imageItem.setData(data) - imageItem.setOrigin(origin) - imageItem.setScale(scale) - imageItem.setAggregationMode(aggregation) - if wasCreated: - print(f"adding: {type(imageItem)}") - plot.addItem(imageItem) - - plot.setActiveImage(legend) - if resetzoom: - plot.resetZoom() - def clear(self): self.getWidget().clear() self.__resetZoomNextTime = True @@ -1224,15 +1115,14 @@ def setData(self, data): if imageItem is None: imageItem = ImageDataAggregated() - imageItem.setData(data) + imageItem.setName("data") imageItem.setColormap(plot.getDefaultColormap()) plot.addItem(imageItem) - plot.setActiveImage(imageItem.getName()) - plot.resetZoom() - else: - imageItem.setData(data) - imageItem.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) + + plot.addImage( + legend="data", data=data, resetzoom=self.__resetZoomNextTime + ) self.__resetZoomNextTime = False def setDataSelection(self, selection): diff --git a/src/silx/gui/plot/items/image_aggregated.py b/src/silx/gui/plot/items/image_aggregated.py index c7c0f684d8..c75846d984 100644 --- a/src/silx/gui/plot/items/image_aggregated.py +++ b/src/silx/gui/plot/items/image_aggregated.py @@ -180,7 +180,7 @@ def _getLevelOfDetails(self) -> Tuple[int, int]: return lodx, lody @docstring(ImageDataBase) - def setData(self, data, copy=True): + def setData(self, data, copy=True, **kwargs): self.__cacheLODData = {} # Reset cache super().setData(data) From af982014d21192a73a60877d8a310a91d1ba9729 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Thu, 26 Sep 2024 12:03:36 +0200 Subject: [PATCH 06/21] suggestions --- src/silx/gui/plot/actions/image.py | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/silx/gui/plot/actions/image.py b/src/silx/gui/plot/actions/image.py index 064921bac5..387f117a64 100644 --- a/src/silx/gui/plot/actions/image.py +++ b/src/silx/gui/plot/actions/image.py @@ -27,18 +27,13 @@ The following QAction are available: -- :class:`CopyAction` -- :class:`PrintAction` -- :class:`SaveAction` +- :class:`AggregationModeAction` """ __authors__ = ["T. Vincent"] __license__ = "MIT" __date__ = "19/09/2024" - - - import logging from silx.gui import qt from silx.gui import icons @@ -47,9 +42,10 @@ _logger = logging.getLogger(__name__) class AggregationModeAction(qt.QWidgetAction): - """Action providing few filters to the image""" + """Action providing filters for an aggregated image""" sigAggregationModeChanged = qt.Signal() + """Signal emitted when the aggregation mode has changed""" def __init__(self, parent): qt.QWidgetAction.__init__(self, parent) From 3b43874a74e46f2c016ed03ac16f78c775bebe67 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Thu, 26 Sep 2024 13:40:08 +0200 Subject: [PATCH 07/21] blank --- src/silx/gui/data/DataViews.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index a869ec196a..2ba6a86d22 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1119,7 +1119,6 @@ def setData(self, data): imageItem.setColormap(plot.getDefaultColormap()) plot.addItem(imageItem) - plot.addImage( legend="data", data=data, resetzoom=self.__resetZoomNextTime ) From 73e566f2f64c228fa95ef4db4a5890ecbfbe8405 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Thu, 26 Sep 2024 14:02:58 +0200 Subject: [PATCH 08/21] set aggregation mode in set data --- src/silx/gui/data/DataViews.py | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 2ba6a86d22..3a622748a7 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1115,6 +1115,7 @@ def setData(self, data): if imageItem is None: imageItem = ImageDataAggregated() + imageItem.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) imageItem.setName("data") imageItem.setColormap(plot.getDefaultColormap()) plot.addItem(imageItem) @@ -1827,8 +1828,31 @@ def createWidget(self, parent): widget.getPlot().getColormapAction().setColormapDialog( self.defaultColorDialog() ) + + self.__aggregationModeAction = AggregationModeAction(parent=widget.getPlot()) + widget.getPlot().toolBar().addAction(self.__aggregationModeAction) + self.__aggregationModeAction.setVisible(True) + #self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) + return widget + def getAggregationModeAction(self): + """Action toggling the aggregation mode action + + :rtype: actions.PlotAction + """ + return self.__aggregationModeAction + + def _aggregationModeChanged(self): + plot = self.getWidget().getPlot() + item = plot._getItem("image") + + if item is None: + return + + aggregationMode = self.getAggregationModeAction().getAggregationMode() + item.setAggregationMode(aggregationMode) + def axesNames(self, data, info): # disabled (used by default axis selector widget in Hdf5Viewer) return None From fa45a02b81a1fe8879e7a0d6985573aadcf02689 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Thu, 26 Sep 2024 16:47:54 +0200 Subject: [PATCH 09/21] setdata --- src/silx/gui/data/DataViews.py | 11 ++++------- src/silx/gui/plot/items/image_aggregated.py | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 3a622748a7..38a42cfc9f 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1072,7 +1072,6 @@ def createWidget(self, parent): self.__aggregationModeAction = AggregationModeAction(parent=widget) widget.toolBar().addAction(self.__aggregationModeAction) - self.__aggregationModeAction.setVisible(True) self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) widget.setKeepDataAspectRatio(True) @@ -1082,10 +1081,8 @@ def createWidget(self, parent): maskToolsWidget.setItemMaskUpdated(True) return widget - def getAggregationModeAction(self): + def getAggregationModeAction(self) -> AggregationModeAction: """Action toggling the aggregation mode action - - :rtype: actions.PlotAction """ return self.__aggregationModeAction @@ -1120,9 +1117,9 @@ def setData(self, data): imageItem.setColormap(plot.getDefaultColormap()) plot.addItem(imageItem) - plot.addImage( - legend="data", data=data, resetzoom=self.__resetZoomNextTime - ) + imageItem.setData(data=data) + if self.__resetZoomNextTime: + plot.resetZoom() self.__resetZoomNextTime = False def setDataSelection(self, selection): diff --git a/src/silx/gui/plot/items/image_aggregated.py b/src/silx/gui/plot/items/image_aggregated.py index c75846d984..c7c0f684d8 100644 --- a/src/silx/gui/plot/items/image_aggregated.py +++ b/src/silx/gui/plot/items/image_aggregated.py @@ -180,7 +180,7 @@ def _getLevelOfDetails(self) -> Tuple[int, int]: return lodx, lody @docstring(ImageDataBase) - def setData(self, data, copy=True, **kwargs): + def setData(self, data, copy=True): self.__cacheLODData = {} # Reset cache super().setData(data) From 6216f465910ec5f20e61d8e0d359508adab93058 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Thu, 26 Sep 2024 16:49:53 +0200 Subject: [PATCH 10/21] correction --- src/silx/gui/data/DataViews.py | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 38a42cfc9f..694bff7859 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1826,30 +1826,8 @@ def createWidget(self, parent): self.defaultColorDialog() ) - self.__aggregationModeAction = AggregationModeAction(parent=widget.getPlot()) - widget.getPlot().toolBar().addAction(self.__aggregationModeAction) - self.__aggregationModeAction.setVisible(True) - #self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) - return widget - def getAggregationModeAction(self): - """Action toggling the aggregation mode action - - :rtype: actions.PlotAction - """ - return self.__aggregationModeAction - - def _aggregationModeChanged(self): - plot = self.getWidget().getPlot() - item = plot._getItem("image") - - if item is None: - return - - aggregationMode = self.getAggregationModeAction().getAggregationMode() - item.setAggregationMode(aggregationMode) - def axesNames(self, data, info): # disabled (used by default axis selector widget in Hdf5Viewer) return None From ba5ec271a05aaa68052783e4d20807f9d4b379a5 Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Thu, 26 Sep 2024 16:50:18 +0200 Subject: [PATCH 11/21] typo --- src/silx/gui/data/DataViews.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 694bff7859..474f2aeff1 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1825,7 +1825,6 @@ def createWidget(self, parent): widget.getPlot().getColormapAction().setColormapDialog( self.defaultColorDialog() ) - return widget def axesNames(self, data, info): From 5ab1d1959df62b9859c1294d5697355114216f6b Mon Sep 17 00:00:00 2001 From: Edgar Date: Sun, 29 Sep 2024 11:40:39 +0200 Subject: [PATCH 12/21] imageaggregate in NXdataWidget --- src/silx/gui/data/DataViews.py | 27 +++++++++++++++++++++++++++ src/silx/gui/data/NXdataWidgets.py | 19 +++++++++++-------- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 474f2aeff1..22138510c7 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1825,7 +1825,26 @@ def createWidget(self, parent): widget.getPlot().getColormapAction().setColormapDialog( self.defaultColorDialog() ) + self.__aggregationModeAction = AggregationModeAction(parent=widget) + widget.getPlot().toolBar().addAction(self.__aggregationModeAction) + self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) return widget + + def getAggregationModeAction(self) -> AggregationModeAction: + """Action toggling the aggregation mode action + """ + return self.__aggregationModeAction + + def _aggregationModeChanged(self): + plot = self.getWidget().getPlot() + item = plot._getItem("image") + + if item is None: + return + + if isinstance(item, ImageDataAggregated): + aggregationMode = self.getAggregationModeAction().getAggregationMode() + item.setAggregationMode(aggregationMode) def axesNames(self, data, info): # disabled (used by default axis selector widget in Hdf5Viewer) @@ -1862,6 +1881,14 @@ def setData(self, data): yscale=y_scale, keep_ratio=(x_units == y_units), ) + + item = self.getWidget().getPlot()._getItem("image") + + if item is None: + return + + if isinstance(item, ImageDataAggregated): + item.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) def getDataPriority(self, data, info): data = self.normalizeData(data) diff --git a/src/silx/gui/data/NXdataWidgets.py b/src/silx/gui/data/NXdataWidgets.py index a2bab7a3d8..8fabd801d4 100644 --- a/src/silx/gui/data/NXdataWidgets.py +++ b/src/silx/gui/data/NXdataWidgets.py @@ -34,6 +34,7 @@ from silx.gui.data.NumpyAxesSelector import NumpyAxesSelector from silx.gui.plot import Plot1D, Plot2D, StackView, ScatterView, items from silx.gui.plot.ComplexImageView import ComplexImageView +from silx.gui.plot.items.image_aggregated import ImageDataAggregated from silx.gui.colors import Colormap from silx.gui.widgets.FrameBrowser import HorizontalSliderWithBrowser @@ -555,6 +556,10 @@ def _updateImage(self): "image", ) ) + imageItem = ImageDataAggregated() + imageItem.setName(legend) + self._plot.addItem(imageItem) + if xcalib.is_affine() and ycalib.is_affine(): # regular image xorigin, xscale = xcalib(0), xcalib.get_slope() @@ -564,14 +569,12 @@ def _updateImage(self): self._plot.getXAxis().setScale("linear") self._plot.getYAxis().setScale("linear") - self._plot.addImage( - image, - legend=legend, - origin=origin, - scale=scale, - replace=True, - resetzoom=False, - ) + + imageItem.setData(image) + imageItem.setOrigin(origin) + imageItem.setScale(scale) + imageItem.setColormap(self._plot.getDefaultColormap()) + else: xaxisscale, yaxisscale = self._axis_scales From 1e44061e4e9d2f0a5cc16797163a36cec6a9e87d Mon Sep 17 00:00:00 2001 From: Edgar Date: Sun, 29 Sep 2024 11:42:22 +0200 Subject: [PATCH 13/21] simplify --- src/silx/gui/data/DataViews.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 22138510c7..f9e810343f 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1843,8 +1843,7 @@ def _aggregationModeChanged(self): return if isinstance(item, ImageDataAggregated): - aggregationMode = self.getAggregationModeAction().getAggregationMode() - item.setAggregationMode(aggregationMode) + item.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) def axesNames(self, data, info): # disabled (used by default axis selector widget in Hdf5Viewer) From ed3e275b36f3e97b1738fdf0c9b358187058196e Mon Sep 17 00:00:00 2001 From: Edgar Date: Sun, 29 Sep 2024 12:26:52 +0200 Subject: [PATCH 14/21] stackview inherits from ImageDataAggregated --- src/silx/gui/data/DataViews.py | 19 +++++++++++++++++++ src/silx/gui/plot/items/image.py | 5 +++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index f9e810343f..36ad358e14 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1335,8 +1335,27 @@ def createWidget(self, parent): widget.setOptionVisible(False) maskToolWidget = widget.getPlotWidget().getMaskToolsDockWidget().widget() maskToolWidget.setItemMaskUpdated(True) + self.__aggregationModeAction = AggregationModeAction(parent=widget) + widget.getPlotWidget().toolBar().addAction(self.__aggregationModeAction) + self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) return widget + def getAggregationModeAction(self) -> AggregationModeAction: + """Action toggling the aggregation mode action + """ + return self.__aggregationModeAction + + def _aggregationModeChanged(self): + plot = self.getWidget().getPlotWidget() + item = plot._getItem("image") + + if item is None: + return + + if isinstance(item, ImageDataAggregated): + aggregationMode = self.getAggregationModeAction().getAggregationMode() + item.setAggregationMode(aggregationMode) + def clear(self): self.getWidget().clear() self.__resetZoomNextTime = True diff --git a/src/silx/gui/plot/items/image.py b/src/silx/gui/plot/items/image.py index 4046b65630..c462b711a1 100644 --- a/src/silx/gui/plot/items/image.py +++ b/src/silx/gui/plot/items/image.py @@ -595,8 +595,9 @@ class MaskImageData(ImageData): pass +from .image_aggregated import ImageDataAggregated -class ImageStack(ImageData): +class ImageStack(ImageDataAggregated): """Item to store a stack of images and to show it in the plot as one of the images of the stack. @@ -605,7 +606,7 @@ class ImageStack(ImageData): """ def __init__(self): - ImageData.__init__(self) + ImageDataAggregated.__init__(self) self.__stack = None """A 3D numpy array (or a mimic one, see ListOfImages)""" self.__stackPosition = None From ea0bd4c1f48cf850741fd38eda276f7ed316ce4e Mon Sep 17 00:00:00 2001 From: Edgar Date: Sun, 27 Oct 2024 18:21:04 +0100 Subject: [PATCH 15/21] aggregation items to ArrayImagePlot --- src/silx/gui/data/DataViews.py | 23 ++--------------------- src/silx/gui/data/NXdataWidgets.py | 29 ++++++++++++++++++++++++----- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 36ad358e14..21feb7de0f 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -37,7 +37,7 @@ from silx.io.nxdata import get_attr_as_unicode from silx.gui.colors import Colormap from silx.gui.dialog.ColormapDialog import ColormapDialog -from silx.gui.plot.actions.image import ImageDataAggregated +from silx.gui.plot.items.image import ImageDataAggregated from silx.gui.plot.actions.image import AggregationModeAction from silx._utils import NP_OPTIONAL_COPY @@ -1844,26 +1844,7 @@ def createWidget(self, parent): widget.getPlot().getColormapAction().setColormapDialog( self.defaultColorDialog() ) - self.__aggregationModeAction = AggregationModeAction(parent=widget) - widget.getPlot().toolBar().addAction(self.__aggregationModeAction) - self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) return widget - - def getAggregationModeAction(self) -> AggregationModeAction: - """Action toggling the aggregation mode action - """ - return self.__aggregationModeAction - - def _aggregationModeChanged(self): - plot = self.getWidget().getPlot() - item = plot._getItem("image") - - if item is None: - return - - if isinstance(item, ImageDataAggregated): - item.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) - def axesNames(self, data, info): # disabled (used by default axis selector widget in Hdf5Viewer) return None @@ -1906,7 +1887,7 @@ def setData(self, data): return if isinstance(item, ImageDataAggregated): - item.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) + item.setAggregationMode(self.getWidget().getAggregationModeAction().getAggregationMode()) def getDataPriority(self, data, info): data = self.normalizeData(data) diff --git a/src/silx/gui/data/NXdataWidgets.py b/src/silx/gui/data/NXdataWidgets.py index 8fabd801d4..28c2169e38 100644 --- a/src/silx/gui/data/NXdataWidgets.py +++ b/src/silx/gui/data/NXdataWidgets.py @@ -35,6 +35,7 @@ from silx.gui.plot import Plot1D, Plot2D, StackView, ScatterView, items from silx.gui.plot.ComplexImageView import ComplexImageView from silx.gui.plot.items.image_aggregated import ImageDataAggregated +from silx.gui.plot.actions.image import AggregationModeAction from silx.gui.colors import Colormap from silx.gui.widgets.FrameBrowser import HorizontalSliderWithBrowser @@ -423,7 +424,25 @@ def __init__(self, parent=None): layout.addWidget(self._auxSigSlider) self.setLayout(layout) + + self.__aggregationModeAction = AggregationModeAction(parent=self) + self.getPlot().toolBar().addAction(self.__aggregationModeAction) + self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) + + def getAggregationModeAction(self) -> AggregationModeAction: + """Action toggling the aggregation mode action + """ + return self.__aggregationModeAction + def _aggregationModeChanged(self): + item = self.getPlot()._getItem("image") + + if item is None: + return + + if isinstance(item, ImageDataAggregated): + item.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) + def _sliderIdxChanged(self, value): self._updateImage() @@ -556,10 +575,7 @@ def _updateImage(self): "image", ) ) - imageItem = ImageDataAggregated() - imageItem.setName(legend) - self._plot.addItem(imageItem) - + if xcalib.is_affine() and ycalib.is_affine(): # regular image xorigin, xscale = xcalib(0), xcalib.get_slope() @@ -570,11 +586,14 @@ def _updateImage(self): self._plot.getXAxis().setScale("linear") self._plot.getYAxis().setScale("linear") + imageItem = ImageDataAggregated() + imageItem.setName(legend) imageItem.setData(image) imageItem.setOrigin(origin) imageItem.setScale(scale) imageItem.setColormap(self._plot.getDefaultColormap()) - + imageItem.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) + self._plot.addItem(imageItem) else: xaxisscale, yaxisscale = self._axis_scales From ef444ad6b50389991d0839472ab8fa2e6cbccc92 Mon Sep 17 00:00:00 2001 From: Edgar Date: Sun, 27 Oct 2024 18:27:01 +0100 Subject: [PATCH 16/21] aggregation items to StackView --- src/silx/gui/data/DataViews.py | 19 ------------------- src/silx/gui/plot/StackView.py | 22 ++++++++++++++++++++++ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 21feb7de0f..f04add1e7c 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1335,26 +1335,7 @@ def createWidget(self, parent): widget.setOptionVisible(False) maskToolWidget = widget.getPlotWidget().getMaskToolsDockWidget().widget() maskToolWidget.setItemMaskUpdated(True) - self.__aggregationModeAction = AggregationModeAction(parent=widget) - widget.getPlotWidget().toolBar().addAction(self.__aggregationModeAction) - self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) return widget - - def getAggregationModeAction(self) -> AggregationModeAction: - """Action toggling the aggregation mode action - """ - return self.__aggregationModeAction - - def _aggregationModeChanged(self): - plot = self.getWidget().getPlotWidget() - item = plot._getItem("image") - - if item is None: - return - - if isinstance(item, ImageDataAggregated): - aggregationMode = self.getAggregationModeAction().getAggregationMode() - item.setAggregationMode(aggregationMode) def clear(self): self.getWidget().clear() diff --git a/src/silx/gui/plot/StackView.py b/src/silx/gui/plot/StackView.py index 85bc50f944..63b8f59eeb 100644 --- a/src/silx/gui/plot/StackView.py +++ b/src/silx/gui/plot/StackView.py @@ -86,6 +86,8 @@ from silx._utils import NP_OPTIONAL_COPY from silx.gui.plot.actions import io as silx_io +from silx.gui.plot.items.image_aggregated import ImageDataAggregated +from silx.gui.plot.actions.image import AggregationModeAction from silx.io.nxdata import save_NXdata from silx.utils.array_like import DatasetView, ListOfImages from silx.math import calibration @@ -289,6 +291,26 @@ def __init__( self.__planeSelection.sigPlaneSelectionChanged.connect( self._profileToolBar.clearProfile ) + + self.__aggregationModeAction = AggregationModeAction(parent=self) + self._plot.toolBar().addAction(self.__aggregationModeAction) + self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) + + def getAggregationModeAction(self) -> AggregationModeAction: + """Action toggling the aggregation mode action + """ + return self.__aggregationModeAction + + def _aggregationModeChanged(self): + plot = self.getPlotWidget() + item = plot._getItem("image") + + if item is None: + return + + if isinstance(item, ImageDataAggregated): + aggregationMode = self.getAggregationModeAction().getAggregationMode() + item.setAggregationMode(aggregationMode) def _saveImageStack(self, plot, filename, nameFilter): """Save all images from the stack into a volume. From 8f58e87dd6b1aed34bfc6e76997a9c9b186ec00b Mon Sep 17 00:00:00 2001 From: Edgar Gutierrez Fernandez Date: Wed, 13 Nov 2024 09:22:22 +0100 Subject: [PATCH 17/21] again --- src/silx/gui/plot/items/image.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/silx/gui/plot/items/image.py b/src/silx/gui/plot/items/image.py index c462b711a1..72fe1796fd 100644 --- a/src/silx/gui/plot/items/image.py +++ b/src/silx/gui/plot/items/image.py @@ -1,4 +1,4 @@ -# /*########################################################################## +# /*######################################################################### # # Copyright (c) 2017-2023 European Synchrotron Radiation Facility # @@ -20,7 +20,7 @@ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # -# ###########################################################################*/ +# ##########################################################################*/ """This module provides the :class:`ImageData` and :class:`ImageRgba` items of the :class:`Plot`. """ From c8d19dd910d71057c744047494b4659213bf3eb4 Mon Sep 17 00:00:00 2001 From: Thomas VINCENT Date: Mon, 18 Nov 2024 16:25:47 +0100 Subject: [PATCH 18/21] simpler implementation by using self._stackItem --- src/silx/gui/plot/StackView.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/silx/gui/plot/StackView.py b/src/silx/gui/plot/StackView.py index 63b8f59eeb..86a2dbe938 100644 --- a/src/silx/gui/plot/StackView.py +++ b/src/silx/gui/plot/StackView.py @@ -302,15 +302,7 @@ def getAggregationModeAction(self) -> AggregationModeAction: return self.__aggregationModeAction def _aggregationModeChanged(self): - plot = self.getPlotWidget() - item = plot._getItem("image") - - if item is None: - return - - if isinstance(item, ImageDataAggregated): - aggregationMode = self.getAggregationModeAction().getAggregationMode() - item.setAggregationMode(aggregationMode) + self._stackItem.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) def _saveImageStack(self, plot, filename, nameFilter): """Save all images from the stack into a volume. From c934c5ecdc1b5367dd1b8231727cc6a7c2b35a55 Mon Sep 17 00:00:00 2001 From: Thomas VINCENT Date: Mon, 18 Nov 2024 16:26:43 +0100 Subject: [PATCH 19/21] remove unused import and useless code in _NXdataImageView it's already done in ArrayImagePlot --- src/silx/gui/data/DataViews.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index f04add1e7c..5c8c5dc762 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -39,7 +39,6 @@ from silx.gui.dialog.ColormapDialog import ColormapDialog from silx.gui.plot.items.image import ImageDataAggregated from silx.gui.plot.actions.image import AggregationModeAction -from silx._utils import NP_OPTIONAL_COPY __authors__ = ["V. Valls", "P. Knobel"] __license__ = "MIT" @@ -1336,7 +1335,7 @@ def createWidget(self, parent): maskToolWidget = widget.getPlotWidget().getMaskToolsDockWidget().widget() maskToolWidget.setItemMaskUpdated(True) return widget - + def clear(self): self.getWidget().clear() self.__resetZoomNextTime = True @@ -1826,6 +1825,7 @@ def createWidget(self, parent): self.defaultColorDialog() ) return widget + def axesNames(self, data, info): # disabled (used by default axis selector widget in Hdf5Viewer) return None @@ -1861,14 +1861,6 @@ def setData(self, data): yscale=y_scale, keep_ratio=(x_units == y_units), ) - - item = self.getWidget().getPlot()._getItem("image") - - if item is None: - return - - if isinstance(item, ImageDataAggregated): - item.setAggregationMode(self.getWidget().getAggregationModeAction().getAggregationMode()) def getDataPriority(self, data, info): data = self.normalizeData(data) From bb290adb829d4aac983cf92156ff1ad14a4103ad Mon Sep 17 00:00:00 2001 From: Thomas VINCENT Date: Mon, 18 Nov 2024 16:54:52 +0100 Subject: [PATCH 20/21] simplify implementation by reusing the same item --- src/silx/gui/data/DataViews.py | 34 ++++++++++------------------------ 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 5c8c5dc762..6acc9c5bce 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1073,30 +1073,24 @@ def createWidget(self, parent): widget.toolBar().addAction(self.__aggregationModeAction) self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged) + self.__imageItem = ImageDataAggregated() + self.__imageItem.setAggregationMode(self.__aggregationModeAction.getAggregationMode()) + self.__imageItem.setName("data") + self.__imageItem.setColormap(widget.getDefaultColormap()) + widget.addItem(self.__imageItem) + widget.setKeepDataAspectRatio(True) widget.getXAxis().setLabel("X") widget.getYAxis().setLabel("Y") maskToolsWidget = widget.getMaskToolsDockWidget().widget() maskToolsWidget.setItemMaskUpdated(True) return widget - - def getAggregationModeAction(self) -> AggregationModeAction: - """Action toggling the aggregation mode action - """ - return self.__aggregationModeAction def _aggregationModeChanged(self): - plot = self.getWidget() - item = plot._getItem("image") - - if item is None: - return - - aggregationMode = self.getAggregationModeAction().getAggregationMode() - item.setAggregationMode(aggregationMode) + self.__imageItem.setAggregationMode(self.__aggregationModeAction.getAggregationMode()) def clear(self): - self.getWidget().clear() + self.__imageItem.setData(numpy.zeros((0, 0), dtype=numpy.float32)) self.__resetZoomNextTime = True def normalizeData(self, data): @@ -1107,16 +1101,8 @@ def normalizeData(self, data): def setData(self, data): data = self.normalizeData(data) plot = self.getWidget() - imageItem = plot._getItem("image") - - if imageItem is None: - imageItem = ImageDataAggregated() - imageItem.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) - imageItem.setName("data") - imageItem.setColormap(plot.getDefaultColormap()) - plot.addItem(imageItem) - - imageItem.setData(data=data) + + self.__imageItem.setData(data=data) if self.__resetZoomNextTime: plot.resetZoom() self.__resetZoomNextTime = False From e6868fe0e99971da5993594c9b5fc1ac059e34c0 Mon Sep 17 00:00:00 2001 From: Thomas VINCENT Date: Mon, 18 Nov 2024 16:55:26 +0100 Subject: [PATCH 21/21] Make the image active to enable mask and histogram --- src/silx/gui/data/DataViews.py | 1 + src/silx/gui/data/NXdataWidgets.py | 1 + 2 files changed, 2 insertions(+) diff --git a/src/silx/gui/data/DataViews.py b/src/silx/gui/data/DataViews.py index 6acc9c5bce..5107227965 100644 --- a/src/silx/gui/data/DataViews.py +++ b/src/silx/gui/data/DataViews.py @@ -1078,6 +1078,7 @@ def createWidget(self, parent): self.__imageItem.setName("data") self.__imageItem.setColormap(widget.getDefaultColormap()) widget.addItem(self.__imageItem) + widget.setActiveImage(self.__imageItem) widget.setKeepDataAspectRatio(True) widget.getXAxis().setLabel("X") diff --git a/src/silx/gui/data/NXdataWidgets.py b/src/silx/gui/data/NXdataWidgets.py index 28c2169e38..147bcfcac9 100644 --- a/src/silx/gui/data/NXdataWidgets.py +++ b/src/silx/gui/data/NXdataWidgets.py @@ -594,6 +594,7 @@ def _updateImage(self): imageItem.setColormap(self._plot.getDefaultColormap()) imageItem.setAggregationMode(self.getAggregationModeAction().getAggregationMode()) self._plot.addItem(imageItem) + self._plot.setActiveImage(imageItem) else: xaxisscale, yaxisscale = self._axis_scales