如何将图像添加到轴的条形图(matplotlib)

时间:2020-05-23 11:08:08

标签: python matplotlib plot figure axes

我要在条形图中添加如下标记图像:

enter image description here

我尝试了AnnotationBbox,但是显示为正方形轮廓。谁能说出与上图完全一样的方法?

编辑:

下面是我的代码

df$Year <- ifelse(df$Month >= 1 & df$Month <= 12*1, '1',
           ifelse(df$Month >= 1+12 & df$Month <= 12*2, '2',
           ifelse(df$Month >= 1+12*2 & df$Month <= 12*3, '3',
                       ...
           ifelse(df$Month >= 1+12*9 & df$Month <= 12*10, '10', NA))))))))))

编辑2:

ax.barh(y = y, width = values, color = r, height = 0.8)

height = 0.8
for i, (value, url) in enumerate(zip(values, image_urls)):
    response = requests.get(url)
    img = Image.open(BytesIO(response.content))

    width, height = img.size
    left = 10
    top = 10
    right = width-10
    bottom = height-10
    im1 = img.crop((left, top, right, bottom)) 
    print(im1.size)
    im1

    ax.imshow(im1, extent = [value - 6, value, i - height / 2, i + height / 2], aspect = 'auto', zorder = 2)

enter image description here

2 个答案:

答案 0 :(得分:1)

您需要使用T格式且背景透明的图像。 (如果图像没有所需的背景,则Gimp或ImageMagick之类的软件可能会有所帮助。)

有了这样的图像,plt.imshow()可以将其放置在绘图中。通过.png给出位置。为防止extent=[x0, x1, y0, y1]强制使用相等的长宽比,请添加imshowaspect='auto'有助于使图像显示在条形图的顶部。之后,zorder=2plt.xlim需要显式设置(同样是因为plt.ylim弄乱了它们。)

下面的示例代码使用了matplotlib的“ ada.png”,因此可以独立测试该代码。现在,它正在countryflags.io之后从this post加载标志。

请注意,图像被放入data coordinates中的盒子中(在这种情况下为6宽和0.9高)。例如,当绘图大小调整时,此框将被拉伸。您可能要根据x比例和图形尺寸将6更改为另一个值。

imshow

example plot

PS:如Ernest在评论和this post中所述,使用import numpy as np import matplotlib.pyplot as plt # import matplotlib.cbook as cbook import requests from io import BytesIO labels = ['CW', 'CV', 'GW', 'SX', 'DO'] colors = ['crimson', 'dodgerblue', 'teal', 'limegreen', 'gold'] values = 30 + np.random.randint(5, 20, len(labels)).cumsum() height = 0.9 plt.barh(y=labels, width=values, height=height, color=colors, align='center') for i, (label, value) in enumerate(zip(labels, values)): # load the image corresponding to label into img # with cbook.get_sample_data('ada.png') as image_file: # img = plt.imread(image_file) response = requests.get(f'https://www.countryflags.io/{label}/flat/64.png') img = plt.imread(BytesIO(response.content)) plt.imshow(img, extent=[value - 8, value - 2, i - height / 2, i + height / 2], aspect='auto', zorder=2) plt.xlim(0, max(values) * 1.05) plt.ylim(-0.5, len(labels) - 0.5) plt.tight_layout() plt.show() 时图像的长宽比保持不变。 (此外,OffsetImagexlim保持不变。)当条形更多时,图像不会缩小,因此您可能需要试验ylim中的因子和x偏移量在OffsetImage(img, zoom=0.65)中。

对于过短的条形,一个额外的选项可以将标志放置在条形之外。或在y轴的左侧。

适用于单杠的代码如下:

AnnotationBbox(..., xybox=(-25, 0))

example using <code>OffsetImage</code>

答案 1 :(得分:1)

要完成@johanC答案,可以在GNU / linux和iso-flags-png python包下使用iso3166中的标志:

import matplotlib.pyplot as plt
from iso3166 import countries
import matplotlib.image as mpimg


def pos_image(x, y, pays, haut):
    pays = countries.get(pays).alpha2.lower()
    fichier = "/usr/share/iso-flags-png-320x240"
    fichier += f"/{pays}.png"
    im = mpimg.imread(fichier)
    ratio = 4 / 3
    w = ratio * haut
    ax.imshow(im,
              extent=(x - w, x, y, y + haut),
              zorder=2)


plt.style.use('seaborn')
fig, ax = plt.subplots()

liste_pays = [('France', 10), ('USA', 9), ('Spain', 5), ('Italy', 5)]

X = [p[1] for p in liste_pays]
Y = [p[0] for p in liste_pays]

haut = .8
r = ax.barh(y=Y, width=X, height=haut, zorder=1)
y_bar = [rectangle.get_y() for rectangle in r]
for pays, y in zip(liste_pays, y_bar):
    pos_image(pays[1], y, pays[0], haut)


plt.show()

给出: enter image description here