Python 绘图包 Matplotlib Introductory(开场)

这些教程涵盖了使用 Matplotlib 创建可视化的基础知识,以及有效使用包的一些最佳实践。

可以简单的绘制出直方图,功率图,条形图,误差图,散点图等。

https://matplotlib.org/tutorials/introductory/sample_plots.html  示例图库
https://matplotlib.org/gallery/index.html 缩略图库

Matplotlib 有大量的代码库,可能会让许多新用户却步,然而 Matplotlib 的大部分内容只需要一个相当简单的概念框架和一些重要的知识点就可以理解。

绘图需要在一定范围的层次上进行操作,从最一般的层次(contour this 2-D array )到最具体的层次(color this screen pixel red )。绘图包的目的是通过所有必要的控制。即:大部分时间使用相对高级的命令,并且在需要时仍然能使用低级命令—帮助尽可能容易地完成可视化数据。

因此 Matplotlib 中的所有内容都被组织在一个层次结构中,位于层次结构顶部的是 Matplotlib “状态机环境”,由 Matplotlib.pyplot 模块提供。在这个级别上使用简单的函数向当前图形的当前轴添加绘图元素(线条、图像、文本等)。

Pyplot 的状态机环境的行为类似于 MATLAB,对于具有 MATLAB 经验的用户来说应该是最熟悉的。

层次结构的下一个级别是面向对象接口的第一个级别,其中 pyplot 仅用于图形创建等少数函数,用户显示创建并跟踪图形和轴对象。在这个级别上用户使用 pyplot 创建图形,并通过这些图形创建一个或多个轴对象,然后这些轴对象用于大多数绘图操作。

Parts of a Figure(图中的部件):

Figure(图):
完整的一个图。该图保留追踪到的所有子 轴域 、一些 Matplotlib 中特有的 Artist(艺术家对象。如:标题,角色说明等)和 canvas 。(不要过于担心 canvas ,这一点非常重要,虽然实际上是这个对象绘制出了你的图,但是作为用户来说或多或少是不可见的)。一个图形可以有任意数量的 轴域 ,但为了有用,至少应该有一个 轴域 。

创建一个新图形最简单的方法是用 pyplot:

import matplotlib.pyplot as plt;

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

plt.show()

Axes(轴域):
所谓的“图”,它的区域是图像和数据的 作用域 。一个给定的图形可以包含多个轴域,但是一个给定的轴域对象只能在一个图中。轴域包含两个(或三个 3D 情况下)轴线对象(注意:Axes(轴域)金额 Axis(轴线)之间的区别),它们(指轴域)负责数据范围(数据范围也可以通过 set_xlim() 和 set_ylim() 轴域方法进行控制)。每个轴域都有一个标题(通过 set_title() 设置)、一个 x-label (通过 set_xlabel() 设置)和 y-label 通过 set_ylabel() 设置。Axes 类及其成员函数是使用 OO 接口的主要接口点。

Axis(轴线):
它们类似 number-line-like 对象。负责设置图形限制并生成刻度(轴线上的标记)和ticklael(刻度标签)。刻度的位置由 Locator 对象确定,刻度标签的线的格式由 Formatter 对象设置。正确的 Locator 和 Formatter 程序组合可以很好地控制刻度位置和标签。

Artist(艺术家):
基本上,在图形上看到的所有东西都是艺术家(Artistd 对象)(甚至包括 Figure,Axes,Axis 对象等)。这包括 Text(文本)对象,Line2D 对象, collection(集合) 对象,Patch(修补)对象等等(你懂的)。当图形绘制时,所有的 Artist(艺术家)被画到 Canvas(画布)上。大多数 Artist(艺术家)都绑定在一个 Axes(轴域)对象上,这样的 Artist(艺术家)不能被多个 Axes(轴域)对象共享,也不能从一个 Axes(轴域)对象移动到另一个 Axes(轴域)对象上。

plotting (绘图)函数所支持的数据类型:
所有 plotting 函数都支持 np.array 或 np.ma.masked_array 数据。array-like 形式的对象和
pandas 数据类有可能支持。最好在图像绘制前将数据对象转换为 np.array 对象。

Matplotlib、pyplot 和 pylab 之间的关系:
Matplotlib 是整个包;Matplotlib.pyplot 是 Matplotlib 中的一个模块;pylab 是与 Matplotlib 一起安装的模块。
Pyplot 为底层 绘图库对象 提供 state-machine 接口。state-machine 会自动和以用户无感的方式创建 Figures(图)对象 和 axes (轴域),以实现所需的绘图操作。例如:

import matplotlib.pyplot as plt;
import numpy as np;

x = np.linspace(0, 2, 100);

plt.plot(x, x,    label = 'linear');
plt.plot(x, x**2, label = 'quadratic');
plt.plot(x, x**3, label = 'cubic');

plt.xlabel('X 标注');
plt.ylabel('Y 标注');

plt.title('标题');

plt.legend();

plt.show();

对 plt.plot() 的第一个调用将自动创建 Figure 和 Axes 对象,以实现所需的绘图。对 plt.plot() 后续的调用会重复使用当前 Axes 对象,并每次添加一行。设置 title 标题、legend 图例等,都会使用当前 Axes 对象,设置相应的 Artist(艺术家)。

Pylab 是一个便捷的模块,它在一个命名空间中被批量导入 Matplotlib.pyplot(用于绘图)和 Numpy(用于数学和数组)。Pylab 是不推荐使用的,并且由于命名空间污染强烈禁止使用它。请使用 pyplot 替代。

对于 non-interactive(非交互式)绘图,建议使用 pyplot 创建图形,然后使用 OO 接口进行绘图。

Coding Styles (编码风格)
在查看此文档和示例时,您将发现不同的编码风格和使用模式。这些风格是完全有效的,并有它们的优点和缺点。几乎所有的例子都可以转换成另一种风格,并得到相同的结果。唯一需要注意的是要避免为自己的代码混合编码风格。

注意
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 接口创建图形,然后使用 object 方法创建其余的图形:

x = np.arange(0, 10, 0.2)
y = np.sin(x)
fig, ax = plt.subplots() 
ax.plot(x, y)
plt.show()

../../_images/sphx_glr_usage_004.png

那么,在例子中为什么不使用 Matlab 风格(它依赖于全局变量和浅的命名空间)而使用另外的方式?对于像这个例子非常简单,仅用在学术(学习)上;用复杂的风格编程,会更清楚的知道程序执行的来龙去脉和发生了什么。对复杂程序来说,这种明确性和清晰性会越来越重要,更丰富和更完整的面向对象接口可能会使程序更容易编写和维护。

很多情况下,会发现自己一遍又一遍地绘制相同的图表,但使用的数据集不同,这导致需要编写专门的函数来绘制图表。 函数如下:

import matplotlib.pyplot as plt;
import numpy as np;

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'})
plt.show()

如果想同时生成两个图:

当然,对于这个例子来说,这样的编程风格麻烦了,但是一旦图表变得稍微复杂一些,风格说带来的回报就体现出来了。

Backends(后端)

什么是后端?
网站和邮件列表中的许多文档都提到了“Backends(后端)”,许多新用户对这个术语感到困惑。Matplotlib 针对许多不同的案例和输出格式。有些从 python shell 交互式地使用 Matplotlib 当输入命令时,会弹出绘图窗口。有些运行 Jupyter 笔记本并绘制内联图以便快速进行数据分析。还有些将 Matplotlib 嵌入到图形界面中,比如 wxpython 或 pygtk,以构建富应用程序。也可以批处理脚本中使用 Matplotlib 从数据模拟中生成 postscript 图像,更可以运行 web 应用服务器来动态提供图形。

为了支持所有案例,Matplotlib 可以针对不同的输出,这些功能中的每一个都称为后端(也就是 Matplotlib 开发者的代码),反之“前端”是面向用户的代码,即:绘图代码,而“后端”完成所有在幕后制作图形的工作。有两种类型的后端:用户界面后端(用于 pygtk、wxpython、tkinter、qt4 或 macosx;也称“交互式后端”)和用于生成图像文件的硬拷贝后端(PNG、SVG、PDF、PS;也称为“非交互式后端”)。

有四种配置后端的方法。如果它们彼此冲突,可以使用下面列表中最后提到的方法,例如调用 use() 将覆盖 Matplotlibrc 中的配置。

backend : WXAgg   # use wxpython with antigrain (agg) rendering 
  • 为当前 shell 或单个脚本设置 MPLBACKEND 环境变量。 在 Unix 上:
export MPLBACKEND=module://my_backend 
python simple_plot.py 
MPLBACKEND="module://my_backend" python simple_plot.py 

在 Windows 上,只有样例可以:

set MPLBACKEND=module://my_backend
python simple_plot.py

设置这个环境变量将覆盖任何 Matplotlibrc 中的后端参数,即使当前工作目录中有 Matplotlibrc。因此在全局设置 MPLBACKEND,例如在 .bashrc 和 .profile,可能会导致与预期相反的结果,所以不推荐使用。

  • 如果脚本依赖于特定的后端,可以使用 use() 函数:
import matplotlib matplotlib.use('PS')
# generate postscript output by default

如果使用 use() 函数,则必须在导入 matplotlib.pyplot 之前完成。在引入 pyplot 之后调用 use() 将不起作用。如果用户希望使用不同的后端,那么使用 use() 将需要对代码进行更改。所以除非绝对必要,因此应该避免显示调用 use()。

注意:
后端名称规范不区分大小写; 例如,"GTK3Agg"和"gtk3agg"是等效的。

 对于典型的 Matplotlib 安装(例如:从二进制安装程序 或 Linux 发行包)。安装后一个可以使用的默认后台已经设置好了,允许交互式工作 和 从脚本文件执行的绘图操作,将输出到屏幕、文件,因此至少在初始阶段不需要使用上面给出的配置后端方法。

但是,如果想编写图形用户界面(GUI)或 Web 应用服务器(Web 应用服务器中的 Matplotlib),或者需要更好地理解程序作了什么 或 正在发生的事情。为了使 图形用户界面 更易于定制,Matplotlib 将呈现程序的概念(实际执行绘图的程序)与画布(绘图的位置)分离开来。用户图形界面的规范渲染器是 Agg,它使用  Anti-Grain Geometry C++库 生成图形的像素(光栅)图像。除了 MacOSX 之外的所有用户界面都可以用于 Agg 渲染,例如:WXAgg,GTK3Agg,QT4Agg,QT5Agg,TkAgg。此外,一些用户界面支持其它渲染引擎。例如:使用 GTK+3,还可以选择 Cairo 图(后端 GTK3Cairo)。

对于渲染引擎,还可以区分 矢量渲染器 和 像素(光栅)渲染器。矢量图形语言发出绘图命令,比如“画一条点到点的直线”,因此是无标度的,像素(光栅)后端生成线的像素表示,其准确性取决于 DPI(分辨率)设置。

下面是 Matplotlib 渲染器的摘要(每个渲染器都有相同的渲染支持;这些是非交互式后端,可以写入文件):

渲染器文件类型描述
Aggpng

像素图形

高质量像素图形 Anti-Grain Geometry 引擎

PSps、eps

矢量图形  Postscript 输出

PDFpdf、Pdf

矢量图形 PDF 格式

SVGsvg

矢量图形 SVG 可缩放向量图形

Cairopng、ps、pdf、Pdf、svg

像素图形 矢量图形 Cairo 图形

下面是支持的用户界面 和 渲染器组合;这些是交互式后端,能够显示在屏幕上,并使用适当的渲染器从上面的表格写入文件:

后端描述
Qt5Agg

在 Qt5 画布中呈现 Agg(需要 PyQt5)这个后端可以在 IPthon 中激活 Matplotlib qt5

Ipympl

在 Jupyter 小部件中呈现 Agg(需要 IPympl)这个后端可以在 Jupyter 笔记本中启用 Matplotlib ipympl

GTK3Agg

在 GTK3.x 画布中呈现 Agg(需要 PyGObject 及 PyCairo 或 Cairocffi)这个后端可以在 IPthon 中激活 Matplotlib gtk3

MacOSX

在 OSX 的 Cocoa 画布中呈现 Agg。这个后端可以在 IPthon 在激活 Matplotlib osx

TkAgg

在 Tk 的画布中呈现 Agg(需要 TkInter)。这个后端可以在 IPython 中激活 Matplotlib tk

NbAgg

在 Jupyter 笔记本中呈现交互式图形。这个后端可以在 Jupyter 笔记本上通过 Matplotlib notebook

WebAgg

使用 show() 会启动一个 tornado 服务器

GTK3Cairo

在 Cairo 的画布中呈现 GTK 3.x(需要 PyGObject 及 PyCairo 或 Cairocffi

Qt4Agg

在 Qt4 的画布中呈现 Agg(需要 PyQt4 或 Pyside)这个后端可以在 IPython 中用 Matplotlib qt4

WXAgg

在 wxWidgets 的画布中呈现 Agg(需要 wxPython)这个后端可以在 IPython 中用 Matplotlib wx

ipympl

Jupyter widget 生态系统发展得太快,无法直接支持 Matplotlib。需要安装 Ipympl:

pip install ipympl
jupyter nbextension enable --py --sys-prefix ipympl

conda install ipympl -c conda-forge

更多细节请参见 jupyter-matplotlib

Gtk 和 Cairo

Gtk3 后端(包括 GTK3Agg 和 GTK3Cairo)依赖于 Cairo (pycairo 1.11.0或 calochoffi)

如何选择 PyQt4 或 PySide?

可以将 QTapi 环境变量分别设置为 pyqt 或 PySide 来使用 PyQt4 或 PySide。

由于要使用的绑定默认值是 PyQt4,Matplotlib 首先尝试导入它,如果导入失败,则尝试导入 PySide。

什么是交互模式?

使用交互式后端(请参阅什么是后端?)绘制到屏幕上。是否以及何时在屏幕上绘制图形,以及在屏幕上绘制图形后,脚本 或 shell 会话是否继续,取决于所调用的函数和方法,以及确定 Matplotlib 是否处于“交互模式”的状态变量。默认的 布尔值 是由 Matplotlibrc 文件设置的,可以像任何其他配置参数一样进行自定义(参见使用样式表和 rcParams 自定义 Matplotlib)。还可以通过 Matplotlib.interactive() 设置它,并且可以通过 Matplotlib.is_interactive() 查询它的值。在绘图命令流的中间打开和关闭交互模式,无论是在脚本中还是在 shell 中,都很少需要并且可能会引起混淆,因此在下面我们将假设所有绘图都是在打开或关闭交互式模式下完成的。

#注意

#在转换到 Matplotlib 版本 1.0 时,
#对交互性(特别是 show() 的角色和行为)进行了重大更改,
#并在 1.0.1 中修复了 bug。在这里,我们描述了主要交互式后端的版本 1.0.1 行为,
#但 Mac OSX 部分例外。

还可以通过 matplotlib.pyplot.ion() 和 matplotlib.pyplot.ioff() 函数,打开或关闭交互模式。

#注意

#交互模式在 IPython 和 python shell 中使用合适的后端,
#但在 IDLE IDE 中不起作用。如果默认后端不支持交互性,
#交互式后端可以使用在什么是后端中讨论的任何方法显示激活?

交互式例子

从一个普通的 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")

如果真在使用某些后端(如:Mac OSX)或 Matplotlib 的旧版本,则可能无法立即看到添加到的情节中的新行。在这种情况下,需要显示调用 draw() 以更新绘图:

plt.draw()

非交互式示例

像前面的例子一样启动一个新的会话,但是现在关闭交互式:

import matplotlib.pyplot as plt
plt.ioff()
plt.plot([1.6, 2.7])

什么都没有发生或者至少屏幕上什么都没有显示(除非你正在使用 Mac OSX 后端,这是不正常的)。为了让图显示出来,需要执行 show():

plt.show()

现在看到了绘图,但是终端命令行没有响应;show() 命令阻止了其它命令的输入,直到关闭绘图窗口。

使用阻塞函数有什么好处?假设需要一个脚本,将文件的内容绘制到屏幕上。如果没有 show() 之类的阻塞命令,脚本将一闪而过,不会在评估上留下预期的内容。

此外,非交互模式会延迟所有绘图,直到 show() 被调用;不必每个命令都重新绘图。

在版本 1.0 之前,show() 通常不能在一个脚本中调用多次(有时侥幸可以);对于 1.0.1 及以上版本,这个限制被取消,因此可以编写这样的脚本:

import numpy as np
import matplotlib.pyplot as plt

plt.ioff()
for i in range(3):
    plt.plot(np.random.rand(10))
    plt.show()

也就是说有三幅图,一个一个地出现。关闭一个下一个出现。

摘要

在交互模式下,Pyplot 函数将自动绘制到屏幕上。

在交互模式绘图时,如果出了 pyplot 函数之外还是用对象方法调用,则在需要刷新绘图时调用 draw()。

在希望生成一个或多个图形并在结束或生成一组新图形之前显示他们的脚本中使用非交互模式。在这种情况下,使用 show() 显示图形并组织执行,知道手动关闭它们。

工作表现

无论是以交互模式探索数据还是以变成方式保存大量情节,渲染过程会成为性能的瓶颈。Matplotlib 提供了几种方法来大大减少渲染时间,代价是略改变绘图的外观(可设置容差)。可用于减少绘制时间的方法取决于正在创建的绘图类型。

简化线段

对于具有线段的绘图(例如:典型的线段、多边型轮廓等),绘制性能可以由 path.simplify 和 path.simplify Matplotlibrc 文件中的阔值参数控制(有关 Matploglib 文件的更多信息,参见用样式表和 rcParams 指定 Matplotlib)。Simplify 参数是一个 布尔值,指示线段是否被简化。Simplify 阔值参数控制简化多少线段;更高的阔值可以更快的渲染。

下面的脚本首先显示的数据没有任何简化,然后显示相同的数据简化。试着和它们互动:

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'] = 1.0
plt.plot(y)
plt.show()

Matplotlib 当前默认的保守简化阔值为 1/9。如果想更改默认设置以使用不同的值,可以改变 Matplotlibrc 文件。或者,可以为交互式绘图(使用最大简化)创建一种新样式,为提升绘图品质(使用最小简化)创建另一种样式,并根据需要激活他们。有关任何执行这些操作的说明,参见使用样式表和 rcParams 自定义 Matplotlib

简化方法是将线段迭代合并为一个矢量,直到下一个线段与矢量的垂直距离(在显示坐标位置中测量)大于路径。

#注意

#在版本 2.1 中对线段的简化方式进行了修改。
#在 2.1 版本之前,这些参数仍然可以提高渲染时间,
#但是在 2.1 及以上版本中,某些类型数据的渲染时间将大大提高。

简化标识

标记也可以简化,尽管没有简化线段那么健壮。简化标记只适用于 Line2D 对象(通过 Marketvery 属性)。无论在哪里传递 Line2D 结构参数,比如 matplotlib.pyplot.plot() 和 matplotlib.axes.Axes.plot(),都可以使用 Marketvery 参数:

plt.plot(x, y, markevery=10)

Markevery 参数允许二次抽样,或者试图均匀间隔(沿着 X 轴)抽样。更多参见 Markevery Demo

将所画的线分割成跟小的块

如果在使用 Agg 后端,然后可以使用 agg.path.chunksize rc 参数。可以指定块大小,任何大于这个数量的行将被分割成多行,每一行最多只有 agg.path.chunksize 多个顶点。(除非 agg.path.chunksize 为 0,否则不存在分块)对于某些类型的数据,将这些数据组 块化 成合理的大小,从而可以大大减少渲染时间。

下面的脚本将首先显示没有任何块大小限制的数据,然后显示块大小为 10000 的相同数据。当图形很大的时候,最大化图形用户界面,然后与它们进行交互:

import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
mpl.rcParams['path.simplify_threshold'] = 1.0

# 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['agg.path.chunksize'] = 0
plt.plot(y)
plt.show()

mpl.rcParams['agg.path.chunksize'] = 10000
plt.plot(y)
plt.show()

图例组

轴(axes)的默认图例行为试图找到覆盖最少数据点的位置(loc='best')。如果有大量的数据点,这可能计算量非常大。在这种情况下,可以提供一特定的位置。

使用快速样式

快速样式可以用来自动设置简化和分块参数到合理的设置,以加速回值大量的数据。它可以通过简单的运行来使用:

import matplotlib.style as mplstyle
mplstyle.use('fast')

它的重量非常轻,所以它与其它样式可以很好地配合,只是要确保快速风格是最后应用,这样其他风格不会覆盖设置:

mplstyle.use(['dark_background', 'ggplot', 'fast'])

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值