2

There are a lot of posts on plotting pre-saved png images as scatter plot markers but I'm wondering if there's a way to take an array of 2D arrays (lets naively call them images) and, given x and y coordinates, use them as scatter markers without having to save out as pngs and then read in.

For example, say you have these rather dull 'images':

import numpy as np
images = np.random.uniform(0,1,(5,10,10))

... that is, we have 5 lots of 10 by 10, 2D images.

If we want to plot these 'images' as markers at the following 5 locations specified by x and y coordinates:

x, y, = np.array([0, 2, -3, 6, 6.5]), np.array([10, 3, -2, -1, 0.2])

... what is the best way to go about doing this?


Closest example I have tried but failed to make work:

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage

# Convert the images into PIL images
# How? Using: https://stackoverflow.com/a/62144323/8188120
# Why? Maybe PIL images are nice and easy for plotting as markers.. I'm grasping at straws really

pil_images = []
for i in range(images.shape[0]):
    pil_images.append(Image.fromarray(np.uint8(images[i])).convert('RGB'))

# Try plotting the images as markers
# Why this method? Saw it in this thread and continued grasping for more straws: https://stackoverflow.com/a/53851017/8188120

fig, ax = plt.subplots()
for i in range(len(pil_images)):
    ab = AnnotationBbox(OffsetImage(pil_images[i]), x[i], y[i], frameon=False)
    ax.add_artist(ab)
fig.savefig(image_path + 'funny_markers.png')
plt.close('all')
user8188120
  • 883
  • 1
  • 15
  • 30

1 Answers1

1

You need to set the limits of the axis accordingly, or they would default to just (0,1):

from matplotlib.offsetbox import OffsetImage, AnnotationBbox
fig, ax = plt.subplots()
for x0, y0, img in zip(x, y, images):
    ab = AnnotationBbox(OffsetImage(img, zoom=5, cmap='gray'), (x0, y0), frameon=False)
    ax.add_artist(ab)
plt.xlim(x.min(), x.max()+1)
plt.ylim(y.min(), y.max()+1)
plt.show()

Output:

enter image description here

Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
  • This worked really nicely, thank you so much for the rapid response! The only thing worth noting is that if your images are very large so that you use zoom < 1 for the rescaling, then there's some automatic interpolation / averaging for the resultant pixels and it would be great if you could choose that rescaling method so as to not lose too much detail. Do you know if that's possible? :) – user8188120 Aug 29 '22 at 16:23
  • 1
    Ah never mind, I found it :D https://matplotlib.org/stable/api/offsetbox_api.html#matplotlib.offsetbox.OffsetImage – user8188120 Aug 29 '22 at 16:33