Matplotlib is hiring a Research Software Engineering Fellow! See discourse for details. Apply by January 3, 2020
本教程介绍一些基本的使用模式和最佳实践,以帮助您开始使用matplotlib。
matplotlib
有一个广泛的代码库,可以令许多新用户望而生畏。然而,大多数matplotlib可以用一个相当简单的概念框架和一些重要的知识点来理解。
绘图需要在一系列级别上进行操作,从最一般的(例如“轮廓此二维数组”)到最具体的(例如“将此屏幕像素涂成红色”)。绘图包的目的是帮助您尽可能容易地可视化数据,并进行所有必要的控制——也就是说,大部分时间使用相对较高级别的命令,并且在需要时仍然能够使用较低级别的命令。
因此,Matplotlib中的所有内容都是按层次组织的。层次结构顶部是matplotlib“状态机环境”,由 matplotlib.pyplot
模块。在这个级别上,简单的函数用于向当前图形中的当前轴添加绘图元素(线、图像、文本等)。
注解
Pyplot的状态机环境的行为与Matlab类似,应该对具有Matlab经验的用户最熟悉。
层次结构中的下一级是面向对象接口的第一级,其中pyplot仅用于创建图形等少数功能,用户显式创建并跟踪图形和轴对象。在这个级别上,用户使用Pyplot创建图形,通过这些图形,可以创建一个或多个轴对象。这些轴对象随后用于大多数打印操作。
对于更多的控制——这对于在GUI应用程序中嵌入Matplotlib图是必不可少的——Pyplot级别可能会完全降低,只剩下一种纯面向对象的方法。
# sphinx_gallery_thumbnail_number = 3
import matplotlib.pyplot as plt
import numpy as np
Figure
¶这个 整体 数字。这个数字记录了所有的孩子 Axes
少量的“特殊”艺术家(头衔、人物传说等),以及 帆布 . (不要太担心画布,它是至关重要的,因为它实际上是一个对象来绘制您的绘图,但作为用户,它或多或少对您是不可见的)。一个数字可以有任何数字 Axes
但要有用,至少要有一个。
创建新图形的最简单方法是使用Pyplot:
fig = plt.figure() # an empty figure with no axes
fig.suptitle('No axes on this figure') # Add a title so we know which it is
fig, ax_lst = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes
Axes
¶这就是你所认为的“绘图”,它是图像中带有数据空间的区域。给定的图形可以包含多个轴,但给定的 Axes
对象只能位于一个 Figure
. 轴包含两个(如果是三维的,则为三个) Axis
对象(注意 Axes 和 Axis )它负责处理数据限制(数据限制也可以通过设置通过 set_xlim()
和 set_ylim()
Axes
方法)。各 Axes
有标题(通过设置 set_title()
)X标签(通过设置 set_xlabel()
)和Y标签集,通过 set_ylabel()
)
这个 Axes
类及其成员函数是使用OO接口的主要入口点。
所有绘图功能 np.array
或 np.ma.masked_array
作为输入。“array like”类,例如 pandas
数据对象和 np.matrix
可能工作,也可能不工作。最好把这些换成 np.array
打印前的对象。
例如,要转换 pandas.DataFrame
::
a = pandas.DataFrame(np.random.rand(4,5), columns = list('abcde'))
a_asndarray = a.values
隐藏一个 np.matrix
::
b = np.matrix([[1,2],[3,4]])
b_asarray = np.asarray(b)
在查看此文档和示例时,您将发现不同的编码样式和使用模式。这些风格是完全有效的,有其利弊。几乎所有的示例都可以转换成另一种样式并获得相同的结果。唯一需要注意的是,避免为自己的代码混合编码样式。
注解
Matplotlib的开发人员必须遵循特定的风格和指南。见 Matplotlib开发者指南 .
在不同的风格中,有两种是官方支持的。因此,这些是使用matplotlib的首选方法。
对于pyplot样式,脚本顶部的导入通常为:
import matplotlib.pyplot as plt
import numpy as np
然后调用np.arange、np.zeros、np.pi、plt.figure、plt.plot、plt.show等。使用pyplot接口创建图形,然后使用其他对象方法:
x = np.arange(0, 10, 0.2)
y = np.sin(x)
fig, ax = plt.subplots()
ax.plot(x, y)
plt.show()
那么,为什么所有额外的类型都是Matlab样式(它依赖于全局状态和平面名称空间)?对于像这个例子这样的简单的事情,唯一的优势是学术性的:更冗长的风格更明确,更清楚地说明事情的来源和发生的事情。对于更复杂的应用程序,这种明确性和清晰性变得越来越有价值,更丰富和更完整的面向对象的接口可能使程序更容易编写和维护。
通常,人们会发现自己一次又一次地绘制相同的图,但是使用不同的数据集,这就需要编写专门的函数来进行绘制。建议的函数签名如下:
def my_plotter(ax, data1, data2, param_dict):
"""
A helper function to make a graph
Parameters
----------
ax : Axes
The axes to draw to
data1 : array
The x data
data2 : array
The y data
param_dict : dict
Dictionary of kwargs to pass to ax.plot
Returns
-------
out : list
list of artists added
"""
out = ax.plot(data1, data2, **param_dict)
return out
# which you would then use as:
data1, data2, data3, data4 = np.random.randn(4, 100)
fig, ax = plt.subplots(1, 1)
my_plotter(ax, data1, data2, {'marker': 'x'})
或者如果你想要两个子图:
fig, (ax1, ax2) = plt.subplots(1, 2)
my_plotter(ax1, data1, data2, {'marker': 'x'})
my_plotter(ax2, data3, data4, {'marker': 'o'})
同样,对于这些简单的例子来说,这种风格似乎是多余的,但是一旦图表变得稍微复杂一些,它就会得到回报。
网站和邮件列表中的很多文档都指的是“后端”,许多新用户对这个术语感到困惑。Matplotlib针对许多不同的用例和输出格式。有些人在python shell中交互地使用matplotlib,当他们输入命令时会弹出绘图窗口。有些人跑 Jupyter 笔记本和绘制内联绘图,以便快速进行数据分析。其他人将matplotlib嵌入到图形用户界面中,比如wxpython或pygtk,以构建丰富的应用程序。有些人在批处理脚本中使用matplotlib从数值模拟中生成PostScript图像,还有一些人运行Web应用服务器来动态地提供图形。
为了支持所有这些用例,matplotlib可以针对不同的输出,这些功能中的每一个都称为后端;“前端”是面向用户的代码,即绘图代码,而“后端”则在幕后完成了所有繁重的工作来生成数字。有两种后端:用户界面后端(用于pygtk、wxpython、tkinter、qt4或macosx;也称为“交互后端”)和硬拷贝后端以生成图像文件(png、svg、pdf、ps;也称为“非交互后端”)。
配置后端有四种方法。如果它们相互冲突,将使用下面列表中最后提到的方法,例如调用 use()
将覆盖您的 matplotlibrc
.
这个 backend
您的 matplotlibrc
文件(见) 使用样式表和RCPARAM自定义Matplotlib ):
backend : WXAgg # use wxpython with antigrain (agg) rendering
设置 MPLBACKEND
环境变量,用于当前shell或单个脚本。在UNIX上::
> export MPLBACKEND=module://my_backend
> python simple_plot.py
> MPLBACKEND="module://my_backend" python simple_plot.py
在窗户上,只有前者是可能的:
> set MPLBACKEND=module://my_backend
> python simple_plot.py
设置此环境变量将重写 backend
参数在 any matplotlibrc
,即使有 matplotlibrc
在当前工作目录中。因此设置 MPLBACKEND
全球范围内,例如 .bashrc
或 .profile
不鼓励,因为这可能导致违反直觉的行为。
如果脚本依赖于特定的后端,则可以使用 use()
功能:
import matplotlib
matplotlib.use('PS') # generate postscript output by default
如果您使用 use()
函数,这必须在导入之前完成 matplotlib.pyplot
. 打电话 use()
导入Pyplot后将不起作用。使用 use()
如果用户要使用不同的后端,则需要更改代码。因此,您应该避免显式地调用 use()
除非绝对必要。
注解
后端名称规范不区分大小写;例如,“gtk3agg”和“gtk3agg”是等效的。
对于matplotlib的典型安装,例如二进制安装程序或Linux发行包,已经设置了一个好的默认后端,允许交互式工作和脚本打印,输出到屏幕和/或文件,因此至少在最初不需要使用上述任何方法。
但是,如果要编写图形用户界面或Web应用程序服务器 (Web应用服务器中的matplotlib 或者需要更好地了解正在发生的事情,继续阅读。为了使图形用户界面的内容更具可定制性,Matplotlib将渲染器的概念(实际绘制的内容)与画布(绘制的位置)分开。用户界面的标准呈现器是 Agg
其中使用 Anti-Grain Geometry 用C++库制作一个栅格(像素)图像的图形。所有用户界面,除了 macosx
可以与agg渲染一起使用,例如, WXAgg
, GTK3Agg
, QT4Agg
, QT5Agg
, TkAgg
. 此外,一些用户界面支持其他渲染引擎。例如,使用GTK+3,还可以选择cairo渲染(后端 GTK3Cairo
)
对于渲染引擎,还可以区分 vector 或 raster 渲染器。矢量图形语言发出“从这一点到这一点画一条线”这样的绘图命令,因此是无比例的,栅格后端生成一个像素表示线,其精度取决于dpi设置。
以下是Matplotlib渲染器的摘要(每个渲染器都有一个同名的备份;这些是 non-interactive backends ,能够写入文件):
渲染器 | 文件类型 | 描述 |
---|---|---|
AGG | png | raster graphics --使用 Anti-Grain Geometry 发动机 |
PS | ps eps | vector graphics —— Postscript 输出 |
vector graphics —— Portable Document Format | ||
SVG | svg | vector graphics —— Scalable Vector Graphics |
Cairo | png ps pdf svg | raster graphics 和 vector graphics --使用 Cairo graphics 类库 |
下面是支持的用户界面和渲染器组合;这些是 交互式后端 ,能够显示到屏幕并使用上表中的适当渲染器写入文件:
后端 | 描述 |
---|---|
QT5AGG | 中的agg渲染 Qt5 画布(需要 PyQt5) . 这个后端可以在ipython中使用 %matplotlib qt5 . |
IPMPUL | 嵌入在jupyter小部件中的agg呈现。(需要IPYMPL)。此后端可以在Jupyter笔记本中启用 %matplotlib ipympl . |
GTK3AGG | 将agg呈现为 GTK 3.x画布(需要 PyGObject, 和 pycairo 或 cairocffi) . 这个后端可以在ipython中使用 %matplotlib gtk3 . |
麦克索克斯 | 在OSX中将agg渲染为可可画布。这个后端可以在ipython中使用 %matplotlib osx . |
TkAgg | 将agg呈现为 Tk 画布(需要 TkInter) . 这个后端可以在ipython中使用 %matplotlib tk . |
恩巴格 | 在Jupyter经典笔记本中嵌入一个交互式图形。此后端可通过以下方式在Jupyter笔记本中启用: %matplotlib notebook . |
WebAgg | 论 show() 将使用交互式图形启动Tornado服务器。 |
GTK3CAIRO | 开罗渲染到 GTK 3.x画布(需要 PyGObject, 和 pycairo 或 cairocffi) . |
QT4AGG | 将agg呈现为 Qt4 画布(需要 PyQt4 或 pyside )这个后端可以在ipython中使用 %matplotlib qt4 . |
WXAgg | 将agg呈现为 wxWidgets 画布(需要 wxPython 4)。这个后端可以在ipython中使用 %matplotlib wx . |
Jupyter小部件生态系统移动太快,无法直接在Matplotlib中支持。安装IPYMPL
pip install ipympl
jupyter nbextension enable --py --sys-prefix ipympl
或
conda install ipympl -c conda-forge
见 jupyter-matplotlib 了解更多详细信息。
GTK3
后端(后端) both GTK3Agg
和 GTK3Cairo
)取决于开罗(pycairo>=1.11.0或cairocfi)。
这个 QT_API
环境变量可以设置为 pyqt
或 pyside
使用 PyQt4
或 PySide
,分别。
因为要使用的绑定的默认值是 PyQt4
, matplotlib
首先尝试导入,如果导入失败,则尝试导入 PySide
.
使用交互式后端(请参见 什么是后端? )允许——但本身并不要求或确保——在屏幕上绘图。是否和何时打印到屏幕,以及在屏幕上绘制绘图后脚本或shell会话是否继续,取决于调用的函数和方法,以及决定Matplotlib是否处于“交互模式”的状态变量。默认布尔值由 matplotlibrc
文件,并且可以像任何其他配置参数一样进行自定义(请参见 使用样式表和RCPARAM自定义Matplotlib )也可以通过设置 matplotlib.interactive()
,其值可以通过 matplotlib.is_interactive()
. 无论是在脚本中还是在shell中,在绘图命令流的中间打开和关闭交互式模式都是很少需要的,并且可能会造成混淆,因此在下面我们将假设所有绘图都是通过打开或关闭交互式模式完成的。
注解
与交互性有关的主要变化,尤其是 show()
在向Matplotlib版本1.0的转换中进行了,并在1.0.1中修复了错误。在这里,我们描述了主交互后端的1.0.1版本的行为,除了 麦克索克斯 .
交互模式也可以通过 matplotlib.pyplot.ion()
,并通过关闭 matplotlib.pyplot.ioff()
.
注解
交互模式在ipython和普通的python shell中使用合适的后端,但它确实可以 not 在空闲的IDE中工作。如果默认后端不支持交互,则可以使用中讨论的任何方法显式激活交互后端。 What is a backend? .
在普通的python提示下,或者在无选项地调用ipython之后,尝试以下操作:
import matplotlib.pyplot as plt
plt.ion()
plt.plot([1.6, 2.7])
假设您运行的是1.0.1或更高版本,并且默认情况下已安装并选择了交互式后端,则应看到绘图,并且终端提示也应处于活动状态;您可以键入其他命令,例如:
plt.title("interactive test")
plt.xlabel("index")
在每一行之后,你会看到图被更新。从1.5版开始,通过其他方式修改绘图 应该 也会自动更新大多数后端的显示。获取对 Axes
实例,并调用该实例的方法:
ax = plt.gca()
ax.plot([3.1, 2.2])
如果你使用某些后端(比如 macosx
或者Matplotlib的旧版本,您可能不会立即看到添加到绘图中的新行。在这种情况下,需要显式调用 draw()
为了更新绘图:
plt.draw()
像前一个示例中那样启动一个新会话,但现在关闭交互式模式:
import matplotlib.pyplot as plt
plt.ioff()
plt.plot([1.6, 2.7])
没有发生任何事情——或者至少没有任何事情显示在屏幕上(除非您正在使用 麦克索克斯 后端,这是异常的)。要使绘图显示,您需要执行以下操作:
plt.show()
现在您看到了绘图,但是您的终端命令行没有响应;该 show()
命令 阻碍 输入附加命令,直到手动终止绘图窗口。
这有什么好处——被迫使用阻塞函数?假设您需要一个将文件内容绘制到屏幕上的脚本。你想看那个情节,然后结束脚本。如果没有诸如show()之类的阻塞命令,脚本将刷新绘图,然后立即结束,在屏幕上什么也不留下。
此外,非交互模式会延迟所有绘图,直到调用show();这比每次脚本中的一行添加新功能时重新绘制绘图更有效。
在版本1.0之前,通常不能在单个脚本中多次调用show()(尽管有时可以摆脱它);对于版本1.0.1及更高版本,取消了此限制,因此可以编写这样的脚本:
这就形成了三个情节,一次一个。也就是说,一旦第一个图关闭,第二个图就会出现。
无论是以交互模式浏览数据还是以编程方式保存大量绘图,渲染性能都可能是管道中的一个痛苦瓶颈。Matplotlib提供了两种方法,可以大大减少渲染时间,但代价是对绘图外观进行细微更改(达到可设置的公差)。可用于减少渲染时间的方法取决于正在创建的绘图类型。
对于具有线段的绘图(例如典型的线图、多边形轮廓等),渲染性能可以由 path.simplify
和 path.simplify_threshold
您的 matplotlibrc
文件(见) 使用样式表和RCPARAM自定义Matplotlib 有关 matplotlibrc
文件)。这个 path.simplify
参数是一个布尔值,指示是否简化线段。这个 path.simplify_threshold
参数控制简化了多少线段;较高的阈值会导致更快的渲染。
下面的脚本将首先显示数据而不进行任何简化,然后通过简化显示相同的数据。试着和他们两个交流:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
# Setup, and create the data to plot
y = np.random.rand(100000)
y[50000:] *= 2
y[np.logspace(1, np.log10(50000), 400).astype(int)] = -1
mpl.rcParams['path.simplify'] = True
mpl.rcParams['path.simplify_threshold'] = 0.0
plt.plot(y)
plt.show()
mpl.rcParams['path.simplify_threshold'