【问题标题】:Annotate specific bars with values from Dataframe on Pandas bar plots在 Pandas 条形图上使用 Dataframe 中的值注释特定条形
【发布时间】:2020-10-09 12:25:22
【问题描述】:

我有一个这样的条形图:

这是我用来生成它的代码:

def performance_plot_builder(data: str, ax: pyplot.Axes):
    df = pandas.read_csv(data, header=0, sep=';')
    df[['library', 'function']] = df.name.str.split('_', expand=True, n=1)
    df = df.pivot('function', 'library', 'elapsed')

    normalized = df.div(df.max(axis=1), axis=0)
    normalized.plot(ax=ax, kind='bar', color=[c.value for c in Color])

    ax.set_ylabel('execution time (normalized)')

    for p in ax.patches:
        ax.annotate(str(p.get_height()), (p.get_x() * 1.005, p.get_height() * 1.005))

数据首先相对于每个项目的两个系列之间的最大值进行归一化,然后绘制。我已经能够注释每个条上的值,但是我想要一些修改:

  1. 我只希望显示在两个值的最大值上的值。例如,对于array_access,只会显示stl 条的值,因为它大于etl

  2. 我最需要的是显示非标准化值而不是现在的标准化值(所以df 数据帧而不是normalized 数据帧。

  3. 我还希望将标签旋转 90 度,以便标签显示在条本身上。

这是我拥有的示例数据框:

library               etl           stl
function
copy         6.922975e-06  6.319098e-06
copy_if      1.369602e-04  1.423410e-04
count        6.135367e-05  1.179409e-04
count_if     1.332942e-04  1.908408e-04
equal        1.099963e-05  1.102448e-05
fill         5.337406e-05  9.352984e-05
fill_n       6.412923e-05  9.354095e-05
find         4.354274e-08  7.804437e-08
find_if      4.792641e-08  9.206846e-08
iter_swap    4.898631e-08  4.911048e-08
rotate       2.816952e-04  5.219732e-06
swap         2.832723e-04  2.882649e-04
swap_ranges  3.492764e-04  3.576686e-04
transform    9.739075e-05  1.080187e-04

我真的不知道该怎么做,因为据我所知,数据是从 Axes 对象中检索到的,但是它包含标准化值。

编辑

我能够用这段代码完成所有的修改:

interleaved = [val for pair in zip(df['etl'], df['stl']) for val in pair]
for v, p in zip(interleaved, ax.patches):
    if p.get_height() == 1:
        ax.text(x=p.get_x() + 0.01, y=0.825, s=f'{v:.1E}', rotation=90, color='white')

但是,这有点硬编码,只有在条形图值被规范化时才有效,它们很可能是,但不一定,所以我想要一个通用的解决方案,独立于规范化值。

【问题讨论】:

    标签: python pandas matplotlib charts


    【解决方案1】:

    我想通了:

    size = len(ax.patches) // 2
    for v_etl, v_stl, p_etl, p_stl in zip(df['etl'], df['stl'], ax.patches[:size], ax.patches[size:]):
        p, v = (p_etl, v_etl) if v_etl > v_stl else (p_stl, v_stl)
        ax.text(x=p.get_x() + 0.18 * p.get_width(), y=p.get_height() - 0.175, s=f'{v:.1E}', rotation=90, color='white')
    

    【讨论】:

      猜你喜欢
      • 2014-10-16
      • 2017-01-23
      • 2020-02-09
      相关资源
      最近更新 更多