【问题标题】:How to add a mean line to a seaborn stripplot or swarmplot如何将平均线添加到 seaborn stripplot 或 swarmplot
【发布时间】:2021-08-01 12:48:18
【问题描述】:

我有一个带有垂直数据的相当简单的条形图。

planets = sns.load_dataset("planets")
sns.stripplot(x="method", y="distance", data=planets, size=4, color=".7")
plt.xticks(rotation=45, ha="right")
plt.show()

我想将每个 x 元素 (method) 的平均值绘制为一个类似于您得到的小水平条:

sns.boxplot(
    x="method",
    y="distance",
    data=planets,
    whis=[50, 50],
    showfliers=False,
    showbox=False,
    showcaps=False
)

但第一个/第三个四分位数没有垂直线(whis=[50,50] 只是点)并显示平均值而不是中位数。也许有一个不涉及箱线图的更优雅的解决方案。

提前致谢。

【问题讨论】:

标签: python matplotlib seaborn boxplot swarmplot


【解决方案1】:
  • 箱线图对象在matplotlib.pyplot.boxplot中定义
    • showmeans=True
    • meanline=True 用线条代替标记
    • meanprops={'color': 'k', 'ls': '-', 'lw': 2} 设置线条的颜色、样式和宽度。
    • medianprops={'visible': False} 使中线不可见
    • whiskerprops={'visible': False} 使晶须线不可见
    • zorder=10 将线放在顶层
  • matplotlib v3.4.2seaborn v0.11.1 中测试
import seaborn as sns
import matplotlib.pyplot as plt

# load the dataset
planets = sns.load_dataset("planets")

p = sns.stripplot(x="method", y="distance", data=planets, size=4, color=".7")
plt.xticks(rotation=45, ha="right")
p.set(yscale='log')

# plot the mean line
sns.boxplot(showmeans=True,
            meanline=True,
            meanprops={'color': 'k', 'ls': '-', 'lw': 2},
            medianprops={'visible': False},
            whiskerprops={'visible': False},
            zorder=10,
            x="method",
            y="distance",
            data=planets,
            showfliers=False,
            showbox=False,
            showcaps=False,
            ax=p)
plt.show()

  • seaborn.swarmplot 类似地工作

【讨论】:

    【解决方案2】:

    这是一个使用ax.hlines 的解决方案,使用groupby 和列表理解求平均值:

    import seaborn as sns
    import matplotlib.pyplot as plt
    
    # load the dataset
    planets = sns.load_dataset("planets")
    
    p = sns.stripplot(x="method", y="distance", data=planets, size=4, color=".7", zorder=1)
    plt.xticks(rotation=45, ha="right")
    p.set(yscale='log');
    
    df_mean = planets.groupby('method', sort=False)['distance'].mean()
    _ = [p.hlines(y, i-.25, i+.25, zorder=2) for i, y in df_mean.reset_index()['distance'].items()]
    

    输出:

    【讨论】:

      【解决方案3】:

      这是另一个类似于箱线图想法但需要较少覆盖的技巧:绘制pointplot,但置信区间宽度为 0,并激活错误栏“caps”以获得可参数化宽度的水平线:

      planets = sns.load_dataset("planets")
      spec = dict(x="method", y="distance", data=planets)
      sns.stripplot(**spec, size=4, color=".7")
      sns.pointplot(**spec, join=False, ci=0, capsize=.7, scale=0)
      plt.xticks(rotation=45, ha="right")
      

      这里明显的一个缺点是,对于具有单一观察的组,引导会被跳过,因此您不会在那里得到平均线。这在实际应用中可能是也可能不是问题。

      另一个技巧是自己进行分组,然后用非常宽的垂直线标记绘制散点图:

      planets = sns.load_dataset("planets")
      variables = dict(x="method", y="distance")
      sns.stripplot(data=planets, **variables, size=4, color=".7")
      sns.scatterplot(
          data=planets.groupby("method")["distance"].mean().reset_index(),
          **variables, marker="|", s=2, linewidth=25
      )
      plt.xticks(rotation=45, ha="right")
      

      【讨论】:

        猜你喜欢
        • 2021-05-01
        • 2021-08-09
        • 2022-06-11
        • 2017-08-26
        • 1970-01-01
        • 2019-08-01
        • 2019-01-21
        • 1970-01-01
        相关资源
        最近更新 更多