From 3cf995f01141f92d7b15759cf64ca173277029df Mon Sep 17 00:00:00 2001 From: Pierre Raybaut Date: Thu, 15 Feb 2024 13:49:12 +0100 Subject: [PATCH] `QwtPlot`: added support for margins Fix #82 --- .vscode/settings.json | 2 +- CHANGELOG.md | 7 +++++++ qwt/__init__.py | 2 +- qwt/interval.py | 15 +++++++++++++++ qwt/plot.py | 44 ++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 65 insertions(+), 5 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f1e25d1..a13d6a6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,7 +24,7 @@ ], "[python]": { "editor.codeActionsOnSave": { - "source.organizeImports": true + "source.organizeImports": "explicit" }, "editor.defaultFormatter": "ms-python.black-formatter" }, diff --git a/CHANGELOG.md b/CHANGELOG.md index 06a66f5..fca4ee3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # PythonQwt Releases +## Version 0.12.0 + +- Added support for margins in `QwtPlot` (see Issue #82): + - Default margins are set to 0.05 (5% of the plot area) at each side of the plot + - Margins are adjustable for each plot axis using `QwtPlot.setAxisMargin` (and + `QwtPlot.axisMargin` to get the current value) + ## Version 0.11.2 - Fixed `TypeError` on `QwtPlotLayout.minimumSizeHint` diff --git a/qwt/__init__.py b/qwt/__init__.py index eed8ce0..3772c76 100644 --- a/qwt/__init__.py +++ b/qwt/__init__.py @@ -27,7 +27,7 @@ .. _GitHub: https://github.com/PlotPyStack/PythonQwt """ -__version__ = "0.11.2" +__version__ = "0.12.0" QWT_VERSION_STR = "6.1.5" import warnings diff --git a/qwt/interval.py b/qwt/interval.py index bd2a5df..9741d96 100644 --- a/qwt/interval.py +++ b/qwt/interval.py @@ -396,3 +396,18 @@ def extend(self, value): if not self.isValid(): return self return QwtInterval(min([value, self.__minValue]), max([value, self.__maxValue])) + + def extend_fraction(self, value): + """ + Extend the interval by a fraction of its width + + :param float value: Fraction + :return: extended interval + """ + if not self.isValid(): + return self + return QwtInterval( + self.__minValue - value * self.width(), + self.__maxValue + value * self.width(), + self.__borderFlags, + ) diff --git a/qwt/plot.py b/qwt/plot.py index 038ae89..b147b68 100644 --- a/qwt/plot.py +++ b/qwt/plot.py @@ -101,6 +101,7 @@ def __init__(self): self.scaleDiv = None # QwtScaleDiv self.scaleEngine = None # QwtScaleEngine self.scaleWidget = None # QwtScaleWidget + self.margin = None # Margin (float) in % class QwtPlot(QFrame): @@ -431,6 +432,7 @@ def initAxesData(self): d.scaleWidget.setTitle(text) d.doAutoScale = True + d.margin = 0.05 d.minValue = 0.0 d.maxValue = 1000.0 d.stepSize = 0.0 @@ -586,6 +588,19 @@ def axisStepSize(self, axisId): else: return 0 + def axisMargin(self, axisId): + """ + :param int axisId: Axis index + :return: Margin in % of the canvas size + + .. seealso:: + + :py:meth:`setAxisMargin()` + """ + if self.axisValid(axisId): + return self.__axisData[axisId].margin + return 0.0 + def axisInterval(self, axisId): """ :param int axisId: Axis index @@ -857,6 +872,24 @@ def setAxisMaxMajor(self, axisId, maxMajor): d.isValid = False self.autoRefresh() + def setAxisMargin(self, axisId, margin): + """ + Set the margin of the scale widget + + :param int axisId: Axis index + :param float margin: Margin in % of the canvas size + + .. seealso:: + + :py:meth:`axisMargin()` + """ + if self.axisValid(axisId): + d = self.__axisData[axisId] + if margin != d.margin: + d.margin = margin + d.isValid = False + self.autoRefresh() + def setAxisTitle(self, axisId, title): """ Change the title of a specified axis @@ -910,15 +943,20 @@ def updateAxes(self): intv[item.xAxis()] |= QwtInterval(rect.left(), rect.right()) if rect.height() >= 0.0: intv[item.yAxis()] |= QwtInterval(rect.top(), rect.bottom()) + for axisId in self.AXES: d = self.__axisData[axisId] minValue = d.minValue maxValue = d.maxValue stepSize = d.stepSize - if d.doAutoScale and intv[axisId].isValid(): + if d.margin is not None: + intv_i = intv[axisId].extend_fraction(d.margin) + else: + intv_i = intv[axisId] + if d.doAutoScale and intv_i.isValid(): d.isValid = False - minValue = intv[axisId].minValue() - maxValue = intv[axisId].maxValue() + minValue = intv_i.minValue() + maxValue = intv_i.maxValue() d.scaleEngine.autoScale(d.maxMajor, minValue, maxValue, stepSize) if not d.isValid: d.scaleDiv = d.scaleEngine.divideScale(