水平堆叠条形图并向每个部分添加标签

2024-04-25

我正在尝试在 matplotlib 中复制以下图像,看起来barh是我唯一的选择。虽然看起来你不能堆叠barh图表所以我不知道该怎么办

如果你知道更好的Python库来绘制这种东西,请告诉我。

这就是我能想到的作为开始的一切:

import matplotlib.pyplot as plt; plt.rcdefaults()
import numpy as np
import matplotlib.pyplot as plt

people = ('A','B','C','D','E','F','G','H')
y_pos = np.arange(len(people))
bottomdata = 3 + 10 * np.random.rand(len(people))
topdata = 3 + 10 * np.random.rand(len(people))
fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111)
ax.barh(y_pos, bottomdata,color='r',align='center')
ax.barh(y_pos, topdata,color='g',align='center')
ax.set_yticks(y_pos)
ax.set_yticklabels(people)
ax.set_xlabel('Distance')

plt.show()

然后我必须使用单独添加标签ax.text这会很乏味。理想情况下,我只想指定要插入的部分的宽度,然后用我选择的字符串更新该部分的中心。外部的标签(例如 3800)我可以稍后添加自己,它主要是条形部分本身的标签,并以我遇到问题的良好方式创建此堆叠方法。您甚至可以以任何方式指定“距离”,即颜色跨度吗?


编辑2:更多异构数据。 (我已经离开了上面的方法,因为我发现每个系列处理相同数量的记录更常见)

回答问题的两个部分:

a) barh返回它绘制的所有补丁的句柄容器。您可以使用补丁的坐标来帮助确定文本位置。

b) 关注these https://stackoverflow.com/a/16654415/1643946 two https://stackoverflow.com/a/16654564/1643946回答我之前提到的问题(参见Matplotlib 中的水平堆叠条形图 https://stackoverflow.com/q/16653815/1643946),您可以通过设置“左”输入水平堆叠条形图。

另外 c) 处理形状不太均匀的数据。

以下是处理形状不太均匀的数据的一种方法,即独立处理每个段。

import numpy as np
import matplotlib.pyplot as plt

# some labels for each row
people = ('A','B','C','D','E','F','G','H')
r = len(people)

# how many data points overall (average of 3 per person)
n = r * 3

# which person does each segment belong to?
rows = np.random.randint(0, r, (n,))
# how wide is the segment?
widths = np.random.randint(3,12, n,)
# what label to put on the segment (xrange in py2.7, range for py3)
labels = range(n)
colors ='rgbwmc'

patch_handles = []

fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111)



left = np.zeros(r,)
row_counts = np.zeros(r,)

for (r, w, l) in zip(rows, widths, labels):
    print r, w, l
    patch_handles.append(ax.barh(r, w, align='center', left=left[r],
        color=colors[int(row_counts[r]) % len(colors)]))
    left[r] += w
    row_counts[r] += 1
    # we know there is only one patch but could enumerate if expanded
    patch = patch_handles[-1][0] 
    bl = patch.get_xy()
    x = 0.5*patch.get_width() + bl[0]
    y = 0.5*patch.get_height() + bl[1]
    ax.text(x, y, "%d%%" % (l), ha='center',va='center')
  
y_pos = np.arange(8)
ax.set_yticks(y_pos)
ax.set_yticklabels(people)
ax.set_xlabel('Distance')

plt.show()

Which produces a graph like this heterogeneous hbars, with a different number of segments present in each series.

请注意,这并不是特别有效,因为每个段都使用单独的调用ax.barh。可能有更有效的方法(例如,通过用零宽度段或 nan 值填充矩阵),但这可能是特定于问题的,并且是一个独特的问题。


编辑:更新以回答问题的两个部分。

import numpy as np
import matplotlib.pyplot as plt

people = ('A','B','C','D','E','F','G','H')
segments = 4

# generate some multi-dimensional data & arbitrary labels
data = 3 + 10* np.random.rand(segments, len(people))
percentages = (np.random.randint(5,20, (len(people), segments)))
y_pos = np.arange(len(people))

fig = plt.figure(figsize=(10,8))
ax = fig.add_subplot(111)

colors ='rgbwmc'
patch_handles = []
left = np.zeros(len(people)) # left alignment of data starts at zero
for i, d in enumerate(data):
    patch_handles.append(ax.barh(y_pos, d, 
      color=colors[i%len(colors)], align='center', 
      left=left))
    # accumulate the left-hand offsets
    left += d
    
# go through all of the bar segments and annotate
for j in range(len(patch_handles)):
    for i, patch in enumerate(patch_handles[j].get_children()):
        bl = patch.get_xy()
        x = 0.5*patch.get_width() + bl[0]
        y = 0.5*patch.get_height() + bl[1]
        ax.text(x,y, "%d%%" % (percentages[i,j]), ha='center')

ax.set_yticks(y_pos)
ax.set_yticklabels(people)
ax.set_xlabel('Distance')

plt.show()

您可以沿着这些方向获得结果(注意:我使用的百分比与条形宽度无关,因为示例中的关系似乎不清楚):

See Matplotlib 中的水平堆叠条形图 https://stackoverflow.com/q/16653815/1643946有关堆叠水平条形图的一些想法。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

水平堆叠条形图并向每个部分添加标签 的相关文章

随机推荐