Skip to content

Commit 00e0ac4

Browse files
Add fig.add_artist method
1 parent 126113f commit 00e0ac4

File tree

3 files changed

+81
-0
lines changed

3 files changed

+81
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
Figure has an `~.figure.Figure.add_artist` method
2+
-------------------------------------------------
3+
4+
A method `~.figure.Figure.add_artist` has been added to the
5+
:class:`~.figure.Figure` class, which allows artists to be added directly
6+
to a figure. E.g.
7+
8+
::
9+
10+
circ = plt.Circle((.7, .5), .05)
11+
fig.add_artist(circ)
12+
13+
In case the added artist has no transform set previously, it will be set to
14+
the figure transform (``fig.transFigure``).
15+
This new method may be useful for adding artists to figures without axes or to
16+
easily position static elements in figure coordinates.

lib/matplotlib/figure.py

+36
Original file line numberDiff line numberDiff line change
@@ -1038,6 +1038,42 @@ def fixlist(args):
10381038
key = fixlist(args), fixitems(kwargs.items())
10391039
return key
10401040

1041+
def add_artist(self, artist, clip=False):
1042+
"""
1043+
Add any :class:`~matplotlib.artist.Artist` to the figure.
1044+
1045+
Usually artists are added to axes objects using
1046+
:meth:`matplotlib.axes.Axes.add_artist`, but use this method in the
1047+
rare cases that adding directly to the figure is necessary.
1048+
1049+
Parameters
1050+
----------
1051+
artist : `~matplotlib.artist.Artist`
1052+
The artist to add to the figure. If the added artist has no
1053+
transform previously set, its transform will be set to
1054+
``figure.transFigure``.
1055+
clip : bool, optional, default ``False``
1056+
An optional parameter ``clip`` determines whether the added artist
1057+
should be clipped by the figure patch. Default is *False*,
1058+
i.e. no clipping.
1059+
1060+
Returns
1061+
-------
1062+
artist : The added `~matplotlib.artist.Artist`
1063+
"""
1064+
artist.set_figure(self)
1065+
self.artists.append(artist)
1066+
artist._remove_method = self.artists.remove
1067+
1068+
if not artist.is_transform_set():
1069+
artist.set_transform(self.transFigure)
1070+
1071+
if clip:
1072+
artist.set_clip_path(self.patch)
1073+
1074+
self.stale = True
1075+
return artist
1076+
10411077
def add_axes(self, *args, **kwargs):
10421078
"""
10431079
Add an axes to the figure.

lib/matplotlib/tests/test_figure.py

+29
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import sys
22
import warnings
3+
import io
34

45
from matplotlib import rcParams
56
from matplotlib.testing.decorators import image_comparison
@@ -373,6 +374,34 @@ def test_figure_repr():
373374
assert repr(fig) == "<Figure size 100x200 with 0 Axes>"
374375

375376

377+
def test_add_artist():
378+
fig, ax = plt.subplots(dpi=100)
379+
l1 = plt.Line2D([.2, .7], [.7, .7])
380+
l2 = plt.Line2D([.2, .7], [.8, .8])
381+
r1 = plt.Circle((20, 20), 100, transform=None)
382+
r2 = plt.Circle((.7, .5), .05)
383+
r3 = plt.Circle((4.5, .8), .55, transform=fig.dpi_scale_trans,
384+
facecolor='crimson')
385+
for a in [l1, l2, r1, r2, r3]:
386+
fig.add_artist(a)
387+
l2.remove()
388+
buf1 = io.BytesIO()
389+
fig.savefig(buf1)
390+
391+
fig2, ax2 = plt.subplots(dpi=100)
392+
l1 = plt.Line2D([.2, .7], [.7, .7], transform=fig2.transFigure)
393+
r1 = plt.Circle((20, 20), 100, transform=None, clip_on=False, zorder=20)
394+
r2 = plt.Circle((.7, .5), .05, transform=fig2.transFigure)
395+
r3 = plt.Circle((4.5, .8), .55, transform=fig.dpi_scale_trans,
396+
facecolor='crimson', clip_on=False, zorder=20)
397+
for a in [l1, r1, r2, r3]:
398+
ax2.add_artist(a)
399+
buf2 = io.BytesIO()
400+
fig2.savefig(buf2)
401+
402+
assert buf1.getvalue() == buf2.getvalue()
403+
404+
376405
@pytest.mark.skipif(sys.version_info < (3, 6), reason="requires Python 3.6+")
377406
@pytest.mark.parametrize("fmt", ["png", "pdf", "ps", "eps", "svg"])
378407
def test_fspath(fmt, tmpdir):

0 commit comments

Comments
 (0)