Skip to content

Use more _setattr_cm, thus fix Text('').get_window_extent(dpi=...) #16828

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

Merged
merged 2 commits into from
Mar 25, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
13 changes: 5 additions & 8 deletions lib/matplotlib/legend_handler.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def legend_artist(self, legend, orig_handle, fontsize, handlebox)

import numpy as np

from matplotlib import cbook
from matplotlib.lines import Line2D
from matplotlib.patches import Rectangle
import matplotlib.collections as mcoll
Expand Down Expand Up @@ -607,19 +608,15 @@ def create_artists(self, legend, orig_handle,
if using_linecoll:
# change the function used by update_prop() from the default
# to one that handles LineCollection
orig_update_func = self._update_prop_func
self._update_prop_func = self._copy_collection_props

for line in leg_stemlines:
self.update_prop(line, stemlines, legend)
with cbook._setattr_cm(
self, _update_prop_func=self._copy_collection_props):
for line in leg_stemlines:
self.update_prop(line, stemlines, legend)

else:
for lm, m in zip(leg_stemlines, stemlines):
self.update_prop(lm, m, legend)

if using_linecoll:
self._update_prop_func = orig_update_func

leg_baseline = Line2D([np.min(xdata), np.max(xdata)],
[bottom, bottom])
self.update_prop(leg_baseline, baseline, legend)
Expand Down
21 changes: 9 additions & 12 deletions lib/matplotlib/quiver.py
Original file line number Diff line number Diff line change
Expand Up @@ -306,18 +306,15 @@ def _init(self):
if not self.Q._initialized:
self.Q._init()
self._set_transform()
_pivot = self.Q.pivot
self.Q.pivot = self.pivot[self.labelpos]
# Hack: save and restore the Umask
_mask = self.Q.Umask
self.Q.Umask = ma.nomask
u = self.U * np.cos(np.radians(self.angle))
v = self.U * np.sin(np.radians(self.angle))
angle = self.Q.angles if isinstance(self.Q.angles, str) else 'uv'
self.verts = self.Q._make_verts(
np.array([u]), np.array([v]), angle)
self.Q.Umask = _mask
self.Q.pivot = _pivot
with cbook._setattr_cm(self.Q, pivot=self.pivot[self.labelpos],
# Hack: save and restore the Umask
Umask=ma.nomask):
u = self.U * np.cos(np.radians(self.angle))
v = self.U * np.sin(np.radians(self.angle))
angle = (self.Q.angles if isinstance(self.Q.angles, str)
else 'uv')
self.verts = self.Q._make_verts(
np.array([u]), np.array([v]), angle)
kw = self.Q.polykw
kw.update(self.kw)
self.vector = mcollections.PolyCollection(
Expand Down
16 changes: 16 additions & 0 deletions lib/matplotlib/tests/test_text.py
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,22 @@ def test_set_position():
assert a + shift_val == b


@pytest.mark.parametrize('text', ['', 'O'], ids=['empty', 'non-empty'])
def test_non_default_dpi(text):
fig, ax = plt.subplots()

t1 = ax.text(0.5, 0.5, text, ha='left', va='bottom')
fig.canvas.draw()
dpi = fig.dpi

bbox1 = t1.get_window_extent()
bbox2 = t1.get_window_extent(dpi=dpi * 10)
np.testing.assert_allclose(bbox2.get_points(), bbox1.get_points() * 10,
rtol=5e-2)
# Text.get_window_extent should not permanently change dpi.
assert fig.dpi == dpi


def test_get_rotation_string():
assert mpl.text.get_rotation('horizontal') == 0.
assert mpl.text.get_rotation('vertical') == 90.
Expand Down
23 changes: 11 additions & 12 deletions lib/matplotlib/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -891,12 +891,12 @@ def get_window_extent(self, renderer=None, dpi=None):
#return _unit_box
if not self.get_visible():
return Bbox.unit()
if dpi is not None:
dpi_orig = self.figure.dpi
self.figure.dpi = dpi
if dpi is None:
dpi = self.figure.dpi
if self.get_text() == '':
tx, ty = self._get_xy_display()
return Bbox.from_bounds(tx, ty, 0, 0)
with cbook._setattr_cm(self.figure, dpi=dpi):
tx, ty = self._get_xy_display()
return Bbox.from_bounds(tx, ty, 0, 0)

if renderer is not None:
self._renderer = renderer
Expand All @@ -905,13 +905,12 @@ def get_window_extent(self, renderer=None, dpi=None):
if self._renderer is None:
raise RuntimeError('Cannot get window extent w/o renderer')

bbox, info, descent = self._get_layout(self._renderer)
x, y = self.get_unitless_position()
x, y = self.get_transform().transform((x, y))
bbox = bbox.translated(x, y)
if dpi is not None:
self.figure.dpi = dpi_orig
return bbox
with cbook._setattr_cm(self.figure, dpi=dpi):
bbox, info, descent = self._get_layout(self._renderer)
x, y = self.get_unitless_position()
x, y = self.get_transform().transform((x, y))
bbox = bbox.translated(x, y)
return bbox

def set_backgroundcolor(self, color):
"""
Expand Down
6 changes: 2 additions & 4 deletions lib/matplotlib/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -1151,10 +1151,8 @@ def __init__(self, targetfig, toolfig):

# During reset there can be a temporary invalid state depending on the
# order of the reset so we turn off validation for the resetting
validate = toolfig.subplotpars.validate
toolfig.subplotpars.validate = False
self.buttonreset.on_clicked(self._on_reset)
toolfig.subplotpars.validate = validate
with cbook._setattr_cm(toolfig.subplotpars, validate=False):
self.buttonreset.on_clicked(self._on_reset)

def _on_slider_changed(self, _):
self.targetfig.subplots_adjust(
Expand Down