【问题标题】:Add image annotations to boxplot向箱线图添加图像注释
【发布时间】:2021-10-28 01:52:34
【问题描述】:

我想向箱线图添加图像注释,类似于他们在这篇文章中对条形图所做的操作: How can I add images to bars in axes (matplotlib)

我的数据框如下所示:

import pandas as pd
import numpy as np

names = ['PersonA', 'PersonB', 'PersonC', 'PersonD','PersonE','PersonF']
regions = ['NorthEast','NorthWest','SouthEast','SouthWest']
dates = pd.date_range(start = '2021-05-28', end = '2021-08-23', freq = 'D')

df = pd.DataFrame({'runtime': np.repeat(dates, len(names))})
df['name'] = len(dates)*names
df['A'] = 40 + 20*np.random.random(len(df))
df['B'] = .1 * np.random.random(len(df))
df['C'] = 1 +.5 * np.random.random(len(df))
df['region'] = np.resize(regions,len(df))

我尝试使用 AnnotationBbox 方法,该方法非常适合我的时间序列,但我不完全确定它是否可以应用在这里。

import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
from matplotlib.cbook import get_sample_data

fig, ax = plt.subplots(
df.boxplot(column='A', by=['name'],ax=ax,showmeans=True, fontsize=8, grid=False)

for name in names:
  rslt_df = df[df['name']==name] 
  val = rslt_df['A'].values[0]
  xy = (0, val)

  fn = get_sample_data(f"{name}.png", asfileobj=False)
  arr_img = plt.imread(fn, format='png')
  imagebox = OffsetImage(arr_img, zoom=0.125)
  imagebox.image.axes = ax

  ab = AnnotationBbox(imagebox, xy,xybox=(15.,0),xycoords='data',boxcoords="offset points",pad=0,frameon=False)
  ax.add_artist(ab)

【问题讨论】:

    标签: python pandas matplotlib annotations boxplot


    【解决方案1】:
    • OP 中的代码如果与Add image annotations to bar plots axis tick labels 非常相似,但需要修改,因为boxplotsbarplots 略有不同。
    • 主要问题是xy 没有正确的值。
      • 可以调整xyxybox 参数以将图像放置在任何位置。
    • 默认情况下,boxplot 将刻度定位在range(1, n+1),如answer 中所述
      • 使用 0 索引重置刻度位置:positions=range(len(names))
    • df 是使用 names = ['PersonA', 'PersonB', 'PersonC'] 创建的,因为只提供了 3 张图片。
    ax = df.boxplot(column='A', by=['name'], showmeans=True, fontsize=8, grid=False, positions=range(len(names)))
    ax.set(xlabel=None, title=None)
    
    # move the xtick labels
    ax.set_xticks(range(len(names)))
    ax.set_xticklabels(countries)
    ax.tick_params(axis='x', which='major', pad=30)
    
    # use the ytick values to locate the image
    y = ax.get_yticks()[1]
    
    for i, (name, data) in enumerate(df.groupby('name')):
    
        xy = (i, y)
    
        fn = f"data/so_data/2021-08-28/{name}.png"  # path to file
        arr_img = plt.imread(fn, format='png')
        imagebox = OffsetImage(arr_img, zoom=0.125)
        imagebox.image.axes = ax
    
        ab = AnnotationBbox(imagebox, xy, xybox=(0, -30), xycoords='data', boxcoords="offset points", pad=0, frameon=False)
        ax.add_artist(ab)
    

    【讨论】:

    • "默认情况下,boxplot 将刻度定位在 range(1, n+1),因此将其重置为 0 索引 position=range(len(names))" WOW。是的,这很有帮助。
    • @p3hndrx 我不知道这个参数,直到前几天我做了这个answer
    【解决方案2】:

    我注意到 y 刻度并不总是以友好的方式定位自己,因此我设置了一个静态 Y 值(x 轴)。创建一个变换 xycoords,允许直接放置在 x 轴下方,无论 y 刻度如何。

    # BOX GRAPH PLOT
    fig, ax = plt.subplots(facecolor='darkslategrey')
    plt.style.use('dark_background')
    
    ax = df.boxplot(column=str(c), by=['name'],ax=ax,showmeans=True, fontsize=8,grid=False,positions=range(len(top)))
    ax.set(xlabel=None, title=None)
    
    
    # move the xtick labels
    ax.set_xticks(range(len(top)))
    ax.tick_params(axis='x', which='major', pad=20)
    
    # use the ytick values to locate the image
    y = ax.get_xticks()[0]
    
    
    for i, (name, data) in enumerate(df.groupby('name')):
        xy = (i, y)
    
        fn = f"{imgsrc}/{name}.png"  # path to file
        arr_img = plt.imread(fn, format='png')
        imagebox = OffsetImage(arr_img, zoom=0.125)
        imagebox.image.axes = ax
    
        trans = ax.get_xaxis_transform()
        ab = AnnotationBbox(imagebox, xy, xybox=(0, -15), xycoords=trans,boxcoords="offset points", pad=0, frameon=False)
        
        ax.add_artist(ab)
    
        plt.show()
    

    【讨论】:

      猜你喜欢
      • 2017-10-30
      • 1970-01-01
      • 2016-09-16
      • 2018-04-08
      • 1970-01-01
      • 2016-10-27
      • 2016-01-26
      • 2016-01-14
      相关资源
      最近更新 更多