Skip to content

Commit b767add

Browse files
committed
FIX: add legend kwarg outside
1 parent aac019d commit b767add

File tree

4 files changed

+38
-133
lines changed

4 files changed

+38
-133
lines changed

examples/text_labels_and_annotations/figlegendoutside_demo.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828
axs[1].plot(x, y3, 'yd-', label='Line3')
2929
h4, = axs[1].plot(x, y4, 'k^', label='Line4')
3030

31-
fig.legend_outside(loc='upper center', ncol=2)
32-
fig.legend_outside(axs=[axs[1]], loc='lower right')
33-
fig.legend_outside(handles=[h2, h4], labels=['curve2', 'curve4'],
34-
loc='center left', borderaxespad=6)
31+
fig.legend(loc='upper center', outside=True, ncol=2)
32+
fig.legend(axs=[axs[1]], outside=True, loc='lower right')
33+
fig.legend(handles=[h2, h4], labels=['curve2', 'curve4'],
34+
outside=True, loc='center left', borderaxespad=6)
3535
plt.show()

lib/matplotlib/figure.py

Lines changed: 32 additions & 128 deletions
Original file line numberDiff line numberDiff line change
@@ -1698,7 +1698,7 @@ def get_axes(self):
16981698
# docstring of pyplot.figlegend.
16991699

17001700
@docstring.dedent_interpd
1701-
def legend(self, *args, **kwargs):
1701+
def legend(self, *args, outside=False, axs=None, **kwargs):
17021702
"""
17031703
Place a legend on the figure.
17041704
@@ -1723,6 +1723,15 @@ def legend(self, *args, **kwargs):
17231723
Parameters
17241724
----------
17251725
1726+
outside: bool
1727+
If ``constrained_layout=True``, then try and place legend outside
1728+
axes listed in *axs*, or highest-level gridspec if axs is empty.
1729+
Note, "center" and "best" options to *loc* do not work with
1730+
``outside=True``
1731+
1732+
axs : sequence of `~.axes.Axes`
1733+
axes to gather handles from (if *handles* is empty).
1734+
17261735
handles : sequence of `.Artist`, optional
17271736
A list of Artists (lines, patches) to be added to the legend.
17281737
Use this together with *labels*, if you need full control on what
@@ -1752,141 +1761,36 @@ def legend(self, *args, **kwargs):
17521761
Not all kinds of artist are supported by the legend command. See
17531762
:doc:`/tutorials/intermediate/legend_guide` for details.
17541763
"""
1764+
if axs is None:
1765+
axs = self.axes
17551766

17561767
handles, labels, extra_args, kwargs = mlegend._parse_legend_args(
1757-
self.axes,
1768+
axs,
17581769
*args,
17591770
**kwargs)
1760-
# check for third arg
1761-
if len(extra_args):
1762-
# cbook.warn_deprecated(
1763-
# "2.1",
1764-
# message="Figure.legend will accept no more than two "
1765-
# "positional arguments in the future. Use "
1766-
# "'fig.legend(handles, labels, loc=location)' "
1767-
# "instead.")
1768-
# kwargs['loc'] = extra_args[0]
1769-
# extra_args = extra_args[1:]
1770-
pass
1771-
l = mlegend.Legend(self, handles, labels, *extra_args, **kwargs)
1772-
self.legends.append(l)
1771+
if outside and not self.get_constrained_layout():
1772+
cbook._warn_external('legend outside=True method needs '
1773+
'constrained_layout=True. Setting False')
1774+
outside = False
1775+
1776+
if not outside:
1777+
l = mlegend.Legend(self, handles, labels, *extra_args, **kwargs)
1778+
self.legends.append(l)
1779+
else:
1780+
loc = kwargs.pop('loc')
1781+
if axs is None:
1782+
gs = self.get_gridspecs()[0]
1783+
else:
1784+
if isinstance(axs, GridSpecBase):
1785+
gs = axs
1786+
else:
1787+
gs = axs[0].get_gridspec()
1788+
l = gs.legend_outside(loc=loc, handles=handles, labels=labels,
1789+
**kwargs)
17731790
l._remove_method = self.legends.remove
17741791
self.stale = True
17751792
return l
17761793

1777-
@docstring.dedent_interpd
1778-
def legend_outside(self, *, loc=None, axs=None, **kwargs):
1779-
"""
1780-
Place a legend on the figure outside a list of axes, and automatically
1781-
make room, stealing space from the axes specified by *axs* (analogous
1782-
to what colorbar does).
1783-
1784-
To make a legend from existing artists on every axes::
1785-
1786-
legend()
1787-
1788-
To specify the axes to put the legend beside::
1789-
1790-
legend(axs=[ax1, ax2])
1791-
1792-
However, note that the legend will appear beside the gridspec that
1793-
owns these axes, so the following two calls will be the same::
1794-
1795-
fig, axs = plt.subplots(2, 2)
1796-
legend(axs=[axs[0, 0], axs[1, 0]])
1797-
legend(axs=axs)
1798-
1799-
To make a legend for a list of lines and labels::
1800-
1801-
legend(
1802-
handles=(line1, line2, line3),
1803-
labels=('label1', 'label2', 'label3'),
1804-
loc='upper right')
1805-
1806-
1807-
Parameters
1808-
----------
1809-
1810-
loc: location code for legend, optional, default=1
1811-
A legend location code, but does not support ``best`` or
1812-
``center``.
1813-
1814-
axs : sequence of `.axes.Axes` or a single `.GridSpecBase`, optional
1815-
A list of axes to put the legend beside, above, or below. This is
1816-
also the list of axes that artists will be taken from if *handles*
1817-
is empty. Note that the legend will be placed adjacent to all the
1818-
axes in the gridspec that the first element in *axs* belongs to,
1819-
so mixing axes from different gridspecs may lead to confusing
1820-
results. Also, its not possible to put the legend between
1821-
two columns or rows of the same gridspec; the legend is always
1822-
outside the gridspec. This can also be passed as a gridspec
1823-
instance directly.
1824-
1825-
handles : sequence of `.Artist`, optional
1826-
A list of Artists (lines, patches) to be added to the legend.
1827-
Use this together with *labels*, if you need full control on what
1828-
is shown in the legend and the automatic mechanism described above
1829-
is not sufficient.
1830-
1831-
The length of handles and labels should be the same in this
1832-
case. If they are not, they are truncated to the smaller length.
1833-
1834-
labels : sequence of strings, optional
1835-
A list of labels to show next to the artists.
1836-
Use this together with *handles*, if you need full control on what
1837-
is shown in the legend and the automatic mechanism described above
1838-
is not sufficient.
1839-
1840-
Other Parameters
1841-
----------------
1842-
1843-
%(_legend_kw_doc)s
1844-
1845-
Returns
1846-
-------
1847-
:class:`matplotlib.legend.Legend` instance
1848-
1849-
Notes
1850-
-----
1851-
Not all kinds of artist are supported by the legend command. See
1852-
:doc:`/tutorials/intermediate/legend_guide` for details.
1853-
1854-
Currently, `~figure.legend_outside` only works if
1855-
``constrained_layout=True``.
1856-
1857-
See Also
1858-
--------
1859-
.figure.legend
1860-
.gridspec.legend
1861-
.axes.Axes.legend
1862-
1863-
"""
1864-
1865-
if not self.get_constrained_layout():
1866-
cbook._warn_external('legend_outside method needs '
1867-
'constrained_layout, using default legend')
1868-
leg = self.legend(loc=loc, **kwargs)
1869-
return leg
1870-
1871-
if loc is None:
1872-
loc = 1 # upper right
1873-
1874-
if axs is None:
1875-
gs = self.get_gridspecs()[0]
1876-
handles, labels, extra_args, kwargs = mlegend._parse_legend_args(
1877-
self.axes, **kwargs)
1878-
else:
1879-
if isinstance(axs, GridSpecBase):
1880-
gs = axs
1881-
else:
1882-
gs = axs[0].get_gridspec()
1883-
1884-
handles, labels, extra_args, kwargs = mlegend._parse_legend_args(
1885-
axs, **kwargs)
1886-
1887-
return gs.legend_outside(loc=loc, handles=handles, labels=labels,
1888-
**kwargs)
1889-
18901794
@docstring.dedent_interpd
18911795
def text(self, x, y, s, fontdict=None, withdash=False, **kwargs):
18921796
"""

lib/matplotlib/gridspec.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,7 @@ def legend_outside(self, handles=None, labels=None, axs=None, **kwargs):
216216
# stack to the top...
217217
layoutbox.vstack([leg._layoutbox, child], padding=paddingh)
218218
self.figure.legends.append(leg)
219+
219220
return leg
220221

221222

lib/matplotlib/tests/test_legend.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ def test_figure_legend_outside():
390390
for nn, todo in enumerate(todos):
391391
fig, axs = plt.subplots(constrained_layout=True, dpi=100)
392392
axs.plot(range(10), label=f'Boo1')
393-
leg = fig.legend_outside(loc=todo)
393+
leg = fig.legend(loc=todo, outside=True)
394394
renderer = fig.canvas.get_renderer()
395395
fig.canvas.draw()
396396
assert_allclose(axs.get_window_extent(renderer=renderer).extents,

0 commit comments

Comments
 (0)