【问题标题】:Matplotlib Control Spacing Between BarsMatplotlib 控制条之间的间距
【发布时间】:2020-08-25 13:58:21
【问题描述】:

我正在尝试在两个特定条之间插入间距,但找不到任何简单的方法来做到这一点。我可以手动添加一个高度为 0 的虚拟行来创建和留空空间,但不能让我控制空间的宽度。有没有更程序化的方法可以用来控制任意位置的条之间的间距?

示例代码:

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

mydict = {
    'Event': ['Running', 'Swimming', 'Biking', '', 'Hiking', 'Jogging'],
    'Completed': [2, 4, 3, 0, 7, 9],
    'Participants': [10, 20, 35, 0, 10, 20]}

df = pd.DataFrame(mydict).set_index('Event')
df = df.assign(Completion=(df.Completed / df.Participants) * 100)

plt.subplots(figsize=(5, 4))

print(df.index)
ax = sns.barplot(x=df.Completion, y=df.index, color="orange", orient='h')

plt.xticks(rotation=60)

plt.tight_layout()
plt.show()

DataFrame 输出示例:

          Completed  Participants  Completion
Event                                        
Running           2            10   20.000000
Swimming          4            20   20.000000
Biking            3            35    8.571429
                  0             0         NaN
Hiking            7            10   70.000000
Jogging           9            20   45.000000

示例输出(在代码外部添加蓝色箭头以显示添加空行的位置。):

【问题讨论】:

    标签: python-3.x pandas matplotlib seaborn


    【解决方案1】:

    我认为您可以访问框的位置和标签的名称。然后修改它们。根据您的用例,您可能会找到更通用的方法,但这适用于给定的示例。

    #define a function to add space starting a specific label
    def add_space_after(ax, label_shift='', extra_space=0):
        bool_space = False
        # get postion of current ticks
        ticks_position = np.array(ax.get_yticks()).astype(float)
        # iterate over the boxes/label
        for i, (patch, label) in enumerate(zip(ax.patches, ax.get_yticklabels())):
            # if the label to start the shift found
            if label.get_text()==label_shift: bool_space = True
            # reposition the boxes and the labels afterward
            if bool_space:
                patch.set_y(patch.get_y() + extra_space)
                ticks_position[i] += extra_space
        # in the case where the spacing is needed
        if bool_space:
            ax.set_yticks(ticks_position)
            ax.set_ylim([ax.get_ylim()[0]+extra_space, ax.get_ylim()[1]])
    
    #note: no more blank row
    mydict = {
        'Event': ['Running', 'Swimming', 'Biking', 'Hiking', 'Jogging'],
        'Completed': [2, 4, 3, 7, 9],
        'Participants': [10, 20, 35, 10, 20]}
    df = pd.DataFrame(mydict).set_index('Event')
    df = df.assign(Completion=(df.Completed / df.Participants) * 100)
    
    ax = sns.barplot(x=df.Completion, y=df.index, color="orange", orient='h')
    plt.xticks(rotation=60)
    plt.tight_layout()
    
    #use the function
    add_space_after(ax, 'Hiking', 0.6)
    
    plt.show()
    

    【讨论】:

    • 感谢您花时间看这个。我没有从函数中得到想要的结果。不是在徒步旅行后增加空间,而是在骑自行车后增加空间。此外,如果我将空间增加到 0.9,它也会增加慢跑后的空间。知道为什么会这样吗?
    • @MBasith 所以第一个问题更多的是函数的错误命名,它应该被称为 add_space_before 因为正如你所看到的,输入的名称是Hiking 所以它在前面添加了空格
    • @MBasith 对于 0.9 的第二个问题,它与 ax.set_ylim([ax.get_ylim()[0]+extra_space, ax.get_ylim()[1]]) 这一行有关,我没有测试所有案例,所以不知道该放什么在这里试试 ax.set_ylim([ax.get_ylim()[0]+extra_space/2, ax.get_ylim()[1]]) if这不是太大的数字
    • 这就像一个魅力!该功能还提供了我正在寻找的灵活性。非常感谢您的帮助。
    • @MBasith 可能需要根据您的需要进行一些调整,但希望总体思路能够为您提供指导 :)