按月-年的散点图矩阵

Matrix of scatterplots by month-year

我的数据位于两列的数据框中:y 和 x。数据指的是过去几年。虚拟数据如下:

np.random.seed(167)
rng = pd.date_range('2017-04-03', periods=365*3)

df = pd.DataFrame(
    {"y": np.cumsum([np.random.uniform(-0.01, 0.01) for _ in range(365*3)]),
     "x": np.cumsum([np.random.uniform(-0.01, 0.01) for _ in range(365*3)])
    }, index=rng
)

在第一次尝试中,我使用以下代码绘制了 Seaborn 的散点图:

import seaborn as sns
import matplotlib.pyplot as plt

def plot_scatter(data, title, figsize):
    fig, ax = plt.subplots(figsize=figsize)
    ax.set_title(title)
    sns.scatterplot(data=data,
                    x=data['x'],
                    y=data['y'])

plot_scatter(data=df, title='dummy title', figsize=(10,7))  

但是,我想生成一个包含 12 个散点图的 4x3 矩阵,每个月一个,以年份为色调。我想我可以在我的数据框中创建第三列来告诉我年份,我尝试了以下操作:

import seaborn as sns
import matplotlib.pyplot as plt

def plot_scatter(data, title, figsize):
    fig, ax = plt.subplots(figsize=figsize)
    ax.set_title(title)
    sns.scatterplot(data=data,
                    x=data['x'],
                    y=data['y'],
                    hue=data.iloc[:, 2])
df['year'] = df.index.year
plot_scatter(data=df, title='dummy title', figsize=(10,7))    

虽然这让我可以看到年份,但它仍然在同一个散点图中显示所有数据,而不是创建多个散点图,每个月一个,所以它没有提供我需要的详细程度。

我可以按月对数据进行切片并构建一个 for 循环,每月绘制一个散点图,但实际上我想要一个矩阵,其中所有散点图都使用相似的轴刻度。有谁知道实现该目标的有效方法?

为了一次创建多个子图,seaborn 引入了 figure-level functionscol= 参数指示应使用数据帧的哪一列来标识子图。 col_wrap= 可用于判断在开始另一行之前有多少子图彼此相邻。

请注意,您不应创建 figure,因为函数会创建自己的新图形。它使用 height=aspect= 参数来说明各个子图的大小。

下面的代码在月份上使用了 sns.relplot()。为月份创建了一个额外的列;定单是明确的。

要删除标题中的 month=,您可以遍历生成的轴(axes_dict 需要最新的 seaborn 版本)。使用 sns.set(font_scale=...) 您可以更改所有文本的默认大小。

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

np.random.seed(167)
dates = pd.date_range('2017-04-03', periods=365 * 3, freq='D')

df = pd.DataFrame({"y": np.cumsum([np.random.uniform(-0.01, 0.01) for _ in range(365 * 3)]),
                   "x": np.cumsum([np.random.uniform(-0.01, 0.01) for _ in range(365 * 3)])
                   }, index=dates)

df['year'] = df.index.year
month_names = pd.date_range('2017-01-01', periods=12, freq='M').strftime('%B')
df['month'] = pd.Categorical.from_codes(df.index.month - 1, month_names)

sns.set(font_scale=1.7)
g = sns.relplot(kind='scatter', data=df, x='x', y='y', hue='year', col='month', col_wrap=4, height=4, aspect=1)
# optionally remove the `month=` in the title
for name, ax in g.axes_dict.items():
    ax.set_title(name)
plt.setp(g.axes, xlabel='', ylabel='')  # remove all x and y labels
g.axes[-2].set_xlabel('x', loc='left')  # set an x label at the left of the second to last subplot
g.axes[4].set_ylabel('y')  # set a y label to 5th subplot

plt.subplots_adjust(left=0.06, bottom=0.06)  # set some more spacing at the left and bottom
plt.show()