在matplotlib中创建一个Diverging Stacked Bar Chart

时间:2014-04-17 19:58:54

标签: python matplotlib plot

我有数据列表,表明对一个(非常不满意)到五个(非常快乐)的量表的回答。我想创建一个图表页面,将这些列表显示为倾斜堆叠的水平条形图。回复列表可以具有不同的大小(例如,当某人选择不回答特定问题时)。以下是数据的最小示例:

likert1 = [1.0, 2.0, 1.0, 2.0, 1.0, 3.0, 3.0, 4.0, 4.0, 1.0, 1.0]
likert2 = [5.0, 4.0, 5.0, 4.0, 5.0, 3.0]

我希望能够用以下内容来绘制:

plot_many_likerts(likert1, likert2)

目前我已经编写了一个迭代列表的函数,并在matplotlib中的共享图上将每个函数绘制为自己的子图:

def plot_many_likerts(*lsts):
    #get the figure and the list of axes for this plot
    fig, axlst = plt.subplots(len(lsts), sharex=True)
    for i in range(len(lsts)):
        likert_horizontal_bar_list(lsts[i], axlst[i], xaxis=[1.0, 2.0, 3.0, 4.0, 5.0])
        axlst[i].axis('off')
    fig.show()

def likert_horizontal_bar_list(lst, ax, xaxis):
    cnt = Counter(lst)
    #del (cnt[None])
    i = 0
    colour_float = 0.00001
    previous_right = 0
    for key in sorted(xaxis):
        ax.barh(bottom=0, width=cnt[key], height=0.4, left=previous_right, color=plt.cm.jet(colour_float),label=str(key))
        i += 1
        previous_right = previous_right + cnt[key]
       colour_float = float(i) / float(len(xaxis))

这种方法效果不错,并且创建了具有相同代表尺寸的堆叠条形图(例如,宽度共享公共轴刻度)。这是一个屏幕截图:

What is currently Produced http://s7.postimg.org/vh0j816gn/figure_1.jpg

我想要的是将这两个图集中在数据集模式的中点(数据集将具有相同的范围)。例如:

What I would like to see http://s29.postimg.org/z0qwv4ryr/figure_2.jpg

关于我如何做到这一点的建议?

1 个答案:

答案 0 :(得分:6)

我需要为一些类似的数据制作一个不同的条形图。我正在使用熊猫,但没有它,这种方法可能会相似。关键机制是在开始时添加一个不可见的缓冲区。

likert_colors = ['white', 'firebrick','lightcoral','gainsboro','cornflowerblue', 'darkblue']
dummy = pd.DataFrame([[1,2,3,4, 5], [5,6,7,8, 5], [10, 4, 2, 10, 5]],
                     columns=["SD", "D", "N", "A", "SA"],
                    index=["Key 1", "Key B", "Key III"])
middles = dummy[["SD", "D"]].sum(axis=1)+dummy["N"]*.5
longest = middles.max()
complete_longest = dummy.sum(axis=1).max()
dummy.insert(0, '', (middles - longest).abs())

dummy.plot.barh(stacked=True, color=likert_colors, edgecolor='none', legend=False)
z = plt.axvline(longest, linestyle='--', color='black', alpha=.5)
z.set_zorder(-1)

plt.xlim(0, complete_longest)
xvalues = range(0,complete_longest,10)
xlabels = [str(x-longest) for x in xvalues]
plt.xticks(xvalues, xlabels)
plt.show()

这种方法有很多局限性。首先,条形图不再获得黑色轮廓,图例将有一个额外的空白元素。我只是隐藏了传说(我认为这可能是一种隐藏单个元素的方法)。我不确定是否有一种方便的方法可以使条形图具有轮廓而不会将轮廓添加到缓冲元素。

首先,我们建立一些颜色和虚拟数据。然后我们计算左边两列的宽度和最中间一列的一半(我知道是#34; SD"," D"和" N&#34 ;, 分别)。我找到了最长的列,并使用其宽度来计算其他列所需的差异。接下来,我将这个新的缓冲区列插入第一个列位置,并带有一个空白标题(感觉很糟糕,lemme告诉你)。为了更好的衡量,我还根据[2]的建议在中间条的中间添加了一条垂直线(axvline)。最后,我通过偏移其标签来调整x轴以获得适当的比例。

您可能希望左侧有更多的水平空间 - 您可以通过添加到"最长的"来轻松实现。

The aligned likert data

[2] Heiberger,Richard M.和Naomi B. Robbins。 "设计用于李克特量表和其他应用的分散堆积条形图。"统计软件期刊57.5(2014):1-32。