【问题标题】:Adding a line to a barplot in Seaborn pads the graph, how do I get rid of the new margins?在 Seaborn 的条形图中添加一条线来填充图形,我如何摆脱新的边距?
【发布时间】:2021-04-25 19:51:24
【问题描述】:

我有一个 seaborn 条形图,上面画了一条线,如下所示:

如您所见,在添加线后出现的绘图上有较厚的边距。如果不添加线,绘图看起来很正常:

plt.margins() 不起作用,基本上会破坏整个图形。不知道为什么。我没有在sns.set() 中尝试额外的 rc-settings,因为我找不到列出所有选项的页面,所以如果有人也可以链接它,我可以将它加入书签,将不胜感激。

条形图是通过以下方式创建的:

sns.set(rc={'figure.figsize': (50, 10), 'axes.labelsize': 25, 'ytick.labelsize': 17, 'axes.labelpad': 15, 'legend.fontsize': 20})
fig, ax1 = plt.subplots()
g = sns.barplot(x='City/Town', y="Value", hue="Metric", data=df, ax=ax1)
g.set_title(title, fontsize=30)
fig.autofmt_xdate()

并且该行添加了:

ax1.plot(range(len(X)), df.Y_pred[df['Metric'] == bar1]*scale, color='red')

其中 X 和 Y 是 numpy ndArrays,而 scale 只是一个 int。

【问题讨论】:

  • @JohanC 这不起作用。我有fig.autofmt_xdate(),因为它修复了 x 轴间距。没有它,许多 x-label 会重叠并变得不可读(这在此图上不是一个大问题,因为它们几乎不可读,但该图是可交互的,并且如果用户愿意,可以显示更少的条目)。

标签: python matplotlib seaborn


【解决方案1】:

这里试图重现你的情节,虽然我无法访问你的数据,也无法确定X 的方式。

似乎发生的事情是,sns.barplot() 明确设置了 x 轴的限制以具有良好的边距。 ax1.plot() 使用 matplotlib 的默认值(通常是宽度的 0.055%)重置边距。因此,一种解决方案是显式设置非常小的边距:ax1.margins(x=0.01)(甚至更小,具体取决于您的数据)。

下面的代码还使用 seaborn 的 lineplot 来获得更多的 x 轴处理方式的一致性(但 lineplot 也使用了 matplotlib 的边距,因此它不是这种填充的解决方案)。 autofmt_xdate() 可以通过显式旋转标签来替换,这样可以更好地控制确切的旋转(但这也不影响填充问题)。

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

np.random.seed(123)
df = pd.DataFrame({'City/Town': np.random.choice([*'ABCDEFGHIJKLMNOP'], 500),
                   'Metric': np.random.choice(['bar1', 'bar2', 'bar3'], 500),
                   'Value': np.random.randint(10, 20, 500)})
sns.set(rc={'figure.figsize': (12, 6), 'axes.labelsize': 25, 'ytick.labelsize': 17, 'axes.labelpad': 15,
            'legend.fontsize': 20})
fig, ax1 = plt.subplots()
sns.barplot(x='City/Town', y="Value", hue="Metric", data=df, ax=ax1)
ax1.set_title('title', fontsize=30)
df1 = df[df['Metric'] == 'bar1']
sns.lineplot(x=df1['City/Town'], y=df1["Value"]*1.2, ci=None, ax=ax1)
ax1.margins(x=0.01)
plt.setp(ax1.get_xticklabels(), rotation=30, ha='right')
plt.tight_layout()
plt.show()

【讨论】:

  • 成功了,非常感谢!我不知道还有 ax.margins() 和 plt.margins()。
  • 如果只有一个子图(注意twinx 也创建了一个子图,但在同一位置),则不会有区别。 plt 对“当前”子图进行操作,该子图通常是最后创建的子图。 (如果您要创建一个最小的可重现示例,那么事情从一开始就很清楚)。另见What is the difference between drawing plots using plot, axes or figure in matplotlib?
【解决方案2】:

我使用子图,上面有线图,下面有马图。 lineplot 总是有更多的填充,所以需要同步它们。 rcParams 对两者都不起作用,因此必须在轴上单独设置:

for ax in [ax1, ax2]:
    ax.margins(x=0.02)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    • 1970-01-01
    • 2019-09-17
    • 2020-10-01
    • 2015-11-22
    相关资源
    最近更新 更多