在matplotlib中堆叠条形图,并在每个部分添加标签(和建议) [英] stack bar plot in matplotlib and add label to each section (and suggestions)

查看:217
本文介绍了在matplotlib中堆叠条形图,并在每个部分添加标签(和建议)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在matplotlib中复制以下图像,看来barh是我唯一的选择.虽然看来您无法堆叠barh图,但我不知道该怎么做

I am trying to replicate the following image in matplotlib and it seems barh is my only option. Though it appears that you can't stack barh graphs so I don't know what to do

如果您知道有更好的python库可以绘制此类内容,请告诉我.

If you know of a better python library to draw this kind of thing, please let me know.

这是我一开始可以想到的:

This is all I could come up with as a start:

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),我以后可以添加自己,主要是条形部分本身的标签,并以我遇到问题的很好的方式创建了这种堆叠方法.您甚至可以通过任何方式指定距离",即颜色范围吗?

I would then have to add labels individually using ax.text which would be tedious. Ideally I would like to just specify the width of the part to be inserted then it updates the center of that section with a string of my choosing. The labels on the outside (e.g. 3800) I can add myself later, it is mainly the labeling over the bar section itself and creating this stacked method in a nice way I'm having problems with. Can you even specify a 'distance' i.e. span of color in any way?

推荐答案

获取更多异构数据. (我离开了上面的方法,因为我发现在每个系列中使用相同数量的记录更为常见)

Edit 2: for more heterogeneous data. (I've left the above method since I find it more usual to work with the same number of records per series)

回答问题的两个部分:

a)barh返回其绘制的所有修补程序的句柄容器.您可以使用补丁的坐标来辅助文本位置.

a) barh returns a container of handles to all the patches that it drew. You can use the coordinates of the patches to aid the text positions.

b)以下这些 两个可以回答我之前提到的问题(请参见 Matplotlib中的水平堆叠条形图),您可以通过设置左侧"输入,水平堆叠条形图.

b) Following these two answers to the question that I noted before (see Horizontal stacked bar chart in Matplotlib), you can stack bar graphs horizontally by setting the 'left' input.

以及c)处理形状不太统一的数据.

and additionally c) handling data that is less uniform in shape.

下面是一种处理形状不均匀的数据的方法,就是简单地独立处理每个段.

Below is one way you could handle data that is less uniform in shape is simply to process each segment independently.

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
labels = xrange(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 , with a different number of segments present in each series.

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

Note that this is not particularly efficient since each segment used an individual call to ax.barh. There may be more efficient methods (e.g. by padding a matrix with zero-width segments or nan values) but this likely to be problem-specific and is a distinct question.

已更新,可以回答问题的两个部分.

updated to answer both parts of the question.

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 xrange(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()

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

You can achieve a result along these lines (note: the percentages I used have nothing to do with the bar widths, as the relationship in the example seems unclear):

有关堆叠水平条形图的一些想法,请参见 Matplotlib中的水平堆叠条形图.

See Horizontal stacked bar chart in Matplotlib for some ideas on stacking horizontal bar plots.

这篇关于在matplotlib中堆叠条形图,并在每个部分添加标签(和建议)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆