matplotlib的“barh”中高度变量的单位是什么?

wb1gzix0  于 2023-10-24  发布在  其他
关注(0)|答案(2)|浏览(105)

在matplotlib的函数barh的定义中:
matplotlib.pyplot.barh(bottom, width, height=0.8, left=None, hold=None, **kwargs)
默认的“height”是0.8,但是当我画一些不同的图的高度例如(30,40,..)和dpi=100.我看到酒吧的高度被改变.它不是固定的.所以我想知道什么是在barh的高度单位和如何使它固定(不依赖于图的高度).

bvuwiixz

bvuwiixz1#

我将把它分成两部分:
我想知道高度的单位是什么
(显然人们一直在想这个since 2009......所以我猜你在好公司!)
这个问题是比较简单的部分-它是分配给图中条形图的高度的百分比。例如,默认值height=0.8意味着条形图的高度将为0.8 * (plot_height / n_bars)。您可以通过设置height=1.0来查看这一点(甚至值> 1,条形图将重叠)。
如果你真的想确定,这里是axes.barh的源代码。这只是调用axes.bar-看看这些行:

nbars = len(bottom)
if len(left) == 1:
    left *= nbars
if len(height) == 1:
    height *= nbars

后来...

args = zip(left, bottom, width, height, color, edgecolor, linewidth)
for l, b, w, h, c, e, lw in args:
    if h < 0:
        b += h
        h = abs(h)
    if w < 0:
        l += w
        w = abs(w)
    r = mpatches.Rectangle(
        xy=(l, b), width=w, height=h,
        facecolor=c,
        edgecolor=e,
        linewidth=lw,
        label='_nolegend_',
        margins=margins
        )
    r.update(kwargs)
    r.get_path()._interpolation_steps = 100
    #print r.get_label(), label, 'label' in kwargs
    self.add_patch(r)
    patches.append(r)

所以你可以看到高度是按nbars缩放的,当你画矩形的时候,它们之间的间隔就是这个高度。
如何使它固定
这是困难的,你将不得不手动设置它。图表上的酒吧最终是matplotlib.patches.Rectangle对象,它有一个宽度和高度.这也是一个百分比。我认为最好的解决方案是手动计算适当的百分比。
下面是一个简短的例子,基于barh demo

import matplotlib.pyplot as plt
plt.rcdefaults()
import numpy as np
import matplotlib.pyplot as plt

# Example data
people = ('Tom', 'Dick', 'Harry', 'Slim', 'Jim')
y_pos = np.arange(len(people))
performance = 3 + 10 * np.random.rand(len(people))
error = np.random.rand(len(people))

plt.figure(figsize=(5,5), dpi=80)
myplot = plt.barh(y_pos, performance, height=0.8, xerr=error, align='center', alpha=0.4)
plt.yticks(y_pos, people)
plt.xlabel('Performance')
plt.title('How fast do you want to go today?')

for obj in myplot:
    # Let's say we want to set height of bars to always 5px..
    desired_h = 5
    current_h = obj.get_height()
    current_y = obj.get_y()
    pixel_h = obj.get_verts()[2][1] - obj.get_verts()[0][1]
    print("current position = ", current_y)
    print("current pixel height = ", pixel_h)

    # (A) Use ratio of pixels to height-units to calculate desired height
    h = desired_h / (pixel_h/current_h)
    obj.set_height(h)
    pixel_h = obj.get_verts()[2][1] - obj.get_verts()[0][1]
    print("now pixel height = ", pixel_h)

    # (B) Move the rectangle so it still aligns with labels and error bars
    y_diff = current_h - h # height is same units as y
    new_y = current_y + y_diff/2
    obj.set_y(new_y)
    print("now position = ", obj.get_y())
plt.show()

A部分计算pixel_h/current_h以获得像素和高度单位之间的转换。然后我们可以将desired_h(像素)除以该比率以获得高度单位的desired_h。这将条形宽度设置为5 px,但条形底部保持不变,因此它不再与标签和错误条对齐。
部分B计算新的y位置。由于yheight使用相同的单位,我们只需将高度差(y_diff)的一半相加即可得到新的位置。这使条形图始终以原始的y位置为中心。
请注意,这只是设置初始大小。例如,如果您调整绘图的大小,则条形图仍将缩放-您必须重写该事件以适当地调整条形图的大小。

qvtsj1bj

qvtsj1bj2#

我试着为我的barh图实现建议的解决方案,但到目前为止还没有成功。
我的问题是在一个可打印的报告中有两个barh图彼此相邻,我希望它们的条形对齐并且高度相同。默认情况下,ax.barh图中的第一个图的条形不对齐,如果第二个图的条形数量不同,则第一个图的条形与第二个图的条形高度不同。
我的图有相同的大小开始,因为我把他们旁边的一页打印出来。
解决方案:我正在做的是添加“隐藏”条,以防其中一个图形的条数比另一个少。
这是一个愚蠢的解决方法,但对我来说很有效。我的情况非常具体,例如,我的barh图有几个条形(最多7个)。如果其中一个图有4个条形,其他7个条形,我会添加3个隐藏的条形,然后两个图都会对齐它们的条形。
由于标签必须定义且唯一,因此我使用string.ascii_letters创建随机标签。

if len(y_labels) < MAX_NO_OF_BARS:
    no_of_hidden_bars = MAX_NO_OF_BARS - len(y_labels)
    random_labels = random.sample(string.ascii_letters, no_of_hidden_bars)
    y_labels += random_labels
    widths += [0] * no_of_hidden_bars

barh_plot = ax.barh(
    y=y_labels
    widths=widths,
    height=0.4,
    color="#235599",
)

现在我只是做一些必要的标签的情节(添加百分比值的权利,酒吧),在这里我也隐藏标签的“隐藏酒吧”。

y_ticks = ax.yaxis.get_major_ticks()
for i, width in enumerate(widths):
    ax.text(
        x=width + 0.02,  # x-axis position
        y=i,  # y-axis position
        verticalalignment="center",
        s="{:.0%}".format(width) if width else "",
        fontsize="xx-small",
    )
    if not width:
        y_ticks[i].label1.set_visible(False)

相关问题