参考书籍:《Python数据科学手册》
许多方法具体配置的完整描述,请参考 Matplotlib库文档。
Matplotlib笔记精选
Matplotlib 是建立在 NumPy 数组基础上的多平台数据可视化程序库,最初被设计用于完善 SciPy 的生态环境。
Matplotlib 最重要的特性之一就是具有良好的操作系统兼容性和图形显示底层接口兼容性。它支持几十种图形显示接口与输出格式,这使得用户无论在哪种操作系统上都可以输出自己想要的图形格式。这种跨平台、面面俱到的特点已经成为Matplotlib 最强大的功能之一。
新版的 Matplotlib 已经可以轻松实现主流的绘图风格。人们不断在 Matplotlib 的基础上开发出新的程序包,实现更加简洁、现代化的API。虽然已经有了封装后的高级工具,但是掌握 Matplotlib 的语法更能让你灵活地控制最终的图形结果。因此,即使新工具的出现说明社区正在逐渐放弃直接使用底层的Matplotlib API 画图的做法,但Matplotlib仍是数据可视化技术中不可或缺的一环。
1.Matplotlib常用技巧
1.1 导入
In[1]: import matplotlib as mpl
import matplotlib.pyplot as plt
# plt 是最常用的接口
1.2 设置绘图样式
使用 plt.style 来选择图形的绘图风格。
In[2]: plt.style.use('classic')
# 这里先选择经典(classic)风格
1.3 如何显示图形
Matplotlib 的最佳实践与你使用的开发环境有关。简单来说,就是有三种开发环境,分别是脚本、IPython shell 和 IPython Notebook。这里仅对IPython Notebook下的操作进行介绍。
补充:
Python Notebook 是一款基于浏览器的交互式数据分析工具,可以将描述性文字、代码、图形、HTML 元素以及更多的媒体形式组合起来,集成到单个可执行的 Notebook文档中。
使用 %matplotlib 命令,可以将图形直接嵌在 IPython Notebook 页面中,有两种展现形式:
%matplotlib notebook # 在 Notebook 中启动交互式图形。
%matplotlib inline # 在 Notebook 中启动静态图形。
这里先选用后者。
在每一个 Notebook 的单元中创建图形就会直接将 PNG 格式图形文件嵌入在单元中。
1.4 将图形保存为文件
Matplotlib 的一个优点是能够将图形保存为各种不同的数据格式。可以用 savefig() 命令将图形保存为文件。
# 如果将图形保存为 PNG 格式
In[5]: fig.savefig('my_figure.png')
# 这样工作文件夹里就有了一个 my_figure.png 文件
# 为了确定,可以用 IPython 的 Image 对象来显示文件内容
In[6]: from IPython.display import Image
Image('my_figure.png')
2.两种画图接口
Matplotlib 有一个容易让人混淆的特性,就是它的两种画图接口:一个是便捷的MATLAB 风格接口,另一个是功能更强大的面向对象接口。
2.1 MATLAB风格接口(plt)
MATLAB 风格的工具位于 pyplot(plt)接口中。
In[9]: plt.figure() # 创建图形
# 创建两个子图中的第一个,设置坐标轴
plt.subplot(2, 1, 1) # (行、列、子图编号)
plt.plot(x, np.sin(x))
# 创建两个子图中的第二个,设置坐标轴
plt.subplot(2, 1, 2)
plt.plot(x, np.cos(x));
这种接口最重要的特性是有状态的(:它会持续跟踪“当前的”图形和坐标轴,所有 plt 命令都可以应用。可以用 plt.gcf()(获取当前图形)和 plt.gca()(获取当前坐标轴)来查看具体信息。
有一个问题,当创建上面的第二个子图时,怎么才能回到第一个子图,并增加新内容呢?虽然用该接口也能实现,但未免过于复杂。
2.2 面向对象接口(ax)
面向对象接口可以适应更复杂的场景,更好地控制你自己的图形。在面向对象接口中,画图函数不再受到当前“活动”图形或坐标轴的限制,而变成了显式的 Figure 和Axes的方 法。
# 同样创造上面的图形
In[10]: # 先创建图形网格
# ax是一个包含两个Axes对象的数组
fig, ax = plt.subplots(2)
# fig,ax = plt.subplots()等价于:fig=plt.figure(), ax=fig.add_subplot(2,3)
# 在每个对象上调用plot()方法
ax[0].plot(x, np.sin(x))
ax[1].plot(x, np.cos(x));
选择哪种绘图风格主要看个人喜好。在画比较复杂的图形时,面向对象方法会更方便。
3.简易线形图
-
基本操作:
In[1]: %matplotlib inline import matplotlib.pyplot as plt plt.style.use('seaborn-whitegrid') import numpy as np
要画 Matplotlib 图形时,都需要先创建一个图形 fig 和一个坐标轴 ax。
# 面向对象 In[2]: fig = plt.figure() ax = plt.axes() # 创建好坐标轴之后,就可以用 ax.plot 画图了 x = np.linspace(0, 10, 1000) # 创建一个1000个元素的数组,这5个数均匀地分配到 0~10 ax.plot(x, np.sin(x));
在 Matplotlib 里面,figure(plt.Figure 类的一个实例)可以被看成是一个能够容纳各种坐标轴、图形、文字和标签的容器。而 axes(plt.Axes 类的一个实例)是一个带有刻度和标签的矩形,最终会包含所有可视化的图形元素。
# 也可以用 pylab 接口画图,这时图形与坐标轴都在底层执行 plt.plot(x, np.sin(x))
如果想在一张图中创建多条线,可以重复调用 plot 命令。
3.1 调整图形:线条的颜色与风格
plt.plot() 函数可以通过相应的参数设置颜色与风格。要修改颜色,就可以使用 color 参数,它支持各种颜色值的字符串。
如果不指定颜色,Matplotlib 就会为多条线自动循环使用一组默认的颜色。
与之类似,你也可以用 linestyle 调整线条的风格。
如果你想用一种更简洁的方式,则可以将 linestyle 和 color 编码组合起来,作为 plt.plot() 函数的一个非关键字参数使用。
3.2 调整图形:坐标轴上下限
虽然 Matplotlib 会自动为你的图形选择最合适的坐标轴上下限,但是有时自定义坐标轴上下限可能会更好。调整坐标轴上下限最基础的方法是 plt.xlim() 和 plt.ylim().
想要让坐标轴逆序显示,那么也可以逆序设置坐标轴刻度值
plt.plot(x, np.sin(x))# 不要漏了这一行代码
plt.xlim(10, 0)
plt.ylim(1.2, -1.2);
还有一个方法是 plt.axis()(不要搞混 axes 和 axis)。通过传入 [xmin,xmax, ymin, ymax] 对应的值,plt.axis() 方法可以让你用一行代码设置 x 和 y 的限值。
plt.axis() 还可以按照图形的内容自动收紧坐标轴,不留空白区域。
plt.plot(x, np.sin(x))# 不要漏了这一行代码
plt.axis('tight');
此外,plt.axis() 还可以实现许多其他更高级的配置。
3.3 设置图形标签
设置图形标签的方法:图形标题、坐标轴标题、简易图例。
还可以通过优化参数来调整这些标签的位置、大小和风格。
在单个坐标轴上显示多条线时,创建图例显示每条线是很有效的方法,可以用plt.legend():
plt.legend() 函数会将每条线的标签与其风格、颜色自动匹配。
注意:
虽然绝大多数的 plt 函数都可以直接转换成 ax 方法(例如 plt.plot() →ax.plot()、plt.legend() → ax.legend() 等),但是并非所有的命令都可以这样用。尤其是用来设置坐标轴上下限、坐标轴标题和图形标题的函数,它们大都稍有差别。
4.简易散点图
4.1 用plt.plot画散点图
In[2]: x = np.linspace(0, 10, 30)
y = np.sin(x)
plt.plot(x, y, 'o', color='black');
函数的第三个参数是一个字符,表示图形符号的类型。与之前用 ‘-’ 和 ‘–’ 设置线条属性类似,对应的图形标记也有缩写形式。
这些代码还可以与线条、颜色代码组合起来,画出一条连接散点的线。
另外,plt.plot 支持许多设置线条和散点属性的参数。
4.2 用plt.scatter画散点图
plt.scatter的功能非常强大,其用法与 plt.plot 函数类似。
In[6]: plt.scatter(x, np.sin(x), marker='o'); # 注意marker关键字标明,与plt.plot不同
plt.scatter 与 plt.plot 的主要差别在于,前者在创建散点图时具有更高的灵活性,可以单独控制每个散点与数据匹配,也可以让每个散点具有不同的属性(大小、表面颜色、边框颜色等)。
4.3 plot与scatter:效率对比
在数据量较小的时候,两者在效率上的差异不大。但是当数据变大到几千个散点时,plt.plot的效率将大大高于 plt.scatter。 这是由于 plt.scatter 会对每个散点进行单独的大小与颜色的渲染,因此渲染器会消耗更多的资源。而在 plt.plot 中,散点基本都彼此复制,因此整个数据集中所有点的颜色、尺寸只需要配置一次。
5.可视化异常处理
在数据可视化的结果中用图形将误差有效地显示出来,就可以提供更充分的信息。
5.1 基本误差线
基本误差线(errorbar):
x = np.linspace(0, 10, 50)
dy = 0.8
y = np.sin(x) + dy * np.random.randn(50)
plt.errorbar(x, y, yerr=dy, fmt='.k');
其中,fmt 是一种控制线条和点的外观的代码格式,语法与 plt.plot 的缩写代码相同。
除了基本选项之外,errorbar 还有许多改善结果的选项。通过这些额外的选项,你可以轻松自定义误差线图形的绘画风格。 常见的比如让误差线的颜色比数据点的颜色浅一点效果会非常好,尤其是在那些比较密集的图形中。
*5.2 连续误差
有时候可能需要显示连续变量的误差。虽然 Matplotlib 没有内置的简便方法可以解决这个问题,但是通过借助其他程序库,再使用 plt.plot 与 plt.fill_between 来解决也可行。
**
7.频次直方图、数据区间划分和分布密度
plt.hist():
# numpy.random.randn(d0,d1,…,dn)
# randn函数返回一个或一组样本,具有标准正态分布。
# dn表格每个维度
# 当没有参数时,返回单个数据
# 标准正态分布又称为u分布,是以0为均值、以1为标准差的正态分布,记为N(0,1)。
In[1]:%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
plt.style.use('seaborn-white')
data = np.random.randn(1000)
In[2]:plt.hist(data)
hist() 有许多用来调整计算过程和显示效果的选项。关于 plt.hist 自定义选项的更多内容都在它的程序文档中。
(在用频次直方图对不同分布特征的样本进行对比时,将 histtype=‘stepfilled’ 与透明性设置参数 alpha 搭配使用的效果非常好。)
-
二维频次直方图与数据区间划分:
-
plt.hist2d:二维频次直方图:
就像将一维数组分为区间创建一维频次直方图一样,我们也可以将二维数组按照二维区间进行切分,来创建二维频次直方图。 plt.hist 函数一样,plt.hist2d 也有许多调整图形与区间划分的配置选项,详细内容都在程序文档中。
-
plt.hexbin:六边形区间划分
二维频次直方图是由与坐标轴正交的方块分割而成的,还有一种常用的方式是用正六边形分割。Matplotlib 提供了 plt.hexbin 满足此类需求,将二维数据集分割成蜂窝状。plt.hexbin 同样也有一大堆有趣的配置选项。
-
核密度估计(KDE):
KDE 方法通过不同的平滑带宽长度(smoothing length)在拟合函数的准确性与平滑性之间作出权衡(无处不在的偏差与方差的取舍问题的一个例子)。
用 Matplotlib 做 KDE 的可视化图的过程比较繁琐。
-
10 多子图
有时候需要从多个角度对数据进行对比。Matplotlib 为此提出了(subplot)的概念:在较大的图形中同时放置一组较小的坐标轴。这些子图可能是画中画、网格图,或者是其他更复杂的布局形式。
10.1 plt.axes:手动创建子图
创建坐标轴最基本的方法就是使用 plt.axes 函数。
前面提到过,这个函数的默认配置是创建一个标准的坐标轴,填满整张图。它还有一个可选参数,由图形坐标系统的四个值构成。这四个值分别表示图形坐标系统的 [bottom, left, width, height](底坐标、左坐标、宽度、高度),数值的取值范围是左下角(原点)为 0,右上角为 1。
ax1 = plt.axes() # 默认坐标轴
ax2 = plt.axes([0.65, 0.65, 0.2, 0.2])
# 第二坐标轴原点位于图形高度 65% 和宽度 65% 的位置
# 第二坐标轴的宽度与高度设置为图形的 20%
面向对象画图接口中类似的命令有 fig.add_axes()。用这个命令创建两个竖直排列的坐标。
In[3]: fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.5, 0.8, 0.4],
xticklabels=[], ylim=(-1.2, 1.2))
ax2 = fig.add_axes([0.1, 0.1, 0.8, 0.4],
ylim=(-1.2, 1.2))
x = np.linspace(0, 10)
ax1.plot(np.sin(x))
ax2.plot(np.cos(x));
# 两个紧挨着的坐标轴(上面的坐标轴没有刻度)
10.2 plt.subplot:简易网格子图
最底层的方法是用 plt.subplot() 在一个网格中创建一个子图。这个命令有三个整型参数——将要创建的网格子图行数、列数和索引值,索引值从 1 开始,从左上角到右下角依次增大。
用面向对象接口的命令 fig.add_subplot() 可以取得同样的效果。
可以用for 快速创建。
(面向对象)通过subplots_adjust 的 hspace 与 wspace 参数设置与图形高度与宽度一致的子图间距, 数值以子图的尺寸为单位(本例中,间距是子图宽度与高度的 40%)。
10.3 plt.subplots:用一行代码创建网格
多了个s。这个函数不是用来创建单个子图的,而是用一行代码创建多个子图,并返回一个包含子图的 NumPy 数组。关键参数是行数与列数,以及可选参数 sharex 与 sharey,通过它们可以设置不同子图之间的关联关系。
10.4 plt.GridSpec:实现更复杂的排列方式
如果想实现不规则的多行多列子图网格,plt.GridSpec() 是最好的工具。plt.GridSpec()对象本身不能直接创建一个图形,它只是 plt.subplot() 命令可以识别的简易接口。
这种类型的分布图十分常见,Seaborn 程序包提供了专门的 API 来实现它们。
11.文字与注释
可以通过 plt.text/ ax.text 命令手动添加注释,它们可以在具体的 x / y 坐标点上放上文字。
ax.text 方法需要一个 x 轴坐标、一个 y 轴坐标、一个字符串和一些可选参数,比如文字的颜色、字号、风格、对齐方式以及其他文字属性。
(如ha=‘right’,即水平对齐方式为向右)
-
坐标变换与文字位置:
默认情况下,上面的文字在各自的坐标系中都是左对齐的。这三个字符串开头的 . 字符基本就是对应的坐标位置。 -
箭头与注释:
plt.annotate():
箭头的风格是通过 arrowprops 字典控制的,里面有许多可用的选项。
13.Matplotlib自定义:配置文件与样式表
14.用Matplotlib画三维图
16.用Seaborn做数据可视化
Matplotlib 的三条主要缺点总结如下:
• Matplotlib 2.0 之前版本的默认配置样式绝对不是用户的最佳选择。之前的默认样式还是仿照 1999 年前后的 MATLAB,却一直在使用。
• Matplotlib 的 API 比较底层。虽然可以实现复杂的统计数据可视化,但是通常都需要写大量的样板代码。
• 由于 Matplotlib 比 Pandas 早十几年,因此它并不是为 Pandas 的DataFrame 设计的。为了实现 Pandas 的 DataFrame 数据的可视化,你必须先提取每个 Series,然后通常还需要将它们合并成适当的格式。如果有一个画图程序库可以智能地使用 DataFrame 的标签画图,那一定会很棒。
这些问题的终结者就是 Seaborn(http://seaborn.pydata.org)。Seaborn 在 Matplotlib 的基础上开发了一套 API(Matplotlib 就是 Seaborn 的底层),为默认的图形样式和颜色设置提供了理智的选择,为常用的统计图形定义了许多简单的高级函数,并与 Pandas DataFrame 的功能有机结合。
# 假设已经导入其他库,设置好基本选项
import seaborn as sns
sns.set() # 可以用Seaborn 的 set() 方法设置样式,再用正常方法即可生成 Seaborn式图形。
16.1.Seaborn图形介绍
Seaborn 的主要思想是用高级命令为统计数据探索和统计模型拟合创建各种图形。
-
频次直方图、KDE和密度图:
除了频次直方图,我们还可以用 KDE 获取变量分布的平滑估计。Seaborn 通过 sns.kdeplot 实现。
distplot 可以让频次直方图与 KDE 结合起来。
如果向 kdeplot 输入的是二维数据集,那么就可以获得一个二维数据可视化图。
用 sns.jointplot 可以同时看到两个变量的联合分布与单变量的独立分布。可以向 jointplot 函数传递一些参数。例如,可以用六边形块代替频次直方图。
-
矩阵图:
数据集载入:
name = sns.load_dataset(“name”)
( name.head() )当你需要对多维数据集进行可视化时,最终都要使用矩阵图(pair plot)。如果想画出所有变量中任意两个变量之间的图形,用矩阵图探索多维数据不同维度间的相关性非常有效。
直接用 sns.pairplot 即可
-
分面频次直方图:
FacetGrid 函数 -
联合分布:
与前面介绍的矩阵图类似,可以用 sns.jointplot 画出不同数据集的联合分布和各数据本身的分布。
联合分布图也可以自动进行 KDE 和回归。
此外Seaborn还支持条形图、因子图等许多类型的图形。