错误条大小的相对大小

时间:2018-02-08 22:33:55

标签: python-3.x matplotlib

是否可以动态控制错误条帽的大小?就像箱形图中的胡须帽一样受到控制?因此,无需将倾覆度设置为某个固定值。从以下示例中可以看到更多内容。

fig = plt.figure()
gs = gridspec.GridSpec(2, 2)
ax0 = fig.add_subplot(gs[0])
ax1 = fig.add_subplot(gs[1])
ax2 = fig.add_subplot(gs[2])
ax3 = fig.add_subplot(gs[3])

n = 3
ax0.bar(list(range(n)),
       np.random.randint(1,20,n),
       yerr=np.random.randn(n),
       edgecolor="red",
       fill=False,
       capsize=5)

ax1.boxplot(np.random.normal(70, 25, (200,n)))

n = 12
ax2.bar(list(range(n)),
       np.random.randint(1,20,n),
       yerr=np.random.randn(n),
       edgecolor="red",
       fill=False,
       capsize= 5)

ax3.boxplot(np.random.normal(70, 25, (200,n)))

enter image description here

更多的话:

是否有可能以某种方式控制相对于箱之间间距的倾覆。如果bin在所有整数上,我希望capsize的宽度为bin_center +/- 0.25

2 个答案:

答案 0 :(得分:2)

如果我理解正确,您希望错误上限的大小自动调整到条形图的宽度,就像在箱线图中一样吗?

在这种情况下,获得所需行为的一种简单方法是将值传递给与柱数成反比的capsize=,因为柱的数量最终将决定它们的宽度。在您对结果感到满意之前,您必须使用确切的比例系数。

fig, axs = plt.subplots(1,2, figsize=(5,2.5))

for ax,n in zip(axs,[3,12]):
    ax.bar(list(range(n)),
       np.random.randint(1,20,n),
       yerr=np.random.randn(n),
       edgecolor="red",
       fill=False,
       capsize=30/n)  # <--- capsize inversly proportional to n

enter image description here

答案 1 :(得分:2)

条形图上的错误栏的上限和箱形图上的胡须上限之间存在巨大差异。晶须帽是图中的实际线(即它们具有起点和终点)。错误栏的上限是标记;与通常情节中的marker="_"相同的标记。

因此,胡须的宽度是线的两个坐标之间的差异,而错误条帽的宽度是markersizemarkersize以点为单位,使其独立于图中的数据单位。这有几个优点:它们在屏幕上保持大小,与数据规模无关,在缩放图时它们保持不变,并且它们在对数刻度上看起来很好。

因此,当要求以数据单位表示错误栏大小时,您实际上是在询问如何在数据单元中缩放标记。例如,可以查看this questionthis one,它们要求缩放数据单元中的分散。

因此,我们的想法是计算当前图中数据单元的点数,然后将错误栏上限的标记大小设置为此数字的倍数。

import matplotlib.pyplot as plt
import numpy as np; np.random.seed(1)

fig, (ax,ax2) = plt.subplots(ncols=2, figsize=(8,4))

n = 3
bar1 = ax.bar(list(range(n)),
       np.random.randint(1,20,n),
       yerr=np.random.randn(n),
       edgecolor="red", fill=False, capsize=1)

n = 12
bar2 = ax2.bar(list(range(n)),
       np.random.randint(1,20,n),
       yerr=np.random.randn(n),
       edgecolor="red", fill=False, capsize=1)

class BarCapSizer():
    def __init__(self, caps, size=1):
        self.size=size
        self.caps = caps
        self.ax = self.caps[0].axes
        self.resize()

    def resize(self):
        ppd=72./self.ax.figure.dpi
        trans = self.ax.transData.transform
        s =  ((trans((self.size,1))-trans((0,0)))*ppd)[0]
        for i,cap in enumerate(self.caps):
            cap.set_markersize(s)

size = 0.5 # data units
bcs1 =  BarCapSizer(bar1.errorbar.lines[1], size )        
bcs2 =  BarCapSizer(bar2.errorbar.lines[1], size )

plt.show()

enter image description here

这显示了0.5个数据单位的倾覆。问题是现在再次修复了这个问题。因此,如果交互式缩放应该保留数据单元中的标记比例,则需要使用事件处理机制来更新标记大小。这可以与here显示的内容类似。

class BarCapSizer():
    def __init__(self, caps, size=1):
        self.size=size
        self.caps = caps
        self.ax = self.caps[0].axes
        self.resize()
        self.cid = ax.figure.canvas.mpl_connect('draw_event', self.update)

    def resize(self):
        ppd=72./self.ax.figure.dpi
        trans = self.ax.transData.transform
        s =  ((trans((self.size,1))-trans((0,0)))*ppd)[0]
        for i,cap in enumerate(self.caps):
            cap.set_markersize(s)

    def update(self,event=None):
        self.resize()
        self.timer = self.ax.figure.canvas.new_timer(interval=10)
        self.timer.single_shot = True
        self.timer.add_callback(lambda : self.ax.figure.canvas.draw_idle())
        self.timer.start()