如何在 python 中的垂直条形图下方制作水平颜色轨道

How to make a horizontal color track underneath a vertical bar plot in python

我正在尝试绘制如下所示的条形图:vertical stacked barplot with a horizontal bar underneath

我使用以下代码在 python 中制作了实际的垂直条形图:

fig, ax = plt.subplots(figsize=[15, 5])
width = 0.75   
ax.bar(labels, my_order["relapse"], width, label=SAMPLE[0], color = "r")
ax.bar(labels, my_order['remission'], width, bottom=my_order['relapse'], label=SAMPLE[1], color = "orange")
ax.set_title('Ratio of cells by patient in each cluster')
ax.legend(bbox_to_anchor=(1.01,0.5), loc='center left') 

my_order 是一个数据框,其中包含一列复发数字和一列缓解数字。我无法创建的部分是下方的单杠。这将根据不同条形图的其他属性进行着色(每个条形图代表一个集群,在这种情况下,如果集群有一个 属性,我想将水平图着色为蓝色,如果有另一个,则为黄色)。有谁知道在 python 中是否可以这样做?或者如果我必须手动执行此操作?在完整的数据集中,整个图中有大约 50 个条形图,因此找到一种不手动执行此操作的方法会很棒。

您可以遍历每个条形位置,并创建一个与条形宽度相同但略低于绘图的彩色矩形。

rectangle 有以下参数:

  • (x, y), width, height
  • transform=ax.get_xaxis_transform():在 x 方向上,值在 "data coordinates" 中测量,这里是 0, 1, 2, ... 用于柱位置;在 y 方向上使用“轴坐标”,从绘图区域顶部的 1 到底部的 0,下面的位置使用负值
  • clip_on=False:正常情况下,当某些东西放在绘图区域之外时,它会被剪掉; clip_on=False 覆盖该行为
  • facecolor=...:内饰颜色
  • edgecolor='black': 黑边
from matplotlib import pyplot as plt
import pandas as pd
import numpy as np

labels = [*'abcdefghijklmnopqrst']
my_order = pd.DataFrame({'relapse': np.random.randint(11, 51, 20),
                         'remission': np.random.randint(11, 51, 20),
                         'cluster': np.random.randint(1, 3, 20)})
fig, ax = plt.subplots(figsize=[15, 5])
width = 0.75
ax.bar(labels, my_order['relapse'], width, label='SAMPLE[0]', color='crimson')
ax.bar(labels, my_order['remission'], width, bottom=my_order['relapse'], label='SAMPLE[1]', color='orange')
ax.set_title('Ratio of cells by patient in each cluster')
legend1 = ax.legend(title='Samples', bbox_to_anchor=(1.01, 0.5), loc='center left')
ax.margins(x=0.01)
color_for_cluster = {1: 'skyblue', 2: 'yellow'}
for i, cluster in enumerate(my_order['cluster']):
    ax.add_patch(plt.Rectangle((i - width / 2, -0.1), width, 0.02,
                               facecolor=color_for_cluster[cluster], edgecolor='black',
                               transform=ax.get_xaxis_transform(), clip_on=False))
handles = [plt.Rectangle((0, 0), 0, 0, facecolor=color_for_cluster[cluster], edgecolor='black', label=cluster)
           for cluster in color_for_cluster]
legend2 = ax.legend(handles=handles, title='Clusters', bbox_to_anchor=(1.01, -0.01), loc='lower left')
ax.add_artist(legend1)  # add the legend again, because the second call to ax.legend removes the first legend
fig.tight_layout()
plt.show()

您也可以使用 plt.Rectangle((i - 1/2, -0.1), 1, 0.02, ...) 让矩形占据整个宽度。