【问题标题】:Python Barplot to represent RangesPython Barplot 表示范围
【发布时间】:2019-12-18 14:50:50
【问题描述】:

我想在 python 中制作一个分类图来表示几个变量的范围。我想也许我会使用条形图并为条形设置范围。这是我的条形图

import matplotlib.pyplot as plt
import numpy as np

data = {'a':.3, 'b': .3, 'c': .3, 'd': .1,'e':.1,'f':.1}

names = list(data.keys())    
values = list(data.values())

plt.bar(names,values)
plt.show()

从给定代码生成的条形图: 请告诉我如何将条形的值设置为range(.3,.4)。换句话说,我希望条形图从说(0.3 到 .4 来表示一个范围)而不是(0 到 .3 目前的方式)。

我知道使用条形图来表示范围很奇怪,如果有人有其他方法让我这样做,请添加您的代码。我真的不在乎,只要我得到一个代表至少 6 个变量范围的图,我可以在其中轻松手动更改范围的值。

【问题讨论】:

标签: python plot range bar-chart lib


【解决方案1】:

一种方法是使用LineCollection 并将线宽设置为类似于条形图。

要使用LineCollection,您需要提供一组 x 值来绘制data 中提供的每个范围。为了创建与您的范围相关的 y 值,我使用了np.arange。由于np.arange 只能计算整数,所以我将data 中的每个值乘以10,然后将结果除以10 以返回输入数据。

data = {'a':(.3,.4), 'b': (.3,.4), 'c': (.3,.4), 'd': (0,.1),'e':(0,.1),'f':(0,.1)}

names = list(data.keys())    
values = list(data.values())

values = [np.arange(a[0]*10, (a[1]+0.1)*10,1)/10 for a in values]
xs = [np.ones(a.shape) for a in values]

xs = [i*a for i,a in zip(range(len(xs)), xs)]

verts = []
for x,y in zip(xs, values):
    verts.append(list(zip(x.tolist(), y.tolist())))

lc = LineCollection(verts, linewidths=40)

fig,ax = plt.subplots()
ax.add_collection(lc)
ax.set_xlim(-0.5,len(values) )
plt.xticks(np.arange(len(values)), names)

【讨论】:

  • 我真的很喜欢这个,但是当我尝试更改所有这些的范围时出现此错误。 ValueError Traceback (最近一次调用最后一次) in () 10 个值 = [np.arange(a[0]*10, (a[1]+0.1)*10,1 )/10 for a in values] 11 xs = [np.ones(a.shape) for a in values] ---> 12 xs = (np.arange(len(values))+1)* xs 13 14 verts = [] ValueError: 操作数无法与形状 (6,) (6,2) 一起广播
  • 你把范围改成什么了?
  • 将它们更改为 (.3,.4),(.3,.4),(.3,.4),(0,.1),(0,.1),( 0,.1),并去掉了“g”。发生了一些奇怪的事情,我可以将 6 个参数中的 5 个更改为我想要的,而当我去更改时,最后一个参数会给我带来错误。再次感谢!
  • 很抱歉,我已经用更改后的值更新了我的答案。这个解决方案比ax.vline 更复杂,但它会准确地绘制你想要的数据。我还看到@Fourier 帖子上的条形图并没有完全停在 0.4。
【解决方案2】:

更新答案

要解决axvline 的问题,必须考虑宽度(像素)与范围的比率。我觉得这是一个黑客。

因此,这里有一个使用axvspan的解决方案。

import numpy as np
from matplotlib import pyplot as plt

data = {'a':(0,.3), 'b': (0.2,.3), 'c': (.1,.3), 'd': (0.3,0.4),'e':(.1,.2),'f':(.1,.4)}

width = 0.5 # adjust to your liking

fig, ax = plt.subplots()

for i, values in enumerate(data.values()):

    ymin, ymax = values

    ax.axvspan(xmin=i-width/2, xmax=i+width/2, ymin=ymin,ymax=ymax)

# to illustrate that ranges are properly drawn
ax.grid(True)

#add ticks 
ax.set_xticks(np.arange(0,len(data)))    
ax.set_xticklabels(data.keys())

输出:

原答案

另一种选择是使用axvline

from matplotlib import pyplot as plt

data = {'a':(0,.3), 'b': (0.2,.3), 'c': (.1,.3), 'd': (0.3,0.4),'e':(.1,.2),'f':(.1,.4)}

for key, values in data.items():
    ymin, ymax = values
    plt.axvline(x=key, ymin=ymin, ymax=ymax, lw=5)

输出:

如果需要,您可以通过调整lw 接近条形图。

【讨论】:

  • 我非常喜欢这个解决方案,但该线在情节上略高于 0.4.. 有什么办法可以解决这个问题吗?似乎是一个奇怪的问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-04
  • 2015-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多