【问题标题】:More efficient matplotlib stacked bar chart - how to calculate bottom values更高效的matplotlib堆积条形图——如何计算底值
【发布时间】:2013-09-27 21:12:47
【问题描述】:

我需要一些帮助,在 python 中使用 matlibplot 制作一组堆叠条形图。我的基本代码如下,但我的问题是如何有效地为第二个元素以外的任何元素生成 bottom 的值。我可以让示例图正确堆叠(始终从下到上 a、b、c、d)

import numpy as np
import matplotlib.pyplot as plt

ind = np.arange(3)

a = [3,6,9]
b = [2,7,1]
c = [0,3,1]
d = [4,0,3]

p1 = plt.bar(ind, a, 1, color='#ff3333')
p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=a)
p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=[a[j] +b[j] for j in range(len(a))])
p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=[a[j] +b[j] +c[j] for j in range(len(a))])

plt.show()

我的最终代码可能有非常多的条,并且不断扩展的函数 bottom = [...] 不是最好的解决方案。如果您还可以解释我需要如何得出该值,那就太好了。有没有一个numpy函数。

非常感谢!!! PS 我已经搜索了答案,但我不明白我能找到什么。

【问题讨论】:

    标签: python numpy matplotlib stackedbarseries


    【解决方案1】:
    [sum(values) for values in zip(a, b, c)]
    

    在 Python 2 中你也可以这样做

    map(sum, zip(a, b, c))
    

    但 Python 3 需要

    list(map(sum, zip(a, b, c)))
    

    这不太好。


    你可以封装这个:

    def sumzip(*items):
        return [sum(values) for values in zip(*items)]
    

    然后做

    p1 = plt.bar(ind, a, 1, color='#ff3333')
    p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=sumzip(a))
    p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=sumzip(a, b))
    p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=sumzip(a, b, c))
    

    也是。


    如果 abcd 是 numpy 数组,您也可以使用 sum([a, b, c])

    a = np.array([3,6,9])
    b = np.array([2,7,1])
    c = np.array([0,3,1])
    d = np.array([4,0,3])
    
    p1 = plt.bar(ind, a, 1, color='#ff3333')
    p2 = plt.bar(ind, b, 1, color='#33ff33', bottom=sum([a]))
    p3 = plt.bar(ind, c, 1, color='#3333ff', bottom=sum([a, b]))
    p4 = plt.bar(ind, d, 1, color='#33ffff', bottom=sum([a, b, c]))
    

    【讨论】:

      【解决方案2】:

      将您的值转换为 numpy 数组将使您的生活更轻松:

      data = np.array([a, b, c, d])
      bottom = np.cumsum(data, axis=0)
      colors = ('#ff3333', '#33ff33', '#3333ff', '#33ffff')
      
      plt.bar(ind, data[0], color=colors[0])
      for j in xrange(1, data.shape[0]):
          plt.bar(ind, data[1], color=colors[j], bottom=bottom[i-1])
      

      或者,摆脱第一个小节的讨厌的特殊情况:

      data = np.array([a, b, c, d])
      bottom = np.vstack((np.zeros((data.shape[1],), dtype=data.dtype),
                          np.cumsum(data, axis=0)[:-1]))
      colors = ('#ff3333', '#33ff33', '#3333ff', '#33ffff')
      for dat, col, bot in zip(data, colors, bottom):
          plt.bar(ind, dat, color=col, bottom=bot)
      

      【讨论】:

      • 如果你使用 matplotlib,所有的东西都会在 anyway 下作为一个 ndarray 结束。还不如让你的生活愉快;)
      • 谢谢,如何在其中添加标签?我有一个我正在堆叠的每个系列的标签/名称列表,但是虽然我已经尝试过,但我无法让它们正确出现。我也尝试过像下面这样运行一个简单的图例,但它并没有真正起作用。:codeplt.legend((pl[0], pm[0],ph[0],pa[0]),( 'L','M','H','At'),bbox_to_anchor=[1.05, 0.5], loc='center')
      【解决方案3】:

      我最近也遇到了同样的问题。之后,我决定把这一切都包在一个很好的课堂上。对于任何感兴趣的人,您都可以在此处获得堆叠条形图类的实现:

      https://github.com/minillinim/stackedBarGraph

      它允许缩放堆叠图以及设置条形宽度和设置高度(带有缩放的内部)。

      给定这样的数据集:

          d = np.array([[101.,0.,0.,0.,0.,0.,0.],
                        [92.,3.,0.,4.,5.,6.,0.],
                        [56.,7.,8.,9.,23.,4.,5.],
                        [81.,2.,4.,5.,32.,33.,4.],
                        [0.,45.,2.,3.,45.,67.,8.],
                        [99.,5.,0.,0.,0.,43.,56.]])
      
          d_heights = [1.,2.,3.,4.,5.,6.]
          d_widths = [.5,1.,3.,2.,1.,2.]
          d_labels = ["fred","julie","sam","peter","rob","baz"]
          d_colors = ['#2166ac',
                      '#fee090',
                      '#fdbb84',
                      '#fc8d59',
                      '#e34a33',
                      '#b30000',
                      '#777777']
      

      它可以制作这样的图像:

      GPLv3 与爱。

      【讨论】:

      • 谢谢 - 我怎样才能在栏之间获得空格?
      • 我更新了代码以允许存在差距。这实际上很简单,如果你从条的宽度中减去一个固定的量,那么它会有效地缩小它们。在那之后,这只是玩 xlims 的问题。主函数调用现在有两个新参数,gap 和 endGaps,底部的两张图片显示了这些参数的使用示例。
      • 喜欢@minillinim 的包裹。感觉太容易了。要添加图例,如果您使用 stacked_colors = ['#2166ac', '#fee090', '#fdbb84']cols=stacked_colors 之类的数组设置颜色,那么很容易将图例添加到由 pandas DataFrame 制作的图中:legends = [] i = 0 for column in df.columns: legends.append(mpatches.Patch(color=stacked_colors[i], label=column)) i+=1 plt.legend(handles=legends)
      【解决方案4】:

      我是这样解决的:

      import numpy as np
      
      dates = # somehow get a list of dates
      labels = # a list of various labels
      colors = # somehow get a list of colors
      
      margin_bottom = np.zeros(dates)
      
      for index, label in enumerate(labels):
          values = # get your values for the label at index-th position from somewhere
          ax.bar(
              dates, values, 
              align='center', label=label, color=colors[index], bottom=margin_bottom
          )
          margin_bottom += values # here you simply add it to the previous margin
          # margin_bottom is a numpy array, adding a list will not change that
      

      它与其他一些解决方案类似,但它不需要始终存储所有边距。相反,它自下而上“构建”堆栈,每次迭代都会增加越来越多的边距。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-01-17
        • 2019-11-28
        • 2021-02-27
        • 2017-11-02
        • 2018-08-02
        • 2017-09-19
        相关资源
        最近更新 更多