Adding the same Patch instance to multiple subplot

2020-07-10 07:18发布

问题:

I am trying to add the same instance of a patch to multiple axes in matplotlib. Here is minimal example:

import matplotlib.pyplot as mpl_plt
import matplotlib.patches as mpl_patches

fig, (axes_1, axes_2) = mpl_plt.subplots(2,1)
axes_1.axis([-5, 5, -5, 5])
axes_2.axis([-5, 5, -5, 5])

# Create ellipse and add it to the axes
ellipse = mpl_patches.Ellipse((1,1), 0.5, 0.8)
axes_1.add_patch(ellipse)
axes_2.add_patch(ellipse)

# Change the position of the ellipse
ellipse.center = (2,2)

# Show the plot
mpl_plt.show()

In this example, the ellipse does not appear in either subplot. If I comment out the line axes_2.add_patch(ellipse), the ellipse appears in the first subplot at its moved location (2,2). Is it possible to have the ellipse appear in multiple axes and have changes to it reflected in both?

My end goal is being able to add artists to different subplots and have changes to the artists reflected in all axes. Even better would be to use zoomed_inset_axes from mpl_toolkits to have an inset plot that shows a close-up of a patch, where changes to the patch would be shown in both the main plot and the inset.

回答1:

One way to do this is using a class to set all your custom settings for the artist. I've made an example class that has a default value for each property. If you then just make a reference to the art function of this class you get a new instance every time but with the exact same parameters. Notice how I changed Ellipse1 to have xy=(2,2) and that showed up on both plots. Just for an added flair, I made it so you could potentially call more than one patch type using getattr. This is assuming there are shared arguments for different patches or? You can make this as complicated or simple as you like I suppose.

import matplotlib.pyplot as mpl_plt
import matplotlib.patches as mpl_patches

class artist_instance:
    def __init__(self,
                 xy=None,
                 width=None,
                 height=None,
                 type=None,
                 ):
        self.xy=xy if xy is not None else (1,1)
        self.width=width if width is not None else 0.5
        self.height=height if height is not None else 0.8
        self.type=type if type is not None else 'Ellipse'

    def art(self):
        return getattr(mpl_patches,self.type)(xy=self.xy,width=self.width,height=self.height)

Ellipse1=artist_instance(xy=(2,2))

fig, (axes_1, axes_2) = mpl_plt.subplots(2,1)
axes_1.axis([-5, 5, -5, 5])
axes_2.axis([-5, 5, -5, 5])

axes_1.add_patch(Ellipse1.art())
axes_2.add_patch(Ellipse1.art())
mpl_plt.show()

Plot Result