【问题标题】:Plot swarmplot or boxplot in the same ax depending on number of datapoints根据数据点的数量在同一轴上绘制 swarmplot 或箱线图
【发布时间】:2018-06-27 07:25:16
【问题描述】:

我有一个包含几列的数据框,其中每列有 5 到 2535 个条目(其余为 NAN)。当列有超过 9 个数字条目时,我想绘制一个箱线图,否则绘制一个 swarmplot。我用我疯狂的绘画技巧来创建一个例子。

问题是我只能将两者都绘制为覆盖图,如this example。我尝试使用 position 关键字,但这仅适用于箱线图,不适用于 swarmplot。那么,如何做到这一点呢?

可以这样生成示例数据集:

np.random.seed(1)
df = pd.DataFrame(np.nan, index=range(100), columns=range(11))
for i, column in enumerate(df.columns):
    if i % 2 == 0:
        fill_till = np.random.randint(1,11)
        df.loc[:fill_till-1,column] = np.random.random(fill_till)
    else:
        fill_till = np.random.randint(11,101)
        df.loc[:fill_till-1,column] = np.random.random(fill_till)

【问题讨论】:

  • 将您的数据表分成两份(一份超过 9 个条目,一份包含其余条目),然后在同一张图中绘制一个 swarmplot 和一个箱线图?
  • 好主意,但列有特定的顺序,图也应该有。如果我理解正确,您的解决方案将首先绘制所有箱线图而不是所有群图(反之亦然)?
  • 根据您的绘画技巧(顺便说一句,这让您获得了我的支持),您绘制的数字是自动排序的。我认为这不是现实,而是分类图。但是您可以使用 plt.plot(column_order, np.repeat(np.nan, len(column_order))) 之类的东西准备轴,以便之后将来自两个数据帧的类别填充到正确的插槽中。

标签: python matplotlib seaborn boxplot


【解决方案1】:

您可以创建数据框的两个副本,一个用于箱线图,一个用于群图。然后,在每个副本中,将列中的值设置为您不想以这种方式绘制nan

col_mask = df.count() > 9
swarm_data = df.copy()
swarm_data.loc[:, col_mask] = np.nan
box_data = df.copy()
box_data.loc[:, ~col_mask] = np.nan

然后将每个复制的数据帧传递给相应的 seaborn 函数。

sns.swarmplot(data=swarm_data)
sns.boxplot(data=box_data)
plt.show()

在创建 swarm 绘图时,seaborn 不会为填充有 nan 的列绘制任何内容,但会在它们所在的位置留出空间。箱线图会发生相反的情况,从而保留您的列顺序。

以上代码生成的图表如下所示:

这种方法也适用于带有非数字标签的列:

【讨论】:

  • 像魅力一样工作。
【解决方案2】:

为了详细说明cmets,这里是一个基本的例子(因为you do not provide a toy data set,很难构造一个,这反映了你的情况)。

import numpy as np
from matplotlib import pyplot as plt
import pandas as pd

#column order
real_order = ["B", "D", "A", "E", "C"]
#first data set
x1 = ["A", "C", "B"]
y1 = [9,     3,   1]
#second dataset
x2 = ["D", "C", "E", "A"]
y2 = [2,    11,   4,   5]

#prepare the axis
plt.plot(real_order, np.repeat(np.nan, len(real_order)))
#fill in bars 
plt.bar(x1, y1, color = "r", label = "bars")
#fill in markers
plt.plot(x2, y2, "b*", label = "markers")
plt.legend()
plt.show()

输出:

【讨论】:

  • 感谢您提供此解决方案。我几乎可以重现它,但我的问题是我在所有位置都有多个点的值,我无法让 plt.scatter 使用这个解决方案。
  • 我现在添加了一个示例数据集
  • 使用@mostlyoxygen 的遮蔽解决方案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-13
  • 2020-07-23
  • 1970-01-01
  • 2023-02-24
  • 2016-02-05
  • 1970-01-01
相关资源
最近更新 更多