如何使用matplotlib为条形图设置基线并让条形长大

时间:2014-02-20 16:53:39

标签: python matplotlib bar-chart

我想用mathplotlib绘制一些数据。我测量了一个基准,我希望将其与参考值进行比较。我计算一个“减速因子”来表示浏览器与另一个浏览器的比较慢。

到目前为止,它看起来几乎像这样:

preliminary picture

情节的代码是:

#!/usr/bin/env python
import numpy as np
# Import Standard error of the mean
from scipy import mean
from scipy.stats import sem


Y_LABEL = "Slowdown factor"
X_LABEL = "Browser"


import matplotlib as mpl

import matplotlib.pyplot as plt



fig = plt.figure()
ax = fig.add_subplot(111)


sampledata={}
for browser in ('firefox',
    'chrome',
    'internet-explorer'
    ):
    sampledata[browser] = {}
    for benchmark in  ('data1', 'data2', 'data3'):
        sampledata[browser][benchmark] = {}

sampledata['firefox']['data1'] = [10,5,20,10,15]
sampledata['chrome']['data1'] = [5,7,9,10,11]
sampledata['internet-explorer']['data1'] = [20,30,40,20,30]


sampledata['firefox']['data2'] = [10,50,20,10,14]
sampledata['chrome']['data2'] = [50,70,90,100,80]
sampledata['internet-explorer']['data2'] = [200,300,400,300,300]


sampledata['firefox']['data3'] = [90,50,100,100,140]
sampledata['chrome']['data3'] = [50,170,90,100,80]
sampledata['internet-explorer']['data3'] = [200,200,100,100,300]


data = {}
for browser in ('firefox',
    'internet-explorer'
    ):
    data[browser] = {}
    for benchmark in  ('data1', 'data2', 'data3',):
        data[browser][benchmark] = sampledata[browser][benchmark]

baselinedata = sampledata['chrome']

## the data
chrome_vanillas = [results_for_benchmark
             for results_for_benchmark in baselinedata.itervalues()]
chrome_vanilla_means = [mean(v) for v in chrome_vanillas]
chrome_vanilla_errors = [sem(v) for v in chrome_vanillas]

baseline_values = chrome_vanillas
baseline_means = chrome_vanilla_means

firefoxes = [results_for_benchmark
             for results_for_benchmark in data['firefox'].itervalues()]
firefoxes = [[float(v)/bl 
            for (v, bl) in zip(v_l, bl_l)]
            for (v_l, bl_l) in zip(firefoxes, baseline_values)]
firefox_means = [mean(v) for v in firefoxes]
firefox_errors = [sem(v) for v in firefoxes]



internet_explorers = [results_for_benchmark
             for results_for_benchmark in data['internet-explorer'].itervalues()]
internet_explorers = [[float(v)/bl
            for (v, bl) in zip(v_l, bl_l)]
            for (v_l, bl_l) in zip(internet_explorers, baseline_values)]
internet_explorer_means = [mean(v) for v in internet_explorers]
internet_explorer_errors = [sem(v) for v in internet_explorers]


N = min(len(browser) for browser in data.itervalues())
ind = np.arange(N)                # the x locations for the groups
width = 0.25                      # the width of the bars



# axes and labels
#ax.set_xlim(-width,len(ind)+width)
#ax.set_ylim(-45,45)
ax.set_ylabel(Y_LABEL)
ax.set_title(X_LABEL)
## the bars
firefox_rects = ax.bar(ind, firefox_means, width,
                color='green',
                yerr=firefox_errors,
                error_kw=dict(elinewidth=2,ecolor='black'))

internet_explorer_rects = ax.bar(ind+width, internet_explorer_means, width,
                    color='blue',
                    yerr=internet_explorer_errors,
                    error_kw=dict(elinewidth=2,ecolor='black'))

xTickMarks = [key
              for key in data.itervalues().next().keys()]
ax.set_xticks(ind+width)
xtickNames = ax.set_xticklabels(xTickMarks)
plt.setp(xtickNames, rotation=45, fontsize=10)

## add a legend
ax.legend( (firefox_rects[0], internet_explorer_rects[0]),
           ('Firefox', 'Internet Explorer') )

plt.savefig('figure.png')

plt.show()

现在,我想将基线设置为1.0,如果值小于1,则让条形长大。我已经看到barset(hBars(1),'BaseValue',2);函数,但它似乎只为我的每个值加1,而不是考虑1作为绘制条形的基础。

bottom parameter,使用{{1}}之类的内容: enter image description here

所以最终的问题是:如何创建一个基线为1.0的图,让条形图长大?

2 个答案:

答案 0 :(得分:3)

您可以结合使用格式化程序(用于刻度)并将1减去数据。

示例:

import matplotlib.pyplot as plt
import matplotlib.ticker as mtick

baseline = 1
data = [1.1,2.0,1.4,0.9,1.6,0.7,0.1]
plt.bar(range(len(data)),[x-baseline for x in data])
plt.gca().yaxis.set_major_formatter(mtick.FuncFormatter(lambda x,_: x+baseline))

plt.show()

答案 1 :(得分:0)

实际上,bottom函数的bar参数可以完全符合您的要求,如果从height参数中减去基线(它不是y}原因是:)

import numpy as np
import matplotlib.pyplot as plt

baseline = 1
data = np.r_[1.1, 2.0, 1.4, 0.9, 1.6, 0.7, 0.1]
plt.bar(range(len(data)), data-baseline, bottom=baseline)

与@ xndrme相比,这可能是更好的方法,因为:

  1. y轴与原始数据(而不是差分数据)具有相同(和正确)的比例,当您尝试设置ylim或叠加另一个图时,其好处将变得明显
  2. 无需额外导入。