0%

Matplotlib

1 Introduction

  • 中文显示乱码问题

Matplotlib 库缺少中文字体,因此在图标上显示中文会出现乱码,解决办法:

1
2
3
4
5
6
7
8
from pyplt import mpl
mpl.rcParams['font.sans-serif'] = ['SimHei']
mpl.rcParams['axes.unicode_minus'] = False

# 或
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

2 Steps

  • import module and set font style to avoid messy code
1
2
3
4
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
  • step one: create figure and fix size (inch)
1
plt.figure(figsize = (12, 8)) # length x width
  • setp two: generate data
1
2
3
4
5
6
start_val = 0 # start value
stop_val = 10 # end value
num_val = 1000 # samples number
x = np.linspace(start_val, stop_val, num_val)
y = np.sin(x)
plt.plot(x, y, '--g,', lw = 2, label = '$sin(x)$')
  • step three: adjust axis and set label
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 调整坐标范围
x_min, y_max = 0, 10
y_min, y_max = 0, 1.5
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)

# set axis label
plt.xlabel('x轴', fontsize = 15)
plt.ylabel('y轴', fontsize = 15)

# ticks: 刻度线
x_location = np.arange(0, 10, 2)
x_labels = ['2019-01-01', '2019-02-01', '2019-03-01', '2019-04-01', '2019-05-01']
y_location = np.arange(-1, 1.5, 1)
y_labels = [u'minimum', u'zero', u'maximum']
plt.xticks(x_location, x_labels, rotation = 45, fontsize = 15)
plt.yticks(y_location, y_labels, fontsize = 15)
  • step four: set grid and legend
1
2
3
4
5
6
7
8
9
# grid
plt.grid(True, ls = ':', color = 'r', alpha = 0.5)

# title
plt.title('函数式绘图 vs 对象式绘图', fontsize = 25)

# legend
plt.legend(loc = 'upper right', fontsize = 15)
plt.show(

2.1 函数式绘图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# step one: create figure and fix size
plt.figure(figsize = (12, 6)) # length x width

# step two: generate data
start_val = 0 # start value
stop_val = 10 # end value
num_val = 1000 # samples number
x = np.linspace(start_val, stop_val, num_val)
y = np.sin(x)
plt.plot(x, y, '--g,', lw = 2, label = '$sin(x)$')

# step three: adjust axis
x_min = 0
x_max = 10
y_min = 0
y_max = 1.5
plt.xlim(x_min, x_max)
plt.ylim(y_min, y_max)

# step four: set axis label
plt.xlabel('x轴', fontsize = 15)
plt.ylabel('y轴', fontsize = 15)

x_location = np.arange(0, 10, 2)
x_labels = ['2019-01-01', '2019-02-01', '2019-03-01', '2019-04-01', '2019-05-01']
y_location = np.arange(-1, 1.5, 1)
y_labels = [u'minimum', u'zero', u'maximum']
plt.xticks(x_location, x_labels, rotation = 45, fontsize = 15)
plt.yticks(y_location, y_labels, fontsize = 15)

# step five: set grid
# ls: linestyle
plt.grid(True, ls = ':', color = 'r', alpha = 0.5)

plt.title('函数式绘图', fontsize = 25)
plt.legend(loc = 'upper right', fontsize = 15)
plt.show()

result:

fig 2-1 函数式绘图

2.2 对象式绘图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import matplotlib.pyplot as plt 
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 对象式绘图
# pyplot 模块中的 figure() 函数创建名为 fig 的 Figure 对象
fig = plt.figure(figsize = (12, 8))

# 在 Figure 对象中创建一个 Axes 对象,每个 Axes 对象即为一个绘图区域
ax = fig.add_subplot(111)

# generate data
start_val, stop_val, num_val = 0, 10, 1000
x = np.linspace(start_val, stop_val, num_val)
y = np.sin(x)

# y = sin(x)
# '--g,': format_string, equals with a combination of linestyle, color, market, 即折线、绿色、像素点
ax.plot(x, y, '--g', lw = 2, label = 'sin(x)')

# 调整坐标范围
x_min, x_max = 0, 10
y_min, y_max = 0, 1.5
ax.set_xlim(x_min, x_max)
ax.set_ylim(y_min, y_max)

# 设置坐标轴标签
plt.xlabel('x轴', fontsize = 15)
plt.ylabel('y轴', fontsize = 15)

x_location = np.arange(0, 10, 2)
x_labels = ['2019-01-01', '2019-02-01', '2019-03-01', '2019-04-01', '2019-05-01']
y_location = np.arange(-1, 1.5, 1)
y_labels = [u'minimum', u'zero', u'maximum']
plt.xticks(x_location, x_labels, rotation = 45, fontsize = 15)
plt.yticks(y_location, y_labels, fontsize = 15)

# ls: linestyle
plt.grid(True, ls = ':', color = 'r', alpha = 0.5)

plt.title('函数式绘图 vs 对象式绘图', fontsize = 25)
plt.legend(loc = 'upper right', fontsize = 15)
plt.show()

result:

fig 2-2 对象式绘图

3 Figure types

3.1 Line attributes

plot() 函数中,可设置参数以调整线条的属性:

  • linestyle: 设定线条类型
  • color: 指定线条的颜色
  • marker: 指定线条的标记风格
  • linewidth: 设定线条的宽度
  • label: 设置线条的标签
1
2
3
4
5
6
7
8
9
10
import matplotlib.pyplot as plt
import numpy as np

start_val, stop_val, num_val = 0, 10, 1000
x = np.linspace(start_val, stop_val, num_val)
y = np.sin(x)

# y = sin(x)
# '--g,': format_string, equals with a combination of linestyle, color, market, 即折线、绿色、像素点
ax.plot(x, y, '--g', lw = 2, label = '$sin(x)$')

3.2 标注点的绘制

当要在图形上给数据添加指向性注释文本时,可以使用 Matplotlib 的 annotate() 函数,支持箭头指示,方便在合适的位置添加描述信息。关键参数如下:

  • s:注释文本内容
  • xy:备注是的坐标点,二维元组格式 (x, y)
1
2
 xy : (float, float)
# The point *(x,y)* to annotate.
  • xytext:注释文本的坐标点,二维元组格式 (x, y)
  • xycoords:被注释点的坐标系属性,默认为 'data'
  • textcoords:设置注释文本的坐标系属性,默认与 xycoords 属性值相同,通常设置为 'offset points' or 'offset pixels', 即相对于被注释点 xy 的偏移量
  • arrowprops:设置箭头的样式,dict 格式

If 'arrowprops' does not contain the key ' arrowstyle', the allowed keys are:

tab 5-1 arrowstyle key-1
Key Description
width The width of the arrow in points
headwidth The width of the base of the arrow head in points
headlength The length of the arrow head in points
shrink Fraction of total length to shrink from both ends
? Any key to matplotlib.patches.FancyArrowPatch

如果 arrowprops 包含了关键词 ' arrowstyle', the above keys are forbidden. The allowed values of 'arrowstyle' are:

tab 5-2 arrowstyle key-2
Name Attrs
'-' None
'->' head_length=0.4,head_width=0.2
'-[' widthB=1.0,lengthB=0.2,angleB=None
'|-|' widthA=1.0,widthB=1.0
'-|>' head_length=0.4,head_width=0.2
'<-' head_length=0.4,head_width=0.2
'<->' head_length=0.4,head_width=0.2
'<|-' head_length=0.4,head_width=0.2
'<|-|>' head_length=0.4,head_width=0.2
'fancy' head_length=0.4,head_width=0.4,tail_width=0.4
'simple' head_length=0.5,head_width=0.5,tail_width=0.2
'wedge' tail_width=0.3,shrink_factor=0.5

Valid keys for ~matplotlib.patches.FancyArrowPatch are:

tab 5-3 ~matplotlib.patches.FancyArrowPatch
Key Description
arrowstyle the arrow style
connectionstyle the connection style
relpos default is (0.5, 0.5)
patchA default is bounding box of the text
patchB default is None
shrinkA default is 2 points
shrinkB default is 2 points
mutation_scale default is text size (in points)
mutation_aspect default is 1
? any key for matplotlib.patches.PathPatch
  • bbox:设置文本周围所添加的外框属性

Case 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# add annotation
ax.annotate(u'The top point',
xy = (np.pi/2, 1), # 箭头指向点的坐标
xytext = (np.pi/2, 1.3), # 注释文本左端的坐标
weight = 'regular', # 注释文本的字体粗细风格,bold:粗体,regular:正常粗细
color = 'g', # 注释文本颜色,green
fontsize = 15, # 注释文本字体大小
arrowprops = { # arrowprops: arrow properties,以字典格式设置箭头属性
'arrowstyle': '->',
'connectionstyle': 'arc3',
'color':'g'
})

ax.annotate(u'The low point',
xy = (np.pi*3/2, -1),
xytext = (np.pi*3/2, -1.3),
weight = 'regular',
color = 'r', # red
fontsize = 15,
arrowprops = {
'arrowstyle': '->',
'connectionstyle': 'arc3',
'color':'r'
})

plt.show()

fig 3-1 Annotation case1

Case 2:绘制以下四种样式的标注点

  • 注释文本 'annotate1' 所对应的样式配置:在 arrowprops 参数中使用关键字 'arrowstyle' 设置 箭头样式 '->',关键字 connectionstyle 设置连接线的样式
  • 注释文本 'annotate2' 所对应的样式配置:在 arrowprops 参数中使用关键字 'arrowstyle' ,允许配置箭头的宽度 width、 箭头两端收缩的百分比 shrink 等
  • 注释文本 'annotate3' 所对应的样式配置:使用 bbox 参数在文本周围添加外框,设置外框为 round 格式
  • 注释文本 'annotate1' 所对应的样式配置:使用 bbox 参数在文本周围添加外框, 设置外框为 round 样式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize = (12, 8))

# 在 Figure 对象中创建一个 Axes 对象,每个 Axes 对象即为一个绘图区域
ax = fig.add_subplot(111)
x = np.arange(10, 20)
y = np.around(np.log(x), 2)
ax.plot(x, y, marker = 'o')

ax.annotate(u'样式1', xy = (x[1], y[1]), xytext = (80, 10), textcoords = 'offset points',
arrowprops = dict(arrowstyle = '->', connectionstyle = 'angle3, angleA = 80, angleB = 50'))

ax.annotate(u'样式2', xy = (x[3], y[3]), xytext = (80, 10), textcoords = 'offset points',
arrowprops = dict(facecolor = 'black', shrink = 0.05, width = 5))

ax.annotate(u'样式3', xy = (x[5], y[5]), xytext = (80, 10), textcoords = 'offset points',
arrowprops = dict(facecolor = 'green', headwidth = 5, headlength = 10),
bbox = dict(boxstyle = 'circle, pad = 0.5', fc = 'yellow', ec = 'k', lw = 1, alpha = 0.5))
# fc: facecolor, ec: edegcolor, lw: lineweight

ax.annotate(u'样式4', xy = (x[7], y[7]), xytext = (80, 10), textcoords = 'offset points',
arrowprops = dict(facecolor = 'blue', headwidth = 5, headlength = 10),
bbox = dict(boxstyle = 'round, pad = 0.5', fc = 'gray', ec = 'k', lw = 1, alpha = 0.5))

plt.show()

result:

fig 3-2 annoatation case2

3.3 参考线/区域的绘制

  • axhline(), axvline()

使用 Matplotlib 的 axhline() 函数、axvline() 函数分别在图形中添加水平参考线和垂直参考线,使用 axhline() 函数时给定 y 轴上的位置,同理axvline() 使用时需要给定 x 轴上的位置

1
2
ax.axhline(y = min(y), c = 'blue', ls = ':', lw = 2)
ax.axvline(x = np.pi*3/2, c = 'blue', ls = '-.', lw = 2)

result:

fig 3-3 Reference line
  • axhspan(), axvspan()

使用 axhspan() 函数、axvspan() 函数分别在图形中添加 sin() 函数平行于 x 轴的参考区域和平行于 y 轴的参考区域,axhspan() 函数需给定 y 轴上的区间位置,同理在 axvspan() 中需给定 x 轴上的区间位置

1
2
ax.axhspan(ymin = 0, ymax = 1, facecolor = 'purple', alpha = 0.3)
ax.axvspan(xmin = np.pi *2, xmax = np.pi * 5/2, facecolor = 'g', alpha = 0.3)

result:

fig 3-4 Reference interval

3.4 双 Y 轴图表的绘制

  • twinx(), twiny()

如果要在同一个 x 轴上显示两个不同数量级别的序列, 可以将第二个序列绘制在右侧辅助的 y 轴上,借助 Matplotlib 的 twinx() 和 twiny() 可以实现两个 y 或 x 轴

1
2
3
4
5
6
7
8
9
ax_aux = ax.twinx()
ax_aux.plot(x, np.arange(1000), color = 'blue', label = 'line 1000')

y_location1 = np.arange(0, 1000, 100)
y_labels1 = np.arange(0, 1000, 100)
ax_aux.set_yticks(y_location1) # 刻度
ax_aux.set_yticklabels(y_labels1, fontsize= 15) # 刻度标签

ax_aux.set_ylabel('Y 轴 - 辅助', fontsize= 15)

result:

fig 3-5 双 Y 轴 图表
  • 添加图例
1
fig.legend(loc = 'upper right', bbox_to_anchor = (1, 1), bbox_transform = ax.transAxes, fontsize = 15)

3.5 条形图的绘制

  • bar()

条形图时通过相同宽度条形的高度/宽度来表现数据差异的图表,可利用 bar() 函数绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize = (12, 8))

# 在 Figure 对象中创建一个 Axes 对象,每个 Axes 对象即为一个绘图区域
ax = fig.add_subplot(111)

# pandas 生成时间序列
date_index = pd.date_range('2019-01-01', freq = 'D', periods = 10)

y_location = np.arange(0, 1000, 200)
y_labels = np.arange(0, 1000, 200)

# 分别模拟生成跌涨时的成交量数据
red_bar = [1000, 0, 0, 0, 879, 986, 213, 0, 0, 0]
green_bar = [0, 200, 599, 567, 0, 0, 0, 234, 998, 489]

# 绘制条形图
ax.bar(date_index, red_bar, facecolor = 'red')
ax.bar(date_index, green_bar, facecolor = 'green')

# 设置轴标签
ax.set_xlabel(u'交易日', fontsize = 15)
ax.set_ylabel(u'手',fontsize = 15)

# 设置标题
ax.set_title(u'成交量', fontsize = 25)

# 显示图形
plt.show()

result:

fig 3-6 条形图

3.6 直方图

  • hist()

绘制直方图,首先要将全部样本数据按照不同的区间范围划分为若干组,每个组为直方图的柱子,柱子宽度表示该组的区间,柱子的高度表示数据出现的次数

  • x:绘制直方图的数据(一维数组形式),例如服从正态分布的随机数组
  • bins:直方图的柱数
  • desity:是否将直方图的频数(数据出现的次数)转换成频率(数据所占的比例)的表示,默认为 False,True表示显示频数统计结果
  • n:直方图中每一个 bar 区间数据的频数或频率, 由参数 density 设定
  • bins:用于返回各个 bin 的区间范围
  • patches:;列表形式返回每个 bin 的图形对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize = (12, 8))
ax = fig.add_subplot(111)

# 绘制直方图
ax.hist(np.random.normal(loc = 0, scale = 1, size = 1000), bins = 50, density = False, color = 'b')

# 设置轴标签
ax.set_xlabel(u'样本值', fontsize = 15)
ax.set_ylabel(u'频数', fontsize = 15)

# 设置标题
ax.set_title(u'正态分布直方图', fontsize = 25)
plt.show()

result:

fig 3-7 直方图

3.7 饼图

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
from pylab import *
rcParams['font.sans-serif']=['SimHei']

labels=["东部","南部","北部","中部"]
sizes=[5,10,20,15]
colors=["red","green","blue","yellow"]
explode=(0,0,0.05,0) # 突出
plt.pie(sizes, explode = explode, labels = labels, colors = colors, labeldistance = 1.1,autopct = "%3.1f%%", shadow = True, startangle = 90, pctdistance = 0.5)
plt.axis("equal")
plt.legend()
plt.show()

result:

fig 3-8 饼图

3.8 K 线图

  • candlestick_ochl(), candlestick2_ochl()

股票的 K 线记录着一个时间段的开盘价、最高价、最低价、收盘价这 4 个数据,定义如下:

1
2
import mpl_finance as mpf
candlestick2_ochl(ax, opens, closea, highs, lows, width = 4, colorup = 'k', colordown = 'r', alpha = 0.75)
  • ochl: opens, closes, highs, lows, 分别表示开盘价、收盘价、最高价、最低价的序列
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
import matplotlib.pyplot as plt
import mpl_finance as mpf
import numpy as np
import pandas as pd
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# 对象式绘图
# pyplt 模块中的 figure() 函数创建名为
fig = plt.figure(figsize = (12, 8))
ax = fig.add_subplot(111)

# 绘制 K 线图
opens = [2320.36, 2300, 2295.35, 2347.22, 2360.75, 2385.43, 2376.41, 2424.92, 2411, 2432.68]
closes = [2320.26, 2291.3, 2347.5, 2358.98, 2382.48, 2385.42, 2419.02, 2428.15, 2433.13, 2334.48]
lows = [2287.3, 2288.26, 2295.35, 2337.35, 2347.89, 2371.23, 2369.57, 2417.58, 2403.3, 2427.7]
highs = [2362.94, 2308.38, 2345.92, 2363.8, 2382.48, 2383.76, 2391.82, 2421.15, 2440.38, 2441.73]

# 绘制 K 线走势
mpf.candlestick2_ochl(ax, opens, closes, highs, lows, width = 0.5, colorup = 'r', colordown = 'g')

# pandas 生成实践序列
date_index = pd.date_range('2019-01-01', freq = 'D', periods = 10)

# 设置 x 轴的范围
ax.set_xlim(0, 10)
# x 轴刻度设定,每15天标一个日期
ax.set_xticks(np.arange(0, 10))
# 标签设置为日期
ax.set_xticklabels([date_index.strftime('%Y-%m-%d')[index] for index in ax.get_xticks()])
# 设置轴标签
ax.set_xlabel(u'Date', fontsize = 15)
ax.set_ylabel(u'Price', fontsize = 15)
ax.set_title(u'日 K 线图', fontsize = 25)

plt.show()

result:

fig 3-9 K 线图

3.9 Time series

当横轴时间过长,不利于展示图片信息时,可以通过 matplotlib.datas 模块和ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))来调整仅显示年份

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import pandas as pd
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

# ticks
data_ticks = pd.date_range(start = '1985-12', freq = 'Y', end = '2019-01')
data_labels = np.arange(1985, 2019)

data = pd.read_csv(r'D:\Demo\University\XMU\Thesis\Master\WTI.csv')
# date_index = data.loc[:, '日期']
x_index = pd.date_range(start = '1986-01', freq = 'M', end = '2019-01')
data1 = data.loc[:, '收盘']
data_pt = data1.to_list()

petrol_price = pd.DataFrame(data_pt, index = x_index, columns = ['Pt_price'])

fig = plt.figure(figsize = (12, 8))
ax = fig.add_subplot(111)

ax.plot(petrol_price, color = 'b', lw = 0.8, label = 'WTI现货离岸价格')

# 设置时间显示格式,%Y%m%d%H 年月日时显示
ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y'))
# plt.xlim((1988, 2019))
plt.xticks(ticks = data_ticks, label = data_labels, rotation = 45)

plt.title('1986-2018年油价(WTI现货离岸价格)趋势图', fontsize = 16)
plt.legend()

plt.show()

result:

fig 3-10 WTI油价趋势表

4 Subplot

当需要在图表上显示多个子图时,可以在 Figure 对象中创建 Axes 对象,于是每个 Axes 对象即为一个独立的绘图区域,创建子图的方法主要有 subplot()、add_subplot()、add_axes() 三种方法

4.1 Create subplot

4.1.1 add_subplot()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize = (12, 8))
ax1 = fig.add_subplot(211) # 子图以 2 行 1 列排布
ax2 = fig.add_subplot(212) # 创建另一个 Axes 对象

ax1.plot(np.arange(100), np.random.randint(0, 10, 100), label = u'0-10 随机数', ls = '-', c ='r', lw = 1)
ax1.set_title(u'0-10 随机数', fontsize = 12)
ax1.legend(loc = 'upper right')

ax2.plot(np.arange(100), np.random.randint(10, 20, 100), label = u'10-20 随机数', ls = '-', c ='y', lw = 1)
ax2.set_title(u'10-20 随机数', fontsize = 12)
ax2.legend(loc = 'upper right')
plt.show()

result:

fig 4-1 subplot

add_subplot() 本质上是以坐标来定位子图位置的,左下角坐标位置时子图在整个 Figure 对象上的绝对坐标,如下

1
2
3
>>> print(ax1, ax2)
# AxesSubplot(0.125,0.536818;0.775x0.343182)
# AxesSubplot(0.125,0.125;0.775x0.343182)

4.1.2 add_axes()

使用 add_axes() 创建子图与 add_subplot() 有所不同,add_axes() 函数中需要给定子图在整个 Figure 对象上的绝对坐标[x0, y0, width, height],即左下角的坐标 (x0, y0) 及其宽度和高度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize = (12, 8))
ax1 = fig.add_axes([0.125, 0.536818, 0.775, 0.343182])
ax2 = fig.add_axes([0.125, 0.125, 0.775, 0.343182])
ax1.plot(np.arange(100), np.random.randint(0, 10, 100), label = u'0-10 随机数', ls = '-', c ='r', lw = 1)
ax1.set_title(u'0-10 随机数', fontsize = 12)
ax1.legend(loc = 'upper right')

ax2.plot(np.arange(100), np.random.randint(10, 20, 100), label = u'10-20 随机数', ls = '-', c ='y', lw = 1)
ax2.set_title(u'10-20 随机数', fontsize = 12)
ax2.legend(loc = 'upper right')

plt.show()

result:

fig 4-2 add_axes

当需要精确定位子图时,可使用 add_axes(),但获取子图精确的位置信息较繁琐

4.1.3 subplot()

add_subplot() 和 add_axes() 是对象式创建子图的方法,而 subplot() 是函数式创建子图的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

plt.figure(figsize = (12, 8))
plt.subplot(211)
plt.plot(np.arange(100), np.random.randint(0, 10, 100), label = u'0-10 随机数', ls = '-', c ='r', lw = 1)
plt.legend(loc = 1)
plt.subplot(212)
plt.plot(np.arange(100), np.random.randint(10, 20, 100), label = u'10-20 随机数', ls = '-', c ='y', lw = 1)
plt.legend(loc = 1)
plt.show()

result is same as above figure.

  • Demo: 使用 subplot 创建 2 行 3 列 排布的多子图,以遍历方式在子图上绘制折线图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
import matplotlib.pyplot as plt
import numpy as np
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

plt.figure(figsize = (12, 8))

fig_ps, axes_ps = plt.subplots(2, 3)
# subplots 返回两个值,fig_ps 表示图像大小信息, axes_ps 表示子图位置信息
print(fig_ps, axes_ps)
for i in range(2):
for j in range(3):
axes_ps[i, j].plot(np.arange(100), np.random.randint(0, 10, 100), c ='y', alpha = 0.5)
plt.show()

result:

fig 4-3 mul-subplot

4.2 布局多子图对象

  • GridSpec module

有时不仅要在多个子图上显示图形,而且也要协调多个子图的位置和比例。三种创建子图的方法中,使用较多的是 add_plot() 方法,而该方法所创建的子图是堆成的子图,因此该方法并不满足非对称子图的应用。 若要创建非对称的子图,可以使用 matplotlib 的 GridSpec 模块。GridSpec 可以自定义子图的位置和调整子图行和列的相对高度和宽度

Import module

1
2
3
4
import matplotlib.gridspec as gridspec # 分割子图

# gridspec.GridSpec 的构造函数
gridspec.GridSpec(nrows, ncols, figure = None, left = None, bottom = None, right = None, top = None, wspace = None, hspace = None, width_ratios = None, height_ratios = None)

参数 nrows 和 ncols 分别表示网格的行列数。用 plt.figure() 创建图表,通过 gridspec.GridSpec() 将整个图表划分为多个区域。由于 GridSpec 返回的实例支持切片方式选取网格区域,因此可以结合 add_subplot() 方法更灵活地添加跨度不同网格大小的子图

left, bottom, right, top 分别控制子图与 Figure 左边、底部、右边、顶部的距离比例。gs[0, : ] 表示该子图占第 0 行和所有列

4.2.1 创建多子图布局

1
2
3
4
5
6
7
8
9
10
11
12
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize = (12, 8), dpi = 100, facecolor = 'white')
gs = gridspec.GridSpec(3, 3)
graph_ax1 = fig.add_subplot(gs[0, :])
graph_ax2 = fig.add_subplot(gs[1, 0:2])
graph_ax3 = fig.add_subplot(gs[1:3, 2])
graph_ax4 = fig.add_subplot(gs[2, 0:2])
plt.show()

result:

fig 4-4 多子图布局图

4.2.2 微调

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False

fig = plt.figure(figsize = (12, 8), dpi = 100, facecolor = 'white')
gs = gridspec.GridSpec(3, 3, left = 0.08, bottom = 0.15, right = 0.99,
top = 0.96, wspace = 0.5, hspace = 0.5, width_ratios = [2, 2, 1],
height_ratios = [2, 1, 1])
graph_ax1 = fig.add_subplot(gs[0, :])
graph_ax2 = fig.add_subplot(gs[1, 0:2])
graph_ax3 = fig.add_subplot(gs[1:3, 2])
graph_ax4 = fig.add_subplot(gs[2, 0:2])
plt.show()

result:

fig 4-5 微调之后的多子图布局

5 Figure properties

5.1 plot()

Function definition:

1
2
3
4
5
# 单线条:
plot([x], y [, fmt], data = None, **kwargs)
# 多线条
plot([x], y [, fmt], [x2], y2 [fmt2], ..., **kwargs)
# fmt = '[color][marker][line]'

其中,[fmt]为可选参数,用一个字符串来定义图形的基本属性,包括颜色(color),点型(marker),线性(linestyle),具体如下:

  • Colors
tab 5-4 color properties
Character Color
'b' blue
'g' green
'r' red
'c' cyan(蓝绿色)
'm' magenta(品红)
'y' yellow
'k' black
'w' white
  • Markers
tab 5-5 marker properties
Character Description
'.' point marker
',' pixel marker
'o' circle marker
'v' triangle_down marker
'^' triangle_up marker
'<' triangle_left marker
'>' triangle_right marker
'1' tri_down marker
'2' tri_up marker
'3' tri_left marker
'4' tri_right marker
's' square marker
'p' pentagon marker(五角形)
'*' star marker
'h' hexagon1 marker(六角形)
'H' hexagon2 marker
'+' plus marker
'x' x marker
'D' diamond marker
'd' thin_diamond marker
'|' vline marker
'_' hline marker
  • Line Styles
Character Description
'-' solid line style
'--' dashed line style(虚线)
'-.' dash-dot line style
':' dotted line style
  • Examples format strings:
Character Description
'b' blue markers with default shape
'ro' red circles
'g-' green solid line
'--' dashed line with default color
'k^:' black triangle_up markers connected by a dotted line

Case:

1
2
3
plt.plot([1, 2, 3, 4, 5], [3, 4, 5, 6, 7], 'go--')
plt.plot([1, 2, 3, 4, 5], [2, 3, 4, 5, 6], color = 'green', marker = 'o', linestyle = 'dashed')
plt.plot([1, 2, 3, 4, 5], [1, 2, 3, 4, 5], color = 'g', marker = 'o', linestyle = 'dashed')

result:

fig 5-1 plot parameter

5.2 Abbreviation

Matplotlib 支持一些属性的关键词简写:

1
2
3
4
5
6
7
8
'linewidth': ['lw']
'linestyle': ['ls']
'facecolor': ['fc']
'edgecolor': ['ec']
'markerfacecolor': ['mfc']
'markeredgecolor': ['mec']
'markeredgewidth': ['mew']
'markersize': ['ms']

eg:

1
2
plt.plot([1, 2, 3, 4, 5], [2, 3, 4, 5, 6], color = 'green', marker = 'o', linestyle = 'dashed', linewidth = 2)
plt.plot([1, 2, 3, 4, 5], [1, 2, 3, 4, 5], c = 'g', marker = 'o', linestyle = 'dashed', lw = 5)

result:

fig 5-2 Abbreviation

5.3 Ticks

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-1, 1, 50)
y1 = 2 * x + 1
y2 = x**2

plt.figure(num = 1)
plt.plot(x, y1, color = 'red')
plt.plot(x, y2, color = 'green', linewidth = 1.0, linestyle = '--')

plt.xlim((-1, 2))
plt.ylim((-2, 3))
plt.xlabel('I am x')
plt.ylabel('I am y')

new_ticks = np.linspace(-1, 2, 5)
print(new_ticks)
plt.xticks(new_ticks) # 刻度
plt.yticks([-2, -1.8, -1, 1.22, 3],
[r'$relly\ bad\ \alpha$', r'$bad$', r'$normal$', r'$good$', r'$really\ good$'])

plt.show()

result:

fig 5-3 Ticks demo

5.4 Axis position

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import matplotlib.pyplot as plt
import numpy as np

x = np.linspace(-3, 3, 50)
y1 = 2 * x + 1
y2 = x**2

plt.figure(num = 1)
plt.plot(x, y1, color = 'red')
plt.plot(x, y2, color = 'green', linewidth = 1.0, linestyle = '--')

plt.xlim((-1, 2))
plt.ylim((-2, 4))
plt.xlabel('I am x')
plt.ylabel('I am y')

new_ticks = np.linspace(-1, 2, 5)
print(new_ticks)
plt.xticks(new_ticks)
plt.yticks([-2, -1.8, -1, 1.22, 3],
[r'$relly\ bad\ \alpha$', r'$bad$', r'$normal$', r'$good$', r'$really\ good$'])

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

plt.show()

result:

fig 5-4 Modify axis position

5.5 legend()

  • loc
Location String Location Code
'best' 0
'upper right' 1
'upper left' 2
'lower left' 3
'lower right' 4
'right' 5
'center left' 6
'center right' 7
'lower center' 8
'upper center' 9
'center' 10

5.6 Add text

1
ax.text(0, 2, 'This is a test text.')

fig 5-5 Add text on figure
-------------This blog is over! Thanks for your reading-------------