Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

silx.gui: support imageaggregate in _plot2d #4174

Merged
merged 23 commits into from
Nov 26, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 81 additions & 3 deletions src/silx/gui/data/DataViews.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
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
EdgarGF93 marked this conversation as resolved.
Show resolved Hide resolved
from silx.gui.plot.actions.image import AggregationModeAction
from silx._utils import NP_OPTIONAL_COPY

__authors__ = ["V. Valls", "P. Knobel"]
__license__ = "MIT"
Expand Down Expand Up @@ -1066,12 +1069,32 @@ def createWidget(self, parent):
widget.setDefaultColormap(self.defaultColormap())
widget.getColormapAction().setColormapDialog(self.defaultColorDialog())
widget.getIntensityHistogramAction().setVisible(True)

self.__aggregationModeAction = AggregationModeAction(parent=widget)
widget.toolBar().addAction(self.__aggregationModeAction)
self.__aggregationModeAction.sigAggregationModeChanged.connect(self._aggregationModeChanged)

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)

def clear(self):
self.getWidget().clear()
Expand All @@ -1084,9 +1107,19 @@ def normalizeData(self, data):

def setData(self, data):
data = self.normalizeData(data)
self.getWidget().addImage(
legend="data", data=data, resetzoom=self.__resetZoomNextTime
)
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)
if self.__resetZoomNextTime:
plot.resetZoom()
self.__resetZoomNextTime = False

def setDataSelection(self, selection):
Expand Down Expand Up @@ -1302,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)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add the AggregationModeAction in the widget which controls the item in the plot.

  • For _Plot2dView above, it is the widget that controls the plot item.
  • Here, the widget controlling the plot item is the StackView, so best to control it's plot item from this widget. Otherwise it adds implicit relations: When looking at the StackView code, one can wonder why an `ImageDataAggregated item is used there.

def clear(self):
self.getWidget().clear()
self.__resetZoomNextTime = True
Expand Down Expand Up @@ -1792,7 +1844,25 @@ 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())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, the widget controlling the plot item is ArrayImagePlot, so the let it handle the aggregation mode as well (this would allow to enable/disable this action according to the displayed item image/scatter)


def axesNames(self, data, info):
# disabled (used by default axis selector widget in Hdf5Viewer)
Expand Down Expand Up @@ -1829,6 +1899,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)
Expand Down
19 changes: 11 additions & 8 deletions src/silx/gui/data/NXdataWidgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -555,6 +556,10 @@ def _updateImage(self):
"image",
)
)
imageItem = ImageDataAggregated()
imageItem.setName(legend)
self._plot.addItem(imageItem)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it doesn't sounds to be the right place to add the image item since it can be a scatter that is added

Suggested change
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()
Expand All @@ -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())
Comment on lines +591 to +594
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds this is where to create and add the image item:

Suggested change
imageItem.setData(image)
imageItem.setOrigin(origin)
imageItem.setScale(scale)
imageItem.setColormap(self._plot.getDefaultColormap())
imageItem = ImageDataAggregated()
imageItem.setName(legend)
imageItem.setData(image)
imageItem.setOrigin(origin)
imageItem.setScale(scale)
imageItem.setColormap(self._plot.getDefaultColormap())
self._plot.addItem(imageItem)


else:
xaxisscale, yaxisscale = self._axis_scales

Expand Down
85 changes: 1 addition & 84 deletions src/silx/gui/plot/ImageView.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)
Expand Down Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions src/silx/gui/plot/actions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@
from . import control
from . import mode
from . import io
from . import image
Loading
Loading