Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit bfcb305

Browse files
committed
SubplotParams.validate-associated fixes.
SubplotParams.validate was previously only used in SubplotTool so that when resetting the SubplotParams, a temporarily invalid SubplotParams would be ignored. But the temporary `validate = False` was put at the wrong place (it should wrap `_on_reset`'s implementation, not its attachment to `buttonreset`). Indeed, setting e.g. "left" to 0.0 and "right" to 0.01 and then pressing reset (when using e.g. tk) would throw an exception (because "left" would first be reset to 0.125 before "right" gets reset to 0.9, and the intermediate state is invalid). Instead, just use the already existing `Widgets.eventson` mechanism to temporarily disable updates. Also apply the corresponding change for Qt's own SubplotTool. Deprecate the then unused (and undocumented) SubplotParams.validate; in order to keep it writable during the deprecation period, slightly tweak the implementation of _deprecate_privatize_attribute.
1 parent cb756d3 commit bfcb305

File tree

6 files changed

+45
-28
lines changed

6 files changed

+45
-28
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
``SubplotParams.validate``
2+
~~~~~~~~~~~~~~~~~~~~~~~~~~
3+
... is deprecated. Use `.SubplotParams.update` to change `.SubplotParams`
4+
while always keeping it in a valid state.

lib/matplotlib/_api/deprecation.py

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -282,18 +282,20 @@ class Foo:
282282
attr = _deprecate_privatize_attribute(*args, **kwargs)
283283
284284
where *all* parameters are forwarded to `deprecated`. This form makes
285-
``attr`` a property which forwards access to ``self._attr`` (same name but
286-
with a leading underscore), with a deprecation warning. Note that the
287-
attribute name is derived from *the name this helper is assigned to*. This
288-
helper also works for deprecating methods.
285+
``attr`` a property which forwards read and write access to ``self._attr``
286+
(same name but with a leading underscore), with a deprecation warning.
287+
Note that the attribute name is derived from *the name this helper is
288+
assigned to*. This helper also works for deprecating methods.
289289
"""
290290

291291
def __init__(self, *args, **kwargs):
292292
self.deprecator = deprecated(*args, **kwargs)
293293

294294
def __set_name__(self, owner, name):
295295
setattr(owner, name, self.deprecator(
296-
property(lambda self: getattr(self, f"_{name}")), name=name))
296+
property(lambda self: getattr(self, f"_{name}"),
297+
lambda self, value: setattr(self, f"_{name}", value)),
298+
name=name))
297299

298300

299301
def rename_parameter(since, old, new, func=None):

lib/matplotlib/backends/backend_qt5.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -777,12 +777,6 @@ def __init__(self, targetfig, parent):
777777

778778
self._figure = targetfig
779779

780-
for lower, higher in [("bottom", "top"), ("left", "right")]:
781-
self._widgets[lower].valueChanged.connect(
782-
lambda val: self._widgets[higher].setMinimum(val + .001))
783-
self._widgets[higher].valueChanged.connect(
784-
lambda val: self._widgets[lower].setMaximum(val - .001))
785-
786780
self._attrs = ["top", "bottom", "left", "right", "hspace", "wspace"]
787781
self._defaults = {attr: vars(self._figure.subplotpars)[attr]
788782
for attr in self._attrs}
@@ -821,7 +815,12 @@ def _export_values(self):
821815
dialog.exec_()
822816

823817
def _on_value_changed(self):
824-
self._figure.subplots_adjust(**{attr: self._widgets[attr].value()
818+
widgets = self._widgets
819+
# Set all mins and maxes, so that this can also be used in _reset().
820+
for lower, higher in [("bottom", "top"), ("left", "right")]:
821+
widgets[higher].setMinimum(widgets[lower].value() + .001)
822+
widgets[lower].setMaximum(widgets[higher].value() - .001)
823+
self._figure.subplots_adjust(**{attr: widgets[attr].value()
825824
for attr in self._attrs})
826825
self._figure.canvas.draw_idle()
827826

@@ -836,7 +835,12 @@ def _tight_layout(self):
836835

837836
def _reset(self):
838837
for attr, value in self._defaults.items():
839-
self._widgets[attr].setValue(value)
838+
widget = self._widgets[attr]
839+
widget.setRange(0, 1)
840+
widget.blockSignals(True)
841+
widget.setValue(value)
842+
widget.blockSignals(False)
843+
self._on_value_changed()
840844

841845

842846
class ToolbarQt(ToolContainerBase, QtWidgets.QToolBar):

lib/matplotlib/figure.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ class SubplotParams:
120120
"""
121121
A class to hold the parameters for a subplot.
122122
"""
123+
123124
def __init__(self, left=None, bottom=None, right=None, top=None,
124125
wspace=None, hspace=None):
125126
"""
@@ -146,17 +147,20 @@ def __init__(self, left=None, bottom=None, right=None, top=None,
146147
The height of the padding between subplots,
147148
as a fraction of the average Axes height.
148149
"""
149-
self.validate = True
150+
self._validate = True
150151
for key in ["left", "bottom", "right", "top", "wspace", "hspace"]:
151152
setattr(self, key, mpl.rcParams[f"figure.subplot.{key}"])
152153
self.update(left, bottom, right, top, wspace, hspace)
153154

155+
# Also remove _validate after deprecation elapses.
156+
validate = _api.deprecate_privatize_attribute("3.5")
157+
154158
def update(self, left=None, bottom=None, right=None, top=None,
155159
wspace=None, hspace=None):
156160
"""
157161
Update the dimensions of the passed parameters. *None* means unchanged.
158162
"""
159-
if self.validate:
163+
if self._validate:
160164
if ((left if left is not None else self.left)
161165
>= (right if right is not None else self.right)):
162166
raise ValueError('left cannot be >= right')

lib/matplotlib/tests/test_api.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,14 +37,19 @@ def f(cls):
3737
def test_deprecate_privatize_attribute():
3838
class C:
3939
def __init__(self): self._attr = 1
40-
def _meth(self, arg): pass
40+
def _meth(self, arg): return arg
4141
attr = _api.deprecate_privatize_attribute("0.0")
4242
meth = _api.deprecate_privatize_attribute("0.0")
4343

44+
c = C()
4445
with pytest.warns(_api.MatplotlibDeprecationWarning):
45-
C().attr
46+
assert c.attr == 1
4647
with pytest.warns(_api.MatplotlibDeprecationWarning):
47-
C().meth(42)
48+
c.attr = 2
49+
with pytest.warns(_api.MatplotlibDeprecationWarning):
50+
assert c.attr == 2
51+
with pytest.warns(_api.MatplotlibDeprecationWarning):
52+
assert c.meth(42) == 42
4853

4954

5055
def test_delete_parameter():

lib/matplotlib/widgets.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1402,11 +1402,7 @@ def __init__(self, targetfig, toolfig):
14021402

14031403
bax = toolfig.add_axes([0.8, 0.05, 0.15, 0.075])
14041404
self.buttonreset = Button(bax, 'Reset')
1405-
1406-
# During reset there can be a temporary invalid state depending on the
1407-
# order of the reset so we turn off validation for the resetting
1408-
with cbook._setattr_cm(toolfig.subplotpars, validate=False):
1409-
self.buttonreset.on_clicked(self._on_reset)
1405+
self.buttonreset.on_clicked(self._on_reset)
14101406

14111407
def _on_slider_changed(self, _):
14121408
self.targetfig.subplots_adjust(
@@ -1417,17 +1413,19 @@ def _on_slider_changed(self, _):
14171413

14181414
def _on_reset(self, event):
14191415
with ExitStack() as stack:
1420-
# Temporarily disable drawing on self and self's sliders.
1416+
# Temporarily disable drawing on self and self's sliders, and
1417+
# disconnect slider events (as the subplotparams can be temporarily
1418+
# invalid, depending on the order in which they are restored).
14211419
stack.enter_context(cbook._setattr_cm(self, drawon=False))
14221420
for slider in self._sliders:
1423-
stack.enter_context(cbook._setattr_cm(slider, drawon=False))
1421+
stack.enter_context(
1422+
cbook._setattr_cm(slider, drawon=False, eventson=False))
14241423
# Reset the slider to the initial position.
14251424
for slider in self._sliders:
14261425
slider.reset()
1427-
# Draw the canvas.
14281426
if self.drawon:
1429-
event.canvas.draw()
1430-
self.targetfig.canvas.draw()
1427+
event.canvas.draw() # Redraw the subplottool canvas.
1428+
self._on_slider_changed(None) # Apply changes to the target window.
14311429

14321430
axleft = _api.deprecated("3.3")(
14331431
property(lambda self: self.sliderleft.ax))

0 commit comments

Comments
 (0)