首页 > 解决方案 > 箱线图和散点图 python

问题描述

我有一个时间序列数据,我想在其上构建一个叠加的散点图和箱线图。数据是这样的:

    TokenUsed   date
0   8   2020-01-05
1   8   2020-01-05
2   8   2020-01-05
3   8   2020-01-05
4   8   2020-01-05
... ... ...
51040   7   2020-02-23
51041   7   2020-02-23
51042   7   2020-02-23
51043   7   2020-02-23
51044   7   2020-02-23

这个时间序列可以整齐地显示为箱线图(我在 x 轴是日期时遇到了麻烦,但解决了将其转换为字符串的问题)。现在,我只想显示总和优于阈值 (>81) 的数据。代码和生成的图像如下:

fig, ax = plt.subplots(figsize = (12,6))  



ax = sns.boxplot(x="date", y="TokenUsed", data=df, ax= ax, whis=[0,100])


ax.axhline(81)

plt.locator_params(axis='x', nbins=10)
plt.show()

样例箱线图 (1)

当我添加散点图时,我得到图像 (2),通过仅过滤 >81 的图像,我得到图像 (3)。我不明白的是为什么它似乎无法匹配两个图之间的 x 轴!

带散点图但不过滤的示例箱线图 (2)

带过滤散点图的示例箱线图 (3)

代码:

fig, ax = plt.subplots(figsize = (12,6))  



ax = sns.boxplot(x="date", y="TokenUsed", data=df, ax= ax, whis=[0,100])
# Without filter
ax = sns.scatterplot(x="date", y="TokenUsed", data=df, ax= ax,color=".25")
# Filter
ax = sns.scatterplot(x="date", y="TokenUsed", data=df[df["TokenUsed"]>81], ax= ax,color=".25")

ax.axhline(81)

plt.locator_params(axis='x', nbins=10)
plt.show()

标签: pythonpandasmatplotlibseaborn

解决方案


回答:

df尝试编辑您的过滤器,以便实际上没有删除任何行。也就是说,专门在TokenUsed列上应用掩码,以便将值替换为NaN(而不是删除整行)。以下是我将如何实现它:

#make a new copy df, use that to plot
df2['TokenUsed'] = df2['TokenUsed'].mask(df2['TokenUsed'] < 81)
ax = sns.scatterplot(x="date", y="TokenUsed", data=df2, ax= ax,color=".25")

解释

警告:这真的是我从自己的观察中对正在发生的事情的理解;我实际上并不知道幕后的实现

seaborn不太了解您预期的日期。创建箱线图并将date列用作 x 轴时,按列seaborn中的每个唯一值对数据进行分组date。它对这些字符串进行排序,然后为每个字符串创建一个整数位置(从 开始0)。 然后根据这些整数值绘制 y 数据,并将 x-tick-labels 替换为相应的字符串 value。因此,在您的情况下,有 8 个唯一的日期字符串,它们被绘制在从0到的 x 位置7。此外,它们看起来像约会实际上并不重要。 您可以将更多字符串值添加到date柱子; 它们相对于先前数据的位置将取决于它们的字母顺序(例如,我猜字符串'00-00-0000'会首先出现,字符串'999'会最后出现)。

过滤器df[df["TokenUsed"]>81]会删除值低于 81的所有行TokenUsed。这意味着过滤后的 DataFrame 将不会有与原始数据一样多的字符串日期值。这会在绘图时产生意想不到的结果。在您过滤的数据中,具有上述值的第一个日期812020-02-09. 因此,在scatterplot调用中,这些值被绘制在x=0,这令人困惑,因为 from 的值2020-01-05被绘制在x=0对 的调用中boxplot

解决方法是确保所有原始日期仍然存在于过滤后的数据中,但将过滤掉的值替换为NaN不绘制任何内容。

这是我用来测试的示例:

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

# fake data, only one date has values over 80
dr = ['01-05-2020'] * 100 + ['01-12-2020'] * 100 + ['01-19-2020'] * 100
data = list(np.random.randint(0,80,200)) + list(np.random.randint(50,150,100))
df = pd.DataFrame({'date':dr, 'TokenUsed':data})

fig, ax = plt.subplots(figsize = (12,6))
ax = sns.boxplot(x="date", y="TokenUsed", data=df, ax=ax, whis=[0,100])

df2 = df.copy()
df2['TokenUsed'] = df2['TokenUsed'].mask(df2['TokenUsed'] < 81)

# the fix
df2 = df.copy()
df2['TokenUsed'] = df2['TokenUsed'].mask(df2['TokenUsed'] < 81)
ax = sns.scatterplot(x="date", y="TokenUsed", data=df2, ax= ax,color=".25")

ax.axhline(81)
plt.locator_params(axis='x', nbins=10)
plt.show()

在此处输入图像描述

如果我使用您应用的相同过滤器,我会遇到同样的问题。


推荐阅读