本案例会对matplotlib的基本操作进行详细介绍,熟悉其核心概念,才能更好的使用python相关可视化工具,不仅仅是matplotlib,还包括许多基于matplotlib开发的第三方可视化工具。

1. Pyplot
2. 调整图线属性——美化
3. 多图和多轴绘制
4. 添加文本
5. 对数坐标轴及其他非线性坐标轴
6. 设置全局渲染方式
后记:如何在图形中显示中文?

1. Pyplot

matplotlib.pyplot是使matplotlib像MATLAB一样工作的函数的集合。每个pyplot函数都会对图形进行一些更改:例如,创建一个图形,在图形中创建一个绘图区域,在绘图区域中绘制一些线条,用标签装饰该绘图等等。

In [ ]:
import matplotlib.pyplot as plt
plt.plot([1,2,3,40])
plt.xlabel('xlabel')
plt.show()
In [ ]:
import matplotlib.pyplot as plt
%matplotlib inline
plt.plot([1,2,3,4])

您可能想知道为什么x轴的范围是0-3,y轴的范围是1-4。如果您向plot()命令提供单个列表或数组,则假定它是一系列值,并为您自动生成x值。由于python范围从0开始,默认的x向量与y的长度相同,但是以0开始。因此x数据是[0,1,2,3]。

plot()是一个多功能的命令,可以对任意的数据对进行绘制。例如,要绘制x对y,您可以调用以下命令:

In [ ]:
plt.plot([1, 2, 3, 4], [1, 4, 9, 16])

对于每个x,y对参数,还有第三个可选的参数,它可以用格式字符串的形式指定图的颜色和线的样式。字符串格式的字母和符号来自MATLAB,并且将一个用于指定图的颜色的字符串与一个指定线型的字符串连接起来。默认的格式字符串是'b-',这是一个实心的蓝线。例如,如果想要绘制红色实心点,则可以使用以下命令:

In [ ]:
plt.plot([1, 2, 3, 4], [1, 4, 9, 16], 'ro')
plt.xlim([0, 5])
plt.ylim([0, 20])

可以随时参阅plot()文档以获取线条样式和格式字符串的完整列表。但是上图有两个点看不清楚,所以必须要调整轴的可视窗口,即通过移动坐标轴范围把点从边缘往中间移。

使用axis()命令可以调整[xmin,xmax,ymin,ymax]列表指定轴的视口(viewport)。

如果matplotlib仅限于使用列表,那么对于数字处理来说是相当无用的。通常我们使用的将多的数据格式是numpy数组ndarray。实际上,所有的序列都在内部转换为了numpy数组。下面的示例显示了使用数组在一个命令中绘制具有不同格式的多个散点图。

In [ ]:
import numpy as np

t = np.arange(0, 5, 0.2)
plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^')
plt.show()

2. 调整图线属性——美化

线条有许多可以设置的属性:线宽,短线风格,抗锯齿等等,有以下几种方法来设置线条属性。

1 使用关键词传参:

In [ ]:
plt.plot(t, t**2, linewidth=2.0)

2 调用Line2D实例的一些设置相关的方法。plot返回了一系列Line2D对象,如line1,line2 = plot(x1,y1,x2,y2)

In [ ]:
line1, line2 = plt.plot(t, t**2, 'b-', t, t**3, 'b-')
line1.set_antialiased(False) # 关闭抗锯齿

3 使用setp()命令。下面的例子使用MATLAB风格的命令设置多个属性。setp非常透明地对多个对象或单个对象进行设置。你可以使用python关键字参数传入的方式或MATLAB风格的字符串/值对进行设置:

In [ ]:
lines = plt.plot(t, t**2, t, t**3)

# 使用关键字参数
plt.setp(lines, color='r', linewidth=3.0)

# 使用MATLAB风格string-value方式进行设置
plt.setp(lines, 'color', 'r', 'linewidth', '3.0')

更多的设置请参阅matplotlib.lines.Line2D

也可以调用setp()查看所有可以设置的图线属性:

In [ ]:
plt.setp(lines)

3. 多图和多轴绘制

MATLAB和pyplot具有当前图形(current figure)和当前轴(current axes)的概念。记住,一个图中可以有多个轴,每个图线都在一定轴范围内进行绘制。所有绘图命令都只适用于当前轴。函数gca()将返回当前轴(一个matplotlib.axes.Axes实例),gcf()将返回当前图(一个matplotlib.figure.Figure实例)。 通常情况下,你不必担心这一点,因为这一切都是在幕后进行的,你常常感觉不到。下面是我们先创建两个子图:

In [ ]:
import numpy as np
import matplotlib.pyplot as plt

def f(t):
    return np.exp(-t) * np.cos(2*np.pi*t)

t1 = np.arange(0.0, 5.0, 0.1)
t2 = np.arange(0.0, 5.0, 0.02)

plt.figure(1)
plt.subplot(211)
plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')

plt.subplot(212)
plt.plot(t2, np.cos(2*np.pi*t2), 'r--')

figure(1)命令在这里是可以去掉的,因为画图时会默认创建figure(1),就如同当你不指定轴axes时,系统会默认创建subplot(111)subplot()命令指定了numrowsnumcolsfignum,其中fignum的范围从1到numrows $\times$ numcols。如果numrows $\times$ numcols < 10,那么这些参数之间的逗号可以省略。所以subplot(211)subplot(2,1,1)是一个意思。

实际上你可以创建任意数量的子图和轴。你可以多次调用figure()创建多个图。当然,每一个图中都可以有任意数量的子图和轴。

In [ ]:
plt.figure(1)                # 第一个图
plt.subplot(211)             # 第一个图中的第一个子图
plt.plot(t, t**2)
plt.subplot(212)             # 第一个图中的第二个子图
plt.plot(t, np.cos(t))


plt.figure(2)                # 第二个图
plt.plot(t, np.exp(t))       # 默认创建subplot(111)

plt.figure(1)                # 切换当前图形到figure 1; 当前子图仍然是subplot(212)
plt.subplot(211)             # 保持当前图,并切换到子图subplot(211)
plt.title('the first subplot in the first figure') # subplot(211)标题设置

如果你想要指定axes的位置,比如不在矩形网格上,那么你可以使用axes()命令,它允许你指定axes的位置([left,bottom,width,height])其中所有的取值都是从0到1。手动放置axes参照例子pylab_examples example code:axes_demo.py,手动指定子图数量及排列方式可以参照例子pylab_examples example code: subplots_demo.py

如果画图太多,内存受限,记得调用close()命令释放内存。

In [ ]:
plt.close('all')

4. 添加文本

调用text()命令可以在图中任意的位置添加文本text,其中xlabel()ylabel()title()指定了在x轴、y轴、标题位置显示文本。更多与文本显示的内容请参考链接Text introduction

In [ ]:
# 设置随机种子,以实现可重复性
np.random.seed(66666)

mu, sigma = 100, 15
x = mu + sigma * np.random.randn(10000)

# 绘制直方图
n, bins, patches = plt.hist(x, 50, normed=1, facecolor='g', linewidth=0.0, alpha=0.75)

plt.xlabel('Smarts')
plt.ylabel('Probability')
plt.title('Histogram of IQ')
plt.text(60, .025, r'$\mu=100,\ \sigma=15$')
plt.axis([40, 160, 0, 0.03])
plt.grid(True)

所有的text()命令都将返回一个matplotlib.text.Text实例。与设置图线属性一样,你也可以通过在text()中使用关键字参数或使用setp()来自定义属性:

In [ ]:
plt.hist(x, 50, normed=1, facecolor='g', linewidth=0.0, alpha=0.75)

# 关键字参数指定
plt.xlabel('my data', fontsize=14, color='red')

# 或setp()设置
#t = plt.xlabel('my data')
#plt.setp(t, fontsize=14, color='red')

所有的文本的属性设置可以参考Text properties and layout

使用公式

matplotlib接受在文本表达式中使用TeX表达式。例如,要在标题中添加数学表达式 $\sigma_i=15$ ,则可以使用美元符号$包裹住TeX数学表达式:

In [ ]:
plt.hist(x, 50, normed=1, facecolor='g', linewidth=0.0, alpha=0.75)
plt.title(r'$\mu=100,\ \sigma=15$')

字符串前的r非常重要,它表明该字符串为原始字符串,不会执行以反斜线开头的转移操作。matplotlib有一个内置的TeX表达式解析器和显示引擎,并且拥有自己的显示字体 - 详细信息请参阅Writing mathematical expressions。 因此,你可以跨平台使用数学文本,而无需安装TeX。如果提前安装了LaTeX和dvipng,那么也可以使用LaTeX渲染表达式,具体参考Text rendering With LaTeX

示意(annotating)文本

通常我们在图中添加文本还有一个目的——示意图形的某些特征。annotate()方法提供了一个向图形中添加示意的非常便捷的方式。

在进行示意时,我们要考虑以下两个关键点:

  1. 需要被示意的位置,用xy参数指定,且接收(x,y)元组
  2. 示意文本添加的位置,用xytext参数指定,且接收(x,y)元组
In [ ]:
ax = plt.subplot(111)

t = np.arange(0.0, 5.0, 0.01)
s = np.cos(2*np.pi*t)
line, = plt.plot(t, s, lw=2)
plt.ylim(-2,2)

plt.annotate('local max', xy=(2, 1), xytext=(3, 1.5),arrowprops=dict(facecolor='black', shrink=0.05),)

在上面的例子中,xyxytext都在直角坐标系内。除此之外,还有另外一些坐标系可供选择,具体可参考Basic annotationAdvanced annotation。更多的例子可参考Annotating Plots

5. 对数坐标轴及其他非线性坐标轴

matplotlib.pyplot不仅支持线性坐标轴,而且还支持对数和逻辑坐标轴(在数据跨越多个数量级时使用)。改变坐标轴的尺度其实很简单:

In [ ]:
plt.xscale('log')

下面显示了具有相同数据不同纵坐标尺度的四个图的示例。

In [ ]:
from matplotlib.ticker import NullFormatter  # 对 logit 坐标尺度有用,防止坐标刻度太多,重叠在一起

np.random.seed(19680801)

mu = 0.5
sigma = 0.4
y = np.random.normal(mu, sigma, size=1000)
y = y[(y > 0) & (y < 1)]
y.sort()
x = np.arange(len(y))

# 绘图
plt.figure(1
        )

# linear
plt.subplot(221)
plt.plot(x, y)
plt.yscale('linear')
plt.title('linear')
plt.grid(True)


# log
plt.subplot(222)
plt.plot(x, y)
plt.yscale('log')
plt.title('log')
plt.grid(True)


# symmetric log
plt.subplot(223)
plt.plot(x, y - y.mean())
plt.yscale('symlog', linthreshy=0.01)
plt.title('symlog')
plt.grid(True)

# logit
plt.subplot(224)
plt.plot(x, y)
plt.yscale('logit')
plt.title('logit')
plt.grid(True)

plt.gca().yaxis.set_minor_formatter(NullFormatter())
plt.subplots_adjust(top=0.92, bottom=0.08, left=0.10, right=0.95, hspace=0.25, wspace=0.35)

6. 设置全局渲染方式

matplotlib的默认渲染设置通常是我们不能忍受的,好在它提供了多种更好看的渲染方式。你可以调用style.available看看有哪些渲染方式,在绘图之初调用style.use()函数,指定渲染方式后,就可以对所有后续作图都使用相同方式进行渲染。全部都试试看把,一定有你钟爱的一款!!

In [ ]:
print plt.style.available
In [ ]:
plt.style.use(u"ggplot")

后记:如何在图形中显示中文?

1 一劳永逸的方法:在matplotlib配置文件中进行全局设置,具体请参考官方设置方法或者其他设置方法

2 暂时解决办法:在代码中主动设置:

In [ ]:
import matplotlib
fontpath = r'./input/msyh.ttf' # ttf文件路径,微软雅黑字体
myfont = matplotlib.font_manager.FontProperties(fname=fontpath)
plt.title('中文',fontproperties=myfont)

© Copyright 2002 - 2012 John Hunter, Darren Dale, Eric Firing, Michael Droettboom and the Matplotlib development team; 2012 - 2016 The Matplotlib development team. Last updated on May 10, 2017. Created using Sphinx 1.5.5