- 作者:
- 分类:知识&开发->AI->工具
- 阅读:2443
- 点赞:5
- 版权:CC BY-SA 4.0
- 创建:2020-05-15
- 更新:2020-10-20
原文链接(持续更新):https://neucrack.com/p/284
链接
官网的教程做得非常好, 如果真的想理解用法,建议静下心慢慢读一读官方教程
安装
pip3 install matplotlib
注意,这里所有都是用的
python3
测试
import matplotlib.pyplot as plt
这里用了别名 plt,大家用的时候都这样用,看起来更简单
基本
先直观看一个例子, 用到了plt.title plt.xlabel plt.ylabel plt.plot plt.show
等
import numpy as np
from matplotlib import pyplot as plt
x = np.arange(1,11)
y = 2 * x + 5
plt.title("Matplotlib demo")
plt.xlabel("x axis caption")
plt.ylabel("y axis caption")
plt.plot(x,y, 'og')
plt.show()
下面从是一些基本的概念和用法:
backends, 特别是无 GUI 的服务器要注意
就是选择后端实现,不同的平台可以选择不一样的后端, 比如在jupyterlab
和 pyqt5
中的后端就会不同, 默认一个是agg
一个是qt5gg
详细地看官方文档说明
- 在matplotlibrc 文件中的
rcParams["backend"]
(默认:agg
) 变量 MPLBACKEND
环境变量matplotlib.use()
函数plt.switch_backend()
函数
# set for server with no Tkagg GUI support, use agg(non-GUI backend)
plt.switch_backend('agg')
取值有: agg
pdf
ps
svg
pgf
cairo
(非交互式的,也就是不需要窗口显示的,一般在服务器或者jupyter等里面使用这种模式), qt5agg
tkagg
等等, 详细的看这里
交互模式
前面的代码, 需要调用plt.show()
才最终显示图片, 如果想要实时显示改变,可以调用plt.ion()
打开交互模式
plt.ion() # plt.ioff()
plt.plot([1.6, 2.7])
# plt.show()
这里的代码在plot()
后就会立刻显示画布,不需要调用show()
,使用某些后端可能需要调用plt.draw()
来刷新
这样就可以用来动态刷新画布上的内容了
基本名词
- figure: 面板,或者说画布, 这很重要, 一个面板对应了一个窗口,或者对应jupyter的一个widget;一个figure包含了至少1个或多个axes
- axis: 轴, x轴y轴z轴,就是数学术语上的坐标轴
- axes: 由一个xy(xyz)坐标系组成的区域。需要依附在一个figure上面,一个figure至少有一个axes, 你可以想象在画板上画了一幅图或者多幅图,这些图就叫axes, 而这些图可是是图片也可以是含有表格等
注意 axis 指axes中一幅图的一个坐标轴,在这里axes不是axis在数学坐标轴术语上的复数形式, 注意区分 - 子图: 通常大家的常规印象是画一张图, 或者在一张图中画多张子图, 但是这里没有子图这个概念, 只有一个figure中有多张图(axes)的概念, 而一张图是axes数量等于1的特殊情况. 如果非要说, 也可以把axes翻译成子图,因为它就是画板上的(子)图
- markers: 数据点
- line: 将数据点连线得到的线段
- legend: 图例
- markers: 标记点,也就是数据点
- trick label: 轴刻度标签
- axis label: 轴名称
基本函数
创建面板: plt.figure
fig = plt.figure() # an empty figure with no Axes
几个经常用的参数:
figsize
: 面板大小, 默认[6.4, 4.8]
, 单位是英寸dpi
: 每英寸的像素点数量, 默认100
facecolor
: 背景颜色, 更多样式设置看后面的美化样式edgecolorcolor
: 边框颜色tight_layout
: 紧凑布局constrained_layoutbool
: 受限布局
这里有很重要的参数: 创建图像的大小就取决于dpi
和figsize
, 创建图像需要先考虑
可以创建多个figure
import matplotlib.pyplot as plt
plt.figure(1) # the first figure
plt.figure(2) # a second figure
plt.figure(1) # 将当前figure又重新设置为第一个
创建axes
: plt.subplot
创建axes
的几种方法如下:
- 默认自动创建:使用
plt.plot()
会自动创建axes
x = np.linspace(0, 2, 100)
#
plt.plot(x, x, label='linear') # Plot some data on the (implicit) axes.
plt.plot(x, x**2, label='quadratic') # etc.
plt.plot(x, x**3, label='cubic')
plt.xlabel('x label')
plt.ylabel('y label')
plt.title("Simple Plot")
plt.legend()
plt.show()
- 或者手动调用
subplots
创建一个或者多个图, 也叫object-oriented
(OO
):
调用这个函数会自动创建一个figure
, figure
的参数也可以放到这个函数里面使用
fig, ax = plt.subplots() # a figure with a single Axes
fig, axs = plt.subplots(3, 2) # a figure with a 3(row)x2(col) grid of Axes # 3行2列
from matplotlib import pyplot as plt
import numpy as np
#
x = np.linspace(0, 2, 100)
# Note that even in the OO-style, we use `.pyplot.figure` to create the figure.
fig, ax = plt.subplots() # Create a figure and an axes.
ax.plot(x, x, label='linear') # Plot some data on the axes.
ax.plot(x, x**2, label='quadratic') # Plot more data on the axes...
ax.plot(x, x**3, label='cubic') # ... and some more.
ax.set_xlabel('x label') # Add an x-label to the axes.
ax.set_ylabel('y label') # Add a y-label to the axes.
ax.set_title("Simple Plot") # Add a title to the axes.
ax.legend() # Add a legend.
plt.show()
注意这里设置标题的函数和
plt
的一系列函数名不一样,需要注意
- 还有一种是调用
subplot
没有s
, matplotlib有当前 figure和当前axes的概念, 选中当前axes, 使用plt
的操作都是对这个axes
的操作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() # 这里不调用也行, 会默认自动调用
# 创建第一个图(ax), 当前 plt 的上下文就是这张图, plt 的很多操作都是对这张图进行操作,比如 plot
plt.subplot(211)
plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')
# 创建第二个图,当前 plt 的上下文就是这张图, plt 的很多操作都是对这张图进行操作,比如 plot
plt.subplot(212)
plt.plot(t2, np.cos(2*np.pi*t2), 'r--')
plt.show()
subplot(nrows, ncols, index, **kwargs)
或者subplot(pos, **kwargs)
, 这里211
的意思就是2行1列第一个图
总结:
使用subplot
和默认创建
这两种方式其实是一种类型, 所以总共就两种方式:
- 一种是使用
plt.subplot
定义axes
, 并选中当前的图,然后用plt
的方法对其进行操作, 我们称之为直接使用pylot
的方式, 这和matlib
的使用方式一样; - 另外一种是使用
plt.subplots
函数,从返回值得到axes
的对象, 然后用这些对象的方法对其进行操作, 我们称之为Object-Oriented
(OO
)(面向对象)的方式
官方推荐使用OO
的方式, 至于原因, 我认为因为面向对象让代码看起来更优雅,更易读
不管用哪种方式, 一定要搞清楚这三个概念,用起来就会很顺手了
- 一个窗口就是一个面板(
figure
),这个面板可以被保存成一张图片到文件系统 - 一个面板里面可以有一个或者多个
axes
(坐标系或者图片)(代码中一般用ax
表示axes
中的一个图), 中文我认为就说成图就好了,把figure说成面板,这样就区分开了,或者按照第一印象把axes
说成子图也行, 虽然不太准确,但是只要理解了也没啥毛病,就是容易让新手误解 - 不要把
axes
和axis
搞混, 后者是坐标系的某一个轴的意思, 这里axes
不是axis
的复数的意思, 这里是专有词,代表面板中的图
图表类型
plot
: 折线图scatter
: 散点图bar
/barh
: 柱状图pie
: 饼图table
: 表fill
: 填充曲线- 更多地可以在这里看到样例
填充数据
使用 plot 函数, 比如 plt.plot(x, y, fmt="og", label='linear')
或者 axes.plot(x, y, label='linear')
, 具体的参数看文档
也可以在一句话中画多条线, 比如这里三条线
plt.plot(t, t, 'r--', t, t**2, 'bs', t, t**3, 'g^')
这里的fmt
参数用字符代表线形状颜色以及数据点样式等,也可以使用专用的关键字参数,比如color
, marker
(数据点样式), linestyle
(线段样式)等: 线段样式 数据点样式 和 颜色 字符表 如下:
字符 | 描述 |
---|---|
‘-‘ | 实线样式 |
‘—‘ | 短横线样式 |
‘-.’ | 点划线样式 |
‘:’ | 虚线样式 |
‘.’ | 点标记 |
‘,’ | 像素标记 |
‘o’ | 圆标记 |
‘v’ | 倒三角标记 |
‘^’ | 正三角标记 |
‘<’ | 左三角标记 |
‘>’ | 右三角标记 |
‘1’ | 下箭头标记 |
‘2’ | 上箭头标记 |
‘3’ | 左箭头标记 |
‘4’ | 右箭头标记 |
‘s’ | 正方形标记 |
‘p’ | 五边形标记 |
‘*’ | 星形标记 |
‘h’ | 六边形标记 1 |
‘H’ | 六边形标记 2 |
‘+’ | 加号标记 |
‘x’ | X 标记 |
‘D’ | 菱形标记 |
‘d’ | 窄菱形标记 |
‘|’ | 竖直线标记 |
‘_’ | 水平线标记 |
字符 | 颜色 |
---|---|
‘b’ | 蓝色 |
‘g’ | 绿色 |
‘r’ | 红色 |
‘c’ | 青色 |
‘m’ | 品红色 |
‘y’ | 黄色 |
‘k’ | 黑色 |
‘w’ | 白色 |
也可以使用可以用字符串下标获取的对象比如字典:
data = {
"x" : np.arange(50),
"y": np.arange(50)
}
plt.plot("x", "y", data = data)
注意目前只支持numpy.ndarray
对象,其它的要先转换,比如:
a = pandas.DataFrame(np.random.rand(4, 5), columns = list('abcde'))
a_asarray = a.values
# and to convert a numpy.matrix
b = np.matrix([[1, 2], [3, 4]])
b_asarray = np.asarray(b)
显示图片
import matplotlib.pyplot as plt
读取图片:
- 直接使用
PIL.Image.open()
from PIL import Image
img_pil = Image.open(test_img)
print(type(img_pil))
matplotlib
依赖于Pillow
来读取读片:
返回np.ndarray
类型, 像素通道排序为[R, G, B]
import matplotlib.image as mpimg\
test_img = "../assets/Alice.jpg"
img_mp = mpimg.imread(test_img)
print(type(img_mp), img_mp.shape, img_mp[0][0])
# <class 'numpy.ndarray'> (240, 320, 3) [235 140 74]
opencv
读取:
返回np.ndarray
类型, 像素通道排列为[B, G, R]
import cv2
test_img = "../assets/Alice.jpg"
img_cv = cv2.imread(test_img)
print(type(img_cv), img_cv.shape, img_cv[0][0])
# <class 'numpy.ndarray'> (240, 320, 3) [ 74 140 235]
这里要注意 opencv
和Pillow
的像素点数据排序不一样, 如果要给plt
显示,需要先转换一下通道顺序
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
显示图片
plt.figure()
plt.subplot(2, 1, 1)
imgplot = plt.imshow(img_mp)
plt.subplot(2, 1, 2)
imgplot = plt.imshow(img_cv)
plt.show()
插值显示
# interpolation 插值显示
# resize image to small image
img_pil.thumbnail((32, 24), Image.ANTIALIAS)
plt.subplot(2, 1, 1)
imgplot = plt.imshow(img_pil)
# display
plt.subplot(2, 1, 2)
imgplot = plt.imshow(img_pil, interpolation="bicubic")
plt.show()
保存图片
print(fig.canvas.get_supported_filetypes())
# {'eps': 'Encapsulated Postscript', 'jpg': 'Joint Photographic Experts Group', 'jpeg': 'Joint Photographic Experts Group', 'pdf': 'Portable Document Format', 'pgf': 'PGF code for LaTeX', 'png': 'Portable Network Graphics', 'ps': 'Postscript', 'raw': 'Raw RGBA bitmap', 'rgba': 'Raw RGBA bitmap', 'svg': 'Scalable Vector Graphics', 'svgz': 'Scalable Vector Graphics', 'tif': 'Tagged Image File Format', 'tiff': 'Tagged Image File Format'}
使用savefig
函数: 详情看这里
savefig(fname, dpi=None, facecolor='w', edgecolor='w',
orientation='portrait', papertype=None, format=None,
transparent=False, bbox_inches=None, pad_inches=0.1,
frameon=None, metadata=None)
对于subplots()
返回的fig
fig.savefig('fig.png', transparent=False, dpi=80, bbox_inches="tight")
或者
plt.savefig('fig.png')
常用方法
可以在这里找到: https://matplotlib.org/api/_as_gen/matplotlib.pyplot.html
前面提到的,一般用两种方式, 一种是使用plt.subplot
定义axes
, 并选中当前的图,然后用plt
的方法对其进行操作;
另外一种是使用plt.subplots
函数,从返回值得到axes
的对象, 然后用这些对象的方法对其进行操作
列一些常用的方法, 参数可以在文档中看
pyplot
(plt
)的方法:plot
: 填充数据axis
: 设置轴的属性, 包括是否显示, 取值范围等, 比如plt.axis([x_min, x_max, y_min, y_max])
, 更多看文档xlim
/ylim
: 轴的取值范围,超出的不显示,上面的函数也能实现suptitle
: 设置figure的标题xlabe
ylabel
: 横坐标 纵坐标title
: axes 的标题gride(bool)
: 现实网格text(x,y,str)
: 特定坐标写字annotate('local max', xy=(2, 1), xytext=(3, 1.5),arrowprops=dict(facecolor='black', shrink=0.05))
: 注解标记xscale
/yscale
: 轴按照某种函数的密度现实, 就是坐标轴刻度间隔不均等,而是按照函数分布colorbar
: 显示颜色图例set_clim(self, vmin=None, vmax=None)
: 限制值范围close
: 关闭figurelegend
: 显示图例
axes
(来自subplots
)的方法:set
: 设置图的属性,包括刻度标签, 轴标签,图标题, 值限制等,详情看apiset_xlim()
: 设置x轴(x_axis)的坐标范围, y轴同理, 也可以ax.set(xlim=(xmin, xmax), ylim=(ymin, ymax))
text
: 写字set_title()
: 设置标题title.set
: 设置标题相关参数set_xlabel()
: 设置x轴标题,y轴同理set_xticks
: 设置x轴刻度值set_xticklabels
: 设置x轴刻度标签值get_xticklabels
: 获取x轴刻度标签值ax.axvline(v, ls='--', color='r')
: 在特定的图中加入一条竖直虚线legend
: 显示图例
显示中文
自定义字体文件:
# from https://www.runoob.com/numpy/numpy-matplotlib.html
import numpy as np
from matplotlib import pyplot as plt
import matplotlib
# fname 为 你下载的字体库路径,注意 SourceHanSansSC-Bold.otf 字体的路径
zhfont1 = matplotlib.font_manager.FontProperties(fname="SourceHanSansSC-Bold.otf")
x = np.arange(1,11)
y = 2 * x + 5
plt.title("菜鸟教程 - 测试", fontproperties=zhfont1)
# fontproperties 设置中文显示,fontsize 设置字体大小
plt.xlabel("x 轴", fontproperties=zhfont1)
plt.ylabel("y 轴", fontproperties=zhfont1)
plt.plot(x,y)
plt.show()
使用系统的字体:plt.rcParams['font.family']
from matplotlib import pyplot as plt
import matplotlib
import numpy as np
a=sorted([f.name for f in matplotlib.font_manager.fontManager.ttflist])
for i in a:
print(i)
plt.rcParams['font.family']=['YouYuan']
x = np.arange(1,11)
y = 2 * x + 5
plt.title("Matplotlib 中文")
plt.xlabel("x axis caption")
plt.ylabel("y axis caption")
plt.plot(x,y,"og")
plt.show()
效率
在大数据量时可能对渲染效率就有要求了
- 比如下面画线段的代码, 后面一段渲染用的时间明显少很多
import matplotlib
# Setup, and create the data to plot
y = np.random.rand(100000)
y[50000:] *= 2
y[np.geomspace(10, 50000, 400).astype(int)] = -1
matplotlib.rcParams['path.simplify'] = True
matplotlib.rcParams['path.simplify_threshold'] = 0.0
plt.plot(y)
plt.show()
matplotlib.rcParams['path.simplify_threshold'] = 1.0
plt.plot(y)
plt.show()
线段分块
matplotlib.rcParams['agg.path.chunksize'] = 10000 # 默认是0
锚点也可以少画来加快渲染
plt.plot(x, y, markevery=10)
图例也可以指定位置而不是自动选择最佳位置
(loc='best')
,减少计算量axes[0].legend(loc='best')
使用 fast style
自动设置前面说的simplification
和 chunking
import matplotlib.style as mplstyle
mplstyle.use('fast')
# 或者
mplstyle.use(['dark_background', 'ggplot', 'fast'])
详细的说明参考官方文档
美化, 样式
有时候画出来的图可能显示不完全, 或者太拥挤等等,需要调整样式, 以及颜色等等
主要使用 style sheet 和rcParams, 参见: https://matplotlib.org/tutorials/introductory/customizing.html
使用 rcParams
详细的参数看这里: https://matplotlib.org/tutorials/introductory/customizing.html#the-matplotlibrc-file
import matplotlib
print(matplotlib.matplotlib_fname()) # '/home/foo/.config/matplotlib/matplotlibrc'
mpl.rcParams['lines.linewidth'] = 2
mpl.rcParams['lines.linestyle'] = '--'
plt.plot(data)
整体颜色风格
使用plt.style.use('ggplot')
, 参数可以传内置的, 也可以传样式文件路径(前面的rcParams
文件), 可以用一个列表, 后面的会覆盖前面的属性
print(plt.style.available)
# ['Solarize_Light2', '_classic_test_patch', 'bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn', 'seaborn-bright', 'seaborn-colorblind', 'seaborn-dark', 'seaborn-dark-palette', 'seaborn-darkgrid', 'seaborn-deep', 'seaborn-muted', 'seaborn-notebook', 'seaborn-paper', 'seaborn-pastel', 'seaborn-poster', 'seaborn-talk', 'seaborn-ticks', 'seaborn-white', 'seaborn-whitegrid', 'tableau-colorblind10']
plt.style.use('ggplot') # 参数可以传内置的, 也可以传样式文件路径, 可以用一个列表, 后面的会覆盖前面的属性
fig, ax = plt.subplots()
plt.show()
如果不想改变全局样式, 可以
with plt.style.context('dark_background'):
plt.plot(np.sin(np.linspace(0, 2 * np.pi)), 'r-o')
plt.show()
自动缩放显示完全所有内容
使用rcParams
, 缩放会导致图片变小,但是能看完全了
plt.rcParams.update({'figure.autolayout': True})
constrained_layout
有时图像太拥挤, 可以用这个, 也可以用tight_layout
, 并不一定每个图像都奏效, 太复杂的图还是需要自己手动调整
plt.figure(constrained_layout=True)
fig1, f1_axes = plt.subplots(ncols=2, nrows=2, constrained_layout=True)
plt.rcParams['figure.constrained_layout.use'] = True
tight_layout
tight_layout
和 constrained_layout
类似, 在生成figure
时指定, tight_layout
也可以在画完元素后调用, 通常用这个效果不错
Figure.set_tight_layout
pyplot.tight_layout
plt.figure(constrained_layout=False, tight_layout = True, figsize=(4,10))
或者
img_num = 2
plt.subplot(img_num, 1, 1)
imgplot = plt.imshow(img_mp)
plt.subplot(img_num, 1, 2)
imgplot = plt.imshow(img_cv)
plt.tight_layout()
plt.show()
边距
fig.subplots_adjust(right=.1)
设置轴标签样式
- 设置轴标签角度
fig, ax = plt.subplots()
ax.barh(group_names, group_data)
labels = ax.get_xticklabels()
plt.setp(labels, rotation=45, horizontalalignment='right')
也可以
ax.set_xticklabels(labels.keys(), rotation=45)
- 设置轴标签格式
def currency(x, pos):
"""The two args are the value and tick position"""
if x >= 1e6:
s = '${:1.1f}M'.format(x*1e-6)
else:
s = '${:1.0f}K'.format(x*1e-3)
return s
ax.xaxis.set_major_formatter(currency)
示例
柱状图
from matplotlib import pyplot as plt
x = [5,8,10]
y = [12,16,6]
x2 = [6,9,11]
y2 = [6,15,7]
plt.bar(x, y, align = 'center')
plt.bar(x2, y2, color = 'g', align = 'center')
plt.title('Bar graph')
plt.ylabel('Y axis')
plt.xlabel('X axis')
plt.show()
范围统计图
统计一组数据在特定范围类的数量, 比如下面统计一组数据的值分别在几个范围(0~100)的数量
import numpy as np
from matplotlib import pyplot as plt
a = np.array([22,87,5,43,56,73,55,54,11,20,51,5,79,31,27])
# numpy
hist,bins = np.histogram(a,bins = [0,20,40,60,80,100])
print (hist)
print (bins)
# matplotlib
plt.hist(a, bins = [0,20,40,60,80,100])
plt.title("histogram")
plt.show()
colorbar
文档: https://matplotlib.org/tutorials/intermediate/constrainedlayout_guide.html#colorbars
tensorflow 显示训练记录(accuracy和loss)
plt.plot(history.history['acc'], color='#2886EA', label="train")
plt.plot(history.history['val_acc'], color = '#3FCD6D', linestyle = ':', marker = '.', label="valid")
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend()
plt.savefig(out_path)
plt.close()
plt.figure()
plt.xlabel('Epoch')
plt.ylabel('accuracy')
plt.plot(hist['epoch'], hist['acc'],
label='Train accuracy')
plt.plot(hist['epoch'], hist['val_acc'],
label = 'Val accuracy')
plt.ylim([0, 1])
plt.legend()
plt.savefig(out_path+".jpg")
plt.close()