8000 Merge pull request #25085 from tacaswell/fix/widget_pdf_save · matplotlib/matplotlib@887f39f · GitHub
[go: up one dir, main page]

Skip to content

Commit 887f39f

Browse files
authored
Merge pull request #25085 from tacaswell/fix/widget_pdf_save
FIX: only try to update blit caches if the canvas we expect
2 parents d77aa13 + 6bb208d commit 887f39f

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

lib/matplotlib/tests/test_widgets.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import functools
2+
import io
23
from unittest import mock
34

45
from matplotlib._api.deprecation import MatplotlibDeprecationWarning
@@ -23,6 +24,45 @@ def ax():
2324
return get_ax()
2425

2526

27+
def test_save_blitted_widget_as_pdf():
28+
from matplotlib.widgets import CheckButtons, RadioButtons
29+
from matplotlib.cbook import _get_running_interactive_framework
30+
if _get_running_interactive_framework() not in ['headless', None]:
31+
pytest.xfail("Callback exceptions are not raised otherwise.")
32+
33+
fig, ax = plt.subplots(
34+
nrows=2, ncols=2, figsize=(5, 2), width_ratios=[1, 2]
35+
)
36+
default_rb = RadioButtons(ax[0, 0], ['Apples', 'Oranges'])
37+
styled_rb = RadioButtons(
38+
ax[0, 1], ['Apples', 'Oranges'],
39+
label_props={'color': ['red', 'orange'],
40+
'fontsize': [16, 20]},
41+
radio_props={'edgecolor': ['red', 'orange'],
42+
'facecolor': ['mistyrose', 'peachpuff']}
43+
)
44+
45+
default_cb = CheckButtons(ax[1, 0], ['Apples', 'Oranges'],
46+
actives=[True, True])
47+
styled_cb = CheckButtons(
48+
ax[1, 1], ['Apples', 'Oranges'],
49+
actives=[True, True],
50+
label_props={'color': ['red', 'orange'],
51+
'fontsize': [16, 20]},
52+
frame_props={'edgecolor': ['red', 'orange'],
53+
'facecolor': ['mistyrose', 'peachpuff']},
54+
check_props={'color': ['darkred', 'darkorange']}
55+
)
56+
57+
ax[0, 0].set_title('Default')
58+
ax[0, 1].set_title('Stylized')
59+
# force an Agg render
60+
fig.canvas.draw()
61+
# force a pdf save
62+
with io.BytesIO() as result_after:
63+
fig.savefig(result_after, format='pdf')
64+
65+
2666
@pytest.mark.parametrize('kwargs', [
2767
dict(),
2868
dict(useblit=True, button=1),

lib/matplotlib/widgets.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,22 @@ def ignore(self, event):
9090
"""
9191
return not self.active
9292

93+
def _changed_canvas(self):
94+
"""
95+
Someone has switched the canvas on us!
96+
97+
This happens if `savefig` needs to save to a format the previous
98+
backend did not support (e.g. saving a figure using an Agg based
99+
backend saved to a vector format).
100+
101+
Returns
102+
-------
103+
bool
104+
True if the canvas has been changed.
105+
106+
"""
107+
return self.canvas is not self.ax.figure.canvas
108+
93109

94110
class AxesWidget(Widget):
95111
"""
@@ -1088,7 +1104,7 @@ def __init__(self, ax, labels, actives=None, *, useblit=True,
10881104

10891105
def _clear(self, event):
10901106
"""Internal event handler to clear the buttons."""
1091-
if self.ignore(event):
1107+
if self.ignore(event) or self._changed_canvas():
10921108
return
10931109
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
10941110
self.ax.draw_artist(self._checks)
@@ -1700,7 +1716,7 @@ def __init__(self, ax, labels, active=0, activecolor=None, *,
17001716

17011717
def _clear(self, event):
17021718
"""Internal event handler to clear the buttons."""
1703-
if self.ignore(event):
1719+
if self.ignore(event) or self._changed_canvas():
17041720
return
17051721
self._background = self.canvas.copy_from_bbox(self.ax.bbox)
17061722
self.ax.draw_artist(self._buttons)
@@ -1971,7 +1987,7 @@ def __init__(self, ax, horizOn=True, vertOn=True, useblit=False,
19711987

19721988
def clear(self, event):
19731989
"""Internal event handler to clear the cursor."""
1974-
if self.ignore(event):
1990+
if self.ignore(event) or self._changed_canvas():
19751991
return
19761992
if self.useblit:
19771993
self.background = self.canvas.copy_from_bbox(self.ax.bbox)
@@ -2110,6 +2126,12 @@ def clear(self, event):
21102126
return
21112127
if self.useblit:
21122128
for canvas, info in self._canvas_infos.items():
2129+
# someone has switched the canvas on us! This happens if
2130+
# `savefig` needs to save to a format the previous backend did
2131+
# not support (e.g. saving a figure using an Agg based backend
2132+
# saved to a vector format).
2133+
if canvas is not canvas.figure.canvas:
2134+
continue
21132135
info["background"] = canvas.copy_from_bbox(canvas.figure.bbox)
21142136

21152137
def onmove(self, event):

0 commit comments

Comments
 (0)
0