器→工具, 工具软件, 数据, 术→技巧

Matplotlib初级入门教程

钱魏Way · · 890 次浏览
!文章内容如有错误或排版问题,请提交反馈,非常感谢!

Matplotlib简介

MATLAB

MATLAB是Matrix&Laboratory两个词的组合,意为矩阵工厂(矩阵实验室)。是由美国Mathworks公司发布的主要面对科学计算、可视化以及交互式程序设计的高科技计算环境。

它将数值分析、矩阵计算、科学数据可视化以及非线性动态系统的建模和仿真等诸多强大功能集成在一个易于使用的视窗环境中,为科学研究、工程设计以及必须进行有效数值计算的众多科学领域提供了一种全面的解决方案,并在很大程度上摆脱了传统非交互式程序设计语言(如C、Fortran)的编辑模式,代表了当今国际科学计算软件的先进水平。

Matplotlib

Matplotlib是Python中使用最广泛的数据可视化库。Matplotlib最早由John Hunter于2002年启动开发,其目的是为了构建一个Matlab式的绘图函数接口。它利用了Python下的数值计算模块Numeric及Numarray,克隆了许多Matlab中的函数,用以帮助用户轻松地获得高质量的二维图形。

Matplotlib可以绘制多种形式的图形包括普通的线图,直方图,饼图,散点图以及误差线图等;可以比较方便的定制图形的各种属性比如图线的类型,颜色,粗细,字体的大小等;它能够很好地支持一部分TeX排版命令,可以比较美观地显示图形中的数学公式。

Matplotlib掌握起来也很容易,由于Matplotlib使用的大部分函数都与Matlab中对应的函数同名,且各种参数的含义,使用方法也一致,这就使得熟悉Matlab的用户使用起来感到得心应手。对那些不熟悉的Matlab的用户而言,这些函数的意义往往也是一目了然的,因此只要花很少的时间就可以掌握。

多年来,我常常使用MATLAB进行数据分析和可视化。MATLAB擅长绘制漂亮的图形。当我开始处理EEG数据时,我发现我需要编写应用程序来与我的数据交互,并在MATLAB中开发了一个EEG分析应用程序。随着应用程序越来越复杂,需要与数据库,http服务器交互,并操作复杂的数据结构,我开始与MATLAB作为一种编程语言的限制而抗争,并决定迁移到Python。Python作为一种编程语言,弥补了MATLAB的所有缺陷,但我很难找到一个2D绘图包(3DVTK则超过了我的所有需求)。

当我去寻找一个Python绘图包时,我有几个要求:

  • 绘图应该看起来不错-发布质量。对我来说一个重要的要求是文本看起来不错(抗锯齿等)
  • 用于包含TeX文档的Postscript输出
  • 可嵌入图形用户界面用于应用程序开发
  • 代码应该足够容易,我可以理解它,并扩展它
  • 绘图应该很容易

没有找到适合我的包,我做了任何自称Python程序员会做的事情:撸起我的袖子开始自己造。我没有任何真正的计算机图形经验,决定模仿MATLAB的绘图功能,因为MATLAB做得很好。这有额外的优势,许多人有很多MATLAB的经验,因此,他们可以很快开始在python中绘图。从开发人员的角度来看,拥有固定的用户接口(pylab接口)非常有用,因为代码库的内容可以重新设计,而不会影响用户代码。

Matplotlib架构

Matplotlib架构从逻辑上分为三层,位于三个不同的层级上。上层内容可以与下层内容进行通讯,但下层内容不可以与上层内容通讯。三层从上至下依次是:

  • Scripting(脚本层)
  • Artist(表现层)
  • Backend(后端层)

它们之间的访问关系是:Scripting访问Artist,Artist访问Backend

Backend层

Backend为最底层,即matplotlib API层。Backend在mpl.backend_bases类下,其中包含了各种键盘、鼠标的Event类、用以绘制线段、图形的RenderBase类、负责将Figure对象和其输出分离开的FigureCanvasBase类等(只是一个接口,具体不同输出,比如PDF、PNG的定义在backends类中)。即所有派生/输出的方法都放在mpl.backends下,比如Qt5后端为mpl.backends.qt5agg。输出PDF的后端为mpl.backend_pdf,这里的类负责和不同的后端/平台进行交互。这样的设计保证了代码的解耦和设计的统一。

不同的后端提供了不同的API,其在backends类中定义,这一层包含了matplotlib的API,也就是若干类的集合,这些类用来在底层实现各种图形元素。主要包括:

  • FigureCanves:用来表示图形的绘制区域
  • Renderer:用来在FigureCanves上绘制内容的对象
  • Event:用来处理用户输入(键盘、鼠标输入)的对象

Artist层

如果说Backend层做的事情是确立了一个Canvas、Renderer、Event的架构,那么Artist层所做的事情就是告诉程序,在Renderer上画什么东西到Canvas上。这一层不用接触后端,不用关系不同实现方法的差异,只需要告诉Backend层需要draw的内容即可。

所有的元素都是mpl.artist.Artist类的实例/子类。ArtistModule包含大量已经定义的元素,包括Tick刻度、Text文本、Patch复合图形(坐标轴、阴影、圆、箭头、Rectangle等)、Figure图形、Legend标签、Line2D线段、Axis坐标轴、Axes复合坐标轴。artistModule中的元素通过draw方法和backendModule进行交互和信息传递,传递是单向的。

整个架构的中间层,所有用来构成一个图像的各种元素都在这里,比如标题、坐标轴、坐标轴标签、标记等内容都是Artist的实例。并且这些元素构成了一个层级结构。

Artist层拥有许多可视化元素,即标题、轴标签、刻度等元素。Artist分为两类,一类是PrimitiveArtist,一类是CompositeArtist:

  • PrimitiveArtist是包含基本图形的独立元素,例如一个矩形、一个圆或者是一个文本标签
  • CompositeArtist是这些简单元素的组合,比如横坐标、纵坐标、图形等

在处理这一层内容的时候,主要打交道的都是上层的图形结构,需要理解其中每个对象在图形中所代表的含义。下图表示了一个Artist对象的结构。

Artist最上层是Figure层,表示图形概念;Axes在Figure上面,表示轴的作图的内容(即轴对象),每个维度会有一个Axes对象;Axis用来展示Axes上的数值(即刻度与刻度值),刻度的位置用Locator对象管理,刻度的标签的格式用Formatter对象调整。

Scripting层

如果说上一层代表了HTML,那么这一层就代表了JavaScript,你可以将这一层看作带有状态保持的交互界面。比如Python的那个交互解释器一样。mpl.pyplot是这一层的全部入口。

该层包含了一个pyplot接口。这个包提供了经典的Python接口,基于编程的方式操作matplotlib,它有自己的命名空间,需要导入NumPy包。

使用Matplotlib Layers绘制图形

使用Artist Layer绘图

# Step One: We import FigureCanvas from Back-end layer.
from matplotlib.backends.backend_agg import FigureCanvasAgg as FigureCanvas

# Step two: We import FigureArtist
from matplotlib.figure import Figure

# Step 3: We create a Figure object using the constructor
fig = Figure()

import numpy as np
np.random.seed(6)
x = np.random.randn(20000)

# Next we create an AxesArtist object.
ax = fig.add_subplot(111)

# Next we call the Axes method hist() function.
ax.hist(x, 100)

# Finally we assign a title to the plot.
ax.set_title('Artist Layer Histogram')

# And we save it, in this case as a PNG file.
fig.savefig('Matplotlib_histogram.png')

  • ax = fig.add_subplot(111):遵循MATLAB公约。创建一个包含一行、一列的网格,并使用网格中的第一个单元格作为执行对象的位置。
  • ax.hist(x, 100):为每个柱状图条创建一个矩形原始Artist layer对象序列,并将它们添加到Exes Container中。100个意味着产生100个柱状图条。

使用Scripting Layer绘图

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

np.random.seed(6)
X = np.random.randn(20000)

plt.hist(X, 100)
plt.title('Scripting Layer Histogram')
plt.savefig('matplotlib_histogram.jpg')

Artist还是Scripting Layer?

显然,使用Scripting layer (matplotlib.pyplot)相对而言更加易用,轻量,语法也更加简单。虽然Artist layer是专业的开发人员的首选。但是最好两者都掌握。

Matplotlib图像结构

  • Canvas(画板)位于最底层,用户一般接触不到
  • Figure(画布)建立在Canvas之上
  • Axes(绘图区)建立在Figure之上
  • 坐标轴(axis)、图例(legend)等辅助显示层以及图像层都是建立在Axes之上

容器层

容器层主要由Canvas(画布)、Figure(图形,绘图区)、Axes(轴)

  • Canvas(画布)底层的系统层,在绘图的过程中充当画板的角色,即放置Figure(绘图区)的工具
  • Figure是Canvas上方的第一层,也是需要用户来操作的应用层的第一层,在绘图的过程中充当画布的角色。
  • Axes是应用层的第二层,在绘图的过程中相当于画布上的绘图区的角色。
  • Figure:指整个图形(可以通过figure()设置画布的大小和分辨率等)
  • Axes(坐标系):数据的绘图区域
  • Axis(坐标轴):坐标系中的一条轴,包含大小限制、刻度和刻度标签

特点为:

  • 一个figure(画布)可以包含多个axes(坐标系/绘图区),但是一个axes只能属于一个figure。
  • 一个axes(坐标系/绘图区)可以包含多个axis(坐标轴),包含两个即为2d坐标系,3个即为3d坐标系

辅助显示层

辅助显示层为Axes(绘图区)内的除了根据数据绘制出的图像以外的内容,主要包括

  • Axes外观(facecolor)
  • 边框线(spines)
  • 坐标轴(axis)
  • 坐标轴名称(axis label)
  • 坐标轴刻度(tick)
  • 坐标轴刻度标签(tick label)
  • 网格线(grid)
  • 图例(legend)
  • 标题(title)

该层的设置可使图像显示更加直观更加容易被用户理解,但又不会对图像产生实质的影响。

图像层

图像层指Axes内通过

  • plot(折线图)
  • scatter(散点图)
  • bar(柱状图)
  • histogram(直方图)
  • pie(饼图)

使用PYPLOT进行绘图

plt.plot()绘图

快速上手plot()绘图

这种图形绘制方法是完全的通过pyplot解释层进行绘图。当调用plt.plot()方法的时候,如果系统没有检测到存在Figure对象和Axes对象,则会创建一个,如果检测到,则直接使用。创建后选择的后端为默认后端,canvas一般为mpl.backends.backends_xxagg类。

plt.plot(np.random.randn(50).cumsum(), 'r--.')

pyplot.plot可以接受绘制对象和一些类似于命令行的参数,可选颜色、点线状态(水平线、垂直线、星标)等各种形状。plot的参数参见Line2D,可以这样指定:

plot(x, y, color='green', linestyle='dashed', marker='o', markerfacecolor='blue', markersize=12)

pyplot可以直接按照面向过程方式处理,调用plt.axis会对当前Axes中的axis属性进行设置。

import matplotlib.pyplot as plt

plt.plot([1, 2, 3, 4], [2, 21, 23, 11], "r^", [12, 21, 43, 21], "b", [0, 2, 12, 40, 18], "y--") #x轴、y轴和其颜色、类型、第二个y轴和其颜色、类型、第三个y轴和其颜色、类型
plt.title("My First plt Figure")
plt.axis([-1, 5, -10, 50]) #sets the min and max of the x and y axes, with v=[xmin, xmax, ymin, ymax]
plt.show()

子图形、标签、刻度、文本

通过面向过程的方法,我们可以快速进行图像绘制,其中有一些比较重要的方法,比如:

  • subplot(m, n, a)在一个Figure和Axes上绘制多个图形,你可以在任何时候返回这个子图进行修改。
  • subplots_adjust()快速调整图形间距
  • title()设置标题
  • grid()设置网格
  • xlabel()设置x轴标签
  • xticks()设置x轴刻度
  • legend()控制图例显示
  • text()在指定位置放置文本
from matplotlib.ticker import NullFormatter
import numpy as np

#设置x轴和y轴的数据
t = np.arange(0, 5, 0.1)
y1 = np.sin(2 * np.pi * t)
y2 = np.sin(2 * np.pi * t)

#设置整体图形外观
plt.subplots_adjust(top=2, bottom=0.08, left=0.10, right=0.95, hspace=0.25, wspace=0.35)

#plt.title("My First plot") not work here
#设置第一个子图形的标题、绘图、标签、网格
plt.subplot(411) #用来水平切分4个,垂直切分1个,调用第1个图形
plt.title("My First plot", fontsize=14) #only work here
plt.plot(t, y1, "b-.") #在这里还可以设置绘制的点的样式、颜色等
plt.ylabel("Value-M1")
plt.grid(True)

#同上,调用第二个图形,设置文本和图例
plt.subplot(412)
plt.plot(t, y2, "r--")
plt.ylabel("Value-M2")
plt.text(1, 0.5, "text1")
plt.text(3, 0.3, "text2")
plt.legend(["Legend"], loc=1) #图例位置和文本内容

#同上,调用第三个图形,gca返回当前instance,设置刻度
plt.subplot(413)
plt.plot(t, y1, "p-.")
plt.gca().xaxis.set_minor_formatter(NullFormatter()) #gca获取当前axes,set..设置刻度

plt.subplot(411)
#你可以在任意时候,回到之前绘制的子图中继续在其上绘制其他图案。比如:
#plt.plot(t, y1, "p-.") #这条命令会绘制在图1中,并且和之前图1存在的内容并存
plt.show()

Figure和Axes:图形、子图形和其轴

Figure和Axes对象

class matplotlib.figure.Figure
(figsize=None, dpi=None, facecolor=None, edgecolor=None, linewidth=0.0, frameon=None, subplotpars=None, tight_layout=None)

Figure还有很多方法,常有的有:

  • add_axes(rect)添加子轴
  • add_subplot(m n a)添加子图
  • clear()清除图像
  • draw(renderer)底层接口
  • gca()当前Axes
  • get_children()获取子元素
  • hold()丑陋的MATLAB兼容性
  • savefig()保存图片
  • set_canvas()底层接口
  • show()显示图片
  • subplots_adjust()子图微调
  • text()放置文字
class matplotlib.axes.Axes
(fig, rect, facecolor=None, frameon=True, sharex=None, sharey=None, label='', xscale=None, yscale=None, axisbg=None, **kwargs)

Axes有很多方法,单独方法大约有100种,因此在这里不再举例,可查阅手册。

调用和创建Figure和Axes对象

使用plt进行绘图固然很方便,但是有时候我们需要细微调整,一般需要使用:

  • gca()返回当前状态下的Axes对象,Fig.gca()的Alias
  • gca().get_children()方便查看当前Axes下的元素
  • gcf()返回当前状态下的Figure对象,一般用以遍历多个图形的Axes(plt.gcf().get_axes())。另一种方法是使用Axes矩阵的索引抽取子Plot的Axes。

对于想要重新画一幅图,而不是将图形绘制在一个Figure中并且区分成几个subplot,直接使用plt.figure()创建一个新的Figure对象,使用plt.gcf()也可以捕获这个对象。每个图形可以有很多子图形构成,每个子图形只有一个Axes,它们可以共享坐标轴,每个子图形都有其各自的AxesSubplot子轴,包含在总的Axes中。

正比如Figure对象和Canvas对象的交互用canvas=FigureCanvasBase(fig)进行操作一样,Figure对象和Axes对象的关联可以使用下面几种方法:

  • axes=plt.subplot(mna)#MATLAB方式,一般仅用作交互,而不捕获输出
  • axes=mpl.axes.Axes(fig,*kwargs#OOP方式,较少使用
  • fig,axes_martix=plt.subplots(nc,nr)#快速方式,适合快速创建Figure对象和Axes对象,一般用于创作指定子图形个数的图。
  • axes=fig.add_subplot(mna)#适合在有Figure对象情况下创建单个子图形,和subplot()类似。相比较subplots,其优点在于可以使用gridspec绘制带有X-Y轴附属图形的图。
  • axes=fig.add_axes([rect])#适合在一个图形指定位置添加一个小的子图形和其Axes。一般用作附属图形的绘制。

一个例子:OOP方式

from mpl_toolkits.mplot3d import Axes3D

fig=plt.figure()#调用一个新的画布
fig2=plt.gcf()#fig2==fig1=>True

ax_sub=fig.add_subplot(2,2,1)#添加子画布,2×2大小,第一个
ax_sub2=fig.add_subplot(2,2,2)#添加子画布,2×2大小,第二个
ax_sub3=fig.add_subplot(2,2,3)#添加子画布,2×2大小,第三个
#需要注意,add_subplot返回的是subaxes对象

一个例子:plt.subplots方式

%matplotlib inline
x=np.arange(0.1,4,0.5)
y=np.exp(-x)
#快速创建图形Fig和AxesMartix
fig,ax=plt.subplots(3,3,sharex=True,sharey=True)
#或者使用fig,((ax1,ax2,ax3),(ax4,ax5,ax6),(ax7,ax8,ax9))=plt.subplots(3,3)
print(ax)

#plot the linear_data on the 5th,8th subplot axes
ax[2][2].plot(x,y,'-')
ax[1][1].plot(x,y**2,'-')

#对于一个包含多个轴的fig,可以使用gcf().get_axis,或者直接对矩阵进行索引和操纵
for ax in plt.gcf().get_axes():
for label in ax.get_xticklabels()+ax.get_yticklabels():
label.set_visible(True)

#necessary on some systems to update the plot
plt.gcf().canvas.draw()

[[<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f8c3b310>
<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f8bec110>
<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f86c11d0>]
[<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f8b16290>
<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f84e7350>
<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f86ed410>]
[<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f8ca8a10>
<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f857ecd0>
<matplotlib.axes._subplots.AxesSubplot object at 0x7f57f855ce50>]]

绘图常用方法

Firure常用方法

  • subplots_adjust等同于调用subplots_adjust(left=None,bottom=None,right=None,top=None,wspace=None,hspace=None)顶级函数,用于调整子plot周围宽度、高度等表现形式。
  • savefig(fname,dpi,bbox_inches,format)保存图像

Axes常用方法

  • hist柱状图/pie饼状图/box箱型图等等
  • plot如果不指定图的类型,比如饼状图或者柱状图,直接传入plot,参数填为data即可。
  • add_patch添加图形
  • annotate添加箭头
  • text添加文本说明
  • get(set)_x(y)lim获得/设置不同轴的范围
  • g/s_(x/y)ticks设置刻度位置#plt.xticks((0,1,2),(“a”,”b”,”c”))可以快速指定位置和标签值。
  • g/s_(x/y)ticklabels设置刻度标签
  • g/s_(x/y)label设置轴名称
  • title题头设置
  • legend图例设置

对于Axes调用get/set等很多方法,其实也可以直接调用plt全局对象,不过调用axes单个元素可以获得更精细的控制,并且更面向对象一些。

fig, ax = plt.subplots(2, 3, sharex=True, sharey=True)
fig.subplots_adjust(left=None, bottom=None, right=None, top=None, wspace=0, hspace=0)
#也可以使用plt顶级函数
#histogram柱状图
ax[0, 0].hist(np.random.randint(1, 500, size=100), bins=50, color="k", alpha=0.5)
ax[0, 1].hist(np.random.randint(1, 500, size=100), bins=50, color="k", alpha=0.5)
ax[0, 2].hist(np.random.randint(1, 500, size=100), bins=50, color="k", alpha=0.5)
ax[1, 0].hist(np.random.randint(1, 500, size=100), bins=50, color="k", alpha=0.5)
ax[1, 1].hist(np.random.randint(1, 500, size=100), bins=50, color="k", alpha=0.5)
ax[1, 2].hist(np.random.randint(1, 500, size=100), bins=50, color="k", alpha=0.5)

fig.savefig("hello.png", format="png", dpi=100, bbox_inches="tight")
#两个较为重要的参数是bbox_inches控制边距,第二个是dpi控制精度

fig, ax = plt.subplots()
ax.plot(np.random.randn(500).cumsum(), label="a")
#此处设置plot的label值,即可以调用legend时自动生成图例。
ax.plot(np.random.randn(500).cumsum(), label="b")
ax.set_xticks([0, 150, 300, 450, 600])
ax.set_xticklabels(["one", "two", "three", "four", "five", "six"])#自动跳过了six
#也可以直接写ax.xticks([真实数值],[对应标签名称])
ax.set_title("table", loc="center")
ax.set_xlabel("numbers")
ax.set_ylabel("values")
ax.legend(loc="best")#legend图例,在plot时传入label进行创建
ax.text(0, 10, "Hello World")
#matplotlib.pyplot.text(x, y, s, fontdict=None, withdash=False, **kwargs)
ax.annotate("", xy=(0, 0), xycoords='data', xytext=(400, 10), textcoords='data', arrowprops=dict(arrowstyle="->", connectionstyle="arc3"),)

SPINES坐标系绘制

%matplotlib inline
fig, ax = plt.subplots()
x = np.arange(-2*np.pi, 2*np.pi, 0.01)
y = np.sin(3*x)/x
y2 = np.sin(2*x)/x
y3 = np.sin(x)/x

ax.plot(x, y, "r")
ax.plot(x, y2, "b")
ax.plot(x, y3, "g")

print(plt.gca(), ax)
#AxesSubplot(0.125,0.125;0.775x0.755)AxesSubplot(0.125,0.125;0.775x0.755)

ax.spines["right"].set_visible(False)
#class matplotlib.spines.Spine(axes, spine_type, path, **kwargs)
ax.spines["top"].set_visible(False)
ax.spines["bottom"].set_position(("data", 0))
ax.spines["left"].set_position(("data", 0))

PATCH图形的绘制

图形绘制需要调用axes.add_patch()方法,传入参数为图形,也就是line/path/patches对象。和Qt图形绘制很类似,底层API。

import matplotlib.path as mpath
import matplotlib.patches as mpatches
fig = plt.figure(figsize=(12, 6))
axes = fig.add_subplot(1, 2, 1)
grid = np.mgrid[0.2:0.8:3j, 0.2:0.8:3j].reshape(2, -1).T
patches = []
#add a circle
circle = mpatches.Circle(grid[0], 0.1, ec="none")
patches.append(circle)
#add a rectangle
rect = mpatches.Rectangle(grid[1]-[0.025, 0.05], 0.05, 0.1, ec="none")
patches.append(rect)
axes.add_patch(patches[0]);axes.add_patch(patches[1])

AXES3D图表绘制

from mpl_toolkits.mplot3d import Axes3D

x = np.arange(8) #生成数据
y = np.random.randint(0, 10, 8)
y2 = y + np.random.randint(0, 3, 8)
y3 = y2 + np.random.randint(0, 3, 8)
y4 = y3 + np.random.randint(0, 3, 8)
y5 = y4 + np.random.randint(0, 3, 8)

fig = plt.figure(); ax = Axes3D(fig) #普通方法调用fig和ax
#或者采用ax = fig.add_subplot(111, projection='3d')绘制子图形。
#For those using older versions of matplotlib,
#change ax = fig.add_subplot(111, projection='3d') to ax = Axes3D(fig).

ax.bar(x, y, 0, zdir="y") #数据和作为第三轴的轴:y
ax.bar(x, y2, 10, zdir="y")
ax.bar(x, y3, 20, zdir="y")
ax.bar(x, y4, 30, zdir="y")
ax.bar(x, y5, 40, zdir="y")
ax.set_xlabel("X label") #标签
ax.set_ylabel("Y label")
ax.set_zlabel("Z label")
ax.view_init(elev=50) #视角
ax.grid(False)
#3D设置在class mpl_toolkits.mplot3d.axes3d.Axes3D(fig, rect=None, *args, **kwargs)

子图网格和多面板绘图

区别与fig.add_subplot(),使用fig.add_axes()方法手动创建一个新的Axes,但是并没有制定该Axes的位置,需要手动指定,一般用作附属图形的绘制,之后调用此子axes,就可以对附属图形进行绘制了。

fig = plt.figure()
ax_1 = fig.add_axes([0.1, 0.1, 1, 1]) #此处定义的是图表的rect[left, bottom, width, height]
ax_2 = fig.add_axes([0.7, 0.7, 0.3, 0.3])
ax_1.plot(np.random.randint(0, 10, 50), "ro")
ax_2.plot(np.random.randint(0, 10, 3), "g--")

在前面add_subplot()的介绍中,可以在此定义”12X”表示水平划分1个,垂直划分2个,选取第X个。但是,为了精确控制位置,可以使用GridSpec对象,传入一个方格大小,然后对其进行切片调用,作为参数传递给add_subplot(),这样就可以进行精细的子图控制。

fig = plt.figure()
gs = plt.GridSpec(3, 3) #新建一个网格
fig.add_subplot(gs[1, :2]).plot(np.random.randint(0, 10, 10), "o") #不再传入1,2,1,而是传入
s2 = fig.add_subplot(gs[0, :2])
s2.plot(np.random.randint(0, 10, 10), "o")
fig.add_subplot(gs[2, 0]).plot(np.random.randint(0, 10, 10), "o")
fig.add_subplot(gs[:2, 2]).plot(np.random.randint(0, 10, 10), "o")
fig.add_subplot(gs[2, 1:]).plot(np.random.randint(0, 10, 10), "o")

下面是一个应用Gridspec的例子:

from matplotlib.gridspec import GridSpec
import numpy as np

fig = plt.figure()
gs = GridSpec(3, 3)
main = fig.add_subplot(gs[1:, 1:])
hist = fig.add_subplot(gs[1:, 0:1])
hist_x = fig.add_subplot(gs[0:1, 1:])

data_x = np.random.random(size=10000)
data_y = np.random.normal(size=10000)

main.scatter(data_x, data_y)
main.set_xlim(0, 1)
hist.hist(data_y, orientation='horizontal', bins=1000) #水平显示
hist.invert_xaxis() #反转X轴以方便比较数据
hist_x.hist(data_x, bins=1000)
hist_x.set_xlim(0, 1)

GCA高级用法

使用plt.gca()可以精细控制绘图,比如:

plt.gca().fill_between(x, y1, y2, alpha, color)

可以绘制两条曲线组成的填充图形,在表示面积的时候很有用,比如积分面积。此外,还可以这样使用:

xaxis = plt.gca().get_xaxis() #从AXES实例中获取XAXIS实例

for item in xaxis.get_ticklabels(): #从XAXIS实例中获取TICKLABELS
item.set_alpha(1) #TICKLABELS由TEXT实例构成,TEXT实例有很多方法
item.set_rotation(45)
item.set_backgroundcolor('r')
item.set_color('w')

gca()本质上是一个Axes对象,查阅文档可以看出,这个对象具有很多可用的方法,比如本例中取出x子轴,并且对此轴的刻度标签进行遍历(Text对象),设置旋转、透明度和颜色、背景,对于较长的时间日期,这样可以使得坐标轴文字不挤在一起。

Matplotlib样式

使用matplotlib自带的几种美化样式,就可以很轻松的对生成的图形进行美化。可以使用matplotlib.pyplot.style.available获取所有的美化样式:

import matplotlib.pyplot as plt
print(plt.style.available)

具体官网查看样式参考表

使用自带的样式进行美化:

import matplotlib.pyplot as plt
plt.style.use('ggplot')
# 使用自定义样式:
plt.style.use('./images/presentation.mplstyle')
plt.style.use('https://github.com/dhaitz/matplotlib-stylesheets/raw/master/pitayasmoothie-light.mplstyle')

Matplotlib常见图表的绘制

Matplotlib是Python中最常用的数据可视化库之一,提供了多种图表类型,帮助用户进行数据分析和展示。以下是Matplotlib中一些常见图表的绘制方法及其基本示例。

线形图(Line Plot)

线形图用于显示数据的趋势和变化。

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]

plt.plot(x, y, marker='o')
plt.title('Line Plot')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.grid(True)
plt.show()

散点图(Scatter Plot)

散点图用于展示两个变量之间的关系。

x = [5, 7, 8, 5, 6, 7, 9, 2, 3, 4, 4, 4, 5, 7, 8, 9, 9, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 5, 6, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6]
y = [7, 4, 3, 4, 2, 4, 4, 6, 8, 9, 1, 3, 2, 5, 6, 7, 8, 9, 9, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4, 5, 6, 1, 2, 3, 4]

plt.scatter(x, y, color='r')
plt.title('Scatter Plot')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.show()

柱状图(Bar Plot)

柱状图用于比较不同类别之间的数值大小。

categories = ['A', 'B', 'C', 'D']
values = [3, 7, 5, 9]

plt.bar(categories, values, color='b')
plt.title('Bar Plot')
plt.xlabel('Categories')
plt.ylabel('Values')
plt.show()

直方图(Histogram)

直方图用于展示数据的分布。

import numpy as np

data = np.random.randn(1000)

plt.hist(data, bins=30, color='g', alpha=0.7)
plt.title('Histogram')
plt.xlabel('Value')
plt.ylabel('Frequency')
plt.show()

饼图(Pie Chart)

饼图用于显示各部分占整体的比例。

labels = ['Python', 'C++', 'Ruby', 'Java']
sizes = [215, 130, 245, 210]
colors = ['gold', 'yellowgreen', 'lightcoral', 'lightskyblue']
explode = (0.1, 0, 0, 0)  # 使第一块突出

plt.pie(sizes, explode=explode, labels=labels, colors=colors, autopct='%1.1f%%', shadow=True, startangle=140)
plt.title('Pie Chart')
plt.axis('equal')  # 使饼图为圆形
plt.show()

箱形图(Box Plot)

箱形图用于显示数据的分布特征,如中位数、四分位数等。

data = [np.random.normal(0, std, 100) for std in range(1, 4)]

plt.boxplot(data, vert=True, patch_artist=True, labels=['x1', 'x2', 'x3'])
plt.title('Box Plot')
plt.xlabel('Dataset')
plt.ylabel('Value')
plt.show()

Matplotlib高级图表类型

热力图

热力图用于展示二维数据的强度或频率,常用于表示矩阵数据或地理数据的密度。

使用 plt.imshow()

plt.imshow()是Matplotlib提供的用于绘制图像和热力图的函数。它将二维数组显示为彩色图像。

import matplotlib.pyplot as plt
import numpy as np

# 生成随机数据
data = np.random.rand(10, 10)

plt.imshow(data, cmap='hot', interpolation='nearest')
plt.colorbar()  # 添加颜色条
plt.title('Heatmap using plt.imshow()')
plt.show()

使用 sns.heatmap()

seaborn库的sns.heatmap()提供了更高级的热力图功能,支持添加注释、调整颜色映射等。

import seaborn as sns

# 使用Seaborn绘制热力图
sns.heatmap(data, annot=True, cmap='coolwarm', linewidths=0.5)
plt.title('Heatmap using sns.heatmap()')
plt.show()

等高线图

等高线图用于表示三维数据的二维切片,常用于地形图和流体动力学。

使用 plt.contour()

plt.contour()绘制等高线图,其中线条表示相同的数值。

x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))

plt.contour(X, Y, Z, levels=20, cmap='viridis')
plt.colorbar()
plt.title('Contour Plot using plt.contour()')
plt.show()

使用 plt.contourf()

plt.contourf()是plt.contour()的填充版本,填充等高线之间的区域。

plt.contourf(X, Y, Z, levels=20, cmap='viridis')
plt.colorbar()
plt.title('Filled Contour Plot using plt.contourf()')
plt.show()

密度图

密度图用于表示数据点的分布密度,常用于大数据集的可视化。

使用 plt.hexbin()

plt.hexbin()创建一个六边形的密度图,适合用于大规模数据的二维分布可视化。

x = np.random.randn(10000)
y = np.random.randn(10000)

plt.hexbin(x, y, gridsize=50, cmap='Blues')
plt.colorbar(label='Counts')
plt.title('Hexbin Plot using plt.hexbin()')
plt.show()

使用 sns.kdeplot()

seaborn提供的sns.kdeplot()用于绘制核密度估计图,可以绘制一维或二维密度图。

sns.kdeplot(x=x, y=y, cmap='Reds', shade=True, bw_adjust=0.5)
plt.title('Kernel Density Estimation using sns.kdeplot()')
plt.show()

Matplotlib图表定制

颜色和样式

Matplotlib是一个功能强大的数据可视化库,提供了丰富的选项来定制图表的颜色和样式,使其更加美观和信息丰富。以下是关于如何在Matplotlib中定制图表颜色和样式的详细指南。

颜色定制

基本颜色

Matplotlib支持多种方式来指定颜色,包括:

  • 颜色名称:如’red’, ‘blue’, ‘green’ 等。
  • 十六进制代码:如’#FF5733’。
  • RGB元组:如(0.1,0.2,0.5),值在0到1之间。
  • 灰度字符串:如’0.5′ 表示中灰色。
import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]

plt.plot(x, y, color='purple', marker='o') #使用颜色名称
plt.show()

颜色映射(Colormap)

颜色映射用于将数值数据映射到颜色,常用于热力图和散点图。

import numpy as np

data = np.random.rand(10, 10)

plt.imshow(data, cmap='viridis') #使用'viridis'颜色映射
plt.colorbar()
plt.show()

Matplotlib提供了多种预定义的颜色映射,如’viridis’,’plasma’,’inferno’,’magma’,’cividis’等。

样式定制

线条样式

线型:可以通过 linestyle 参数设置,如 ‘-‘(实线),’–‘(虚线),’-.’(点划线),’:’(点线)。

plt.plot(x, y, linestyle='--') #使用虚线
plt.show()

线宽:可以通过 linewidth 参数设置。

plt.plot(x, y, linewidth=2.5) #设置线宽
plt.show()

标记样式

标记类型:可以通过 marker 参数设置,如 ‘o’(圆圈),’s’(方块),’^’(三角形)。

plt.plot(x, y, marker='s') #使用方块标记
plt.show()

标记大小:可以通过 markersize 参数设置。

plt.plot(x, y, marker='o', markersize=10) #设置标记大小
plt.show()

样式表

Matplotlib提供了一些预定义的样式表,可以通过plt.style.use()使用。

plt.style.use('ggplot') #使用'ggplot'样式
plt.plot(x, y)
plt.show()

常用的样式表包括’ggplot’,’seaborn’,’bmh’,’fivethirtyeight’,’dark_background’等。

自定义主题

可以通过rcParams全局修改Matplotlib的默认设置,以实现全局样式定制。

plt.rcParams['lines.linewidth'] = 2
plt.rcParams['lines.linestyle'] = '--'
plt.rcParams['axes.titlesize'] = 14

plt.plot(x, y)
plt.title('Custom Style')
plt.show()

更多参考:Matplotlib点、线形状及颜色–标点符(biaodianfu.com)

图例和注释

在数据可视化中,图例和注释是两个重要的元素,它们可以帮助观众更好地理解图表中的信息。Matplotlib提供了灵活的功能来添加和定制图例和注释。下面是关于如何在Matplotlib中使用图例和注释的详细介绍。

图例(Legend)

图例用于标识图表中的不同数据系列或元素,帮助观众理解每种颜色或样式代表的含义。

添加图例

可以使用plt.legend()或ax.legend()方法添加图例。通常情况下,图例会根据label参数自动生成。

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y1 = [2, 3, 5, 7, 11]
y2 = [1, 4, 6, 8, 10]

plt.plot(x, y1, label='Series 1')
plt.plot(x, y2, label='Series 2')
plt.legend() #添加图例
plt.show()

定制图例

  • 位置:可以通过loc 参数设置图例的位置,如 ‘upperright’, ‘lowerleft’, ‘center’ 等。也可以使用数字代码(如 0 表示 ‘best’ 自动选择最佳位置)。
  • 标题:使用title 参数为图例添加标题。
  • 字体大小:使用fontsize 参数设置图例的字体大小。
  • 透明度:使用framealpha 参数设置图例背景的透明度。
plt.legend(loc='upper left')
plt.legend(title='Legend Title')
plt.legend(fontsize='small')
plt.legend(framealpha=0.5)

自定义图例元素

可以通过 handles 和 labels 参数自定义图例元素。

lines = plt.plot(x, y1, x, y2)
plt.legend(lines, ['Custom Label 1', 'Custom Label 2'])

注释(Annotation)

注释用于在图表中添加文本,指示特定的数据点或解释图表中的某些特征。

添加注释

使用 plt.annotate() 或 ax.annotate() 方法添加注释。

plt.plot(x, y1)
plt.annotate('Peak', xy=(3, 5), xytext=(3, 6),
arrowprops=dict(facecolor='black', shrink=0.05))
plt.show()
  • xy:指定要注释的点的坐标。
  • xytext:指定注释文本的位置。
  • arrowprops:用于定义箭头的样式。

定制注释

  • 字体大小和颜色:可以通过 fontsize 和 color 参数设置注释文本的字体大小和颜色。
  • 对齐方式:可以通过 horizontalalignment 和 verticalalignment 参数设置文本的对齐方式。
  • 背景颜色:使用 bbox 参数设置注释文本的背景颜色。
plt.annotate('Peak', xy=(3, 5), xytext=(3, 6),
arrowprops=dict(facecolor='black', shrink=0.05),
fontsize=12, color='red')
plt.annotate('Peak', xy=(3, 5), xytext=(3, 6),
arrowprops=dict(facecolor='black', shrink=0.05),
ha='center', va='bottom')
plt.annotate('Peak', xy=(3, 5), xytext=(3, 6),
arrowprops=dict(facecolor='black', shrink=0.05),
bbox=dict(boxstyle='round,pad=0.5', edgecolor='red', facecolor='yellow'))

文本(Text)

plt.text() 是 Matplotlib 中用于在图表的特定位置添加文本的函数。与 plt.annotate() 类似,plt.text() 提供了一种简单的方法来在图表中放置文本标签,但没有附带箭头或其他注释功能。它非常适合用于添加标题、标签或其他说明性文字。

plt.text() 基本用法

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]

plt.plot(x, y, marker='o')

# 在图表的 (x,y) 坐标位置添加文本
plt.text(2, 5, 'This is a point', fontsize=12, color='red')

plt.title('Example of plt.text()')
plt.xlabel('X-axis')
plt.ylabel('Y-axis')
plt.grid(True)
plt.show()

参数说明

  • x, y:文本的位置坐标。指定文本在数据坐标系中的位置。
  • s:要显示的文本字符串。
  • fontsize:文本的字体大小。
  • color:文本的颜色。
  • fontweight:文本的字体粗细,如 ‘normal’, ‘bold’。
  • ha(horizontalalignment):水平对齐方式,如 ‘center’, ‘right’, ‘left’。
  • va(verticalalignment):垂直对齐方式,如 ‘center’, ‘top’, ‘bottom’。
  • rotation:文本的旋转角度。
  • bbox:文本背景的边框属性。可以用来设置背景颜色、边框样式等。

示例

# 设置文本对齐方式
plt.text(2, 5, 'Left aligned', fontsize=12, color='blue', ha='left', va='center')
plt.text(3, 7, 'Center aligned', fontsize=12, color='green', ha='center', va='center')
plt.text(4, 9, 'Right aligned', fontsize=12, color='purple', ha='right', va='center')
# 添加背景框
plt.text(2, 5, 'With background', fontsize=12, color='black',
bbox=dict(facecolor='yellow', alpha=0.5, boxstyle='round,pad=1'))
# 旋转文本
plt.text(3, 7, 'Rotated text', fontsize=12, color='red', rotation=45)

坐标轴和刻度

Matplotlib 提供了强大的功能来定制图表的坐标轴和刻度,以提高数据可视化的精度和美观度。以下是关于如何在 Matplotlib 中处理坐标轴和刻度的详细介绍。

坐标轴(Axes)

基本概念

  • 轴(Axis):表示图表中的水平(x轴)和垂直(y轴)线。
  • 刻度(Ticks):轴上的标记,用于指示数据点的数值。
  • 刻度标签(Tick Labels):刻度旁边的文本,表示刻度的数值。

设置轴标签

可以使用 plt.xlabel() 和 plt.ylabel() 为坐标轴添加标签。

import matplotlib.pyplot as plt

x = [1, 2, 3, 4, 5]
y = [2, 3, 5, 7, 11]

plt.plot(x, y)
plt.xlabel('X-axis Label')
plt.ylabel('Y-axis Label')
plt.title('Axis Labels Example')
plt.show()

刻度(Ticks)

设置刻度

可以使用 plt.xticks() 和 plt.yticks() 自定义刻度的位置和标签。

plt.plot(x, y)

# 自定义刻度位置和标签
plt.xticks(ticks=[1, 2, 3, 4, 5], labels=['One', 'Two', 'Three', 'Four', 'Five'])
plt.yticks(ticks=[2, 4, 6, 8, 10], labels=['Two', 'Four', 'Six', 'Eight', 'Ten'])
plt.show()

刻度方向和位置

可以使用 tick_params() 方法调整刻度的方向、长度、颜色和位置。

plt.plot(x, y)

#调整刻度参数
plt.tick_params(axis='x', direction='in', length=6, width=2, colors='r')
plt.tick_params(axis='y', direction='out', length=6, width=2, colors='b')
plt.show()

主刻度和次刻度

  • 主刻度(Major Ticks):主要的刻度线,通常用于标识关键数据点。
  • 次刻度(Minor Ticks):次要的刻度线,用于提高刻度的精度。

可以使用matplotlib.ticker模块设置次刻度。

import matplotlib.ticker as ticker

fig, ax = plt.subplots()
ax.plot(x, y)

#设置主刻度
ax.xaxis.set_major_locator(ticker.MultipleLocator(1))
ax.yaxis.set_major_locator(ticker.MultipleLocator(2))

#设置次刻度
ax.xaxis.set_minor_locator(ticker.AutoMinorLocator(4))
ax.yaxis.set_minor_locator(ticker.AutoMinorLocator(4))

#显示网格
ax.grid(which='both')
plt.show()

坐标轴范围

可以使用plt.xlim()和plt.ylim()设置坐标轴的显示范围。

plt.plot(x, y)

#设置坐标轴范围
plt.xlim(0, 6)
plt.ylim(0, 12)
plt.show()

坐标轴样式

可以使用plt.gca()获取当前轴对象,然后使用其方法自定义轴的样式。

ax = plt.gca()

#设置轴的边框颜色和线宽
ax.spines['top'].set_color('none')
ax.spines['right'].set_color('none')
ax.spines['left'].set_linewidth(2)
ax.spines['bottom'].set_linewidth(2)

plt.plot(x, y)
plt.show()

刻度的设置

在数据可视化中,有时候需要使用对数刻度来更好地表示数据的范围或变化趋势。对数刻度可以帮助处理具有指数增长或缩放不均匀的数据。Matplotlib提供了plt.xscale()和plt.yscale()函数来设置坐标轴为对数刻度。

  • xscale(‘log’):将x轴设置为对数刻度。
  • yscale(‘log’):将y轴设置为对数刻度。

Matplotlib允许自定义对数刻度的基础和非对数刻度的显示。

更改对数刻度的基数

默认情况下,对数刻度的基数是10,但可以更改为其他值(如2或e)。

plt.xscale('log', base=2)
plt.yscale('log', base=2)

显示非对数刻度

可以使用matplotlib.ticker模块来显示非对数刻度。

import matplotlib.ticker as ticker

fig, ax = plt.subplots()
ax.plot(x, y)
ax.set_xscale('log')
ax.set_yscale('log')

#设置主要和次要刻度
ax.xaxis.set_major_locator(ticker.LogLocator(base=10.0, numticks=10))
ax.yaxis.set_major_locator(ticker.LogLocator(base=10.0, numticks=10))
ax.xaxis.set_minor_locator(ticker.LogLocator(base=10.0, subs='auto'))
ax.yaxis.set_minor_locator(ticker.LogLocator(base=10.0, subs='auto'))

#显示网格
ax.grid(which='both', linestyle='--', linewidth=0.5)
plt.show()

子图和多图

在数据可视化中,常常需要在同一窗口中展示多个图表,以便于比较不同数据集或不同视角下的数据。Matplotlib提供了强大的功能来创建子图和多图布局,主要通过plt.subplot()和plt.subplots()函数实现。

子图(Subplot)

使用 plt.subplot()

plt.subplot()函数用于在一个图形窗口中创建多个子图。它采用三个参数:nrows, ncols, 和index。

  • nrows:子图的行数。
  • ncols:子图的列数。
  • index:当前子图的索引(从1开始)。
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)

plt.figure(figsize=(10, 6))

#第一个子图
plt.subplot(2, 2, 1) #2行2列的布局,第1个位置
plt.plot(x, np.sin(x))
plt.title('Sine Wave')

#第二个子图
plt.subplot(2, 2, 2) #2行2列的布局,第2个位置
plt.plot(x, np.cos(x))
plt.title('Cosine Wave')

#第三个子图
plt.subplot(2, 2, 3) #2行2列的布局,第3个位置
plt.plot(x, np.tan(x))
plt.title('Tangent Wave')

#第四个子图
plt.subplot(2, 2, 4) #2行2列的布局,第4个位置
plt.plot(x, np.exp(x))
plt.title('Exponential')

plt.tight_layout() #自动调整子图间距
plt.show()

使用 plt.subplots()

plt.subplots()是创建子图的更灵活的方法,它返回一个包含所有子图的Figure对象和Axes对象的数组。

fig, axs = plt.subplots(2, 2, figsize=(10, 6))

axs[0, 0].plot(x, np.sin(x))
axs[0, 0].set_title('Sine Wave')

axs[0, 1].plot(x, np.cos(x))
axs[0, 1].set_title('Cosine Wave')

axs[1, 0].plot(x, np.tan(x))
axs[1, 0].set_title('Tangent Wave')

axs[1, 1].plot(x, np.exp(x))
axs[1, 1].set_title('Exponential')

plt.tight_layout()
plt.show()

多图布局(Multiple Figures)

创建多个图形窗口

可以通过多次调用plt.figure()创建多个图形窗口。

#第一个图形窗口
plt.figure(1)
plt.plot(x, np.sin(x))
plt.title('Sine Wave')

#第二个图形窗口
plt.figure(2)
plt.plot(x, np.cos(x))
plt.title('Cosine Wave')

plt.show()

在同一窗口中显示多个图形

可以通过 plt.subplots() 创建多行多列的图形布局。

fig, axs = plt.subplots(3, 1, figsize=(8, 12)) # 3行1列的布局

axs[0].plot(x, np.sin(x))
axs[0].set_title('Sine Wave')

axs[1].plot(x, np.cos(x))
axs[1].set_title('Cosine Wave')

axs[2].plot(x, np.tan(x))
axs[2].set_title('Tangent Wave')

plt.tight_layout()
plt.show()

自定义子图布局

可以使用 GridSpec 进行更复杂的子图布局。GridSpec 允许更精细地控制子图的布局和位置。

import matplotlib.gridspec as gridspec

fig = plt.figure(figsize=(10, 6))
gs = gridspec.GridSpec(3, 3)

ax1 = fig.add_subplot(gs[0, :]) # 第一行占满
ax2 = fig.add_subplot(gs[1, :-1]) # 第二行前两列
ax3 = fig.add_subplot(gs[1:, -1]) # 第二行和第三行最后一列
ax4 = fig.add_subplot(gs[-1, 0]) # 第三行第一列
ax5 = fig.add_subplot(gs[-1, -2]) # 第三行第二列

ax1.plot(x, np.sin(x))
ax2.plot(x, np.cos(x))
ax3.plot(x, np.tan(x))
ax4.plot(x, np.exp(x))
ax5.plot(x, np.log(x+1))

plt.tight_layout()
plt.show()

调整子图布局

在使用 Matplotlib 绘制多个子图时,常常会遇到子图之间的元素(如轴标签、标题)重叠的问题。为了自动调整子图之间的间距,使得每个子图的内容能够更清晰地展示,Matplotlib 提供了 plt.tight_layout() 函数。

plt.tight_layout() 函数用于自动调整子图之间的空白区域,以避免重叠。它会计算每个子图的尺寸和位置,调整子图之间的间距,使得整个图形的布局更加紧凑和美观。

基本用法

在创建多个子图之后,可以直接调用 plt.tight_layout() 来调整布局。

import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(0, 10, 100)

fig, axs = plt.subplots(2, 2, figsize=(10, 6))

axs[0, 0].plot(x, np.sin(x))
axs[0, 0].set_title('Sine Wave')

axs[0, 1].plot(x, np.cos(x))
axs[0, 1].set_title('Cosine Wave')

axs[1, 0].plot(x, np.tan(x))
axs[1, 0].set_title('Tangent Wave')

axs[1, 1].plot(x, np.exp(x))
axs[1, 1].set_title('Exponential')

# 调用 tight_layout 调整子图布局
plt.tight_layout()
plt.show()

参数说明

plt.tight_layout() 提供了一些参数,可以用于进一步控制布局的细节:

  • pad:图像边缘与子图之间的填充距离,默认值是 0.8。
  • h_pad:垂直方向的子图间距。
  • w_pad:水平方向的子图间距。
  • rect:一个形如 [left, bottom, right, top] 的列表,用于指定子图所占的区域。

注意事项

  • tight_layout() 可能会与一些自定义布局(如使用 GridSpec)产生冲突,因此在复杂布局中需要谨慎使用。
  • 当图形窗口的大小调整时,tight_layout 可能需要重新调用以更新布局。
  • 如果 tight_layout 没有达到预期效果,可以手动调整子图参数或考虑使用 subplots_adjust() 进行更精细的控制。

Matplotlib 高级功能

三维绘图

Matplotlib 的三维绘图功能是通过 mpl_toolkits.mplot3d 模块实现的。这一模块提供了丰富的工具,可以用来创建和展示三维数据。

基础设置

要使用 Matplotlib 的三维绘图功能,首先需要导入 Axes3D 类。通常的做法是:

import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import numpy as np

创建三维图形

创建三维坐标系

在 Matplotlib 中,三维图形是通过在 Figure 对象上添加一个三维坐标系实现的。

fig = plt.figure()
ax = fig.add_subplot(111, projection='3d') # 111 表示 1 行 1 列的第 1 个子图

三维散点图

三维散点图用于展示三维数据点的分布。

# 生成随机数据
x = np.random.standard_normal(100)
y = np.random.standard_normal(100)
z = np.random.standard_normal(100)

# 绘制三维散点图
ax.scatter(x, y, z, c='r', marker='o')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.title('3D Scatter Plot')
plt.show()

三维曲面图

三维曲面图用于展示三维数据的表面。

# 生成网格数据
x = np.linspace(-5, 5, 100)
y = np.linspace(-5, 5, 100)
X, Y = np.meshgrid(x, y)
Z = np.sin(np.sqrt(X**2 + Y**2))

# 绘制三维曲面图
ax.plot_surface(X, Y, Z, cmap='viridis')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.title('3D Surface Plot')
plt.show()

三维线图

三维线图用于展示三维空间中的线条或路径。

#生成数据
z = np.linspace(0, 1, 100)
x = z * np.sin(25 * z)
y = z * np.cos(25 * z)

#绘制三维线图
ax.plot(x, y, z, label='parametric curve')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.title('3D Line Plot')
plt.show()

三维等高线图

三维等高线图用于展示三维数据的等高线。

#绘制三维等高线图
ax.contour3D(X, Y, Z, 50, cmap='binary')
ax.set_xlabel('X Label')
ax.set_ylabel('Y Label')
ax.set_zlabel('Z Label')
plt.title('3D Contour Plot')
plt.show()

自定义和美化

  • 颜色映射(Colormap):可以通过 cmap 参数设置不同的颜色映射,如 viridis, plasma, inferno 等。
  • 透明度(Alpha):可以通过 alpha 参数调整透明度。
  • 标签和标题:使用 set_xlabel(), set_ylabel(), set_zlabel() 设置轴标签,使用 set_title() 设置标题。

动态交互

Matplotlib的三维绘图支持交互式旋转和缩放,通常在使用IPython或Jupyter Notebook时表现最佳。确保在绘图前使用%matplotlib notebook或%matplotlib widget以启用交互功能。

动画

Matplotlib提供了一个强大的子模块matplotlib.animation,用于创建动画。动画可以用于展示数据的动态变化,帮助更好地理解时间序列数据或模拟过程。

基础设置

要使用Matplotlib的动画功能,首先需要导入FuncAnimation类。

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.animation import FuncAnimation

基本动画结构

创建动画的基本步骤

  • 准备数据:定义要展示的数据。
  • 初始化函数:设置图形的初始状态。
  • 更新函数:定义动画每一帧的更新逻辑。
  • 创建动画对象:使用FuncAnimation 将初始化和更新函数结合,生成动画。

示例:绘制一个简单的正弦波动画

#准备数据
x = np.linspace(0, 2 * np.pi, 100)

#创建图形和轴
fig, ax = plt.subplots()
line, = ax.plot(x, np.sin(x))

#初始化函数
def init():
    line.set_ydata(np.sin(x))
    return line,

#更新函数
def update(frame):
    line.set_ydata(np.sin(x + frame / 10.0)) #更新数据
    return line,

#创建动画
ani = FuncAnimation(fig, update, frames=np.arange(0, 100), init_func=init, blit=True)

plt.show()

动画参数详解

  • fig:Figure对象,表示要绘制动画的图形。
  • update:更新函数,用于定义每一帧的更新逻辑。
  • frames:帧数,可以是整数、迭代器或生成器,表示动画的帧数。
  • init_func:初始化函数,用于设置动画的初始状态。
  • blit:布尔值,表示是否使用blitting优化动画性能。设置为 True 可以提高性能,但需要更新的对象数量较少。

高级功能

动态调整动画参数

可以通过调整interval和repeat参数来控制动画的播放速度和循环行为。

ani = FuncAnimation(fig, update, frames=np.arange(0, 100), init_func=init, blit=True, interval=50, repeat=False)
  • interval:两帧之间的时间间隔(毫秒)。
  • repeat:布尔值,表示动画是否循环。

保存动画

Matplotlib可以将动画保存为视频文件(如MP4)或GIF文件。需要安装ffmpeg或imagemagick等工具。

ani.save('sine_wave_animation.mp4', writer='ffmpeg')

交互式动画

在Jupyter Notebook中,可以使用%matplotlib notebook或%matplotlib widget来启用交互式动画。

复杂动画示例

可以创建更复杂的动画,例如展示多个子图的动态变化或三维动画。

fig, ax = plt.subplots(2, 1)

x = np.linspace(0, 2 * np.pi, 100)
line1, = ax[0].plot(x, np.sin(x))
line2, = ax[1].plot(x, np.cos(x))

def update(frame):
    line1.set_ydata(np.sin(x + frame / 10.0))
    line2.set_ydata(np.cos(x + frame / 10.0))
    return line1, line2

ani = FuncAnimation(fig, update, frames=np.arange(0, 100), blit=True)
plt.show()

交互模式

Matplotlib提供了一种交互模式,允许在绘图过程中动态更新图形而不必在每次更新后调用plt.show()。这对于需要实时更新的应用程序(如数据流可视化或实时监控)非常有用。plt.ion()和plt.ioff()是用于控制Matplotlib交互模式的两个函数。

交互模式概述

  • 交互模式(Interactive Mode):在此模式下,Matplotlib会在每次绘图命令后自动更新图形窗口。这意味着您可以动态更新图形,而无需显式调用show()。
  • 非交互模式(Non-interactive Mode):这是Matplotlib的默认模式。在这种模式下,图形窗口在调用show() 时才会更新。

使用 plt.ion() 和 plt.ioff()

启用交互模式:plt.ion()

通过调用plt.ion()可以启用交互模式。启用后,任何绘图命令都会立即反映在图形窗口中。

import matplotlib.pyplot as plt
import numpy as np

plt.ion() #启用交互模式

x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)

fig, ax = plt.subplots()
line, = ax.plot(x, y)

for phase in np.linspace(0, 2 * np.pi, 100):
    line.set_ydata(np.sin(x + phase))
    plt.draw() #更新图形
    plt.pause(0.1) #暂停以便查看变化

在上面的示例中,plt.draw() 用于重绘当前图形,而 plt.pause() 则用于暂停执行以便查看图形的变化。

禁用交互模式:plt.ioff()

通过调用 plt.ioff() 可以禁用交互模式,返回到非交互模式。在非交互模式下,您需要调用 plt.show() 来显示图形。

plt.ioff() # 禁用交互模式

x = np.linspace(0, 2 * np.pi, 100)
y = np.sin(x)

plt.plot(x, y)
plt.title("Non-interactive Mode Example")
plt.show() # 需要调用 show() 才能显示图形

使用场景

  • 实时数据可视化:交互模式适用于需要动态更新图形的场景,如实时数据流的监控。
  • 调试和开发:在调试绘图代码时,交互模式可以帮助快速查看结果,而不必每次都调用 show()。
  • 静态报告和展示:对于静态数据可视化,非交互模式通常更合适,因为图形更新不频繁,且需要完整的绘图展示。

注意事项

  • 在某些环境中(如 Jupyter Notebook),交互模式的行为可能与预期不同。在这种情况下,使用 %matplotlib notebook 或 %matplotlib inline 可以更好地控制交互行为。
  • 使用交互模式时,确保在绘图循环中适当地使用 pause() 以避免过快的更新导致图形无法清晰显示。
  • 交互模式可能会增加系统资源的使用,尤其是在频繁更新图形时,因此在实际应用中应根据需求合理使用。

自定义图形对象

创建自定义 Artist 对象

在 Matplotlib 中,Artist 是所有可视化对象(如图形、文本、线条等)的基类。通过创建自定义 Artist 对象,您可以实现高度定制化的可视化效果。自定义 Artist 对象通常用于需要特殊绘图逻辑的场景。下面是如何创建和使用自定义 Artist 对象的详细步骤。

导入必要的模块

首先,确保导入 Matplotlib 的基础模块和 Artist 类。

import matplotlib.pyplot as plt
from matplotlib.artist import Artist

定义自定义 Artist 类

创建一个类继承自 Artist,并实现其绘制逻辑。

class MyCustomArtist(Artist):
    def __init__(self, x, y, size=10, color='red'):
        super().__init__()
        self.x = x
        self.y = y
        self.size = size
        self.color = color

    def draw(self, renderer):
        # 这里实现自定义的绘制逻辑
        gc = renderer.new_gc()
        gc.set_foreground(self.color)
        renderer.draw_circle(gc, self.x, self.y, self.size)
        gc.restore()

在这个示例中,MyCustomArtist 类定义了一个简单的自定义 Artist,绘制一个圆圈。draw 方法实现了实际的绘图逻辑,其中 renderer 是 Matplotlib 用于绘制图形的渲染器对象。

使用自定义 Artist

创建一个 Matplotlib 图形并将自定义 Artist 添加到其中。

fig, ax = plt.subplots()

# 创建并添加自定义 Artist 对象
custom_artist = MyCustomArtist(0.5, 0.5, size=0.1, color='blue')
ax.add_artist(custom_artist)

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
plt.title("Custom Artist Example")
plt.show()

自定义 Artist 的应用场景

  • 特殊标记和符号:可以用来绘制特殊的标记和符号,这些标记可能在标准 Matplotlib 中无法直接绘制。
  • 高性能绘图:在需要频繁更新或大量绘制对象的场景下,定制 Artist 可以实现更高效的绘图。
  • 复杂图形:当标准的绘图函数无法满足需求时,自定义 Artist 可以帮助实现复杂的绘图逻辑。

注意事项

  • 性能考虑:在实现 draw 方法时,应尽量优化绘图逻辑,避免不必要的计算和渲染。
  • 交互性:自定义 Artist 需要手动处理交互性(如点击事件),因为默认的事件处理可能无法识别自定义对象。
  • 渲染器接口:了解 Matplotlib 的渲染器接口有助于更好地实现自定义绘图逻辑。

通过创建自定义 Artist 对象,您可以在 Matplotlib 中实现高度定制化的可视化效果,满足特殊的绘图需求。无论是用于科学研究还是数据分析,自定义 Artist 都能帮助您更好地表达数据的特征和规律。

使用 Patch 和 Line2D 创建图形元素

在 Matplotlib 中,Patch 和 Line2D 是两个常用的基础类,用于创建各种图形元素。Patch 通常用于绘制形状,如矩形、圆形、多边形等,而 Line2D 用于绘制线条。通过这两个类,可以创建复杂的自定义图形。下面是如何使用 Patch 和 Line2D 创建图形元素的详细介绍。

使用 Patch 创建图形元素

Patch 是一个基类,许多形状如矩形、圆形、多边形等都是其子类。以下是一些常用的 Patch 子类及其用法。

矩形(Rectangle)

import matplotlib.pyplot as plt
import matplotlib.patches as patches

fig, ax = plt.subplots()

# 创建矩形 Patch
rect = patches.Rectangle((0.1, 0.1), 0.5, 0.3, linewidth=1, edgecolor='r', facecolor='none')
ax.add_patch(rect)

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
plt.title("Rectangle Patch Example")
plt.show()

圆形(Circle)

# 创建圆形 Patch
circle = patches.Circle((0.5, 0.5), 0.2, color='blue', alpha=0.5)
ax.add_patch(circle)

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
plt.title("Circle Patch Example")
plt.show()

多边形(Polygon)

# 创建多边形 Patch
polygon = patches.Polygon([[0.2, 0.2], [0.4, 0.6], [0.6, 0.2]], closed=True, color='green')
ax.add_patch(polygon)

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
plt.title("Polygon Patch Example")
plt.show()

使用 Line2D 创建线条元素

Line2D 是用于绘制线条的类,通常不直接使用,而是通过 plot 函数间接创建。但也可以手动创建 Line2D 对象以实现更灵活的控制。

from matplotlib.lines import Line2D

fig, ax = plt.subplots()

# 创建Line2D对象
line = Line2D([0, 1], [0, 1], linewidth=2, color='purple')
ax.add_line(line)

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
plt.title("Line2D Example")
plt.show()

综合示例

结合Patch和Line2D创建复杂图形。

fig, ax = plt.subplots()

# 添加矩形
rect = patches.Rectangle((0.1, 0.1), 0.5, 0.3, linewidth=1, edgecolor='r', facecolor='none')
ax.add_patch(rect)

# 添加圆形
circle = patches.Circle((0.5, 0.5), 0.2, color='blue', alpha=0.5)
ax.add_patch(circle)

# 添加多边形
polygon = patches.Polygon([[0.2, 0.2], [0.4, 0.6], [0.6, 0.2]], closed=True, color='green')
ax.add_patch(polygon)

# 添加线条
line = Line2D([0, 1], [0.5, 0.5], linewidth=2, color='purple')
ax.add_line(line)

ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
plt.title("Combined Patch and Line2D Example")
plt.show()

参考链接:

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注