图表可视化#
备注
下面的示例假设您正在使用 Jupyter。
本节演示通过图表进行可视化。有关表格数据可视化的信息,请参见 表格可视化 部分。
我们使用引用matplotlib API的标准约定:
In [1]: import matplotlib.pyplot as plt
In [2]: plt.close("all")
我们在 pandas 中提供了基本功能,可以轻松创建看起来不错的图表。有关超越此处记录的基本功能的可视化库,请参见 生态系统页面。
备注
所有对 np.random
的调用都使用 123456 进行种子设定。
基本绘图:plot
#
我们将演示基础知识,有关一些高级策略,请参阅 食谱。
Series 和 DataFrame 上的 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 轴。
在 DataFrame 上,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();
你可以使用 x
和 y
关键字在 plot()
中绘制一列与另一列的关系:
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");
备注
有关更多格式和样式选项,请参见下面的 格式化。
其他图表#
绘图方法允许使用除默认线图之外的几种绘图样式。这些方法可以作为 kind
关键字参数提供给 plot()
,包括:
例如,可以通过以下方式创建条形图:
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
中有几个 绘图函数 接受 Series
或 DataFrame
作为参数。这些包括:
条形图#
对于标记的、非时间序列数据,您可能希望生成一个条形图:
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);
直方图#
直方图可以通过使用 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);
更多信息请参见 hist
方法和 matplotlib hist 文档。
现有的接口 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));
箱形图#
箱线图可以通过调用 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
,其键为 boxes
、whiskers
、medians
和 caps
。如果 dict
中缺少某些键,则默认颜色将用于相应的艺术家。此外,箱线图有 sym
关键字用于指定离群点的样式。
当你通过 color
关键字传递其他类型的参数时,它将直接传递给 matplotlib 用于所有 boxes
、 whiskers
、 medians
和 caps
的颜色化。
颜色应用于每个要绘制的框。如果你想要更复杂的上色,你可以通过传递 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=False
和 positions
关键字可以绘制水平和自定义位置的箱形图。
In [44]: df.plot.box(vert=False, positions=[1, 4, 5, 6, 8]);
更多信息请参见 boxplot
方法和 matplotlib boxplot 文档。
现有的接口 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
关键字创建的分面也会影响输出类型:
|
Faceted |
输出类型 |
---|---|---|
|
不 |
axes |
|
是的 |
2-D 轴的 ndarray |
|
不 |
axes |
|
是的 |
系列轴 |
|
不 |
艺术家字典 |
|
是的 |
艺术家字典系列 |
|
不 |
namedtuple |
|
是的 |
一系列的 namedtuples |
Groupby.boxplot
总是返回一个 return_type
的 Series
。
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()
区域图#
你可以使用 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);
散点图#
散点图可以通过使用 DataFrame.plot.scatter()
方法绘制。散点图需要 x 轴和 y 轴的数值列。这些可以通过 x
和 y
关键字指定。
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
。建议指定 color
和 label
关键字以区分每个组。
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
,则会生成一个离散的颜色条:
Added in version 1.3.0.
In [76]: df.plot.scatter(x="a", y="b", c="species", cmap="viridis", s=50);
你可以传递 matplotlib 支持的其他关键字 scatter
。下面的示例展示了使用 DataFrame
的一列作为气泡大小的气泡图。
In [77]: df.plot.scatter(x="a", y="b", s=df["c"] * 200);
更多信息请参见 scatter
方法和 matplotlib scatter 文档。
六边形分箱图#
你可以使用 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)
点周围计数的直方图。你可以通过传递值给 C
和 reduce_C_function
参数来指定替代的聚合方式。C
指定每个 (x, y)
点的值,而 reduce_C_function
是一个单参数函数,它将一个箱子中的所有值缩减为一个数字(例如 mean
、max
、sum
、std
)。在这个例子中,位置由列 a
和 b
给出,而值由列 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);
更多信息请参见 hexbin
方法和 matplotlib hexbin 文档。
饼图#
你可以使用 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));
你可以使用 labels
和 colors
关键字来指定每个楔形的标签和颜色。
警告
大多数 pandas 图表使用 label
和 color
参数(注意这些词没有“s”)。为了与 matplotlib.pyplot.pie()
保持一致,你必须使用 labels
和 colors
。
如果你想隐藏楔形标签,请指定 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 饼图文档。
绘图时处理缺失数据#
pandas 在绘制包含缺失数据的 DataFrames
或 Series
时,会采取务实的态度。缺失值会根据绘图类型被删除、忽略或填充。
绘图类型 |
NaN 处理 |
---|---|
线 |
在NaN处留空 |
线 (堆叠) |
填充0’s |
Bar |
填充0’s |
Scatter |
删除 NaN |
直方图 |
删除 NaN(按列) |
Box |
删除 NaN(按列) |
区域 |
填充0’s |
KDE |
删除 NaN(按列) |
Hexbin |
删除 NaN |
Pie |
填充0’s |
如果这些默认值不是你想要的,或者如果你想明确如何处理缺失值,请在绘图前考虑使用 fillna()
或 dropna()
。
绘图工具#
这些函数可以从 pandas.plotting
导入,并接受一个 Series
或 DataFrame
作为参数。
散点矩阵图#
你可以使用 pandas.plotting
中的 scatter_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");
密度图#
你可以使用 Series.plot.kde()
和 DataFrame.plot.kde()
方法创建密度图。
In [95]: ser = pd.Series(np.random.randn(1000))
In [96]: ser.plot.kde();
Andrews 曲线#
Andrews 曲线允许将多元数据绘制为大量曲线,这些曲线是使用样本的属性作为傅里叶级数的系数创建的,更多信息请参见 Wikipedia 条目。通过对这些曲线进行不同颜色编码,可以可视化数据聚类。属于同一类样本的曲线通常会更接近,并形成更大的结构。
注意:“Iris”数据集可在此处获取 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");
平行坐标#
平行坐标是一种用于绘制多元数据的绘图技术,参见 Wikipedia 条目 以获取介绍。平行坐标允许人们直观地看到数据中的集群并估计其他统计数据。使用平行坐标,点被表示为连接的线段。每一垂直线代表一个属性。一组连接的线段代表一个数据点。趋于聚集的点将显得更接近。
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
参数,当 lag=1
时,图基本上是 data[:-1]
与 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);
自相关图#
自相关图常用于检查时间序列中的随机性。这是通过计算不同时间滞后的数据值的自相关性来完成的。如果时间序列是随机的,那么任何和所有时间滞后分离的自相关性都应该接近零。如果时间序列是非随机的,那么一个或多个自相关性将显著非零。图中显示的水平线对应于95%和99%的置信带。虚线是99%的置信带。更多关于自相关图的信息,请参见 Wikipedia条目。
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 图#
Bootstrap 图用于直观评估统计数据(如均值、中位数、中程数等)的不确定性。从数据集中选择指定大小的随机子集,计算该子集的统计数据,并重复该过程指定次数。生成的图和直方图构成了 bootstrap 图。
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。
注意:“Iris”数据集可在此处获取 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");
图表格式化#
设置绘图样式#
从版本1.5及以上,matplotlib 提供了多种预配置的绘图样式。设置样式可以轻松地使图表具有您想要的总体外观。设置样式就像在创建图表之前调用 matplotlib.style.use(my_plot_style)
一样简单。例如,您可以写 matplotlib.style.use('ggplot')
来使用 ggplot 风格的图表。
你可以在 matplotlib.style.available
看到各种可用的样式名称,并且尝试它们非常简单。
通用绘图样式参数#
大多数绘图方法都有一组控制返回图的布局和格式的关键字参数:
In [122]: plt.figure();
In [123]: ts.plot(style="k--", label="Series");
对于每种绘图类型(例如 line
、bar
、scatter
),任何额外的参数关键字都会传递给相应的 matplotlib 函数(ax.plot()
、ax.bar()
、ax.scatter()
)。这些可以用来控制额外的样式,超出了 pandas 提供的范围。
控制图例#
你可以将 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);
控制标签#
你可以设置 xlabel
和 ylabel
参数来为图表的 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);
另请参见 logx
和 loglog
关键字参数。
在次要 y 轴上绘图#
要在次要 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);
时间序列图的自定义格式化器#
pandas 为时间序列图提供了自定义格式化工具。这些工具改变了日期和时间轴标签的格式。默认情况下,自定义格式化工具仅应用于由 pandas 创建的图表,使用 DataFrame.plot()
或 Series.plot()
。要让它们应用于所有图表,包括那些由 matplotlib 创建的图表,请设置选项 pd.options.plotting.matplotlib.register_converters = True
或使用 pandas.plotting.register_matplotlib_converters()
。
抑制刻度分辨率调整#
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);
如果你有多个需要抑制的图表,可以在 with
语句中使用 pandas.plotting.plot_params
中的 use
方法:
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")
.....:
自动日期刻度调整#
TimedeltaIndex
现在使用原生的 matplotlib 刻度定位器方法,对于刻度标签重叠的图形,调用 matplotlib 的自动日期刻度调整功能非常有用。
更多信息请参见 autofmt_xdate
方法和 matplotlib 文档。
子图#
在 DataFrame
中的每个 Series
可以使用 subplots
关键字在不同的轴上绘制:
In [146]: df.plot(subplots=True, figsize=(6, 6));
使用布局和定位多个轴#
子图的布局可以通过 layout
关键字指定。它可以接受 (行数, 列数)
。layout
关键字也可以在 hist
和 boxplot
中使用。如果输入无效,将引发 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
关键字传递多个轴时,layout
、sharex
和 sharey
关键字不会影响输出。你应该显式传递 sharex=False
和 sharey=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");
带误差线的绘图#
带误差线的绘图在 DataFrame.plot()
和 Series.plot()
中得到支持。
水平和垂直误差棒可以通过 xerr
和 yerr
关键字参数提供给 plot()
。误差值可以使用多种格式指定:
作为一个
DataFrame
或带有与绘图DataFrame
的columns
属性匹配的列名的错误dict
,或与Series
的name
属性匹配。作为
str
指示DataFrame
的哪些列包含误差值。作为原始值(
list
、tuple
或np.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);
不对称误差线也受支持,但在这种情况下必须提供原始误差值。对于一个长度为 N
的 Series
,应提供一个 2xN
数组,指示上下(或左右)误差。对于一个 MxN
的 DataFrame
,不对称误差应在 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);
绘制表格#
现在在 DataFrame.plot()
和 Series.plot()
中支持使用 matplotlib 绘制表格,使用 table
关键字。table
关键字可以接受 bool
、DataFrame
或 Series
。绘制表格的简单方法是指定 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);
此外,你可以传递一个不同的 DataFrame
或 Series
到 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
,它从 DataFrame
或 Series
创建一个表格,并将其添加到 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 表格文档。
颜色映射#
在绘制大量列时可能出现的一个问题是,由于默认颜色的重复,一些系列可能难以区分。为了解决这个问题,DataFrame
绘图支持使用 colormap
参数,该参数接受一个 Matplotlib colormap 或一个与 Matplotlib 注册的 colormap 名称对应的字符串。默认 matplotlib colormaps 的可视化效果可在此处查看 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");
安德鲁斯曲线图:
In [211]: plt.figure();
In [212]: andrews_curves(data, "Name", colormap="winter");
直接使用 Matplotlib 绘图#
在某些情况下,直接使用 matplotlib 准备图表可能仍然是首选或必要的,例如当某种类型的图表或定制尚未被 pandas 支持时。Series
和 DataFrame
对象表现得像数组,因此可以直接传递给 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);
绘图后端#
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等)来生成图表。一些实现了pandas后端的库列在 生态系统页面 上。
开发者指南可以在 https://pandas.pydata.org/docs/dev/development/extending.html#plotting-backends 找到