Skip to content
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

Adding a legend to a SubFigure doesn't work #20723

Closed
tomneep opened this issue Jul 23, 2021 · 4 comments · Fixed by #20859
Closed

Adding a legend to a SubFigure doesn't work #20723

tomneep opened this issue Jul 23, 2021 · 4 comments · Fixed by #20859
Labels
Good first issue Open a pull request against these issues if there are no active ones! topic: legend
Milestone

Comments

@tomneep
Copy link
Contributor

tomneep commented Jul 23, 2021

Bug report

Bug summary

Adding a legend to a SubFigure doesn't work

Code for reproduction

import matplotlib.pyplot as plt

subfig = plt.figure().subfigures()
ax = subfig.subplots()
ax.plot([0, 1, 2], [0, 1, 2], label="test")
subfig.legend()

Actual outcome

Traceback (most recent call last):
  File "bug_test.py", line 5, in <module>
    subfig.legend()
  File "/.../matplotlib/lib/matplotlib/figure.py", line 1068, in legend
    l = mlegend.Legend(self, handles, labels, *extra_args,
  File "/.../matplotlib/lib/matplotlib/legend.py", line 441, in __init__
    raise TypeError("Legend needs either Axes or Figure as parent")
TypeError: Legend needs either Axes or Figure as parent

Expected outcome

I'd expect this to work and produce a legend. The example is of course a bit contrived but it would be useful to allow a legend per subfigure

Changing L437 here to check against FigureBase fixes it.

if isinstance(parent, Axes):
self.isaxes = True
self.axes = parent
self.set_figure(parent.figure)
elif isinstance(parent, Figure):
self.isaxes = False
self.set_figure(parent)
else:
raise TypeError("Legend needs either Axes or Figure as parent")
self.parent = parent

I can make a PR at some point but wanted to flag the issue here in case anyone gets to it first.

Matplotlib version

  • Operating system: macOS 11.4
  • Matplotlib version (import matplotlib; print(matplotlib.__version__)): 3.4.2.post1350+gdba02be18e
  • Matplotlib backend (print(matplotlib.get_backend())): TkAgg
  • Python version: Python 3.8.3
@jklymak
Copy link
Member

jklymak commented Jul 23, 2021

Yep that was just an oversight, not a design decision ;-)

@story645 story645 added Good first issue Open a pull request against these issues if there are no active ones! topic: legend labels Jul 23, 2021
@tacaswell tacaswell added this to the v3.5.0 milestone Jul 23, 2021
@tomneep
Copy link
Contributor Author

tomneep commented Jul 24, 2021

I don't want to complicate this too much, but a further issue arrises even after changing the line I suggest above (let me know if this should be a separate issue)

fig = plt.figure()
subfig = fig.subfigures()
ax = subfig.subplots()
ax.plot([0, 1, 2], [0, 1, 2], label="test")
subfig.legend()
print(fig.get_default_bbox_extra_artists())

doesn't include the legend and so the legend is cut off if saving the figure with bbox_inches="tight":

[<matplotlib.figure.SubFigure object at 0x7fb5cbbe8790>,
 <matplotlib.lines.Line2D object at 0x7fb5cbc0db50>,
 <matplotlib.spines.Spine object at 0x7fb5cadc73a0>,
 <matplotlib.spines.Spine object at 0x7fb5cb8ed820>,
 <matplotlib.spines.Spine object at 0x7fb5cb8ed6d0>,
 <matplotlib.spines.Spine object at 0x7fb5cad61f70>,
 <matplotlib.axis.XAxis object at 0x7fb5cadc7be0>,
 <matplotlib.axis.YAxis object at 0x7fb5cbbe8e50>,
 <matplotlib.patches.Rectangle object at 0x7fb5cbbfd760>]

Adding something like

if self.subfigs:
    return [artist for subfig in self.subfigs
            for artist in subfig.get_default_bbox_extra_artists()]

to the start of

def get_default_bbox_extra_artists(self):
bbox_artists = [artist for artist in self.get_children()
if (artist.get_visible() and artist.get_in_layout())]
for ax in self.axes:
if ax.get_visible():
bbox_artists.extend(ax.get_default_bbox_extra_artists())
return bbox_artists

seems to do the trick, but let me know if there are any better ideas.

@jklymak
Copy link
Member

jklymak commented Jul 24, 2021

OK, so all that logic seems wrong - get_default_bbox_extra_artists should probably only return SubFigure, and its bbox should include the legend. Can you indeed open a new issue for this?

@BhaswatiRoy
Copy link

Can we add a legend like this way for the subplots?

image

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Good first issue Open a pull request against these issues if there are no active ones! topic: legend
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants