Pandas 中文参考指南

Chart visualization

以下示例假设你在使用 Jupyter

本部分演示通过图表进行可视化。有关表格数据的可视化的信息,请参阅 Table Visualization 部分。

我们使用标准惯例来引用 matplotlib API:

In [1]: import matplotlib.pyplot as plt

In [2]: plt.close("all")

我们在 pandas 中提供了基础知识,可以轻松地创建出色的绘图。有关超出此处记录的基础知识的可视库,请参阅 the ecosystem page

np.random 的所有调用都以 123456 为种子。

Basic plotting: plot

我们将演示基础知识,有关一些高级策略,请参阅 cookbook

序列和数据框上的 plot 方法只是一个简单的包装器,用于链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot[_plt.plot()]:

In [3]: np.random.seed(123456)

In [4]: ts = pd.Series(np.random.randn(1000), index=pd.date_range("1/1/2000", periods=1000))

In [5]: ts = ts.cumsum()

In [6]: ts.plot();

如果索引包含日期,它会调用 gcf().autofmt_xdate() 以尝试根据上述内容很好地设置 x 轴的格式。

在数据框上, plot() 是绘制所有带有标签的列的便捷方式:

In [7]: df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list("ABCD"))

In [8]: df = df.cumsum()

In [9]: plt.figure();

In [10]: df.plot();

你可以使用 plot() 中的 xy 关键词,根据另一列绘制一列:

In [11]: df3 = pd.DataFrame(np.random.randn(1000, 2), columns=["B", "C"]).cumsum()

In [12]: df3["A"] = pd.Series(list(range(len(df))))

In [13]: df3.plot(x="A", y="B");

有关更多格式化和样式选项,请在下面参阅 formatting

Other plots

除了默认的线图以外,绘图方法允许使用少数几种绘图样式。这些方法可以作为 plot()kind 关键词参数提供,包括:

  1. ‘bar’‘barh’ 表示条形图

  2. ‘hist’ for histogram

  3. ‘box’ for boxplot

  4. ‘kde’‘density’ 表示密度图

  5. ‘area’ for area plots

  6. ‘scatter’ for scatter plots

  7. ‘hexbin’ 表示六边形箱型图

  8. ‘pie’ for pie plots

例如,可以如下方式创建一个条形图:

In [14]: plt.figure();

In [15]: df.iloc[5].plot(kind="bar");

你还可以使用 DataFrame.plot.<kind> 方法来创建这些其他绘图,而不必提供 kind 关键词参数。这可以让你更轻松地发现绘图方法及其使用的特定参数:

In [16]: df = pd.DataFrame()

In [17]: df.plot.<TAB>  # noqa: E225, E999
df.plot.area     df.plot.barh     df.plot.density  df.plot.hist     df.plot.line     df.plot.scatter
df.plot.bar      df.plot.box      df.plot.hexbin   df.plot.kde      df.plot.pie

除了这些 kind 之外,还有使用单独界面的 DataFrame.hist()DataFrame.boxplot()方法。

最后,pandas.plotting_中还有几个 plotting functions,它们将 _SeriesDataFrame作为参数。这些包括:

图表也可以用 errorbarstables进行装饰。

Bar plots

对于带标签的非时间序列数据,您可能希望绘制条形图:

In [18]: plt.figure();

In [19]: df.iloc[5].plot.bar();

In [20]: plt.axhline(0, color="k");

调用 DataFrame 的 plot.bar()方法会生成一个多条形图:

In [21]: df2 = pd.DataFrame(np.random.rand(10, 4), columns=["a", "b", "c", "d"])

In [22]: df2.plot.bar();

若要生成堆积条形图,传递 stacked=True

In [23]: df2.plot.bar(stacked=True);

要获得水平条形图,请使用 _barh_方法:

In [24]: df2.plot.barh(stacked=True);

Histograms

可以使用 DataFrame.plot.hist()Series.plot.hist()方法绘制直方图。

In [25]: df4 = pd.DataFrame(
   ....:     {
   ....:         "a": np.random.randn(1000) + 1,
   ....:         "b": np.random.randn(1000),
   ....:         "c": np.random.randn(1000) - 1,
   ....:     },
   ....:     columns=["a", "b", "c"],
   ....: )
   ....:

In [26]: plt.figure();

In [27]: df4.plot.hist(alpha=0.5);

可以使用 _stacked=True_对直方图进行堆叠。可以使用 _bins_关键字更改直方图的分组大小。

In [28]: plt.figure();

In [29]: df4.plot.hist(stacked=True, bins=20);

您可以传递 matplotlib _hist_支持的其他关键字。例如,可以通过 _orientation='horizontal'_和 _cumulative=True_绘制水平和累积直方图。

In [30]: plt.figure();

In [31]: df4["a"].plot.hist(orientation="horizontal", cumulative=True);

有关详细信息,请参阅链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.hist.html#matplotlib.axes.Axes.hist[_hist] 方法和 matplotlib hist documentation

仍然可以使用现有的接口 _DataFrame.hist_来绘制直方图。

In [32]: plt.figure();

In [33]: df["A"].diff().hist();

DataFrame.hist()在多个子图上绘制列的直方图:

In [34]: plt.figure();

In [35]: df.diff().hist(color="k", alpha=0.5, bins=50);

可以指定 _by_关键字来绘制分组直方图:

In [36]: data = pd.Series(np.random.randn(1000))

In [37]: data.hist(by=np.random.randint(0, 4, 1000), figsize=(6, 4));

此外,还可以在 DataFrame.plot.hist()中指定 _by_关键字。

在 1.4.0 版中已更改。

In [38]: data = pd.DataFrame(
   ....:     {
   ....:         "a": np.random.choice(["x", "y", "z"], 1000),
   ....:         "b": np.random.choice(["e", "f", "g"], 1000),
   ....:         "c": np.random.randn(1000),
   ....:         "d": np.random.randn(1000) - 1,
   ....:     },
   ....: )
   ....:

In [39]: data.plot.hist(by=["a", "b"], figsize=(10, 5));

Box plots

可以通过调用 Series.plot.box()DataFrame.plot.box()DataFrame.boxplot()绘制箱线图,以可视化每列中的值的分布。

例如,这里是一个箱线图,表示在 [0,1) 上的均匀随机变量的 10 次观测的五次试验。

In [40]: df = pd.DataFrame(np.random.rand(10, 5), columns=["A", "B", "C", "D", "E"])

In [41]: df.plot.box();

可以通过传递 color_关键字来对箱线图进行着色。您可以传递一个 _dict,其键是 boxeswhiskersmedians_和 _caps。如果 _dict_中缺少某些键,则会为相应的艺术家使用默认颜色。此外,箱线图还有 _sym_关键字来指定离群点样式。

当你通过 color 关键字传递其他类型的参数时,它将直接将其传递给 matplotlib 以供 boxeswhiskersmedianscaps 着色。

颜色应用于要绘制的每一个方框。如果你想进行更复杂的着色,你可以通过传递 return_type 来获取每个绘制的图形。

In [42]: color = {
   ....:     "boxes": "DarkGreen",
   ....:     "whiskers": "DarkOrange",
   ....:     "medians": "DarkBlue",
   ....:     "caps": "Gray",
   ....: }
   ....:

In [43]: df.plot.box(color=color, sym="r+");

此外,你还可以传递 matplotlib 支持的其他关键字 boxplot。例如,可以通过 vert=Falsepositions 关键字绘制水平和自定义位置的箱形图。

In [44]: df.plot.box(vert=False, positions=[1, 4, 5, 6, 8]);

请参阅链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.boxplot.html#matplotlib.axes.Axes.boxplot[_boxplot] 方法和更多 matplotlib boxplot documentation

现有的 DataFrame.boxplot 接口仍可用于绘制箱形图。

In [45]: df = pd.DataFrame(np.random.rand(10, 5))

In [46]: plt.figure();

In [47]: bp = df.boxplot()

你可以使用 by 关键字参数创建分层箱形图来创建分组。例如:

In [48]: df = pd.DataFrame(np.random.rand(10, 2), columns=["Col1", "Col2"])

In [49]: df["X"] = pd.Series(["A", "A", "A", "A", "A", "B", "B", "B", "B", "B"])

In [50]: plt.figure();

In [51]: bp = df.boxplot(by="X")

你还可以传递一组待绘制的列,以及按多列分组:

In [52]: df = pd.DataFrame(np.random.rand(10, 3), columns=["Col1", "Col2", "Col3"])

In [53]: df["X"] = pd.Series(["A", "A", "A", "A", "A", "B", "B", "B", "B", "B"])

In [54]: df["Y"] = pd.Series(["A", "B", "A", "B", "A", "B", "A", "B", "A", "B"])

In [55]: plt.figure();

In [56]: bp = df.boxplot(column=["Col1", "Col2"], by=["X", "Y"])

你还可以使用 DataFrame.plot.box() 创建分组,例如:

在 1.4.0 版中已更改。

In [57]: df = pd.DataFrame(np.random.rand(10, 3), columns=["Col1", "Col2", "Col3"])

In [58]: df["X"] = pd.Series(["A", "A", "A", "A", "A", "B", "B", "B", "B", "B"])

In [59]: plt.figure();

In [60]: bp = df.plot.box(column=["Col1", "Col2"], by="X")

boxplot 中,可以通过 return_type 关键字控制返回类型。有效的选择是 {"axes", "dict", "both", None}。通过 DataFrame.boxplot 使用 by 关键字创建的分面也会影响输出类型:

return_type

分面

输出类型

None

None

维度为 2 的轴 ndarray

'axes'

'axes'

轴序列

'dict'

艺术家字典

'dict'

艺术家字典系列

'both'

命名元组

'both'

命名元组系列

Groupby.boxplot 总会返回 Seriesreturn_type

In [61]: np.random.seed(1234)

In [62]: df_box = pd.DataFrame(np.random.randn(50, 2))

In [63]: df_box["g"] = np.random.choice(["A", "B"], size=50)

In [64]: df_box.loc[df_box["g"] == "B", 1] += 3

In [65]: bp = df_box.boxplot(by="g")

上面按数字列拆分子图,然后按 g 列的值拆分。下面的子图按 g 的值拆分,然后再按数字列拆分。

In [66]: bp = df_box.groupby("g").boxplot()

Area plot

可以通过 Series.plot.area()DataFrame.plot.area() 创建面积图。面积图默认堆叠。为了生成堆叠面积图,每列都必须是全正值或全负值。

当输入数据包含 NaN 时,它将自动填充为 0。如果你想删除或用不同值填充,在调用 plot 之前使用 dataframe.dropna()dataframe.fillna()

In [67]: df = pd.DataFrame(np.random.rand(10, 4), columns=["a", "b", "c", "d"])

In [68]: df.plot.area();

要生成非堆叠图,传递 stacked=False。除非另有指定,否则 Alpha 值设置为 0.5:

In [69]: df.plot.area(stacked=False);

Scatter plot

可以使用 DataFrame.plot.scatter() 方法绘制散点图。散点图需要 x 轴和 y 轴的数字列。可以通过 xy 关键字来指定这些列。

In [70]: df = pd.DataFrame(np.random.rand(50, 4), columns=["a", "b", "c", "d"])

In [71]: df["species"] = pd.Categorical(
   ....:     ["setosa"] * 20 + ["versicolor"] * 20 + ["virginica"] * 10
   ....: )
   ....:

In [72]: df.plot.scatter(x="a", y="b");

要在单个轴内绘制多列组,重复 plot 方法指定目标 ax。建议指定 colorlabel 关键字以区分每个组。

In [73]: ax = df.plot.scatter(x="a", y="b", color="DarkBlue", label="Group 1")

In [74]: df.plot.scatter(x="c", y="d", color="DarkGreen", label="Group 2", ax=ax);

关键字 c 可以作为列的名称,为每个点提供颜色:

In [75]: df.plot.scatter(x="a", y="b", c="c", s=50);

如果向 c 传递分类列,那么将生成离散颜色条:

1.3.0 版中的新增功能。

In [76]: df.plot.scatter(x="a", y="b", c="species", cmap="viridis", s=50);

你可以传递 matplotlib 链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.scatter.html#matplotlib.axes.Axes.scatter[_scatter] 支持的其他关键字。下面的示例展示了使用 DataFrame 列作为气泡大小的带气泡的图表。

In [77]: df.plot.scatter(x="a", y="b", s=df["c"] * 200);

请参见链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.scatter.html#matplotlib.axes.Axes.scatter[_scatter] 方法和 matplotlib scatter documentation 以获取更多信息。

Hexagonal bin plot

可以通过 DataFrame.plot.hexbin() 创建六边形箱形图。如果数据太密集而无法逐个绘制每个点,六边形箱形图可以成为散点图的有用替代。

In [78]: df = pd.DataFrame(np.random.randn(1000, 2), columns=["a", "b"])

In [79]: df["b"] = df["b"] + np.arange(1000)

In [80]: df.plot.hexbin(x="a", y="b", gridsize=25);

一个有用的关键字参数是 gridsize;它控制 x 方向上的六边形数量,默认为 100。更大的 gridsize 意味着更多、更小的箱。

默认情况下,计算每个 (x, y) 点周围计数的直方图。你可以通过向 Creduce_C_function 参数传递值来指定备选聚合。C 指定每个 (x, y) 点的值,而 reduce_C_function 是一个自变量函数,它将箱子中的所有值简化为一个数字(例如 meanmaxsumstd)。在这个示例中,位置由列 ab 给出,而值由列 z 给出。这些箱使用 NumPy 的 max 函数聚合。

In [81]: df = pd.DataFrame(np.random.randn(1000, 2), columns=["a", "b"])

In [82]: df["b"] = df["b"] + np.arange(1000)

In [83]: df["z"] = np.random.uniform(0, 3, 1000)

In [84]: df.plot.hexbin(x="a", y="b", C="z", reduce_C_function=np.max, gridsize=25);

请参阅此链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.hexbin.html#matplotlib.axes.Axes.hexbin[_hexbin] 方法和 matplotlib hexbin documentation 以了解更多信息。

Pie plot

您可以使用 DataFrame.plot.pie()Series.plot.pie() 创建饼形图。如果您的数据包含任何 NaN,它们将自动填充为 0。如果您的数据中存在任何负值,则会引发 ValueError

In [85]: series = pd.Series(3 * np.random.rand(4), index=["a", "b", "c", "d"], name="series")

In [86]: series.plot.pie(figsize=(6, 6));

对于饼形图,最好使用正方形图形,即图形宽高比为 1。您可以创建宽度和高度相等的图形,或通过在返回的 axes 对象上调用 ax.set_aspect('equal') 在绘制后强制宽高比相等。

请注意,带有 DataFrame 的饼形图要求您通过 y 自变量或 subplots=True 指定目标列。当指定 y 时,将绘制所选列的饼图。如果指定 subplots=True,则将绘制每个列的饼图作为子图。默认情况下,每个饼图中都将绘制一个图例;指定 legend=False 以隐藏它。

In [87]: df = pd.DataFrame(
   ....:     3 * np.random.rand(4, 2), index=["a", "b", "c", "d"], columns=["x", "y"]
   ....: )
   ....:

In [88]: df.plot.pie(subplots=True, figsize=(8, 4));

您可以使用 labelscolors 关键字指定每个楔形的标签和颜色。

警告

大多数熊猫图使用 labelcolor 自变量(请注意这两个自变量上缺少“s”)。为了与 _matplotlib.pyplot.pie() 保持一致,您必须使用 labelscolors

如果您想隐藏楔形标签,请指定 labels=None。如果指定 fontsize,则该值将应用于楔形标签。此外, _matplotlib.pyplot.pie() 支持的其他关键字也可以使用。

In [89]: series.plot.pie(
   ....:     labels=["AA", "BB", "CC", "DD"],
   ....:     colors=["r", "g", "b", "c"],
   ....:     autopct="%.2f",
   ....:     fontsize=20,
   ....:     figsize=(6, 6),
   ....: );
   ....:

如果您传递的总和小于 1.0 的值,则将对它们进行重新缩放,使其相加为 1。

In [90]: series = pd.Series([0.1] * 4, index=["a", "b", "c", "d"], name="series2")

In [91]: series.plot.pie(figsize=(6, 6));

请参阅 matplotlib pie documentation 以了解更多信息。

Plotting with missing data

熊猫尝试实际地绘制包含缺失数据的 DataFramesSeries。根据绘图类型,舍弃、留出或填充缺失值。

绘图类型

NaN 处理

在 NaN 处留出间隙

行(堆叠)

填充 0

条形

填充 0

散点

舍弃 NaN

直方图

(按行丢弃)NaN

盒形图

(按行丢弃)NaN

面积图

填充 0

核密度估计(KDE)

(按行丢弃)NaN

六边形网格图

舍弃 NaN

饼图

填充 0

如果这些默认值不符合您的需求,或您想明确如何处理缺失值,请考虑在绘图之前使用 fillna()dropna()

Plotting tools

这些函数可以从 pandas.plotting 导入,并将 SeriesDataFrame 作为参数。

Scatter matrix plot

您可以使用 pandas.plottingscatter_matrix 方法创建散点图矩阵:

In [92]: from pandas.plotting import scatter_matrix

In [93]: df = pd.DataFrame(np.random.randn(1000, 4), columns=["a", "b", "c", "d"])

In [94]: scatter_matrix(df, alpha=0.2, figsize=(6, 6), diagonal="kde");

Density plot

您可以使用 Series.plot.kde()DataFrame.plot.kde() 方法创建密度图。

In [95]: ser = pd.Series(np.random.randn(1000))

In [96]: ser.plot.kde();

Andrews curves

安德鲁斯曲线允许将多变量数据绘制为大量的曲线,这些曲线是使用样本的属性作为傅立叶级数的系数创建的,请参阅 Wikipedia entry 以获取更多信息。通过对每个类的曲线着不同的颜色,可以可视化数据聚类。属于同一类样本的曲线通常会靠得更近并形成更大的结构。

注:“鸢尾”数据集可用 here 获取。

In [97]: from pandas.plotting import andrews_curves

In [98]: data = pd.read_csv("data/iris.data")

In [99]: plt.figure();

In [100]: andrews_curves(data, "Name");

Parallel coordinates

并行坐标是一种绘制多变量数据的绘图技术,请参阅 Wikipedia entry 了解介绍。并行坐标允许人们查看数据中的聚类,并直观地估计其他统计数据。使用并行坐标,点表示为连接的线段。每条垂直线代表一个属性。一组连接的线段代表一个数据点。倾向于聚类的点将靠得更近。

In [101]: from pandas.plotting import parallel_coordinates

In [102]: data = pd.read_csv("data/iris.data")

In [103]: plt.figure();

In [104]: parallel_coordinates(data, "Name");

Lag plot

滞后图用于检查数据集或时间序列是否是随机的。随机数据在滞后图中不应显示任何结构。非随机结构意味着底层数据不是随机的。可以传递 lag 参数,而当 lag=1 时,绘图实际上是 data[:-1] vs. data[1:]

In [105]: from pandas.plotting import lag_plot

In [106]: plt.figure();

In [107]: spacing = np.linspace(-99 * np.pi, 99 * np.pi, num=1000)

In [108]: data = pd.Series(0.1 * np.random.rand(1000) + 0.9 * np.sin(spacing))

In [109]: lag_plot(data);

Autocorrelation plot

自相关图通常用于检查时间序列中的随机性。这是通过针对不同时间滞后处的数据值计算自相关来完成的。如果时间序列是随机的,则对于任何和所有时间滞后分离,此类自相关都应该接近零。如果时间序列不是随机的,那么一个或多个自相关将显著不为零。绘图中显示的水平线对应于 95% 和 99% 置信带。虚线为 99% 置信带。有关自相关图的更多信息,请参阅 Wikipedia entry

In [110]: from pandas.plotting import autocorrelation_plot

In [111]: plt.figure();

In [112]: spacing = np.linspace(-9 * np.pi, 9 * np.pi, num=1000)

In [113]: data = pd.Series(0.7 * np.random.rand(1000) + 0.3 * np.sin(spacing))

In [114]: autocorrelation_plot(data);

Bootstrap plot

自举图用于直观地评估统计的不确定性,例如均值、中位数、中值范围等。从数据集中选择特定大小的随机子集,针对此子集计算相关统计数据,并重复该过程指定次数。生成的绘图和直方图构成了自举图。

In [115]: from pandas.plotting import bootstrap_plot

In [116]: data = pd.Series(np.random.rand(1000))

In [117]: bootstrap_plot(data, size=50, samples=500, color="grey");

RadViz

RadViz 是一种可视化多变量数据的方法。它基于一个简单的弹簧张力最小化算法。基本上,您在平面上设置了许多点。在我们的例子中,它们等距分布在单位圆上。每个点代表某个属性。然后,假装数据集中每个样本都通过一个弹簧连接到这些点中的每一个,其刚度与该属性的数值成正比(它们被归一化为单位区间)。我们的样本稳定下来的平面上的点(我们的样本上作用的力处于平衡状态)将绘制表示我们样本的点。根据该样本所属的类别,该样本将被涂上不同的颜色。有关更多信息,请参阅 R 包 Radviz

注:“鸢尾”数据集可用 here 获取。

In [118]: from pandas.plotting import radviz

In [119]: data = pd.read_csv("data/iris.data")

In [120]: plt.figure();

In [121]: radviz(data, "Name");

Plot formatting

Setting the plot style

从 1.5 版开始,matplotlib 提供了一系列预配置的绘图样式。设置样式可用于轻松地为绘图赋予您想要的总体外观。只需在创建绘图之前调用 matplotlib.style.use(my_plot_style) 即可设置样式。例如,您可以编写 matplotlib.style.use('ggplot') 以获得 ggplot 风格的绘图。

您可以在 matplotlib.style.available 查看可用的各种样式名称,试用也非常简单。

General plot style arguments

大多数绘制方法都有一组关键词参数,用于控制返回的绘制图的布局和格式:

In [122]: plt.figure();

In [123]: ts.plot(style="k--", label="Series");

对于每种类型的绘制图(例如 linebarscatter),任何其他实参关键词都会传给相对应的 matplotlib 函数(链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.plot.html#matplotlib.axes.Axes.plot[_ax.plot()]、链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.bar.html#matplotlib.axes.Axes.bar[_ax.bar()]、链接:https://matplotlib.org/stable/api/as_gen/matplotlib.axes.Axes.scatter.html#matplotlib.axes.Axes.scatter[_ax.scatter()])。除了 pandas 提供的内容外,这些内容还可以用于控制其他样式。

Controlling the legend

您可以将 legend 实参设置为 False 以隐藏默认显示的图例。

In [124]: df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list("ABCD"))

In [125]: df = df.cumsum()

In [126]: df.plot(legend=False);

Controlling the labels

您可以设置 xlabelylabel 实参,以便为 x 和 y 轴提供自定义标签。默认情况下,pandas 会选取索引名称作为 xlabel,而将其保留为空值以用作 ylabel。

In [127]: df.plot();

In [128]: df.plot(xlabel="new x", ylabel="new y");

Scales

您可以传递 logy 来获取对数刻度的 Y 轴。

In [129]: ts = pd.Series(np.random.randn(1000), index=pd.date_range("1/1/2000", periods=1000))

In [130]: ts = np.exp(ts.cumsum())

In [131]: ts.plot(logy=True);

另请参阅 logxloglog 关键词实参。

Plotting on a secondary y-axis

若要在辅助 y 轴上绘制数据,请使用 secondary_y 关键词:

In [132]: df["A"].plot();

In [133]: df["B"].plot(secondary_y=True, style="g");

若要在 DataFrame 中绘制一些列,请将列的名称提供给 secondary_y 关键词:

In [134]: plt.figure();

In [135]: ax = df.plot(secondary_y=["A", "B"])

In [136]: ax.set_ylabel("CD scale");

In [137]: ax.right_ax.set_ylabel("AB scale");

请注意,在辅助 y 轴上绘制的列在图例中会自动标记为 “(right)”。若要关闭自动标记,请使用 mark_right=False 关键词:

In [138]: plt.figure();

In [139]: df.plot(secondary_y=["A", "B"], mark_right=False);

Custom formatters for timeseries plots

pandas 为时间序列图提供了自定义格式化程序。这些程序会更改日期和时间的轴标签格式。默认情况下,自定义格式化程序仅应用于 pandas 使用 DataFrame.plot()Series.plot() 创建的绘制图。若让它们应用于所有绘制图,包括 matplotlib 创建的绘制图,请设置选项 pd.options.plotting.matplotlib.register_converters = True 或使用 pandas.plotting.register_matplotlib_converters()

Suppressing tick resolution adjustment

pandas 包含针对常规频率时间序列数据的自动刻度解析调整。对于 pandas 无法推断频率信息的有限案例(例如在外部创建的 twinx 中),您可以选择禁止这种行为以便进行对齐。

这是默认行为,请注意 x 轴刻度标签的执行方式:

In [140]: plt.figure();

In [141]: df["A"].plot();

使用 x_compat 参数,您可以禁止这种行为:

In [142]: plt.figure();

In [143]: df["A"].plot(x_compat=True);

如果您有多个需要禁止的绘制图,则可以在 pandas.plotting.plot_params 中的 use 方法用在 with 语句中:

In [144]: plt.figure();

In [145]: with pd.plotting.plot_params.use("x_compat", True):
   .....:     df["A"].plot(color="r")
   .....:     df["B"].plot(color="g")
   .....:     df["C"].plot(color="b")
   .....:

Automatic date tick adjustment

TimedeltaIndex 现在使用基本的 matplotlib 刻度定位器方法,这有助于调用 matplotlib 中适用于刻度标签重叠的数字自动刻度调整。

请参阅 autofmt_xdate 方法和 matplotlib documentation 以了解详情。

Subplots

DataFrame 中的每个 Series 都可以使用 subplots 关键词在不同的轴上绘制:

In [146]: df.plot(subplots=True, figsize=(6, 6));

Using layout and targeting multiple axes

子图的布局可以通过 layout 关键词指定。它可以接受 (rows, columns)layout 关键词也可以在 histboxplot 中使用。如果输入无效,则会触发 ValueError

layout 指定的行 x 列可以包含的轴数必须大于所需的子图数。如果布局可以包含比所需的更多的轴,则不会绘制空白轴。类似于 NumPy 数组的 reshape 方法,你可以使用 -1 为一个维度自动计算行数或列数(给定另一个维度)。

In [147]: df.plot(subplots=True, layout=(2, 3), figsize=(6, 6), sharex=False);

上面的示例与使用以下代码相同:

In [148]: df.plot(subplots=True, layout=(2, -1), figsize=(6, 6), sharex=False);

所需列数(3)源自于要绘制的序列数和给定的行数(2)。

你可以将多个预先创建的轴作为类列表通过 ax 关键字传递。这允许多个复杂的布局。传递的轴必须与要绘制的子图数相同。

通过 ax 关键字传递多个轴时,layoutsharexsharey 关键字不会影响输出。你应该明确传递 sharex=Falsesharey=False,否则会看到警告。

In [149]: fig, axes = plt.subplots(4, 4, figsize=(9, 9))

In [150]: plt.subplots_adjust(wspace=0.5, hspace=0.5)

In [151]: target1 = [axes[0][0], axes[1][1], axes[2][2], axes[3][3]]

In [152]: target2 = [axes[3][0], axes[2][1], axes[1][2], axes[0][3]]

In [153]: df.plot(subplots=True, ax=target1, legend=False, sharex=False, sharey=False);

In [154]: (-df).plot(subplots=True, ax=target2, legend=False, sharex=False, sharey=False);

另一个选项是将 ax 参数传递给 Series.plot() 以便在特定轴上绘制:

In [155]: np.random.seed(123456)

In [156]: ts = pd.Series(np.random.randn(1000), index=pd.date_range("1/1/2000", periods=1000))

In [157]: ts = ts.cumsum()

In [158]: df = pd.DataFrame(np.random.randn(1000, 4), index=ts.index, columns=list("ABCD"))

In [159]: df = df.cumsum()
In [160]: fig, axes = plt.subplots(nrows=2, ncols=2)

In [161]: plt.subplots_adjust(wspace=0.2, hspace=0.5)

In [162]: df["A"].plot(ax=axes[0, 0]);

In [163]: axes[0, 0].set_title("A");

In [164]: df["B"].plot(ax=axes[0, 1]);

In [165]: axes[0, 1].set_title("B");

In [166]: df["C"].plot(ax=axes[1, 0]);

In [167]: axes[1, 0].set_title("C");

In [168]: df["D"].plot(ax=axes[1, 1]);

In [169]: axes[1, 1].set_title("D");

Plotting with error bars

使用误差线进行绘图在 DataFrame.plot()Series.plot() 中支持。

可以将水平和垂直误差线提供给 plot()xerryerr 关键字参数。可以使用各种格式指定误差值:

  1. 作为与绘图 DataFramecolumns 属性匹配的列名称的误差 DataFramedict,或者与 Seriesname 属性匹配。

  2. 作为一个 str 指示绘图 DataFrame 的哪些列包含误差值。

  3. 作为原始值(listtuplenp.ndarray)。必须与绘图 DataFrame/ Series 相同长度。

以下是一个轻松绘制原始数据的组均值加上标准差的示例。

# Generate the data
In [170]: ix3 = pd.MultiIndex.from_arrays(
   .....:     [
   .....:         ["a", "a", "a", "a", "a", "b", "b", "b", "b", "b"],
   .....:         ["foo", "foo", "foo", "bar", "bar", "foo", "foo", "bar", "bar", "bar"],
   .....:     ],
   .....:     names=["letter", "word"],
   .....: )
   .....:

In [171]: df3 = pd.DataFrame(
   .....:     {
   .....:         "data1": [9, 3, 2, 4, 3, 2, 4, 6, 3, 2],
   .....:         "data2": [9, 6, 5, 7, 5, 4, 5, 6, 5, 1],
   .....:     },
   .....:     index=ix3,
   .....: )
   .....:

# Group by index labels and take the means and standard deviations
# for each group
In [172]: gp3 = df3.groupby(level=("letter", "word"))

In [173]: means = gp3.mean()

In [174]: errors = gp3.std()

In [175]: means
Out[175]:
                data1     data2
letter word
a      bar   3.500000  6.000000
       foo   4.666667  6.666667
b      bar   3.666667  4.000000
       foo   3.000000  4.500000

In [176]: errors
Out[176]:
                data1     data2
letter word
a      bar   0.707107  1.414214
       foo   3.785939  2.081666
b      bar   2.081666  2.645751
       foo   1.414214  0.707107

# Plot
In [177]: fig, ax = plt.subplots()

In [178]: means.plot.bar(yerr=errors, ax=ax, capsize=4, rot=0);

还支持非对称误差线,但是必须在这种情况下提供原始误差值。对于长度为 NSeries,应该提供一个 2xN 数组,指示上下(或左右)误差。对于长度为 MxNDataFrame,非对称误差必须位于 Mx2xN 数组中。

以下是如何使用非对称误差线绘制最小值/最大值范围的一个示例。

In [179]: mins = gp3.min()

In [180]: maxs = gp3.max()

# errors should be positive, and defined in the order of lower, upper
In [181]: errors = [[means[c] - mins[c], maxs[c] - means[c]] for c in df3.columns]

# Plot
In [182]: fig, ax = plt.subplots()

In [183]: means.plot.bar(yerr=errors, ax=ax, capsize=4, rot=0);

Plotting tables

使用 matplotlib 表格进行绘图现在在 DataFrame.plot()Series.plot() 中支持 table 关键字。table 关键字可以接受 boolDataFrameSeries。绘制表格的简单方法是指定 table=True。数据将被转置以符合 matplotlib 的默认布局。

In [184]: np.random.seed(123456)

In [185]: fig, ax = plt.subplots(1, 1, figsize=(7, 6.5))

In [186]: df = pd.DataFrame(np.random.rand(5, 3), columns=["a", "b", "c"])

In [187]: ax.xaxis.tick_top()  # Display x-axis ticks on top.

In [188]: df.plot(table=True, ax=ax);

此外,你可以将不同的 DataFrameSeries 传递给 table 关键字。数据将按打印方法中显示的内容绘制(不会自动转置)。如有需要,应该像下面示例中看到的那样手动转置。

In [189]: fig, ax = plt.subplots(1, 1, figsize=(7, 6.75))

In [190]: ax.xaxis.tick_top()  # Display x-axis ticks on top.

In [191]: df.plot(table=np.round(df.T, 2), ax=ax);

还有一个辅助函数 pandas.plotting.table,它从 DataFrameSeries 创建一个表格,并将其添加到 matplotlib.Axes 实例。此函数可以接受 matplotlib table 所具有的关键字。

In [192]: from pandas.plotting import table

In [193]: fig, ax = plt.subplots(1, 1)

In [194]: table(ax, np.round(df.describe(), 2), loc="upper right", colWidths=[0.2, 0.2, 0.2]);

In [195]: df.plot(ax=ax, ylim=(0, 2), legend=None);

注意:您可以使用 axes.tables 属性在轴上获取表格实例以进行进一步装饰。请参阅 matplotlib table documentation 了解更多信息。

Colormaps

绘制大量列时的一个潜在问题是,由于默认颜色的重复,很难区分某些序列。为了解决这个问题,DataFrame 绘图支持使用 colormap 参数,它接受 matplotlib colormap 或作为在 matplotlib 中注册的配色表名称的字符串。matplotlib 默认配色表的可视化可在 here 处获得。

由于 matplotlib 并不直接支持基于行的绘图的色彩映射,因此颜色会根据 DataFrame 中列数确定的均匀间隔进行选择。没有考虑背景颜色,因此某些色彩映射会产生不可见线条。

要使用 cubehelix 色彩映射,我们可以传递 colormap='cubehelix'

In [196]: np.random.seed(123456)

In [197]: df = pd.DataFrame(np.random.randn(1000, 10), index=ts.index)

In [198]: df = df.cumsum()

In [199]: plt.figure();

In [200]: df.plot(colormap="cubehelix");

或者,我们可以传递色彩映射本身:

In [201]: from matplotlib import cm

In [202]: plt.figure();

In [203]: df.plot(colormap=cm.cubehelix);

色彩映射还可用于其他绘图类型,如条形图:

In [204]: np.random.seed(123456)

In [205]: dd = pd.DataFrame(np.random.randn(10, 10)).map(abs)

In [206]: dd = dd.cumsum()

In [207]: plt.figure();

In [208]: dd.plot.bar(colormap="Greens");

平行坐标图:

In [209]: plt.figure();

In [210]: parallel_coordinates(data, "Name", colormap="gist_rainbow");

Andrews 曲线图:

In [211]: plt.figure();

In [212]: andrews_curves(data, "Name", colormap="winter");

Plotting directly with Matplotlib

在某些情况下,可能更喜欢或有必要使用 matplotlib 直接准备绘图,例如当 pandas (尚) 不支持某种绘图类型或自定义项时。SeriesDataFrame 对象的行为类似于数组,因此可以将其直接传递给 matplotlib 函数,而无需显式强制转换。

pandas 还会自动注册识别日期索引的格式化程序和定位器,从而将日期和时间支持扩展到 matplotlib 中几乎所有可用的绘图类型。虽然此格式设置无法提供通过 pandas 绘图时获得的相同精细度级别,但在大量绘制点时,此方法会更快。

In [213]: np.random.seed(123456)

In [214]: price = pd.Series(
   .....:     np.random.randn(150).cumsum(),
   .....:     index=pd.date_range("2000-1-1", periods=150, freq="B"),
   .....: )
   .....:

In [215]: ma = price.rolling(20).mean()

In [216]: mstd = price.rolling(20).std()

In [217]: plt.figure();

In [218]: plt.plot(price.index, price, "k");

In [219]: plt.plot(ma.index, ma, "b");

In [220]: plt.fill_between(mstd.index, ma - 2 * mstd, ma + 2 * mstd, color="b", alpha=0.2);

Plotting backends

pandas 可以通过第三方绘图后端进行扩展。其主要思路是让用户选择不同于基于 Matplotlib 提供的后端的绘图后端。

这可通过在 plot 函数中传递“backend.module”作为 backend 参数来实现。例如:

>>> Series([1, 2, 3]).plot(backend="backend.module")

或者,您还可以全局设置此选项,这样您就不需要在每个 plot 调用中指定关键字。例如:

>>> pd.set_option("plotting.backend", "backend.module")
>>> pd.Series([1, 2, 3]).plot()

或者:

>>> pd.options.plotting.backend = "backend.module"
>>> pd.Series([1, 2, 3]).plot()

这将或多或少等于:

>>> import backend.module
>>> backend.module.plot(pd.Series([1, 2, 3]))

然后,后端模块可以使用其他可视化工具(Bokeh、Altair、hvplot 等)生成绘图。 the ecosystem page 上列出了实现 pandas 后端的一些库。