I want to read a list of images into Python/Matplotlib and then plot this images instead of other markers (like points) in a graph. I have tried with imshow but I didn't succeed, because I cannot shift the image to another position and scale it appropriately. Maybe somebody has a good idea : )
Asked
Active
Viewed 4.7k times
57

Brian Tompsett - 汤莱恩
- 5,753
- 72
- 57
- 129

Anna Christine
- 860
- 1
- 6
- 14
-
There are some other questions about this [here](http://stackoverflow.com/questions/4860417/placing-custom-images-in-a-plot-window-as-custom-data-markers-or-to-annotate-t) and [here](http://matplotlib.1069221.n5.nabble.com/custom-markers-from-images-td4166.html), although whether those solutions will work for you depends on exactly what you need. – BrenBarn Mar 21 '14 at 18:10
-
2Try this: http://matplotlib.org/examples/pylab_examples/demo_annotation_box.html – Nitish Mar 21 '14 at 18:15
2 Answers
61
There are two ways to do this.
- Plot the image using
imshow
with theextent
kwarg set based on the location you want the image at. - Use an
OffsetImage
inside anAnnotationBbox
.
The first way is the easiest to understand, but the second has a large advantage. The annotation box approach will allow the image to stay at a constant size as you zoom in. Using imshow
will tie the size of the image to the data coordinates of the plot.
Here's an example of the second option:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
from matplotlib.cbook import get_sample_data
def main():
x = np.linspace(0, 10, 20)
y = np.cos(x)
image_path = get_sample_data('ada.png')
fig, ax = plt.subplots()
imscatter(x, y, image_path, zoom=0.1, ax=ax)
ax.plot(x, y)
plt.show()
def imscatter(x, y, image, ax=None, zoom=1):
if ax is None:
ax = plt.gca()
try:
image = plt.imread(image)
except TypeError:
# Likely already an array...
pass
im = OffsetImage(image, zoom=zoom)
x, y = np.atleast_1d(x, y)
artists = []
for x0, y0 in zip(x, y):
ab = AnnotationBbox(im, (x0, y0), xycoords='data', frameon=False)
artists.append(ax.add_artist(ab))
ax.update_datalim(np.column_stack([x, y]))
ax.autoscale()
return artists
main()

Tom Kurushingal
- 6,086
- 20
- 54
- 86

Joe Kington
- 275,208
- 71
- 604
- 463
-
9
-
I've tried your method, and it does not work for me. Do you think you could take a look at my follow-up question? It's here: https://stackoverflow.com/questions/48896088/ – jds Feb 21 '18 at 17:16
-
this is great, also just pointing out that the zoom parameter can be used to control the size of the points (specified as images) – bibzzzz Aug 12 '19 at 07:20
52
If you want different images:
This is now the first reply when googling "matplotlib scatter with images". If you're like me and actually need to plot different images on each image, try this minimalied example instead. Just be sure to input your own images.
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
def getImage(path, zoom=1):
return OffsetImage(plt.imread(path), zoom=zoom)
paths = [
'a.jpg',
'b.jpg',
'c.jpg',
'd.jpg',
'e.jpg']
x = [0,1,2,3,4]
y = [0,1,2,3,4]
fig, ax = plt.subplots()
ax.scatter(x, y)
for x0, y0, path in zip(x, y,paths):
ab = AnnotationBbox(getImage(path), (x0, y0), frameon=False)
ax.add_artist(ab)

Mitchell van Zuylen
- 3,905
- 4
- 27
- 64
-
2I had to `ax.add_artist(ab)` at the end in the loop. Is it possible it's left out of the example? – Joshua R. Jun 12 '19 at 21:58
-
1@JoshuaR. Yes, you're right. I was a little overzealous tidying up the example. `ax.add_artist(ab)` should indeed be added. – Mitchell van Zuylen Jun 14 '19 at 10:56
-
@MitchellvanZuylen what if I want to use only a single image for all points? Thanks – pukumarathe Feb 10 '21 at 08:56
-
1@pukumarathe In the current version, we pass a different value for `path` for each point. If you want the same image, you can pass the same value for `path` each time. Or, even better load the image once `im = OffsetImage(plt.imread(path))` and then replace `getImage(path)` in the for loop to `im` – Mitchell van Zuylen Feb 10 '21 at 11:53
-
@MitchellvanZuylen Great it works, the exactly I wanted. Thanks !! How can I reduce the size of marker image. Any suggestion? – pukumarathe Feb 10 '21 at 14:25
-
1`OffsetImage` takes an `zoom` parameter. You can play around with that, which can make the images smaller (or even larger, I think) – Mitchell van Zuylen Feb 11 '21 at 09:39