Matplotlib: 如何绘制图片而不是点?

58
我希望能够在Python/Matplotlib中读取一系列图片并在图表中绘制这些图片,而不是使用其他标记(如点)。我已经尝试使用imshow,但没有成功,因为我无法将图像移到另一个位置并适当地缩放它。也许有人有好的想法:)它应该看起来像这样!(没有海绵宝宝,但当然有非常严肃的数据!)

这里还有一些关于此问题的其他问题:这里这里,尽管这些解决方案是否适用于您取决于您需要什么。 - BrenBarn
2
试试这个:http://matplotlib.org/examples/pylab_examples/demo_annotation_box.html - Nitish
2个回答

63

有两种方法可以实现这个功能。

  1. 使用 imshow 函数绘制图像,通过设置 extent 参数来确定图像位置。
  2. AnnotationBbox 中使用 OffsetImage

第一种方法比较容易理解,但第二种方法具有很大的优势。注释框方法将允许图像在缩放时保持恒定的大小。而使用 imshow 会将图像的大小与绘图的数据坐标绑定。

这里是第二个选项的示例:

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()

输入图像描述


9
那是艾达·洛夫莱斯吗?太棒了。 - Matthew Turner
我尝试了你的方法,但对我无效。你能否看一下我的后续问题?链接在这里:https://stackoverflow.com/questions/48896088/ - jds
这很棒,还要指出的是,缩放参数可以用来控制点的大小(指定为图像)。 - bibzzzz

53

如果你想要不同的图片:

现在这是谷歌搜索“matplotlib scatter with 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)

输入图像描述


2
我必须在循环结束时添加 ax.add_artist(ab)。有可能这个例子中漏掉了吗? - Joshua R.
1
@JoshuaR。是的,你说得对。我在整理示例时有点过度热情了。确实应该添加ax.add_artist(ab) - Mitchell van Zuylen
@MitchellvanZuylen 如果我想为所有点使用单个图像怎么办?谢谢 - pukumarathe
1
在当前版本中,我们为每个点传递了不同的“path”值。如果您想要相同的图像,则可以每次传递相同的“path”值。或者,更好的方法是加载一次图像 im = OffsetImage(plt.imread(path)),然后将for循环中的 getImage(path) 替换为 im - Mitchell van Zuylen
@MitchellvanZuylen 太好了,它能正常工作,就是我想要的。谢谢!!你有什么建议可以帮我缩小标记图像的大小吗? - pukumarathe
1
OffsetImage 接受一个 zoom 参数。你可以尝试调整它,这可以使图像变小(或者甚至更大,我想)。 - Mitchell van Zuylen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接