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 1 commit
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
126 changes: 126 additions & 0 deletions src/silx/gui/data/DataViews.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
EdgarGF93 marked this conversation as resolved.
Show resolved Hide resolved
from silx._utils import NP_OPTIONAL_COPY

__authors__ = ["V. Valls", "P. Knobel"]
__license__ = "MIT"
Expand Down Expand Up @@ -1066,13 +1068,128 @@ 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")
maskToolsWidget = widget.getMaskToolsDockWidget().widget()
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)
EdgarGF93 marked this conversation as resolved.
Show resolved Hide resolved

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
Expand All @@ -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
EdgarGF93 marked this conversation as resolved.
Show resolved Hide resolved



def setDataSelection(self, selection):
self.getWidget().setGraphTitle(self.titleForSelection(selection))

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
12 changes: 12 additions & 0 deletions src/silx/gui/plot/PlotWindow.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ def __init__(
)
self._intensityHistoAction.setVisible(False)

self.__aggregationModeAction = self.group.addAction(
actions.image.AggregationModeAction(parent=self)
)
self.__aggregationModeAction.setVisible(False)

EdgarGF93 marked this conversation as resolved.
Show resolved Hide resolved
self._medianFilter2DAction = self.group.addAction(
actions_medfilt.MedianFilter2DAction(self, parent=self)
)
Expand Down Expand Up @@ -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
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