Search code examples
pythonmatplotlibimshow

How can I embed an image on each of my subplots in matplotlib?


I'm trying to put a little arrow in the corner of each of my subplots. Below is the sample code I'm using:

import matplotlib.pyplot as plt
import matplotlib.image as image
from numpy import linspace

xs = linspace(0, 1, 100)
im = image.imread('arrow.png')

def multi_plot():
    fig, axes = plt.subplots(4, 1)
    x = 0
    for axis in axes:
        axis.plot(xs, xs**2)
        axis.imshow(im, extent=(0.4, 0.6, .5, .7), zorder=-1, aspect='auto')
    plt.show()

multi_plot()

Unfortunately, this produces 4 subplots that are entirely dominated by the arrows and the plots themselves are not seen.

Example output - Incorrect:

Example output - Incorrect

What do I need to do so that each individual subplot has a small image and the plot itself can be seen?


Solution

  • I think it's worthwhile thinking about putting the image in a box and place it similar to the legend, using a loc argument. The advantage is that you don't need to care about extents and data coordinates at all. You also wouldn't need to take care of what happens when zooming or panning the plot. Further it allows to keep the image in it's original resolution (zoom=1 in below code).

    import matplotlib.pyplot as plt
    import matplotlib.image as image
    from numpy import linspace
    
    from matplotlib.offsetbox import OffsetImage,AnchoredOffsetbox
    
    
    xs = linspace(0, 1, 100)
    im = image.imread('arrow.png')
    
    
    def place_image(im, loc=3, ax=None, zoom=1, **kw):
        if ax==None: ax=plt.gca()
        imagebox = OffsetImage(im, zoom=zoom*0.72)
        ab = AnchoredOffsetbox(loc=loc, child=imagebox, frameon=False, **kw)
        ax.add_artist(ab)
    
    
    def multi_plot():
        fig, axes = plt.subplots(4, 1)
        for axis in axes:
            axis.plot(xs, xs**2)
            place_image(im, loc=2, ax=axis, pad=0, zoom=1)
        plt.show()
    
    multi_plot()
    

    enter image description here