首页 > 解决方案 > 具有数字线间距分布的 Seaborn 条形图

问题描述

我想制作一个具有数字线型间距的条形图。

所以如果我们有这样的数据:

d = {'Avg_Price': [22.1, 19.98, 24.4, 24.4, 12.0, 41.98, 12.0, 35.0, 25.84, 25.0, 60.0], 
     'estimated_purchasers': [2796.9999999999995, 1000.0, 672.98, 672.98, 335.0, 299.0, 500.0, 104.22, 42.96, 500.0, 225.0]}

revenues = pd.DataFrame(data=d)

这只是一个基本的条形图:

ax = sns.barplot(x='Avg_Price',
                 y='estimated_purchasers',
                 data=revenues)

我希望它像数字线一样间隔(所以让我们从 0 到 60 等距) - 更像这样:

在此处输入图像描述

我可能完全想多了,但我该怎么做呢?

标签: pythonseaborn

解决方案


您遇到的最大问题是 aseaborn自动将条形图转换为具有分类的 x 轴。因此,seaborn 不是真正的数字位置,而是将您的 x 轴重新采样到 0 - (唯一 x 值的数量)的范围内,然后用该类别的字符串表示形式标记它们。要实现您想要的情节,您可以

  • 使用 seaborn 实现一个解决方法来修复 x 轴范围,并将绘制的矩形移动到适当的位置(这需要对 matplotlib 有一些深入的了解)
import seaborn as sns
import matplotlib.pyplot as plt
sns.set() # invoke seaborn styling

# manually making axes to make a wider plot for viewing
fig, ax = plt.subplots(figsize=(12, 4))

ax = sns.barplot(x='Avg_Price',
                 y='estimated_purchasers',
                 data=revenues)

# Get all unique x-values in ascending order
x_values = sorted(revenues["Avg_Price"].unique())

# New xlim spans from -1 to [max(x_values) + 1]
ax.set_xlim(-1, x_values[-1] + 1)

# a barplot w/ error bars are rectangles (patches) & lines
# so we fetch all artists related to these to update their position on the Axes
artists = zip(ax.patches, ax.lines)
for x_val, (rect, err_line) in zip(x_values, artists):
    # ensure everything is centered on the x_val
    new_rect_x = x_val - (rect.get_width() / 2)
    rect.set_x(new_rect_x)
    
    err_line.set_xdata([x_val, x_val])
    
# Take care to update the x-axis itself
new_xticks = [0, 30, 60]
ax.set_xticks(new_xticks)
ax.set_xticklabels(new_xticks)

在此处输入图像描述

在这种情况下,我首选的解决方案是一起跳过 seaborn

  • 通过 matplotlib 自己绘制绘图
import seaborn as sns
import matplotlib.pyplot as plt
sns.set() # invoke seaborn styling

# Perform data aggregation explicitly instead of relying on seaborn
agg_rev = (
    revenues.groupby("Avg_Price")["estimated_purchasers"]
    .agg(["mean", "sem"])
    .reset_index()
)
agg_rev["sem"] = agg_rev["sem"].fillna(0)

# Now we can plot :)
fig, ax = plt.subplots(figsize=(12, 4))
ax.bar(x="Avg_Price", height="mean", data=agg_rev)
ax.errorbar(x="Avg_Price", y="mean", yerr="sem", data=agg_rev, fmt="none", ecolor="black")

ax.set_xticks([0, 30, 60])

ax.set_xlabel("Avg Price")
ax.set_ylabel("estimated_purchases")

ax.grid(False, axis="x") # turn off vertical gird lines b/c they look silly

在此处输入图像描述


推荐阅读