Python 数据分析(PYDA)第三版(四)(1)https://developer.aliyun.com/article/1482383
8.3 重塑和旋转
有许多用于重新排列表格数据的基本操作。这些操作被称为重塑或旋转操作。
使用分层索引进行重塑
分层索引提供了在 DataFrame 中重新排列数据的一致方法。有两个主要操作:
stack
这将从数据中的列旋转或旋转到行。
unstack
这将从行旋转到列。
我将通过一系列示例来说明这些操作。考虑一个具有字符串数组作为行和列索引的小 DataFrame:
In [126]: data = pd.DataFrame(np.arange(6).reshape((2, 3)), .....: index=pd.Index(["Ohio", "Colorado"], name="state"), .....: columns=pd.Index(["one", "two", "three"], .....: name="number")) In [127]: data Out[127]: number one two three state Ohio 0 1 2 Colorado 3 4 5
在这些数据上使用stack
方法将列旋转为行,生成一个 Series:
In [128]: result = data.stack() In [129]: result Out[129]: state number Ohio one 0 two 1 three 2 Colorado one 3 two 4 three 5 dtype: int64
从具有分层索引的 Series 中,您可以使用unstack
将数据重新排列回 DataFrame:
In [130]: result.unstack() Out[130]: number one two three state Ohio 0 1 2 Colorado 3 4 5
默认情况下,最内层级别被取消堆叠(与stack
相同)。您可以通过传递级别编号或名称来取消堆叠不同的级别:
In [131]: result.unstack(level=0) Out[131]: state Ohio Colorado number one 0 3 two 1 4 three 2 5 In [132]: result.unstack(level="state") Out[132]: state Ohio Colorado number one 0 3 two 1 4 three 2 5
如果在每个子组中未找到级别中的所有值,则取消堆叠可能会引入缺失数据:
In [133]: s1 = pd.Series([0, 1, 2, 3], index=["a", "b", "c", "d"], dtype="Int64") In [134]: s2 = pd.Series([4, 5, 6], index=["c", "d", "e"], dtype="Int64") In [135]: data2 = pd.concat([s1, s2], keys=["one", "two"]) In [136]: data2 Out[136]: one a 0 b 1 c 2 d 3 two c 4 d 5 e 6 dtype: Int64
堆叠默认会过滤掉缺失数据,因此该操作更容易反转:
In [137]: data2.unstack() Out[137]: a b c d e one 0 1 2 3 <NA> two <NA> <NA> 4 5 6 In [138]: data2.unstack().stack() Out[138]: one a 0 b 1 c 2 d 3 two c 4 d 5 e 6 dtype: Int64 In [139]: data2.unstack().stack(dropna=False) Out[139]: one a 0 b 1 c 2 d 3 e <NA> two a <NA> b <NA> c 4 d 5 e 6 dtype: Int64
当您在 DataFrame 中取消堆叠时,取消堆叠的级别将成为结果中的最低级别:
In [140]: df = pd.DataFrame({"left": result, "right": result + 5}, .....: columns=pd.Index(["left", "right"], name="side")) In [141]: df Out[141]: side left right state number Ohio one 0 5 two 1 6 three 2 7 Colorado one 3 8 two 4 9 three 5 10 In [142]: df.unstack(level="state") Out[142]: side left right state Ohio Colorado Ohio Colorado number one 0 3 5 8 two 1 4 6 9 three 2 5 7 10
与unstack
一样,调用stack
时,我们可以指定要堆叠的轴的名称:
In [143]: df.unstack(level="state").stack(level="side") Out[143]: state Colorado Ohio number side one left 3 0 right 8 5 two left 4 1 right 9 6 three left 5 2 right 10 7
将“长”格式旋转为“宽”格式
在数据库和 CSV 文件中存储多个时间序列的常见方法有时被称为长或堆叠格式。在此格式中,单个值由表中的一行表示,而不是每行多个值。
让我们加载一些示例数据,并进行少量时间序列整理和其他数据清理:
In [144]: data = pd.read_csv("examples/macrodata.csv") In [145]: data = data.loc[:, ["year", "quarter", "realgdp", "infl", "unemp"]] In [146]: data.head() Out[146]: year quarter realgdp infl unemp 0 1959 1 2710.349 0.00 5.8 1 1959 2 2778.801 2.34 5.1 2 1959 3 2775.488 2.74 5.3 3 1959 4 2785.204 0.27 5.6 4 1960 1 2847.699 2.31 5.2
首先,我使用pandas.PeriodIndex
(表示时间间隔而不是时间点),在 Ch 11: Time Series 中更详细地讨论,将year
和quarter
列组合起来,将索引设置为每个季度末的datetime
值:
In [147]: periods = pd.PeriodIndex(year=data.pop("year"), .....: quarter=data.pop("quarter"), .....: name="date") In [148]: periods Out[148]: PeriodIndex(['1959Q1', '1959Q2', '1959Q3', '1959Q4', '1960Q1', '1960Q2', '1960Q3', '1960Q4', '1961Q1', '1961Q2', ... '2007Q2', '2007Q3', '2007Q4', '2008Q1', '2008Q2', '2008Q3', '2008Q4', '2009Q1', '2009Q2', '2009Q3'], dtype='period[Q-DEC]', name='date', length=203) In [149]: data.index = periods.to_timestamp("D") In [150]: data.head() Out[150]: realgdp infl unemp date 1959-01-01 2710.349 0.00 5.8 1959-04-01 2778.801 2.34 5.1 1959-07-01 2775.488 2.74 5.3 1959-10-01 2785.204 0.27 5.6 1960-01-01 2847.699 2.31 5.2
在这里,我在 DataFrame 上使用了pop
方法,该方法返回一个列,同时从 DataFrame 中删除它。
然后,我选择一部分列,并给columns
索引命名为"item"
:
In [151]: data = data.reindex(columns=["realgdp", "infl", "unemp"]) In [152]: data.columns.name = "item" In [153]: data.head() Out[153]: item realgdp infl unemp date 1959-01-01 2710.349 0.00 5.8 1959-04-01 2778.801 2.34 5.1 1959-07-01 2775.488 2.74 5.3 1959-10-01 2785.204 0.27 5.6 1960-01-01 2847.699 2.31 5.2
最后,我使用stack
重新塑造,使用reset_index
将新的索引级别转换为列,最后给包含数据值的列命名为"value"
:
In [154]: long_data = (data.stack() .....: .reset_index() .....: .rename(columns={0: "value"}))
现在,ldata
看起来像这样:
In [155]: long_data[:10] Out[155]: date item value 0 1959-01-01 realgdp 2710.349 1 1959-01-01 infl 0.000 2 1959-01-01 unemp 5.800 3 1959-04-01 realgdp 2778.801 4 1959-04-01 infl 2.340 5 1959-04-01 unemp 5.100 6 1959-07-01 realgdp 2775.488 7 1959-07-01 infl 2.740 8 1959-07-01 unemp 5.300 9 1959-10-01 realgdp 2785.204
在这种所谓的长格式中,每个时间序列的每一行在表中代表一个单独的观察。
数据经常以这种方式存储在关系型 SQL 数据库中,因为固定的模式(列名和数据类型)允许item
列中的不同值的数量随着数据添加到表中而改变。在前面的例子中,date
和item
通常会成为主键(在关系数据库术语中),提供关系完整性和更容易的连接。在某些情况下,以这种格式处理数据可能更加困难;您可能更喜欢拥有一个 DataFrame,其中包含一个以date
列中的时间戳为索引的每个不同item
值的列。DataFrame 的pivot
方法正好执行这种转换:
In [156]: pivoted = long_data.pivot(index="date", columns="item", .....: values="value") In [157]: pivoted.head() Out[157]: item infl realgdp unemp date 1959-01-01 0.00 2710.349 5.8 1959-04-01 2.34 2778.801 5.1 1959-07-01 2.74 2775.488 5.3 1959-10-01 0.27 2785.204 5.6 1960-01-01 2.31 2847.699 5.2
传递的前两个值分别是要使用的列,作为行和列索引,最后是一个可选的值列,用于填充 DataFrame。假设您有两个值列,希望同时重塑:
In [159]: long_data["value2"] = np.random.standard_normal(len(long_data)) In [160]: long_data[:10] Out[160]: date item value value2 0 1959-01-01 realgdp 2710.349 0.802926 1 1959-01-01 infl 0.000 0.575721 2 1959-01-01 unemp 5.800 1.381918 3 1959-04-01 realgdp 2778.801 0.000992 4 1959-04-01 infl 2.340 -0.143492 5 1959-04-01 unemp 5.100 -0.206282 6 1959-07-01 realgdp 2775.488 -0.222392 7 1959-07-01 infl 2.740 -1.682403 8 1959-07-01 unemp 5.300 1.811659 9 1959-10-01 realgdp 2785.204 -0.351305
通过省略最后一个参数,您可以获得一个具有分层列的 DataFrame:
In [161]: pivoted = long_data.pivot(index="date", columns="item") In [162]: pivoted.head() Out[162]: value value2 item infl realgdp unemp infl realgdp unemp date 1959-01-01 0.00 2710.349 5.8 0.575721 0.802926 1.381918 1959-04-01 2.34 2778.801 5.1 -0.143492 0.000992 -0.206282 1959-07-01 2.74 2775.488 5.3 -1.682403 -0.222392 1.811659 1959-10-01 0.27 2785.204 5.6 0.128317 -0.351305 -1.313554 1960-01-01 2.31 2847.699 5.2 -0.615939 0.498327 0.174072 In [163]: pivoted["value"].head() Out[163]: item infl realgdp unemp date 1959-01-01 0.00 2710.349 5.8 1959-04-01 2.34 2778.801 5.1 1959-07-01 2.74 2775.488 5.3 1959-10-01 0.27 2785.204 5.6 1960-01-01 2.31 2847.699 5.2
请注意,pivot
等同于使用set_index
创建一个分层索引,然后调用unstack
:
In [164]: unstacked = long_data.set_index(["date", "item"]).unstack(level="item") In [165]: unstacked.head() Out[165]: value value2 item infl realgdp unemp infl realgdp unemp date 1959-01-01 0.00 2710.349 5.8 0.575721 0.802926 1.381918 1959-04-01 2.34 2778.801 5.1 -0.143492 0.000992 -0.206282 1959-07-01 2.74 2775.488 5.3 -1.682403 -0.222392 1.811659 1959-10-01 0.27 2785.204 5.6 0.128317 -0.351305 -1.313554 1960-01-01 2.31 2847.699 5.2 -0.615939 0.498327 0.174072
从“宽”格式到“长”格式的旋转
DataFrame 的pivot
的逆操作是pandas.melt
。与在新的 DataFrame 中将一个列转换为多个不同,它将多个列合并为一个,生成一个比输入更长的 DataFrame。让我们看一个例子:
In [167]: df = pd.DataFrame({"key": ["foo", "bar", "baz"], .....: "A": [1, 2, 3], .....: "B": [4, 5, 6], .....: "C": [7, 8, 9]}) In [168]: df Out[168]: key A B C 0 foo 1 4 7 1 bar 2 5 8 2 baz 3 6 9
"key"
列可以是一个组指示器,其他列是数据值。在使用pandas.melt
时,我们必须指示哪些列(如果有的话)是组指示器。让我们在这里只使用"key"
作为唯一的组指示器:
In [169]: melted = pd.melt(df, id_vars="key") In [170]: melted Out[170]: key variable value 0 foo A 1 1 bar A 2 2 baz A 3 3 foo B 4 4 bar B 5 5 baz B 6 6 foo C 7 7 bar C 8 8 baz C 9
使用pivot
,我们可以重新塑造回原始布局:
In [171]: reshaped = melted.pivot(index="key", columns="variable", .....: values="value") In [172]: reshaped Out[172]: variable A B C key bar 2 5 8 baz 3 6 9 foo 1 4 7
由于pivot
的结果从用作行标签的列创建索引,我们可能希望使用reset_index
将数据移回到列中:
In [173]: reshaped.reset_index() Out[173]: variable key A B C 0 bar 2 5 8 1 baz 3 6 9 2 foo 1 4 7
您还可以指定要用作“值”列的列的子集:
In [174]: pd.melt(df, id_vars="key", value_vars=["A", "B"]) Out[174]: key variable value 0 foo A 1 1 bar A 2 2 baz A 3 3 foo B 4 4 bar B 5 5 baz B 6
pandas.melt
也可以在没有任何组标识符的情况下使用:
In [175]: pd.melt(df, value_vars=["A", "B", "C"]) Out[175]: variable value 0 A 1 1 A 2 2 A 3 3 B 4 4 B 5 5 B 6 6 C 7 7 C 8 8 C 9 In [176]: pd.melt(df, value_vars=["key", "A", "B"]) Out[176]: variable value 0 key foo 1 key bar 2 key baz 3 A 1 4 A 2 5 A 3 6 B 4 7 B 5 8 B 6
8.4 结论
现在您已经掌握了一些关于 pandas 的基础知识,用于数据导入、清理和重新组织,我们准备继续使用 matplotlib 进行数据可视化。当我们讨论更高级的分析时,我们将回到书中的其他领域来探索 pandas 的更多功能。
九、绘图和可视化
原文:
wesmckinney.com/book/plotting-and-visualization
译者:飞龙
此开放访问网络版本的《Python 数据分析第三版》现已作为印刷版和数字版的伴侣提供。如果您发现任何勘误,请在此处报告。请注意,由 Quarto 生成的本站点的某些方面与 O’Reilly 的印刷版和电子书版本的格式不同。
如果您发现本书的在线版本有用,请考虑订购纸质版或无 DRM 的电子书以支持作者。本网站的内容不得复制或再生产。代码示例采用 MIT 许可,可在 GitHub 或 Gitee 上找到。
制作信息丰富的可视化(有时称为*图)是数据分析中最重要的任务之一。它可能是探索过程的一部分,例如,帮助识别异常值或所需的数据转换,或者作为生成模型想法的一种方式。对于其他人,构建用于网络的交互式可视化可能是最终目标。Python 有许多附加库用于制作静态或动态可视化,但我主要关注matplotlib和构建在其之上的库。
matplotlib 是一个桌面绘图包,旨在创建适合出版的图形和图表。该项目由 John Hunter 于 2002 年发起,旨在在 Python 中实现类似 MATLAB 的绘图界面。matplotlib 和 IPython 社区合作简化了从 IPython shell(现在是 Jupyter 笔记本)进行交互式绘图。matplotlib 支持所有操作系统上的各种 GUI 后端,并且可以将可视化导出为所有常见的矢量和光栅图形格式(PDF、SVG、JPG、PNG、BMP、GIF 等)。除了一些图表外,本书中几乎所有的图形都是使用 matplotlib 生成的。
随着时间的推移,matplotlib 衍生出了许多用于数据可视化的附加工具包,这些工具包使用 matplotlib 进行底层绘图。其中之一是seaborn,我们将在本章后面探讨。
在本章中跟随代码示例的最简单方法是在 Jupyter 笔记本中输出图形。要设置这个,可以在 Jupyter 笔记本中执行以下语句:
%matplotlib inline
注意
自 2012 年第一版以来,已经创建了许多新的数据可视化库,其中一些(如 Bokeh 和 Altair)利用现代网络技术创建交互式可视化,与 Jupyter 笔记本很好地集成。与在本书中使用多个可视化工具不同,我决定坚持使用 matplotlib 来教授基础知识,特别是因为 pandas 与 matplotlib 有很好的集成。您可以根据本章的原则学习如何使用其他可视化库。
9.1 简要的 matplotlib API 入门
使用 matplotlib 时,我们使用以下导入约定:
In [13]: import matplotlib.pyplot as plt
在 Jupyter 中运行%matplotlib notebook
(或在 IPython 中运行%matplotlib
),我们可以尝试创建一个简单的图。如果一切设置正确,应该会出现一个类似 Simple line plot 的线图:
In [14]: data = np.arange(10) In [15]: data Out[15]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) In [16]: plt.plot(data)
图 9.1:简单线图
虽然像 seaborn 和 pandas 内置绘图函数将处理许多制作图形的琐碎细节,但如果您希望自定义超出提供的函数选项之外的内容,您需要了解一些关于 matplotlib API 的知识。
注意
本书中没有足够的空间来全面介绍 matplotlib 的功能广度和深度。它应该足以教会您如何上手。matplotlib 图库和文档是学习高级功能的最佳资源。
图和子图
matplotlib 中的绘图位于 Figure
对象中。您可以使用 plt.figure
创建一个新的图:
In [17]: fig = plt.figure()
在 IPython 中,如果您首先运行 %matplotlib
来设置 matplotlib 集成,将会出现一个空白绘图窗口,但在 Jupyter 中,直到我们使用更多命令之前,什么都不会显示。
plt.figure
有许多选项;特别是,如果保存到磁盘,figsize
将保证图的特定大小和纵横比。
您不能在空白图中制作绘图。您必须使用 add_subplot
创建一个或多个 subplots
:
In [18]: ax1 = fig.add_subplot(2, 2, 1)
这意味着图应该是 2 × 2(因此总共最多四个绘图),我们选择了四个子图中的第一个(从 1 编号)。如果您创建下两个子图,您将得到一个看起来像 一个空的 matplotlib 图,带有三个子图 的可视化:
In [19]: ax2 = fig.add_subplot(2, 2, 2) In [20]: ax3 = fig.add_subplot(2, 2, 3)
图 9.2:一个空的 matplotlib 图,带有三个子图
提示:
使用 Jupyter 笔记本的一个细微之处是,每次评估单元格后绘图都会重置,因此您必须将所有绘图命令放在一个单独的笔记本单元格中。
在这里,我们在同一个单元格中运行所有这些命令:
fig = plt.figure() ax1 = fig.add_subplot(2, 2, 1) ax2 = fig.add_subplot(2, 2, 2) ax3 = fig.add_subplot(2, 2, 3)
这些绘图轴对象有各种方法,可以创建不同类型的绘图,最好使用轴方法而不是像 plt.plot
这样的顶级绘图函数。例如,我们可以使用 plot
方法制作一条线图(参见单个绘图后的数据可视化):
In [21]: ax3.plot(np.random.standard_normal(50).cumsum(), color="black", ....: linestyle="dashed")
图 9.3:单个绘图后的数据可视化
当您运行此命令时,您可能会注意到类似 的输出。matplotlib 返回引用刚刚添加的绘图子组件的对象。大多数情况下,您可以安全地忽略此输出,或者您可以在行末加上分号以抑制输出。
附加选项指示 matplotlib 绘制一条黑色虚线。这里由 fig.add_subplot
返回的对象是 AxesSubplot
对象,您可以通过调用每个实例方法直接在其他空子图上绘制(参见添加额外绘图后的数据可视化):
In [22]: ax1.hist(np.random.standard_normal(100), bins=20, color="black", alpha=0 .3); In [23]: ax2.scatter(np.arange(30), np.arange(30) + 3 * np.random.standard_normal (30));
图 9.4:添加额外绘图后的数据可视化
alpha=0.3
样式选项设置了叠加绘图的透明度。
您可以在 matplotlib 文档 中找到绘图类型的全面目录。
为了更方便地创建子图网格,matplotlib 包括一个 plt.subplots
方法,它创建一个新图并返回一个包含创建的子图对象的 NumPy 数组:
In [25]: fig, axes = plt.subplots(2, 3) In [26]: axes Out[26]: array([[<Axes: >, <Axes: >, <Axes: >], [<Axes: >, <Axes: >, <Axes: >]], dtype=object)
然后,axes
数组可以像二维数组一样索引;例如,axes[0, 1]
指的是顶部行中心的子图。您还可以使用 sharex
和 sharey
指示子图应具有相同的 x 或 y 轴。当您在相同比例上比较数据时,这可能很有用;否则,matplotlib 会独立自动缩放绘图限制。有关此方法的更多信息,请参见 表 9.1。
表 9.1:matplotlib.pyplot.subplots
选项
参数 | 描述 |
nrows |
子图的行数 |
ncols |
子图的列数 |
sharex |
所有子图应使用相同的 x 轴刻度(调整 xlim 将影响所有子图) |
sharey |
所有子图应使用相同的 y 轴刻度(调整 ylim 将影响所有子图) |
subplot_kw |
传递给 add_subplot 调用的关键字字典,用于创建每个子图 |
**fig_kw |
创建图时使用subplots 的附加关键字,例如plt.subplots(2, 2, figsize=(8, 6)) |
调整子图周围的间距
默认情况下,matplotlib 在子图周围留有一定量的填充和子图之间的间距。这些间距都是相对于绘图的高度和宽度指定的,因此如果您通过编程或使用 GUI 窗口手动调整绘图大小,绘图将动态调整自身。您可以使用Figure
对象上的subplots_adjust
方法更改间距:
subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=None, hspace=None)
wspace
和hspace
控制子图之间使用的百分比图宽度和图高度的间距。这里是一个您可以在 Jupyter 中执行的小例子,我将间距缩小到零(参见没有子图间距的数据可视化):
fig, axes = plt.subplots(2, 2, sharex=True, sharey=True) for i in range(2): for j in range(2): axes[i, j].hist(np.random.standard_normal(500), bins=50, color="black", alpha=0.5) fig.subplots_adjust(wspace=0, hspace=0)
图 9.5:没有子图间距的数据可视化
您可能会注意到轴标签重叠。matplotlib 不会检查标签是否重叠,因此在这种情况下,您需要通过指定显式刻度位置和刻度标签自行修复标签(我们将在后面的部分刻度、标签和图例中看到如何做到这一点)。
颜色、标记和线型
matplotlib 的线plot
函数接受 x 和 y 坐标数组以及可选的颜色样式选项。例如,要用绿色虚线绘制x
与y
,您可以执行:
ax.plot(x, y, linestyle="--", color="green")
提供了许多常用颜色的颜色名称,但您可以通过指定其十六进制代码(例如,"#CECECE"
)来使用光谱上的任何颜色。您可以查看plt.plot
的文档字符串以查看一些支持的线型。在线文档中提供了更全面的参考资料。
线图还可以具有标记来突出实际数据点。由于 matplotlib 的plot
函数创建连续线图,插值点之间的插值,有时可能不清楚点位于何处。标记可以作为附加样式选项提供(参见带有标记的线图):
In [31]: ax = fig.add_subplot() In [32]: ax.plot(np.random.standard_normal(30).cumsum(), color="black", ....: linestyle="dashed", marker="o");
图 9.6:带有标记的线图
对于线图,您会注意到默认情况下后续点是线性插值的。这可以通过drawstyle
选项进行更改(参见带有不同 drawstyle 选项的线图):
In [34]: fig = plt.figure() In [35]: ax = fig.add_subplot() In [36]: data = np.random.standard_normal(30).cumsum() In [37]: ax.plot(data, color="black", linestyle="dashed", label="Default"); In [38]: ax.plot(data, color="black", linestyle="dashed", ....: drawstyle="steps-post", label="steps-post"); In [39]: ax.legend()
图 9.7:带有不同 drawstyle 选项的线图
在这里,由于我们将label
参数传递给plot
,我们能够使用ax.legend
创建一个图例,以标识每条线。我在刻度、标签和图例中更多地讨论图例。
注意
无论您在绘制数据时是否传递了label
选项,都必须调用ax.legend
来创建图例。
刻度、标签和图例
大多数类型的绘图装饰都可以通过 matplotlib 轴对象上的方法访问。这包括xlim
、xticks
和xticklabels
等方法。它们分别控制绘图范围、刻度位置和刻度标签。它们可以以两种方式使用:
- 不带参数调用返回当前参数值(例如,
ax.xlim()
返回当前 x 轴绘图范围) - 带参数调用设置参数值(例如,
ax.xlim([0, 10])
将 x 轴范围设置为 0 到 10)
所有这些方法都作用于活动或最近创建的AxesSubplot
。每个对应于 subplot 对象本身的两种方法;在xlim
的情况下,这些方法是ax.get_xlim
和ax.set_xlim
。
设置标题、轴标签、刻度和刻度标签
为了说明如何自定义坐标轴,我将创建一个简单的图和一个随机漫步的绘图(参见用于说明 xticks 的简单绘图(带有默认标签)):
In [40]: fig, ax = plt.subplots() In [41]: ax.plot(np.random.standard_normal(1000).cumsum());
图 9.8:用于说明 xticks 的简单图表(带有默认标签)
要更改 x 轴刻度,最简单的方法是使用set_xticks
和set_xticklabels
。前者指示 matplotlib 在数据范围内放置刻度的位置;默认情况下,这些位置也将是标签。但是我们可以使用set_xticklabels
设置任何其他值作为标签:
In [42]: ticks = ax.set_xticks([0, 250, 500, 750, 1000]) In [43]: labels = ax.set_xticklabels(["one", "two", "three", "four", "five"], ....: rotation=30, fontsize=8)
rotation
选项将 x 轴刻度标签设置为 30 度旋转。最后,set_xlabel
为 x 轴命名,set_title
为子图标题(请参见用于说明自定义 xticks 的简单图表以查看生成的图):
In [44]: ax.set_xlabel("Stages") Out[44]: Text(0.5, 6.666666666666652, 'Stages') In [45]: ax.set_title("My first matplotlib plot")
图 9.9:用于说明自定义 xticks 的简单图表
修改 y 轴的过程与此示例中的x
替换为y
相同。axes 类有一个set
方法,允许批量设置绘图属性。从前面的示例中,我们也可以这样写:
ax.set(title="My first matplotlib plot", xlabel="Stages")
添加图例
图例是识别图表元素的另一个关键元素。有几种方法可以添加图例。最简单的方法是在添加每个图表元素时传递label
参数:
In [46]: fig, ax = plt.subplots() In [47]: ax.plot(np.random.randn(1000).cumsum(), color="black", label="one"); In [48]: ax.plot(np.random.randn(1000).cumsum(), color="black", linestyle="dashed ", ....: label="two"); In [49]: ax.plot(np.random.randn(1000).cumsum(), color="black", linestyle="dotted ", ....: label="three");
一旦您完成了这一步,您可以调用ax.legend()
来自动创建图例。生成的图表在带有三条线和图例的简单图表中:
In [50]: ax.legend()
图 9.10:带有三条线和图例的简单图表
legend
方法有几个其他选项可用于位置loc
参数。有关更多信息,请参阅文档字符串(使用ax.legend?
)。
loc
图例选项告诉 matplotlib 在哪里放置图例。默认值是"best"
,它会尝试选择一个最不起眼的位置。要从图例中排除一个或多个元素,请不传递标签或传递label="_nolegend_"
。
Python 数据分析(PYDA)第三版(四)(3)https://developer.aliyun.com/article/1482385