编码训练:Matplotlib指南

本小子最近这几天在做一个关于Python科学计算方面的讲稿,做完Python简介部分后,核心的关于科学计算部分烦难了。编程语言这东西,讲起来着实不是一件好差事。想当年本小子大一上C课程的时候,叫我们C的老师绝对是催眠的好手,一堂课还没上到半个小时,下面听趴一片,那时绝对的NB。所以,本小子想通过一些具体的实例,结合实验室研究方向做一些Python方面的介绍与演示。Python科学计算这部分,其实自己了解得不多,而且国内关于这方面的中文资料更是少之又少。今天在查Matplotlib模块时,发觉了一个不错的译文资料。这么好的译文资料,竟然雪藏了。那个Python八荣八耻最后一条怎么说来着,“以总结分享为荣”,本小子偷偷地把它扒过来了,又犯罪了,囧。不过,本小子还是需要再一次的郑重申明,本译文来自[Reverland的知行阁]

翻译自:Matplotlib tutorialNicolas P. Rougier - Euroscipy 2012

这个教程基于可以从scipy lecture note得到的 Mike Müller的教程

源代码可从这里获得。图像在figures文件夹内,所有的脚本位于scripts文件夹。

所有的代码和材料以Creative Commons Attribution 3.0 United States License (CC-by)发布。

特别感谢Bill Wing和Christoph Deil的检查和校正。

引言

matplotlib大概是被使用最多的二维绘图Python包。它不仅提供一个非常快捷的用python可视化数据的方法,而且提供了出版质量的多种格式图像。我们将要探索matplotlib包含最常见情况的交互模式。

Ipython 和 pylab模式

IPython是一个增强的Python交互shell,它拥有很多有趣的特性包括被命名的输入与输出,可使用shell命令,增强的调试和许多其它特性。当我们在命令参数中用-pylab(自从IPython0.12版变成--pylab),它容许交互的matplotlib会话有像Matlab/Mathematica样的功能。

pylab

pylab提供了一个针对matplotlib面向对象绘图库的程序界面。它模仿Matlab(TM)开发。因此,pylab大部分的绘图命令和参数和Matlab(TM)相似。重要的命令被交互示例解释。

简单绘图

在这一部分,我们想在同一个图片中绘制正弦和余弦函数。从默认设置开始,我们将一步一步地改进使它看上去更棒。

首先获得正弦和余弦函数的数据:

from pylab import *

X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
C,S = np.cos(X), np.sin(X)

X现在是一个numpy数组,包含从-π到+π(包含π)等差分布的256个值。C是正弦(256个值),S是余弦(256个值)。

运行这个例子,你可以在IPython交互会话键入它们

[[email protected] ~]$ ipython2 --pylab
Python 2.7.3 (default, Apr 24 2012, 00:00:54)
Type "copyright", "credits" or "license" for more information.

IPython 0.13 -- An enhanced Interactive Python.
?         -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help      -> Python's own help system.
object?   -> Details about 'object', use 'object??' for extra details.

Welcome to pylab, a matplotlib-based Python environment [backend: Qt4Agg].
For more information, type 'help(pylab)'.

或者你可以下载每个示例然后使用普通的的python运行它:

$ python exercice_1.py

你可以点击相应图片的获得每一步的源码。

使用默认

using defaults

matplotlib有一套允许定制各种属性的默认设置。你可以几乎控制matplotlib中的每一个默认属性:图像大小,每英寸点数,线宽,色彩和样式,子图(axes),坐标轴和网格属性,文字和字体属性,等等。虽然matplotlib的默认设置在大多数情况下相当好,你却可能想要在一些特别的情形下更改一些属性。

from pylab import *

X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
C,S = np.cos(X), np.sin(X)

plot(X,C)
plot(X,S)

show()

示例默认

using defaults

在以下脚本中,我们示例(并注释)所有影响图像外观的图像设定。这些设定被显式地设置成它们的默认值,但是现在你可以交互地尝试这些值来探索它们的作用(参考之后的线条属性线条样式)。

# Import everything from matplotlib (numpy is accessible via 'np' alias)
from pylab import *

# Create a new figure of size 8x6 points, using 80 dots per inch
figure(figsize=(8,6), dpi=80)

# Create a new subplot from a grid of 1x1
subplot(1,1,1)

X = np.linspace(-np.pi, np.pi, 256,endpoint=True)
C,S = np.cos(X), np.sin(X)

# Plot cosine using blue color with a continuous line of width 1 (pixels)
plot(X, C, color="blue", linewidth=1.0, linestyle="-")

# Plot sine using green color with a continuous line of width 1 (pixels)
plot(X, S, color="green", linewidth=1.0, linestyle="-")

# Set x limits
xlim(-4.0,4.0)

# Set x ticks
xticks(np.linspace(-4,4,9,endpoint=True))

# Set y limits
ylim(-1.0,1.0)

# Set y ticks
yticks(np.linspace(-1,1,5,endpoint=True))

# Save figure using 72 dots per inch
# savefig("exercice_2.png",dpi=72)

# Show result on screen
show()

更改色彩和线宽

using defaults

首先,我们想要余弦是蓝色而正弦是红色,它们的线条都稍厚一点。我们将也稍微更改图片大小来使它更宽一点。

figure(figsize=(10,6), dpi=80)
plot(X, C, color="blue", linewidth=2.5, linestyle="-")
plot(X, S, color="red",  linewidth=2.5, linestyle="-")

设置边界

using defaults

当前的图像边界有点太紧了一点,而且我们想要预留一点空间使数据点更清晰。

xlim(X.min()*1.1, X.max()*1.1)
ylim(C.min()*1.1, C.max()*1.1)

设置刻度

using defaults

当前刻度并不理想,因为它们不显示正余弦中我们感兴趣的值(+/-π,+/-π/2)。我们将更改它们让它们只显式这些值。

xticks( [-np.pi, -np.pi/2, 0, np.pi/2, np.pi])
yticks([-1, 0, +1])

设置刻度标签

using defaults

刻度已经放置合适但是他们的标签并不很清楚,我们可以猜出3.142是π但是最好让它更直接。当我们设置刻度值时,我们也可以在第二个参数列表中提供相应的标签。注意,我们用latex获得更好渲染的标签。

xticks([-np.pi, -np.pi/2, 0, np.pi/2, np.pi],
       [r'$-\pi$', r'$-\pi/2$', r'$0$', r'$+\pi/2$', r'$+\pi$'])

yticks([-1, 0, +1],
       [r'$-1$', r'$0$', r'$+1$'])

移动轴线(spine)

using defaults

轴线(spines)是连接刻度标志和标示数据区域边界的线。它们现在可以被放置在任意地方,它们在子图的边缘。我们将改变这点,因为我们想让它们位于中间。因为一共有四个轴线(上/下/左/右)。我们将通过将它们的颜色设置成None,舍弃位于顶部和右部轴线。然后我们把底部和左部的轴线移动到数据空间坐标中的零点。

ax = gca()
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))

添加图例

using defaults

让我们在图片左上角添加一个图例。这仅仅需要向plot命令添加关键字参数label(之后将被图例框使用)。

plot(X, C, color="blue", linewidth=2.5, linestyle="-", label="cosine")
plot(X, S, color="red",  linewidth=2.5, linestyle="-", label="sine")

legend(loc='upper left')

注解某些点

using defaults

让我们现在使用annotate命令注解一些我们感兴趣的点。我们选择2π/3作为我们想要注解的正弦和余弦值。我们将在曲线上做一个标记和一个垂直的虚线。然后,使用annotate命令来显示一个箭头和一些文本。

t = 2*np.pi/3
plot([t,t],[0,np.cos(t)], color ='blue', linewidth=2.5, linestyle="--")
scatter([t,],[np.cos(t),], 50, color ='blue')

annotate(r'$sin(\frac{2\pi}{3})=\frac{\sqrt{3}}{2}$',
		 xy=(t, np.sin(t)), xycoords='data',
		 xytext=(+10, +30), textcoords='offset points', fontsize=16,
		 arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

plot([t,t],[0,np.sin(t)], color ='red', linewidth=2.5, linestyle="--")
scatter([t,],[np.sin(t),], 50, color ='red')

annotate(r'$cos(\frac{2\pi}{3})=-\frac{1}{2}$',
		 xy=(t, np.cos(t)), xycoords='data',
		 xytext=(-90, -50), textcoords='offset points', fontsize=16,
		 arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.2"))

魔鬼在于细节

using defaults

由于蓝色和红色的线,刻度标签现在很难看清。。我们可以让它们更大并且调整它们的属性使它们的背景半透明。这将让我们把数据和标签都看清。

for label in ax.get_xticklabels() + ax.get_yticklabels():
	label.set_fontsize(16)
	label.set_bbox(dict(facecolor='white', edgecolor='None', alpha=0.65 ))

图像,子区,子图,刻度(Figures,Subplots,Axes,Ticks)

Note:这一段很绕,我不知道该怎么翻译好。在matplotlib中axes容器处于核心地位。翻译成子图因为在《Python科学计算》中作者这样称呼.subplot翻译成子区

目前我们已经隐式地使用了图像(figure)和子图(axes)的创建。这对快速绘图很方便。我们通过显式使用figure,subplot,axes可以控制更多图像的呈现。一个图像(figure)意味着用户界面的整个窗口。在一个图像中可以有些子区(subplot)。subplot将绘图放置在常规的网格位置上而axes允许更自由的放置。它们都非常有用,取决于你的意图。我们已经隐式地使用了figure和subplot。当我们调用plot时,matplotlib调用gca来获取当前axes反过来调用gcf()获取当前图像(figure)。如果没有当前图像(figure),它调用figure()创建一个,严格地说,是创建一个subplot(111)。让我们详细看看。

图像(Figure)

图像是一个图形用户界面的窗口,以”Figure #”作为标题。相对于Python通常是0索引的,图像是从一开始的。这显然是matlab风格。这里有几个决定图像外观的参数:

参数 默认 描述
num 1 图像编号
figsize figure.figsize 图像大小(宽度,高度)(英寸)
dpi figure.dpi 每英寸分辨率
facecolor figure.facecolor 背景色
edgecolor figure.edgecolor 绘图背景边沿色
frameon True 绘制框架与否

默认可以在资源文件1指定,并将在大多数时间被使用。只有图像的编号频繁变动。

当你使用图形用户界面时,你可以通过点击右上角2x来关闭一个图像。但也可以用一种编程方式调用close来关闭一个图像。取决于参数它关闭(1)当前图像(无参数),(2)一个指定的图像(以图像编号或图像实例作为参数),(3)所有图像(以all作为参数)。

和其它对象一样,你可以通过setpset_somethin方法来设置图像属性。

子区(subplots)

using defaults

using defaults

using defaults

你可以通过subplot在正常网格中布置图像。你需要指定行数和列数和区域的编号。注意gridspec命令是个更强大的选择。

子图(axes)

using defaults

using defaults

using defaults

子图和子区(subplot)非常相似,但是允许把图片放置到图像(figure)中的任何地方。所以如果我们想要在一个大图片中嵌套一个小点的图片,我们通过子图(axes)来完成它。

刻度(ticks)

良好格式化的刻度是准备发表的图片中的重要部分。Matplotlib为刻度提供完全可配置的系统。刻度定位器指定刻度出现的位置,刻度格式器让刻度看起来如你所愿。主刻度和次要刻度可以分别放置和格式化,每个默认主刻度并不显示,也就是,它们只有一个空列表,因为它们作为空定位器(NullLocator)(参见下面)。

刻度定位器(Tick Locator)

这有几个针对不同种类需求的各种定位器:

Class Description
NullLocator 没有刻度.
 
IndexLocator 每到一个基数的倍数点放置一个刻度
 
FixedLocator 刻度位置是固定的
 
LinearLocator 决定刻度位置
 
MultipleLocator 在每个基于基数倍数的整数点放置刻度
 
AutoLocator 在不错的位置选择不超过n个间隔
 
LogLocator 以log坐标决定刻度位置
 

所有这些定位器源于matplotlib基类matplotlib.ticker.Locator。你可以源于它创建你自己的定位器。处理时间刻度可能非常棘手。因此,matplotlib在matplotlib.dates中提供了特殊的定位器。

其它种类绘图

常规绘图

reguler plots

从下面的代码开始,尝试重新生成上边的填充图形。

from pylab import *

n = 256
X = np.linspace(-np.pi,np.pi,n,endpoint=True)
Y = np.sin(2*X)

plot (X, Y+1, color='blue', alpha=1.00)
plot (X, Y-1, color='blue', alpha=1.00)
show()

提示:你需要使用fill_between命令。

点击图片获取答案。

散点图(scatter plots)

reguler plots

从以下代码开始,尝试生成上边的图形,注意标记大小,颜色和透明度。

from pylab import *

n = 1024
X = np.random.normal(0,1,n)
Y = np.random.normal(0,1,n)

scatter(X,Y)
show()

提示:色彩由(X,Y)角度给出。

点击图像获取答案。

条形图(bar plots)

reguler plots

从以下代码开始,尝试生成上边的图形,添加标签和红色条形。

from pylab import *

n = 12
X = np.arange(n)
Y1 = (1-X/float(n)) * np.random.uniform(0.5,1.0,n)
Y2 = (1-X/float(n)) * np.random.uniform(0.5,1.0,n)

bar(X, +Y1, facecolor='#9999ff', edgecolor='white')
bar(X, -Y2, facecolor='#ff9999', edgecolor='white')

for x,y in zip(X,Y1):
	text(x+0.4, y+0.05, '%.2f' % y, ha='center', va= 'bottom')

ylim(-1.25,+1.25)
show()

提示:你要注意文本对齐。

点击图像获取答案。

等高线图(contour plots)

reguler plots

从以下代码开始,尝试生成上边的图形,注意色彩表。(参见色彩表)

from pylab import *

def f(x,y): return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2)

n = 256
x = np.linspace(-3,3,n)
y = np.linspace(-3,3,n)
X,Y = np.meshgrid(x,y)

contourf(X, Y, f(X,Y), 8, alpha=.75, cmap='jet')
C = contour(X, Y, f(X,Y), 8, colors='black', linewidth=.5)
show()

提示:你需要使用clabel命令。

点击图像获取答案。

Imshow

reguler plots

从以下代码开始,尝试生成上边的图形,添加标签和红色条形。

from pylab import *

def f(x,y): return (1-x/2+x**5+y**3)*np.exp(-x**2-y**2)

n = 10
x = np.linspace(-3,3,4*n)
y = np.linspace(-3,3,3*n)
X,Y = np.meshgrid(x,y)
imshow(f(X,Y)), show()

提示:你需要注意imshow命令中图像的_来源_,并且使用色彩条(colorbar)。

点击图像获取答案。

饼图(Pie charts)

reguler plots

从以下代码开始,尝试生成上边的图形,添加标签和红色条形。

from pylab import *

n = 20
Z = np.random.uniform(0,1,n)
pie(Z), show()

提示:你需要改变Z。

点击图像获取答案。

矢量图(quiver plots)

reguler plots

从以下代码开始,尝试生成上边的图形,注意色彩和方向。

from pylab import *

n = 8
X,Y = np.mgrid[0:n,0:n]
quiver(X,Y), show()

提示:你需要画两次箭头。

点击图像获取答案。

网格(grids)

reguler plots

从以下代码开始,尝试生成上边的图形,添加标签和红色条形。

from pylab import *

axes = gca()
axes.set_xlim(0,4)
axes.set_ylim(0,3)
axes.set_xticklabels([])
axes.set_yticklabels([])

show()

点击图像获取答案。

多图绘制

reguler plots

从以下代码开始,尝试生成上边的图形,添加标签和红色条形。

from pylab import *

subplot(2,2,1)
subplot(2,2,3)
subplot(2,2,4)

show()

提示:你可以对不同部分使用几个subplot命令。

点击图像获取答案。

极轴图

reguler plots

从以下代码开始,尝试生成上边的图形,添加标签和红色条形。

from pylab import *

axes([0,0,1,1])

N = 20
theta = np.arange(0.0, 2*np.pi, 2*np.pi/N)
radii = 10*np.random.rand(N)
width = np.pi/4*np.random.rand(N)
bars = bar(theta, radii, width=width, bottom=0.0)

for r,bar in zip(radii, bars):
	bar.set_facecolor( cm.jet(r/10.))
	bar.set_alpha(0.5)

show()

提示:你仅仅需要修改_axes_这行。

点击图像获取答案。

三维绘图

reguler plots

从以下代码开始,尝试生成上边的图形,添加标签和红色条形。

from pylab import *
from mpl_toolkits.mplot3d import Axes3D

fig = figure()
ax = Axes3D(fig)
X = np.arange(-4, 4, 0.25)
Y = np.arange(-4, 4, 0.25)
X, Y = np.meshgrid(X, Y)
R = np.sqrt(X**2 + Y**2)
Z = np.sin(R)

ax.plot_surface(X, Y, Z, rstride=1, cstride=1, cmap='hot')

show()

提示:你需要使用contourf命令。

点击图像获取答案。

绘制文本

reguler plots

试着从头做这个!提示:看一看matplotlib logo

点击图像获取答案。

此教程之外

matplotlib受益于丰富的文档和巨大的用户和开发者社区。这有几个有关的链接:

教程

pyplot教程

图像教程

文本教程

artist对象教程

路径教程

变换教程

matplotlib文档

用户手册

常见问题

截图

代码文档

代码相当好的文档化了,你可以在python会话中快速查询指定命令

>>> from pylab import *
>>> help(plot)
Help on function plot in module matplotlib.pyplot:

plot(*args, **kwargs)
   Plot lines and/or markers to the
   :class:`~matplotlib.axes.Axes`.  *args* is a variable length
   argument, allowing for multiple *x*, *y* pairs with an
   optional format string.  For example, each of the following is
   legal::

	 plot(x, y)         # plot x and y using default line style and color
	 plot(x, y, 'bo')   # plot x and y using blue circle markers
	 plot(y)            # plot y using x as index array 0..N-1
	 plot(y, 'r+')      # ditto, but with red plusses

   If *x* and/or *y* is 2-dimensional, then the corresponding columns
   will be plotted.

画廊(Galleries)

当你搜寻如何绘制指定图像时,matplotlib gallery也相当有用。每个例子和它的源码一同被提供。

一个较小的画廊在这里

邮件列表

最后,这里有一个用户邮件列表,那里你可以寻求帮助。一个开发者邮件列表是更加技术性的。

快速参考

没什么好翻译的,看原文吧……传送门

线条属性

线型

标记

色彩表


  1. 资源文件? 

  2. 有时是左上角 

请我喝杯咖啡

取消

感谢您的支持,我会继续写出更优秀的文章!

扫码支持
扫码支持
请我喝杯咖啡

打开微信扫一扫,即可进行扫码打赏哦

comments powered by Disqus