- 作者:
- 分类:知识&开发->AI->工具
- 阅读:10370
- 点赞:6
- 版权: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 npfrom matplotlib import pyplot as pltx = np.arange(1,11)y = 2 * x + 5plt.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: 每英寸的像素点数量, 默认100facecolor: 背景颜色, 更多样式设置看后面的美化样式edgecolorcolor: 边框颜色tight_layout: 紧凑布局constrained_layoutbool: 受限布局
这里有很重要的参数: 创建图像的大小就取决于dpi 和figsize, 创建图像需要先考虑
可以创建多个figure
import matplotlib.pyplot as pltplt.figure(1) # the first figureplt.figure(2) # a second figureplt.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 Axesfig, axs = plt.subplots(3, 2) # a figure with a 3(row)x2(col) grid of Axes # 3行2列
from matplotlib import pyplot as pltimport 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 的很多操作都是对这张图进行操作,比如 plotplt.subplot(211)plt.plot(t1, f(t1), 'bo', t2, f(t2), 'k')# 创建第二个图,当前 plt 的上下文就是这张图, plt 的很多操作都是对这张图进行操作,比如 plotplt.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.matrixb = np.matrix([[1, 2], [3, 4]])b_asarray = np.asarray(b)
显示图片
import matplotlib.pyplot as plt
读取图片:
- 直接使用
PIL.Image.open()
from PIL import Imageimg_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 cv2test_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 imageimg_pil.thumbnail((32, 24), Image.ANTIALIAS)plt.subplot(2, 1, 1)imgplot = plt.imshow(img_pil)# displayplt.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的标题xlabeylabel: 横坐标 纵坐标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.htmlimport numpy as npfrom matplotlib import pyplot as pltimport matplotlib# fname 为 你下载的字体库路径,注意 SourceHanSansSC-Bold.otf 字体的路径zhfont1 = matplotlib.font_manager.FontProperties(fname="SourceHanSansSC-Bold.otf")x = np.arange(1,11)y = 2 * x + 5plt.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 pltimport matplotlibimport numpy as npa=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 + 5plt.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 ploty = np.random.rand(100000)y[50000:] *= 2y[np.geomspace(10, 50000, 400).astype(int)] = -1matplotlib.rcParams['path.simplify'] = Truematplotlib.rcParams['path.simplify_threshold'] = 0.0plt.plot(y)plt.show()matplotlib.rcParams['path.simplify_threshold'] = 1.0plt.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 mplstylemplstyle.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 matplotlibprint(matplotlib.matplotlib_fname()) # '/home/foo/.config/matplotlib/matplotlibrc'mpl.rcParams['lines.linewidth'] = 2mpl.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_layoutpyplot.tight_layout
plt.figure(constrained_layout=False, tight_layout = True, figsize=(4,10))
或者
img_num = 2plt.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 sax.xaxis.set_major_formatter(currency)
示例
柱状图
from matplotlib import pyplot as pltx = [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 npfrom matplotlib import pyplot as plta = np.array([22,87,5,43,56,73,55,54,11,20,51,5,79,31,27])# numpyhist,bins = np.histogram(a,bins = [0,20,40,60,80,100])print (hist)print (bins)# matplotlibplt.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()


