介�

Matplotlib �能是 Python 2D-绘图领域使用最广泛的套件。它能让使用者很轻�地将数�图形化,并且�供多样化的输出格�。这里将会探索 matplotlib 的常�用法。

IPython 以� pylab 模�

IPython 是 Python 的一个增强版本。它在下列方�有所增强:命�输入输出�使用系统命令(shell commands)�排错(debug)能力。我们在命令行终端给 IPython 加上�数 -pylab (0.12 以�的版本是 --pylab)之�,就�以� Matlab 或者 Mathematica 那样以交互的方�绘图。

pylab

pylab 是 matplotlib ��对象绘图库的一个接�。它的语法和 Matlab �分相近。也就是说,它主�的绘图命令和 Matlab 对应的命令有相似的�数。

本篇文章使用的实例��下载:

Download

下载包包�两个目录:

  • figures:存放实例代ç �生æˆ�的图片
  • scripts:存放实例代ç �

�级绘制

这一节中,我们将从简到�:先�试用默认�置在�一张图上绘制正弦和余弦函数图�,然��步美化它。

第一步,是�得正弦函数和余弦函数的值:

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 和 S 则分别是这 256 个值对应的余弦和正弦函数值组�的 numpy 数组。

你�以在 IPython 的交互模�下测试代�,也�以下载代�(下载链接就是这些示例图),然�执行:

python exercise_1.py

使用默认�置[��文件]

Matplotlib 的默认�置都�许用户自定义。你�以调整大多数的默认�置:图片大�和分辨率(dpi)�线宽�颜色�风格��标轴��标轴以�网格的属性�文字与字体属性等。�过,matplotlib 的默认�置在大多数情况下已��得足够好,你�能�在很少的情况下�会想更改这些默认�置。

import numpy as np
import matplotlib.pyplot as plt

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

plt.plot(X,C)
plt.plot(X,S)

plt.show()

默认�置的具体内容[��文件]

下�的代�中,我们展现了 matplotlib 的默认�置并辅以注释说明,这部分�置包�了有关绘图样�的所有�置。代�中的�置与默认�置完全相�,你�以在交互模�中修改其中的值�观察效果。

# 导入 matplotlib 的所有内容(nympy �以用 np 这个�字�使用)
from pylab import *

# 创建一个 8 * 6 点(point)的图,并设置分辨率为 80
figure(figsize=(8,6), dpi=80)

# 创建一个新的 1 * 1 的�图,接下�的图样绘制在其中的第 1 �(也是唯一的一�)
subplot(1,1,1)

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

# 绘制余弦曲线,使用�色的�连续的�宽度为 1 (�素)的线�
plot(X, C, color="blue", linewidth=1.0, linestyle="-")

# 绘制正弦曲线,使用绿色的�连续的�宽度为 1 (�素)的线�
plot(X, S, color="green", linewidth=1.0, linestyle="-")

# 设置横轴的上下�
xlim(-4.0,4.0)

# 设置横轴记�
xticks(np.linspace(-4,4,9,endpoint=True))

# 设置纵轴的上下�
ylim(-1.0,1.0)

# 设置纵轴记�
yticks(np.linspace(-1,1,5,endpoint=True))

# 以分辨率 72 ��存图片
# savefig("exercice_2.png",dpi=72)

# 在�幕上显示
show()

改�线�的颜色和粗细[��文件]

首先,我们以�色和红色分别表示余弦和正弦函数,而�将线��粗一点。接下�,我们在水平方�拉伸一下整个图。

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

设置图片边界[��文件]

当�的图片边界设置得�好,所以有些地方看得�是很清楚。

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

更好的方�是这样:

xmin ,xmax = X.min(), X.max()
ymin, ymax = Y.min(), Y.max()

dx = (xmax - xmin) * 0.2
dy = (ymax - ymin) * 0.2

xlim(xmin - dx, xmax + dx)
ylim(ymin - dy, ymax + dy)

设置记�[��文件]

我们讨论正弦和余弦函数的时候,通常希望知�函数在 ±π 和 ±π2 的值。这样看�,当�的设置就�那么�想了。

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

设置记�的标签[��文件]

记�现在没问题了,�过标签��大符�期望。我们�以把 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$'])
...

移动脊柱[��文件]

�标轴线和上�的记�连在一起就形�了脊柱(Spines,一�线段上有一系列的凸起,是�是很�脊柱骨啊~),它记录了数�区域的范围。它们�以放在任��置,�过至今为止,我们都把它放在图的四边。

实际上�幅图有四�脊柱(上下左�),为了将脊柱放在图的中间,我们必须将其中的两�(上和�)设置为无色,然�调整剩下的两�到�适的�置——数�空间的 0 点。

...
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))
...

添加图例[��文件]

我们在图的左上角添加一个图例。为此,我们�需�在 plot 函数里以「键 - 值�的形�增加一个�数。

...
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')
...

给一些特殊点�注释[��文件]

我们希望在 2π/3 的�置给两�函数曲线加上一个注释。首先,我们在对应的函数图��置上画一个点;然�,�横轴引一�垂线,以虚线标记;最�,写上标签。

...

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"))
...

精益求精[��文件]

�标轴上的记�标签被曲线挡�了,作为强迫症患者(雾)这是�能�的。我们�以把它们放大,然�添加一个白色的��明底色。这样�以��标签和曲线�时��。

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

图���图��标轴和记�

到目�为止,我们都用��的方法�绘制图�和�标轴。快速绘图中,这是很方便的。我们也�以显�地控制图���图��标轴。Matplotlib 中的「图��指的是用户界�看到的整个窗�内容。在图�里�有所谓「�图�。�图的�置是由�标网格确定的,而「�标轴����此�制,�以放在图�的任��置。我们已���地使用过图�和�图:当我们调用 plot 函数的时候,matplotlib 调用 gca() 函数以� gcf() 函数�获�当�的�标轴和图�;如果无法获�图�,则会调用 figure() 函数�创建一个——严格地说,是用 subplot(1,1,1) 创建一个�有一个�图的图�。

图�

所谓「图��就是 GUI 里以「Figure #�为标题的那些窗�。图�编�从 1 开始,与 MATLAB 的风格一致,而于 Python 从 0 开始编�的风格��。以下�数是图�的属性:

�数默认值�述
num1图�的数�
figsizefigure.figsize图�的长和宽(英寸)
dpifigure.dpi分辨率(点/英寸)
facecolorfigure.facecolor绘图区域的背景颜色
edgecolorfigure.edgecolor绘图区域边缘的颜色
frameonTrue是�绘制图�边缘

这些默认值�以在�文件中指明。�过除了图�数�这个�数,其余的�数都很少修改。

你在图形界�中�以按下�上角的 X �关闭窗�(OS X 系统是左上角)。Matplotlib 也�供了�为 close 的函数�关闭这个窗�。close 函数的具体行为�决于你�供的�数:

  1. �传递�数:关闭当�窗�;
  2. 传递窗�编�或窗�实例(instance)作为�数:关闭指定的窗�;
  3. all:关闭所有窗�。

和其他对象一样,你�以使用 setp 或者是 set_something 这样的方法�设置图�的属性。

�图

你�以用�图�将图样(plot)放在�匀的�标网格中。用 subplot 函数的时候,你需�指明网格的行列数�,以�你希望将图样放在哪一个网格区域中。此外,gridspec 的功能更强大,你也�以选择它�实现这个功能。

[��文件]

[��文件]

[��文件]

[��文件]

�标轴

�标轴和�图功能类似,�过它�以放在图�的任��置。因此,如果你希望在一副图中绘制一个�图,就�以用这个功能。

[��文件]

[��文件]

记�

良好的记�是图�的��组�部分。Matplotlib 里的记�系统里的�个细节都是�以由用户个性化�置的。你�以用 Tick Locators �指定在那些�置放置记�,用 Tick Formatters �调整记�的样�。主�和次�的记��以以��的方�呈现。默认情况下,�一个次�的记�都是��的,也就是说,默认情况下的次�记�列表是空的——NullLocator。

Tick Locators

下�有为��需求设计的一些 Locators。

类型 说明
NullLocator No ticks.
IndexLocator Place a tick on every multiple of some base number of points plotted.
FixedLocator Tick locations are fixed.
LinearLocator Determine the tick locations.
MultipleLocator Set a tick on every integer that is multiple of some base.
AutoLocator Select no more than n intervals at nice locations.
LogLocator Determine the tick locations for log axes.

这些 Locators 都是 matplotlib.ticker.Locator 的�类,你�以�此定义自己的 Locator。以日期为 ticks 特别��,因此 Matplotlib �供了 matplotlib.dates �实现这一功能。

其他类型的图

接下�的内容是练习。请�用你学到的知识,从�供的代�开始,实现�图所示的效果。具体的答案�以点击�图下载。

普通图[��文件]

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()

散点图[��文件]

from pylab import *

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

scatter(X,Y)
show()

�形图[��文件]

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()

等高线图[��文件]

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()

�度图(Imshow)[��文件]

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()

饼状图[��文件]

from pylab import *

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

�场图(Quiver Plots)[��文件]

from pylab import *

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

网格[��文件]

from pylab import *

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

show()

多�网格[��文件]

from pylab import *

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

show()

�轴图[��文件]

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()

3D 图[��文件]

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()

手稿图[��文件]

import numpy as np
import matplotlib.pyplot as plt

eqs = []
eqs.append((r"$W^{3\beta}_{\delta_1 \rho_1 \sigma_2} = U^{3\beta}_{\delta_1 \rho_1} + \frac{1}{8 \pi 2} \int^{\alpha_2}_{\alpha_2} d \alpha^\prime_2 \left[\frac{ U^{2\beta}_{\delta_1 \rho_1} - \alpha^\prime_2U^{1\beta}_{\rho_1 \sigma_2} }{U^{0\beta}_{\rho_1 \sigma_2}}\right]$"))
eqs.append((r"$\frac{d\rho}{d t} + \rho \vec{v}\cdot\nabla\vec{v} = -\nabla p + \mu\nabla^2 \vec{v} + \rho \vec{g}$"))
eqs.append((r"$\int_{-\infty}^\infty e^{-x^2}dx=\sqrt{\pi}$"))
eqs.append((r"$E = mc^2 = \sqrt{{m_0}^2c^4 + p^2c^2}$"))
eqs.append((r"$F_G = G\frac{m_1m_2}{r^2}$"))


plt.axes([0.025,0.025,0.95,0.95])

for i in range(24):
    index = np.random.randint(0,len(eqs))
    eq = eqs[index]
    size = np.random.uniform(12,32)
    x,y = np.random.uniform(0,1,2)
    alpha = np.random.uniform(0.25,.75)
    plt.text(x, y, eq, ha='center', va='center', color="#11557c", alpha=alpha,
             transform=plt.gca().transAxes, fontsize=size, clip_on=True)

plt.xticks([]), plt.yticks([])
# savefig('../figures/text_ex.png',dpi=48)
plt.show()

更多�考

入门教程

Matplotlib 文档

Numpy 文档

原文:http://www.loria.fr/~rougier/teaching/matplotlib/

译文:http://liam0205.me/2014/09/11/matplotlib-tutorial-zh-cn/