使用Seaborn FacetGrid绘制时间序列

9 投票
1 回答
7861 浏览
提问于 2025-04-20 04:39

我有一个数据表(data),它有一个简单的整数索引和5列。列的名称分别是 Date(日期)、Country(国家)、AgeGroup(年龄组)、Gender(性别)和 Stat(统计数据)。为了保护隐私,名字都换了。我想制作一个 FacetGrid,其中 Country 用来定义行,AgeGroup 用来定义列,而 Gender 则用来定义颜色。对于这些特定的内容,我想生成一个时间序列图。也就是说,我应该得到一组图表,每个图表上有两条时间序列(1条男性,1条女性)。我已经接近实现这个目标:

g = sns.FacetGrid(data, row='Country', col='AgeGroup', hue='Gender')
g.map(plt.plot, 'Stat')

不过,这样做只是在x轴上显示样本数量,而不是日期。有没有什么快速的解决办法呢?

更一般来说,我知道使用 FacetGrid 的方法是先创建网格,然后将一个绘图函数映射到它上面。如果我想自己写一个绘图函数,它需要遵循什么样的规则呢?特别是,我该如何编写自己的绘图函数(以便传递给 map 用于 FacetGrid),使其能够接受来自数据集的多列数据呢?

1 个回答

10

我先来回答你更一般的问题。你可以传给 FacetGrid.map 的函数有几个规则:

  • 这些函数必须接受类似数组的输入作为位置参数,第一个参数对应 x 轴,第二个参数对应 y 轴(不过,关于第二个条件我稍后会详细说)。
  • 它们还必须接受两个关键字参数:colorlabel。如果你想使用一个 hue 变量,那么这些参数应该传给底层的绘图函数,不过如果这些参数对你正在制作的特定图表不相关,你可以选择接收 **kwargs 但不做任何处理。
  • 当被调用时,它们必须在“当前活动”的 matplotlib Axes 上绘制图表。

可能会有一些情况,你的函数绘制的图表看起来是正确的,但并没有接受 xy 这样的输入。我觉得这就是你使用 plt.plot 时的情况。这样的话,使用 map 后,直接调用 g.set_axis_labels("Date", "Stat") 来正确命名你的坐标轴会更简单。你可能还想用 g.set(xticklabels=dates) 来获得更有意义的刻度。

还有一个更通用的函数,叫 FacetGrid.map_dataframe。这里的规则类似,但你传入的函数必须接受一个名为 data 的数据框输入,而不是接受类似数组的位置输入,而是接受与数据框中变量对应的字符串。在每次遍历这些面板时,函数会被调用,并且输入的数据框只包含该 rowcolhue 组合的值。

所以在你的具体情况下,你需要写一个函数,我们可以称之为 plot_by_date,它应该看起来像这样:

def plot_by_date(x, y, color=None, label=None):

    ...

(我在函数的具体内容上可能帮不了你,因为我其实对日期和 matplotlib 的处理不太了解)。最终结果是,当你调用这个函数时,它应该在当前活动的 Axes 上绘制图表。然后执行

g.map(plot_by_date, "Date", "Stat")

我觉得这样应该就能工作了。

撰写回答