From 8e8338038fc301cfd12e1e099fdf25cd9d8c91f2 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 17 Apr 2025 10:19:05 +0200 Subject: [PATCH 1/5] yaxis arcsinh with matplotlib --- src/silx/gui/plot/PlotWindow.py | 6 ++++ src/silx/gui/plot/actions/control.py | 29 +++++++++++++++++++ .../gui/plot/backends/BackendMatplotlib.py | 6 ++++ src/silx/gui/plot/items/axis.py | 11 +++++-- 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/silx/gui/plot/PlotWindow.py b/src/silx/gui/plot/PlotWindow.py index 7f330478fc..304b1c9267 100644 --- a/src/silx/gui/plot/PlotWindow.py +++ b/src/silx/gui/plot/PlotWindow.py @@ -183,6 +183,12 @@ def __init__( self.yAxisLogarithmicAction.setVisible(logScale) self.addAction(self.yAxisLogarithmicAction) + self.yAxisArcsinhAction = self.group.addAction( + actions.control.YAxisArcsinhAction(self, parent=self) + ) + self.yAxisArcsinhAction.setVisible(logScale) + self.addAction(self.yAxisArcsinhAction) + self.gridAction = self.group.addAction( actions.control.GridAction(self, gridMode="both", parent=self) ) diff --git a/src/silx/gui/plot/actions/control.py b/src/silx/gui/plot/actions/control.py index 210166b7d8..099f2c58e0 100755 --- a/src/silx/gui/plot/actions/control.py +++ b/src/silx/gui/plot/actions/control.py @@ -282,6 +282,35 @@ def _actionTriggered(self, checked=False): scale = self.axis.LOGARITHMIC if checked else self.axis.LINEAR self.axis.setScale(scale) + +class YAxisArcsinhAction(PlotAction): + """QAction controlling Y axis arcsinh scale on a :class:`.PlotWidget`. + + :param plot: :class:`.PlotWidget` instance on which to operate + :param parent: See :class:`QAction` + """ + + def __init__(self, plot, parent=None): + super().__init__( + plot, + icon="colormap-norm-arcsinh", + text="Arcsinh scale", + tooltip="Arcsinh y-axis when checked", + triggered=self._actionTriggered, + checkable=True, + parent=parent, + ) + self.axis = plot.getYAxis() + self.setChecked(self.axis.getScale() == self.axis.ARCSINH) + self.axis.sigScaleChanged.connect(self._setCheckedIfArcsinhScale) + + def _setCheckedIfArcsinhScale(self, scale): + self.setChecked(scale == self.axis.ARCSINH) + + def _actionTriggered(self, checked=False): + scale = self.axis.ARCSINH if checked else self.axis.LINEAR + self.axis.setScale(scale) + class GridAction(PlotAction): """QAction controlling grid mode on a :class:`.PlotWidget`. diff --git a/src/silx/gui/plot/backends/BackendMatplotlib.py b/src/silx/gui/plot/backends/BackendMatplotlib.py index 434815bc86..92a13eae44 100755 --- a/src/silx/gui/plot/backends/BackendMatplotlib.py +++ b/src/silx/gui/plot/backends/BackendMatplotlib.py @@ -1321,6 +1321,12 @@ def setYAxisLogarithmic(self, flag): self.ax.set_yscale("linear") self.ax.yaxis.set_major_formatter(DefaultTickFormatter()) + def setYAxisArcsinh(self): + self.ax2.set_yscale("asinh") + self.ax2.yaxis.set_major_formatter(DefaultTickFormatter()) + self.ax.set_yscale("asinh") + self.ax.yaxis.set_major_formatter(DefaultTickFormatter()) + def setYAxisInverted(self, flag): if self.ax.yaxis_inverted() != bool(flag): self.ax.invert_yaxis() diff --git a/src/silx/gui/plot/items/axis.py b/src/silx/gui/plot/items/axis.py index d96a6a9067..f2dc01129a 100644 --- a/src/silx/gui/plot/items/axis.py +++ b/src/silx/gui/plot/items/axis.py @@ -63,7 +63,10 @@ class Axis(qt.QObject): LOGARITHMIC = "log" """Constant defining a logarithmic scale""" - _SCALES = {LINEAR, LOGARITHMIC} + ARCSINH = "arcsinh" + """Constant defining an arcsinh scale""" + + _SCALES = {LINEAR, LOGARITHMIC, ARCSINH} sigInvertedChanged = qt.Signal(bool) """Signal emitted when axis orientation has changed""" @@ -242,7 +245,6 @@ def setScale(self, scale): for item in plot.getItems(): item._updated() plot._invalidateDataRange() - if scale == self.LOGARITHMIC: self._internalSetLogarithmic(True) if vmin <= 0: @@ -254,6 +256,8 @@ def setScale(self, scale): self.setLimits(dataRange[0], vmax) else: self.setLimits(*dataRange) + elif scale == self.ARCSINH: + self._internalSetArcsinh() elif scale == self.LINEAR: self._internalSetLogarithmic(False) else: @@ -451,6 +455,9 @@ def _internalSetLimits(self, ymin, ymax): def _internalSetLogarithmic(self, flag): self._getBackend().setYAxisLogarithmic(flag) + def _internalSetArcsinh(self): + self._getBackend().setYAxisArcsinh() + def setInverted(self, flag=True): """Set the axis orientation. From e343cec7a56c39623492d9eee497455fa7c523fe Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 17 Apr 2025 10:42:35 +0200 Subject: [PATCH 2/5] asinh icon --- src/silx/gui/plot/actions/control.py | 2 +- src/silx/resources/gui/icons/plot-yasinh.svg | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 src/silx/resources/gui/icons/plot-yasinh.svg diff --git a/src/silx/gui/plot/actions/control.py b/src/silx/gui/plot/actions/control.py index 099f2c58e0..6a81640fd6 100755 --- a/src/silx/gui/plot/actions/control.py +++ b/src/silx/gui/plot/actions/control.py @@ -293,7 +293,7 @@ class YAxisArcsinhAction(PlotAction): def __init__(self, plot, parent=None): super().__init__( plot, - icon="colormap-norm-arcsinh", + icon="plot-yasinh", text="Arcsinh scale", tooltip="Arcsinh y-axis when checked", triggered=self._actionTriggered, diff --git a/src/silx/resources/gui/icons/plot-yasinh.svg b/src/silx/resources/gui/icons/plot-yasinh.svg new file mode 100644 index 0000000000..b520d46a66 --- /dev/null +++ b/src/silx/resources/gui/icons/plot-yasinh.svg @@ -0,0 +1,10 @@ + + + + + + + + + asinh + \ No newline at end of file From 4aec9c1829dbe442bdeddb12961ebb8ef091ab70 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 17 Apr 2025 10:47:58 +0200 Subject: [PATCH 3/5] opengl? --- src/silx/gui/plot/backends/BackendOpenGL.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/silx/gui/plot/backends/BackendOpenGL.py b/src/silx/gui/plot/backends/BackendOpenGL.py index e21d63ac9c..edf96d9a0f 100755 --- a/src/silx/gui/plot/backends/BackendOpenGL.py +++ b/src/silx/gui/plot/backends/BackendOpenGL.py @@ -1596,6 +1596,9 @@ def setYAxisLogarithmic(self, flag): self._plotFrame.yAxis.isLog = flag self._plotFrame.y2Axis.isLog = flag + def setYAxisArcsinh(self): + ... + def setYAxisInverted(self, flag): if flag != self._plotFrame.isYAxisInverted: self._plotFrame.isYAxisInverted = flag From ecc1e1f0fb80acadf0fa9576287a7bb9da80c272 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 17 Apr 2025 11:21:40 +0200 Subject: [PATCH 4/5] flags and opengl --- src/silx/gui/plot/backends/BackendMatplotlib.py | 13 +++++++++---- src/silx/gui/plot/backends/BackendOpenGL.py | 13 +++++++++++-- src/silx/gui/plot/items/axis.py | 6 +++--- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/silx/gui/plot/backends/BackendMatplotlib.py b/src/silx/gui/plot/backends/BackendMatplotlib.py index 92a13eae44..df2dda6ca1 100755 --- a/src/silx/gui/plot/backends/BackendMatplotlib.py +++ b/src/silx/gui/plot/backends/BackendMatplotlib.py @@ -1321,12 +1321,17 @@ def setYAxisLogarithmic(self, flag): self.ax.set_yscale("linear") self.ax.yaxis.set_major_formatter(DefaultTickFormatter()) - def setYAxisArcsinh(self): - self.ax2.set_yscale("asinh") + def setYAxisArcsinh(self, flag): + if flag: + self.ax2.set_yscale("asinh") + self.ax.set_yscale("asinh") + return + + self.ax2.set_yscale("linear") self.ax2.yaxis.set_major_formatter(DefaultTickFormatter()) - self.ax.set_yscale("asinh") + self.ax.set_yscale("linear") self.ax.yaxis.set_major_formatter(DefaultTickFormatter()) - + def setYAxisInverted(self, flag): if self.ax.yaxis_inverted() != bool(flag): self.ax.invert_yaxis() diff --git a/src/silx/gui/plot/backends/BackendOpenGL.py b/src/silx/gui/plot/backends/BackendOpenGL.py index edf96d9a0f..fdb7484b9b 100755 --- a/src/silx/gui/plot/backends/BackendOpenGL.py +++ b/src/silx/gui/plot/backends/BackendOpenGL.py @@ -154,6 +154,7 @@ def __init__( attribute vec2 position; uniform mat4 matrix; uniform bvec2 isLog; + uniform bvec2 isAsinh; const float oneOverLog10 = 0.43429448190325176; @@ -165,6 +166,9 @@ def __init__( if (isLog.y) { posTransformed.y = oneOverLog10 * log(position.y); } + if (isAsinh.y) { + posTransformed.y = asinh(position.y); + } gl_Position = matrix * vec4(posTransformed, 0.0, 1.0); } """ @@ -1596,8 +1600,13 @@ def setYAxisLogarithmic(self, flag): self._plotFrame.yAxis.isLog = flag self._plotFrame.y2Axis.isLog = flag - def setYAxisArcsinh(self): - ... + def setYAxisArcsinh(self, flag): + if flag != self._plotFrame.yAxis.isAsinh or flag != self._plotFrame.y2Axis.isAsinh: + if flag and self._keepDataAspectRatio: + _logger.warning("KeepDataAspectRatio is ignored with asinh axes") + + self._plotFrame.yAxis.isAsinh = flag + self._plotFrame.y2Axis.isAsinh = flag def setYAxisInverted(self, flag): if flag != self._plotFrame.isYAxisInverted: diff --git a/src/silx/gui/plot/items/axis.py b/src/silx/gui/plot/items/axis.py index f2dc01129a..c6a15da2d5 100644 --- a/src/silx/gui/plot/items/axis.py +++ b/src/silx/gui/plot/items/axis.py @@ -257,7 +257,7 @@ def setScale(self, scale): else: self.setLimits(*dataRange) elif scale == self.ARCSINH: - self._internalSetArcsinh() + self._internalSetArcsinh(True) elif scale == self.LINEAR: self._internalSetLogarithmic(False) else: @@ -455,8 +455,8 @@ def _internalSetLimits(self, ymin, ymax): def _internalSetLogarithmic(self, flag): self._getBackend().setYAxisLogarithmic(flag) - def _internalSetArcsinh(self): - self._getBackend().setYAxisArcsinh() + def _internalSetArcsinh(self, flag): + self._getBackend().setYAxisArcsinh(flag) def setInverted(self, flag=True): """Set the axis orientation. From 3f1a3d7746d9e8fb8131c4c449ef0a3f2abb8969 Mon Sep 17 00:00:00 2001 From: Edgar Date: Thu, 17 Apr 2025 11:40:44 +0200 Subject: [PATCH 5/5] no opengl --- src/silx/gui/plot/backends/BackendOpenGL.py | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/silx/gui/plot/backends/BackendOpenGL.py b/src/silx/gui/plot/backends/BackendOpenGL.py index fdb7484b9b..5746690fde 100755 --- a/src/silx/gui/plot/backends/BackendOpenGL.py +++ b/src/silx/gui/plot/backends/BackendOpenGL.py @@ -154,7 +154,6 @@ def __init__( attribute vec2 position; uniform mat4 matrix; uniform bvec2 isLog; - uniform bvec2 isAsinh; const float oneOverLog10 = 0.43429448190325176; @@ -166,9 +165,6 @@ def __init__( if (isLog.y) { posTransformed.y = oneOverLog10 * log(position.y); } - if (isAsinh.y) { - posTransformed.y = asinh(position.y); - } gl_Position = matrix * vec4(posTransformed, 0.0, 1.0); } """ @@ -1601,12 +1597,7 @@ def setYAxisLogarithmic(self, flag): self._plotFrame.y2Axis.isLog = flag def setYAxisArcsinh(self, flag): - if flag != self._plotFrame.yAxis.isAsinh or flag != self._plotFrame.y2Axis.isAsinh: - if flag and self._keepDataAspectRatio: - _logger.warning("KeepDataAspectRatio is ignored with asinh axes") - - self._plotFrame.yAxis.isAsinh = flag - self._plotFrame.y2Axis.isAsinh = flag + ... def setYAxisInverted(self, flag): if flag != self._plotFrame.isYAxisInverted: