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

Skip to content

Commit 3a7f060

Browse files
Sanat GuptaSanat Gupta
authored andcommitted
Preserve legend settings when regenerating in Qt figure options
When using the Qt figure options dialog to regenerate a legend, previously only ncols and draggable state were preserved. This caused all other legend customizations (loc, fontsize, frameon, shadow, title, mode, spacing, etc.) to be lost. This change extracts and reapplies these properties when regenerating the legend. Closes #17775
1 parent 6871ecc commit 3a7f060

2 files changed

Lines changed: 152 additions & 1 deletion

File tree

lib/matplotlib/backends/qt_editor/figureoptions.py

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,11 +248,34 @@ def apply_callback(data):
248248
if generate_legend:
249249
draggable = None
250250
ncols = 1
251+
legend_kwargs = {}
251252
if axes.legend_ is not None:
252253
old_legend = axes.get_legend()
253254
draggable = old_legend._draggable is not None
254255
ncols = old_legend._ncols
255-
new_legend = axes.legend(ncols=ncols)
256+
# Preserve location and positioning
257+
legend_kwargs['loc'] = old_legend._loc
258+
if old_legend._bbox_to_anchor is not None:
259+
legend_kwargs['bbox_to_anchor'] = (
260+
old_legend._bbox_to_anchor.bounds)
261+
# Preserve styling
262+
legend_kwargs['fontsize'] = old_legend._fontsize
263+
legend_kwargs['frameon'] = old_legend.get_frame_on()
264+
legend_kwargs['shadow'] = old_legend.shadow
265+
legend_kwargs['framealpha'] = (
266+
old_legend.get_frame().get_alpha())
267+
legend_kwargs['title'] = (
268+
old_legend.get_title().get_text())
269+
# Preserve layout settings
270+
if old_legend._mode is not None:
271+
legend_kwargs['mode'] = old_legend._mode
272+
legend_kwargs['columnspacing'] = (
273+
old_legend.columnspacing)
274+
legend_kwargs['labelspacing'] = old_legend.labelspacing
275+
legend_kwargs['handlelength'] = old_legend.handlelength
276+
legend_kwargs['handletextpad'] = (
277+
old_legend.handletextpad)
278+
new_legend = axes.legend(ncols=ncols, **legend_kwargs)
256279
if new_legend:
257280
new_legend.set_draggable(draggable)
258281

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
"""Tests for legend preservation in Qt figure options dialog."""
2+
import matplotlib
3+
matplotlib.use('Agg')
4+
import matplotlib.pyplot as plt
5+
6+
7+
def test_legend_properties_preserved():
8+
"""
9+
Test that legend properties are preserved when the legend is
10+
regenerated via the Qt figure options dialog.
11+
12+
Regression test for https://github.com/matplotlib/matplotlib/issues/17775
13+
"""
14+
fig, ax = plt.subplots()
15+
ax.plot(range(5), label='a')
16+
ax.plot(range(3)[::-1], label='b')
17+
18+
ax.legend(
19+
loc='upper right',
20+
fontsize=14,
21+
frameon=False,
22+
shadow=True,
23+
title='My Legend',
24+
ncols=2,
25+
columnspacing=3.0,
26+
labelspacing=1.5,
27+
handlelength=4.0,
28+
handletextpad=1.2,
29+
)
30+
31+
old_legend = ax.get_legend()
32+
old_loc = old_legend._loc
33+
old_fontsize = old_legend._fontsize
34+
old_frameon = old_legend.get_frame_on()
35+
old_shadow = old_legend.shadow
36+
old_title = old_legend.get_title().get_text()
37+
old_ncols = old_legend._ncols
38+
old_columnspacing = old_legend.columnspacing
39+
old_labelspacing = old_legend.labelspacing
40+
old_handlelength = old_legend.handlelength
41+
old_handletextpad = old_legend.handletextpad
42+
43+
# Simulate what the patched figureoptions code does
44+
draggable = old_legend._draggable is not None
45+
ncols = old_legend._ncols
46+
legend_kwargs = {}
47+
legend_kwargs['loc'] = old_legend._loc
48+
if old_legend._bbox_to_anchor is not None:
49+
legend_kwargs['bbox_to_anchor'] = (
50+
old_legend._bbox_to_anchor.bounds)
51+
legend_kwargs['fontsize'] = old_legend._fontsize
52+
legend_kwargs['frameon'] = old_legend.get_frame_on()
53+
legend_kwargs['shadow'] = old_legend.shadow
54+
legend_kwargs['framealpha'] = old_legend.get_frame().get_alpha()
55+
legend_kwargs['title'] = old_legend.get_title().get_text()
56+
if old_legend._mode is not None:
57+
legend_kwargs['mode'] = old_legend._mode
58+
legend_kwargs['columnspacing'] = old_legend.columnspacing
59+
legend_kwargs['labelspacing'] = old_legend.labelspacing
60+
legend_kwargs['handlelength'] = old_legend.handlelength
61+
legend_kwargs['handletextpad'] = old_legend.handletextpad
62+
63+
new_legend = ax.legend(ncols=ncols, **legend_kwargs)
64+
if new_legend:
65+
new_legend.set_draggable(draggable)
66+
67+
assert new_legend._loc == old_loc
68+
assert new_legend._fontsize == old_fontsize
69+
assert new_legend.get_frame_on() == old_frameon
70+
assert new_legend.shadow == old_shadow
71+
assert new_legend.get_title().get_text() == old_title
72+
assert new_legend._ncols == old_ncols
73+
assert new_legend.columnspacing == old_columnspacing
74+
assert new_legend.labelspacing == old_labelspacing
75+
assert new_legend.handlelength == old_handlelength
76+
assert new_legend.handletextpad == old_handletextpad
77+
78+
plt.close(fig)
79+
80+
81+
def test_legend_regeneration_no_existing_legend():
82+
"""
83+
Test that regenerating a legend when none exists still works.
84+
"""
85+
fig, ax = plt.subplots()
86+
ax.plot(range(5), label='a')
87+
88+
assert ax.get_legend() is None
89+
90+
new_legend = ax.legend(ncols=1)
91+
assert new_legend is not None
92+
assert len(new_legend.get_texts()) == 1
93+
assert new_legend.get_texts()[0].get_text() == 'a'
94+
95+
plt.close(fig)
96+
97+
98+
def test_legend_mode_preserved():
99+
"""
100+
Test that mode='expand' is preserved on legend regeneration.
101+
"""
102+
fig, ax = plt.subplots()
103+
ax.plot(range(5), label='a')
104+
ax.plot(range(3)[::-1], label='b')
105+
106+
ax.legend(
107+
loc='lower left',
108+
mode='expand',
109+
ncols=2,
110+
)
111+
112+
old_legend = ax.get_legend()
113+
old_mode = old_legend._mode
114+
old_loc = old_legend._loc
115+
116+
legend_kwargs = {}
117+
legend_kwargs['loc'] = old_legend._loc
118+
legend_kwargs['fontsize'] = old_legend._fontsize
119+
legend_kwargs['frameon'] = old_legend.get_frame_on()
120+
if old_legend._mode is not None:
121+
legend_kwargs['mode'] = old_legend._mode
122+
123+
new_legend = ax.legend(ncols=old_legend._ncols, **legend_kwargs)
124+
125+
assert new_legend._mode == old_mode
126+
assert new_legend._loc == old_loc
127+
128+
plt.close(fig)

0 commit comments

Comments
 (0)