【问题标题】:How to plot a horizontal stacked bar with annotations如何绘制带有注释的水平堆积条
【发布时间】:2020-11-17 23:15:22
【问题描述】:
  • 我将离散分布的示例用作 matplotlib Discrete distribution as horizontal bar chart 上的水平条形图示例来创建一个图表,显示 2017 年什罗普郡选举中的投票份额。

  • 但是,由于我不知道如何操作数据,我不得不在程序中手动输入我的数据,这显然是我自己的无知。

  • 我在 CSV 文件中有相关数据,因此可以将其作为数据框加载。

    • CSV 中每个选区都有一行,其中有 63 行,每个党(保守党、LD、工党、绿党、独立党)的投票百分比列有 5 个实质性列。
  • 我想获得有关如何更改数据形式的建议,使其类似于此图表的输入。

  • 我不确定它是什么,但似乎可能是具有键和值的字典类型:

我的数据部分读取:

import pandas as pd
import matplotlib.pyplot as plt

category_names = ['Labour', 'LD', 'Indep', 'Green', 'Tory']
results = {'Abbey': [16, 56, 4,0, 24],
           'Albrighton': [0, 0, 32, 0, 68],
           'Alveley & Claverley': [0, 25, 0, 0, 75],
           'Bagley': [30, 30, 0, 0, 40],
           'Battlefield': [34, 0, 0, 9, 57],
           'Bayston Hill, Column & Sutton': [53, 4, 3, 7, 33],
           'Belle Vue': [43,28,0,5,24]}


# setup dataframe using the dict provided in the OP
df = pd.DataFrame(results, index=category_names)

# display(df)
        Abbey  Albrighton  Alveley & Claverley  Bagley  Battlefield  Bayston Hill, Column & Sutton  Belle Vue
Labour     16           0                    0      30           34                             53         43
LD         56           0                   25      30            0                              4         28
Indep       4          32                    0       0            0                              3          0
Green       0           0                    0       0            9                              7          5
Tory       24          68                   75      40           57                             33         24

  • 当作为 pandas 数据框输入时,我试图直接从 csv 文件中获取要像这样格式化的数据。

  • 尝试了 values 方法和 to_dict 方法,虽然它们得到的数据看起来相似,但它们并不完全正确。

    • 我认为有必要将数据划分为键和值,但这正是我的知识达到极限的地方。

【问题讨论】:

    标签: python pandas matplotlib data-transform


    【解决方案1】:

    选项 1:'Party' 作为 y 轴

    使用 3.4.2 版中的 matplotlib

    • 使用matplotlib.pyplot.bar_label
    • 有关其他格式选项,请参阅 matplotlib: Bar Label Demo 页面。
    • pandas 1.3.2python 3.81.matplotlib 3.4.21. 中测试
      • 1。所需的最低版本
      • labels = [f'{v.get_width():.0f}' if v.get_width() > 0 else '' for v in c ] 不使用赋值表达式 (:=)
    • 对竖线使用.get_height()
    ax = df.plot.barh(stacked=True, cmap='tab10', figsize=(16, 10))
    
    for c in ax.containers:
    
        # format the number of decimal places and replace 0 with an empty string
        labels = [f'{w:.0f}' if (w := v.get_width()) > 0 else '' for v in c ]
        
        ax.bar_label(c, labels=labels, label_type='center')
    

    在 3.4.2 版本之前使用 matplotlib

    • 在循环中提取.patch 组件,然后仅绘制大于0 的值的注释。
    # plot 
    ax = df.plot.barh(stacked=True, cmap='tab10', figsize=(16, 10))
    
    # annotations:
    for p in ax.patches:
        left, bottom, width, height = p.get_bbox().bounds
        if width > 0:
             ax.annotate(f'{width:0.0f}', xy=(left+width/2, bottom+height/2), ha='center', va='center')
    

    选项 2:'Ward' 作为 y 轴

    • 使用pandas.DataFrame.T 交换IndexColumns
      • 'Ward' 现在将成为索引,'Party' 将成为列
    # transpose df from the OP so Party is the in the columns and Ward is the index
    dft = df.T
    
    # display(dft)
                                   Labour  LD  Indep  Green  Tory
    Abbey                              16  56      4      0    24
    Albrighton                          0   0     32      0    68
    Alveley & Claverley                 0  25      0      0    75
    Bagley                             30  30      0      0    40
    Battlefield                        34   0      0      9    57
    Bayston Hill, Column & Sutton      53   4      3      7    33
    Belle Vue                          43  28      0      5    24
    

    使用版本 3.4.2 中的 matplotlib

    # plot
    ax = df.T.plot.barh(stacked=True, figsize=(16, 10))
    
    plt.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
    
    # annotations:
    for c in ax.containers:
        
        # format the number of decimal places and replace 0 with an empty string
        labels = [f'{w:.0f}' if (w := v.get_width()) > 0 else '' for v in c ]
        
        ax.bar_label(c, labels=labels, label_type='center')
    

    在 3.4.2 版本之前使用 matplotlib

    # plot
    ax = dft.plot.barh(stacked=True, figsize=(16, 10))
    
    plt.legend(loc='center left', bbox_to_anchor=(1.0, 0.5))
    
    # annotations:
    for p in ax.patches:
        left, bottom, width, height = p.get_bbox().bounds
        if width > 0:
             ax.annotate(f'{width:0.0f}', xy=(left+width/2, bottom+height/2), ha='center', va='center')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      • 2017-08-09
      • 2020-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多