Pandas 将范围绘制为条形图

Pandas Plot range as bar

我有如下Dataframe(这个table只是一个例子,类型和尺寸更多):

df = pd.DataFrame({
'type':['A','A','B','B','C','C','D','D'],
'size':['a','b','c','d','e','f','g','h'],
'Nx':[4.3,2.4,2.5,4.4,3.5,1.8,4.5,2.8],
'min':[0.5,2.5,0.7,3.2,0.51,2,0.3,3],
'max':[1.5,3.4,1.7,4.3,1.51,3,1.2,4]})

print(df)
ax=df.plot.bar(x='type',y='max',stacked=True,bottom=df['min'])
ax.plt(x='type',y='Nx')

这是结果:

  type size   Nx   min   max
0    A    a  4.3  0.50  1.50
1    A    b  2.4  2.50  3.40
2    B    c  2.5  0.70  1.70
3    B    d  4.4  3.20  4.30
4    C    e  3.5  0.51  1.51
5    C    f  1.8  2.00  3.00
6    D    g  4.5  0.30  1.20
7    D    h  2.8  3.00  4.00

我如何通过只有一列用于类型 A、B、C 来绘制此数据。然后为类型、Nx 绘制散点图,如下所示:

您可以添加一个名为 height 等于 max - min 的新列,因为 plt.bar 方法采用高度参数,然后通过 ['type','size'] 重新索引 DataFrame。然后遍历这个多索引 DataFrame 的级别,并为每个独特的类型和大小组合绘制一个具有不同颜色的条。

这还需要您定义自己的调色板。我从 plt.cm 中选择了一个离散的调色板,并将整数值映射到每种颜色。当您遍历每个唯一的类型和尺寸时,您可以为最内层的循环设置一个计数器,以确保同一类型中的每个条具有不同的颜色。

注意:这确实假设没有多个行具有相同的类型和大小。

为了表明这是可推广的,我添加了另一个类型 'D' 和大小 'i' 的条,它在图中显示为一个不同的条。

import pandas as pd
import matplotlib.pyplot as plt

## added a third size to type D
df = pd.DataFrame({
'type':['A','A','B','B','C','C','D','D','D'],
'size':['a','b','c','d','e','f','g','h','i'],
'Nx':[4.3,2.4,2.5,4.4,3.5,1.8,4.5,2.8,5.6],
'min':[0.5,2.5,0.7,3.2,0.51,2,0.3,3,4.8],
'max':[1.5,3.4,1.7,4.3,1.51,3,1.2,4,5.3]})

## create a height column for convenience
df['height'] = df['max'] - df['min']
df_grouped = df.set_index(['type','size'])

## create a list of as many colors as there are categories
cmap = plt.cm.get_cmap('Accent', 10)

## loop through the levels of the grouped DataFrame
for each_type, df_type in df_grouped.groupby(level=0):
    color_idx=0
    for each_size, df_type_size in df_type.groupby(level=1):
        color_idx += 1
        plt.bar(x=[each_type]*len(df_type_size), height=df_type_size['height'], bottom=df_type_size['min'], width=0.4, 
            edgecolor='grey', color=cmap(color_idx))
        plt.scatter(x=[each_type]*len(df_type_size), y=df_type_size['Nx'], color=cmap(color_idx))

plt.ylim([0, 7])
plt.show()