DataWhale matplotlib 学习记录
一、Matplotlib 初相识
1. 认识matplotlib
Matplotlib是一个Python 2D绘图库,能够以多种硬拷贝格式和跨平台的交互式环境生成出版物质量的图形,用来绘制各种静态,动态,交互式的图表。
我们所熟知的pandas和seaborn的绘图接口其实也是基于matplotlib所作的高级封装。
2.一个简单的绘图
Code
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
fig, ax = plt.subplots() #创建一个包含一个axes的figure
ax.plot([1, 2, 3, 4], [1, 4, 2, 3]) #绘制图像
plt.show() #显示图像
3.Figure的组成
完整的matplotlib图像通常会包含以下四个层级,每个层级也叫container(容器)
- Figure: 顶层级别,用来容纳所有的绘图元素
- Axes: matplotlib的核心,容纳了大量元素来构造一幅幅子图,一个 figure可以由多个或一个子图组成
- Axis: axes的下属层级,用于处理所有和坐标轴,网格有关的元素
- Tick: axis的下属层级,用来处理所有与刻度有关的元素
4.两种绘图接口
Code_1
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x = np.linspace(0, 2, 100)
#作为序列生成器, numpy.linspace()函数用于在线性空间中以均匀步长生成数字序列。
#array = numpy.linspace(start, end, num=num_points)将在start和end之间生成一个统一的序列,共有num_points个元素。
#num_points更大,曲线更顺滑
fig, ax = plt.subplots()
#创建子图plt.subplots(nrows, ncols)
#在一个界面内以网格布局,展示多个函数图像,以二维数组一样的位置,设置该处的内容
ax.plot(x, x, label = 'linear')
ax.plot(x, x**2, label = 'quadratic')
ax.plot(x, x**3, label = 'cubic')
ax.set_xlabel('x label')
ax.set_ylabel('y label')
ax.set_title('Simple Plot')
ax.legend() #用于给图像加图例
#图例是集中于地图一角或一侧的地图上各种符号和颜色所代表内容与指标的说明,有助于更好的认识地图。
plt.show()
Code_2
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x = np.linspace(0, 2, 100)
plt.plot(x, x, label = 'linear')
plt.plot(x, x**2, label = 'quadratic')
plt.plot(x, x**3, label = 'cubic')
plt.xlabel('x label')
plt.ylabel('y label')
plt.title('Simple Plot')
plt.legend()
plt.show()
关于更多matplotlib.pyplot.subplots(nrows, ncols)使用请点击参见
Matplotlib subplots()函数 - Matplotlib教程™ (yiibai.com)
link:https://www.yiibai.com/matplotlib/matplotlib_subplots_function.html
关于更多的matplotlib.pyplot.legend(*args, **kwargs)使用请点击参见:matplotlib中plt.legend等的使用方法 - Rogn - 博客园 (cnblogs.com)
link:https://www.cnblogs.com/lfri/p/12248629.html
5.通用绘图模板
Code
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
#step1 准备数据
x = np.linspace(0, 2, 100)
y = x**2
#step2 设置绘图样式
mpl.rc('lines', linewidth = 4, linestyle = '-.')
#stpe3 定义布局
fig, ax = plt.subplots()
#step4 绘制图像
ax.plot(x, y, label = 'linear')
#step5 添加标签,文字和图例
ax.set_xlabel('x label')
ax.set_ylabel('y label')
ax.set_title('Simple Plot Template')
ax.legend()
plt.show()
6.思考题
- 请思考两种绘图模式的优缺点和各自适合的使用场景
- 在第五节绘图模板中我们是以OO模式作为例子展示的,请思考并写一个pyplot绘图模式的简单模板
OO-style代码更复杂,但更适用于复杂图像
而pyplot绘图可以使得代码更简洁,但只适合与简单的图像
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
#step1 准备数据
x = np.linspace(0, 2, 100)
y = x**2
#step2 设置绘图样式
mpl.rc('lines', linewidth = 4, linestyle = '-.')
#step3 绘制图像
plt.plot(x, y, label = 'linear')
#step4 添加标签,文字和图例
plt.xlabel('x label')
plt.ylabel('y label')
plt.title('Simple Plot Template')
plt.legend()
plt.show()
二、艺术画笔见乾坤
1.概述
1.1matplotlib的三层api
matplotlib的基础绘图逻辑是:用Artist对象在画布(canvas)上绘制(Render)图形。
三层api:
matplotlib.backend_bases.FigureCanvas 代表了绘图区,所有的图像都是在绘图区完成的
matplotlib.backend_bases.Renderer 代表了渲染器,可以近似理解为画笔,控制如何在 FigureCanvas 上画图。
matplotlib.artist.Artist 代表了具体的图表组件,即调用了Renderer的接口在Canvas上作图。
前两者处理程序和计算机的底层交互的事项,第三项Artist就是具体的调用接口来做出我们想要的图,比如图形、文本、线条的设定。所以通常来说,我们95%的时间,都是用来和matplotlib.artist.Artist类打交道的。
1.2 Artist的分类
Artist 有两种类型: primitives 和 containers
primitive
是基本要素,它包含一些我们要在绘图区作图用到的标准图形对象,如曲线Line2D,文字text,矩形Rectangle,图像image等。
container
是容器,即用来装基本要素的地方,包括图形figure、坐标系Axes和坐标轴Axis。他们之间的关系如下图所示:
2.基本元素 - primitives
2.1—2DLines
更多内容见Line2D文档:matplotlib.lines.Line2D — Matplotlib 3.5.1 documentation
matplotlib 中曲线的绘制, 主要由类 **matplotlib.lines.Line2D **完成
常用的参数:
**xdata:**x轴上的取值,默认为range(1, len(ydata + 1))
ydata: y轴上的取值
linewidth: 线条的宽度
color: 线条颜色
marker: 点的标记,即形状(参考matplotlib.markers — Matplotlib 3.5.1 documentation)
**markersize:**标记的size
设置Line2D的属性
# 1) 直接在plot()函数中设置
x = range(0,5)
y = [2,5,7,8,10]
plt.plot(x,y, linewidth=10); # 设置线的粗细参数为10
# 2) 通过获得线对象,对线对象进行设置
x = range(0,5)
y = [2,5,7,8,10]
line, = plt.plot(x, y, '-') # 这里等号坐标的line,是一个列表解包的操作,目的是获取plt.plot返回列表中的Line2D对象
line.set_antialiased(False); # 关闭抗锯齿功能
# 3) 获得线属性,使用setp()函数设置
x = range(0,5)
y = [2,5,7,8,10]
lines = plt.plot(x, y)
plt.setp(lines, color='r', linewidth=10);
绘制lines
plot方法绘制:
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x = range(0, 5)
y1 = [2, 5, 7, 8, 10]
y2 = [3, 6, 8, 9, 11]
fig, ax = plt.subplots()
ax.plot(x, y1)
ax.plot(x, y2)
print(ax.lines) # 可以看到有两个对象
plt.show()
Line2D绘制:
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from matplotlib.lines import Line2D # Line2D所需库
x = range(0, 5)
y1 = [2, 5, 7, 8, 10]
y2 = [3, 6, 8, 9, 11]
fig, ax = plt.subplots()
lines = [Line2D(x, y1), Line2D(x, y2, color = 'orange')] # 显式创建
for line in lines:
ax.add_line(line) # 添加到子图 ax
ax.set_xlim(0, 4) # 对X轴设置坐标值的范围
ax.set_ylim(2, 11)
plt.show()
误差折线图绘制(errorbar)
常用参数如下:
x: x轴取值
**y:**y轴取值
yerr: y轴误差
xerr: x轴误差
fmt: 指定折线图中某个点的颜色,形状,线条风格,例如‘co–’
ecolor: error bar的颜色
elinewidth: 指定error bar的线条宽度
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
fig = plt.figure()
x = np.arange(10)
y = 2.5 * np.sin(x / 20 * np.pi)
yerr = np.linspace(0.05, 0.2, 10)
plt.errorbar(x, y + 3, yerr = yerr, label = 'both limits (default)')
plt.show()
2.2 patches
matplotlib.patches.Patch类是二维图形类,并且它是众多二维图形的父类,它的所有子类见matplotlib.patches API ,
hist-直方图
matplotlib.pyplot.hist(x,bins=None,range=None, density=None, bottom=None, histtype=‘bar’, align=‘mid’, log=False, color=None, label=None, stacked=False, normed=None)
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x = np.random.randint(0, 100, 100) # 0 - 100 的 100个数据集
bins = np.arange(0, 101, 10) #设置连续的边界值,即直方图的宽度为10
plt.hist(x, bins, color = 'orange', alpha = 0.5) #alpha为透明度
plt.xlabel('scores')
plt.ylabel('count')
plt.xlim(0,100)
plt.show()
bar-柱状图
matplotlib.pyplot.bar(left, height, alpha=1, width=0.8, color=, edgecolor=, label=, lw=3)
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
y = range(1, 17)
plt.bar(np.arange(16), y, alpha = 0.5, width = 0.5,
color = 'yellow', edgecolor = 'red',
label = 'The First Bar', lw = 4)
#lw 是红色的这个内边框的宽度
plt.show()
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
fig = plt.figure()
ax1 = fig.add_subplot(111)
for i in range(1, 17):
rect = plt.Rectangle((i + 0.25, 0), 0.5 , i)
ax1.add_patch(rect)
ax1.set_xlim(0, 16)
ax1.set_ylim(0, 16)
plt.show()
Polygon - 多边形
matplotlib.patches.Polygon类是多边形类。它的构造函数:
class matplotlib.patches.Polygon(xy, closed=True, **kwargs)
xy是一个N×2的numpy array,为多边形的顶点。
closed为True则指定多边形将起点和终点重合从而显式关闭多边形。
matplotlib.patches.Polygon类中常用的是fill类,它是基于xy绘制一个填充的多边形,它的定义:
matplotlib.pyplot.fill(*args, data=None, **kwargs)
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x = np.linspace(0, 5 * np.pi, 1000)
y1 = np.sin(x)
y2 = np.sin(2 * x)
plt.fill(x, y1, color = 'g', alpha = 0.3)
plt.show()
Wedge-契形
matplotlib.patches.Polygon类是多边形类。其基类是matplotlib.patches.Patch,它的构造函数:
class matplotlib.patches.Wedge(center, r, theta1, theta2, width=None, **kwargs)
一个Wedge-契形 是以坐标x,y为中心,半径为r,从θ1扫到θ2(单位是度)。
如果宽度给定,则从内半径r -宽度到外半径r画出部分楔形。wedge中比较常见的是绘制饼状图。
matplotlib.pyplot.pie语法:
matplotlib.pyplot.pie(x, explode=None, labels=None, colors=None, autopct=None, pctdistance=0.6, shadow=False, labeldistance=1.1, startangle=0, radius=1, counterclock=True, wedgeprops=None, textprops=None, center=0, 0, frame=False, rotatelabels=False, *, normalize=None, data=None)
制作数据x的饼图,每个楔子的面积用x/sum(x)表示。
其中最主要的参数是前4个:
- x:契型的形状,一维数组。
- explode:如果不是等于None,则是一个len(x)数组,它指定用于偏移每个楔形块的半径的分数。
- labels:用于指定每个契型块的标记,取值是列表或为None。
- colors:饼图循环使用的颜色序列。如果取值为None,将使用当前活动循环中的颜色。
- startangle:饼状图开始的绘制的角度。
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
explode = (0, 0.1, 0.2, 0) # 看图 对应每个块突出的距离 0则不分离
fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode = explode, labels = labels,
autopct = '%1.1f%%', shadow = True, startangle = 90)
ax1.axis('equal') #等宽高则为圆形
plt.show()
当然,正常情况下是这样玩,所以设置 hogs对应的explode为0.1即可
2.3 collections
collections类是用来绘制一组对象的集合,collections有许多不同的子类,如RegularPolyCollection, CircleCollection, Pathcollection, 分别对应不同的集合子类型。其中比较常用的就是散点图,它是属于PathCollection子类,scatter方法提供了该类的封装,根据x与y绘制不同大小或颜色标记的散点图。 它的构造方法:
Axes.scatter(self, x, y, s=None, c=None, marker=None, cmap=None, norm=None, vmin=None, vmax=None, alpha=None, linewidths=None, verts=, edgecolors=None, *, plotnonfinite=False, data=None, **kwargs)
其中最主要的参数是前5个:
- x:数据点x轴的位置
- y:数据点y轴的位置
- s:尺寸大小
- c:可以是单个颜色格式的字符串,也可以是一系列颜色
- marker: 标记的类型
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
x = [0,2,4,6,8,10]
y = [10] * len(x)
s = [20*2**n for n in range(len(x))]
plt.scatter(x, y, s = s)
plt.show()
2.4 images
images是matplotlib中绘制image图像的类,其中最常用的imshow可以根据数组绘制成图像,它的构造函数:
class matplotlib.image.AxesImage(ax, cmap=None, norm=None, interpolation=None, origin=None, extent=None, filternorm=True, filterrad=4.0, resample=False, **kwargs)
imshow根据数组绘制图像
matplotlib.pyplot.imshow(X, cmap=None, norm=None, aspect=None, interpolation=None, alpha=None, vmin=None, vmax=None, origin=None, extent=None, shape=, filternorm=1, filterrad=4.0, imlim=, resample=None, url=None, *, data=None, **kwargs)
使用imshow画图时首先需要传入一个数组,数组对应的是空间内的像素位置和像素点的值,interpolation参数可以设置不同的差值方法,具体效果如下。
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
from matplotlib.lines import Line2D # Line2D所需库
methods = [None, 'none', 'nearest', 'bilinear', 'bicubic', 'spline16',
'spline36', 'hanning', 'hamming', 'hermite', 'kaiser', 'quadric',
'catrom', 'gaussian', 'bessel', 'mitchell', 'sinc', 'lanczos']
grid = np.random.rand(4, 4)
fig, axs = plt.subplots(nrows=3, ncols=6, figsize=(9, 6),
subplot_kw={'xticks': [], 'yticks': []})
for ax, interp_method in zip(axs.flat, methods):
ax.imshow(grid, interpolation=interp_method, cmap='viridis')
ax.set_title(str(interp_method))
plt.tight_layout()
plt.show()
3. 对象容器 - Object container
容器会包含一些
primitives
,并且容器还有它自身的属性。
比如Axes Artist
,它是一种容器,它包含了很多primitives
,比如Line2D
,Text
;同时,它也有自身的属性,比如xscal
,用来控制X轴是linear
还是log
的
3.1 Figure容器
matplotlib.figure.Figure
是Artist
最顶层的container
对象容器,它包含了图表中的所有元素。一张图表的背景就是在Figure.patch
的一个矩形Rectangle
。
当我们向图表添加Figure.add_subplot()
或者Figure.add_axes()
元素时,这些都会被添加到Figure.axes
列表中。
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
fig = plt.figure()
ax1 = fig.add_subplot(211) # 作一幅2*1的图,选择第1个子图
ax2 = fig.add_axes([0.1, 0.1, 0.7, 0.3]) # 位置参数,四个数分别代表了(left,bottom,width,height)
plt.show()
print(ax1)
print(fig.axes) # fig.axes 中包含了subplot和axes两个实例, 刚刚添加的
由于Figure
维持了current axes
,因此你不应该手动的从Figure.axes
列表中添加删除元素,而是要通过Figure.add_subplot()
、Figure.add_axes()
来添加元素,通过Figure.delaxes()
来删除元素。但是你可以迭代或者访问Figure.axes
中的Axes
,然后修改这个Axes
的属性。
添加网格线
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
fig = plt.figure()
ax1 = fig.add_subplot(211)
for ax in fig.axes:
ax.grid(True)
plt.show()
Figure
也有它自己的text、line、patch、image
。你可以直接通过add primitive
语句直接添加。但是注意Figure
默认的坐标系是以像素为单位,你可能需要转换成figure坐标系:(0,0)表示左下点,(1,1)表示右上点。
Figure容器的常见属性:
Figure.patch
属性:Figure的背景矩形
Figure.axes
属性:一个Axes实例的列表(包括Subplot)
Figure.images
属性:一个FigureImages patch列表
Figure.lines
属性:一个Line2D实例的列表(很少使用)
Figure.legends
属性:一个Figure Legend实例列表(不同于Axes.legends)
Figure.texts
属性:一个Figure Text实例列表
3.2 Axes容器
matplotlib.axes.Axes
是matplotlib的核心。大量的用于绘图的Artist
存放在它内部,并且它有许多辅助方法来创建和添加Artist
给它自己,而且它也有许多赋值方法来访问和修改这些Artist
。
和Figure
容器类似,Axes
包含了一个patch属性,对于笛卡尔坐标系而言,它是一个Rectangle
;对于极坐标而言,它是一个Circle
。这个patch属性决定了绘图区域的形状、背景和边框。
import matplotlib.pyplot as plt
import matplotlib as mpl
import numpy as np
fig = plt.figure()
ax = fig.add_subplot(111)
rect = ax.patch # axes的patch是一个Rectangle实例
rect.set_facecolor('green')
plt.show()
Axes
有许多方法用于绘图,如.plot()、.text()、.hist()、.imshow()
等方法用于创建大多数常见的primitive
(如Line2D,Rectangle,Text,Image
等等)。在primitives
中已经涉及,不再赘述。
Subplot就是一个特殊的Axes,其实例是位于网格中某个区域的Subplot实例。其实你也可以在任意区域创建Axes,通过Figure.add_axes([left,bottom,width,height])来创建一个任意区域的Axes,其中left,bottom,width,height都是[0—1]之间的浮点数,他们代表了相对于Figure的坐标。
你不应该直接通过Axes.lines
和Axes.patches
列表来添加图表。因为当创建或添加一个对象到图表中时,Axes
会做许多自动化的工作:
它会设置Artist中figure和axes的属性,同时默认Axes的转换;
它也会检视Artist中的数据,来更新数据结构,这样数据范围和呈现方式可以根据作图范围自动调整。
你也可以使用Axes的辅助方法.add_line()
和.add_patch()
方法来直接添加。
另外Axes还包含两个最重要的Artist container:
ax.xaxis
:XAxis对象的实例,用于处理x轴tick以及label的绘制
ax.yaxis
:YAxis对象的实例,用于处理y轴tick以及label的绘制
会在下面章节详细说明。
Axes容器的常见属性有:
artists
: Artist实例列表
patch
: Axes所在的矩形实例
collections
: Collection实例
images
: Axes图像
legends
: Legend 实例
lines
: Line2D 实例
patches
: Patch 实例
texts
: Text 实例
xaxis
: matplotlib.axis.XAxis 实例
yaxis
: matplotlib.axis.YAxis 实例
3.3 Axis容器
matplotlib.axis.Axis
实例处理tick line
、grid line
、tick label
以及axis label
的绘制,它包括坐标轴上的刻度线、刻度label
、坐标网格、坐标轴标题。通常你可以独立的配置y轴的左边刻度以及右边的刻度,也可以独立地配置x轴的上边刻度以及下边的刻度。
刻度包括主刻度和次刻度,它们都是Tick刻度对象。
Axis
也存储了用于自适应,平移以及缩放的data_interval
和view_interval
。它还有Locator实例和Formatter实例用于控制刻度线的位置以及刻度label。
每个Axis都有一个label
属性,也有主刻度列表和次刻度列表。这些ticks
是axis.XTick
和axis.YTick
实例,它们包含着line primitive
以及text primitive
用来渲染刻度线以及刻度文本。
刻度是动态创建的,只有在需要创建的时候才创建(比如缩放的时候)。Axis也提供了一些辅助方法来获取刻度文本、刻度线位置等等。
三、布局格式定方圆
1.子图
1.1 使用plt.subplots绘制均匀状态下的子图
subplots 返回元素分别是画布和子图构成的列表
参数列表第一个参数是行行,第二个参数是列数,默认都是 1
figsize 是整个画布的大小,sharex和sharey表示是否所有子图都共享一个坐标轴
tight_layout 可以调整子图的相对大小,使得文字间不会互相重叠导致被遮盖
import numpy as np
#import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
fig, axs = plt.subplots(2, 5, figsize = (10, 4), sharex = True, sharey = True)
fig.suptitle('样例1', size = 20)
for i in range(2):
for j in range(5):
axs[i][j].scatter(np.random.randn(10), np.random.randn(10))
# randn函数返回n个数据样本,具有标准正态分布。
axs[i][j].set_title('第%d行,第%d列'%(i+1,j+1))
axs[i][j].set_xlim(-5,5)
axs[i][j].set_ylim(-5,5)
if i==1: axs[i][j].set_xlabel('横坐标')
if j==0: axs[i][j].set_ylabel('纵坐标')
fig.tight_layout() # 调整相对大小,使字符不会重叠
plt.show()
看一下不共享坐标轴和不调整相对大小的样子
subplots是面向对象的写法,显式创建一个或多个axes对象,然后进行对应的子图上绘图操作。
下面来看一下subplot的写法:
subplot的调用一般需要传入三个参数,分别是总行数,总列数,当前子图的index(索引)(n行,m列的图共有n*m个子图,index分别为1,2,3,… nm)
从上到下,从左到右递增。
如图 3*3 的
plt.figure()
# 子图1
plt.subplot(2,2,1)
plt.plot([1,2], 'r')
# 子图2
plt.subplot(2,2,2)
plt.plot([1,2], 'b')
#子图3
plt.subplot(224) # 当三位数都小于10时,可以省略中间的逗号,这行命令等价于plt.subplot(2,2,4)
plt.plot([1,2], 'g');
运行结果:
除了常规的直角坐标系,我们也可以通过projection方法画出类似的极坐标系图表
import numpy as np
#import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
N = 150
r = 2 * np.random.rand(N) #rand函数根据给定维度生成[0,1)之间的数据
theta = 2 * np.pi * np.random.rand(N)
area = 200 * r**2
colors = theta
plt.subplot(projection='polar')
plt.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75)
plt.show()
# 首先设置一下画布的大小和背景色
fig = plt.figure(figsize=(10, 6), facecolor='lightyellow')
# 再设置极坐标系
ax = plt.axes(polar=True) # 实例化极坐标系
ax.set_theta_direction(-1) # 顺时针为极坐标正方向
ax.set_theta_zero_location('N') # 极坐标 0° 方向为 N
#添加数据
data = [805, 598, 831, 586, 357, 562, 692, 623, 575, 605, 623, 585, 573,
323, 805, 873, 773, 500, 396, 744, 892, 795, 598, 494, 469, 373]
theta = np.linspace(0, 2 * np.pi, len(data)) # 等分极坐标系
# 在极坐标系中画柱形图
ax.bar(x=theta, # 柱体的角度坐标
height=data, # 柱体的高度, 半径坐标
width=0.33, # 柱体的宽度
);
data.sort() # 排序一下数据,使图形呈递增的样子变化
theta = np.linspace(0, 2 * np.pi, len(data)) # 等分极坐标系
# 在极坐标系中画柱形图
ax.bar(x = theta, # 柱体的角度坐标
height = data, # 柱体的高度, 半径坐标
width = 0.33, # 柱体的宽度
color = np.random.random((len(data),3)) # 生成 n行m列的数据,范围为 [0,1)
);
最后挖空中心,添加文字标注,去掉轴线
# 绘制中心空白,既然是画笔,那么我们再画上一层就好啦
ax.bar(x=theta, # 柱体的角度坐标
height=130, # 柱体的高度, 半径坐标
width=0.33, # 柱体的宽度
color='white'
)
# 添加数据标注
labs = data # 直接用他的数据大小做标注吧,懒得输入数据了emm
for angle, data, lab in zip(theta, data, labs):
ax.text(angle+0.03, data+100, str(data) )
ax.set_axis_off(); # 关闭坐标轴
总的代码:
import numpy as np
#import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
# 首先设置一下画布的大小和背景色
fig = plt.figure(figsize=(10, 6), facecolor='lightyellow')
# 再设置极坐标系
ax = plt.axes(polar=True) # 实例化极坐标系
ax.set_theta_direction(-1) # 顺时针为极坐标正方向
ax.set_theta_zero_location('N') # 极坐标 0° 方向为 N
#添加数据
data = [805, 598, 831, 586, 357, 562, 692, 623, 575, 605, 623, 585, 573,
323, 805, 873, 773, 500, 396, 744, 892, 795, 598, 494, 469, 373]
data.sort() # 排序一下数据,使图形呈递增的样子变化
theta = np.linspace(0, 2 * np.pi, len(data)) # 等分极坐标系
# 在极坐标系中画柱形图
ax.bar(x = theta, # 柱体的角度坐标
height = data, # 柱体的高度, 半径坐标
width = 0.33, # 柱体的宽度
color = np.random.random((len(data),3)) # 生成 n行m列的数据,范围为 [0,1)
);
# 绘制中心空白
ax.bar(x=theta, # 柱体的角度坐标
height=130, # 柱体的高度, 半径坐标
width=0.33, # 柱体的宽度
color='white'
)
# 添加数据标注
labs = data # 直接用他的数据大小做标注吧,懒得输入数据了emm
for angle, data, lab in zip(theta, data, labs):
ax.text(angle+0.03, data+100, str(data) )
ax.set_axis_off(); # 关闭坐标轴
plt.show()
3.2 GridSpec 绘制非均匀子图
非均匀的两层含义:
- 指图的比例大小不同,不过没有跨行跨列
- 指图为跨列或跨行
利用 add_gridspec 可以指定相对宽度比例参数 width_ratios 和 高度比例参数 height_ratios
import numpy as np
#import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
fig = plt.figure(figsize=(10, 4))
spec = fig.add_gridspec(nrows=2, ncols=5, width_ratios=[1,2,3,4,5], height_ratios=[1,3])
# 可以看图中体会这里的宽高比,不再赘述
fig.suptitle('样例2', size=20)
for i in range(2):
for j in range(5):
ax = fig.add_subplot(spec[i, j])
ax.scatter(np.random.randn(10), np.random.randn(10))
ax.set_title('第%d行,第%d列'%(i+1,j+1))
if i==1: ax.set_xlabel('横坐标')
if j==0: ax.set_ylabel('纵坐标')
fig.tight_layout()
plt.show()
可以看到,我们可以通过spec[i,j]来实现跨图
import numpy as np
#import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
fig = plt.figure(figsize=(10, 4))
spec = fig.add_gridspec(nrows=2, ncols=6, width_ratios=[2,2.5,3,1,1.5,2], height_ratios=[1,2])
fig.suptitle('样例3', size=20)
# sub1
ax = fig.add_subplot(spec[0, :3])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub2
ax = fig.add_subplot(spec[0, 3:5])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub3
ax = fig.add_subplot(spec[:, 5])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub4
ax = fig.add_subplot(spec[1, 0])
ax.scatter(np.random.randn(10), np.random.randn(10))
# sub5
ax = fig.add_subplot(spec[1, 1:5])
ax.scatter(np.random.randn(10), np.random.randn(10))
fig.tight_layout()
plt.show()
2、子图的方法
直线的常用画法有 axhline, axvline, axline (水平,垂直,任意方向)
import numpy as np
#import pandas as pd
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
fig, ax = plt.subplots(figsize=(4,3))
ax.axhline(0.5,0.2,0.8)
ax.axvline(0.5,0.2,0.8)
ax.axline([0.3,0.3],[0.7,0.7]);
plt.show()
使用grid方法可以添加灰色网格线
使用 set_xscale 可以设置坐标轴的规度(指对数坐标等,相当于缩放坐标轴)
四、文字图例尽眉目
1.Figure和Axes上的文本
Matplotlib具有广泛的文本支持,包括对数学表达式的支持、对栅格和矢量输出的TrueType支持、具有任意旋转的换行分隔文本以及Unicode支持。
1.1 文本API示例
pyplot API | OO API | description |
---|---|---|
text | text | 在子图axes的任意位置添加文本 |
annotate | annotate | 在子图axes的任意位置添加注解,包含指向性的箭头 |
xlabel | set_xlabel | 为子图axes添加x轴标签 |
ylabel | set_ylabel | 为子图axes添加y轴标签 |
title | set_title | 为子图axes添加标题 |
figtext | text | 在画布figure的任意位置添加文本 |
suptitle | suptitle | 为画布figure添加标题 |
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot()
# 分别为figure和ax设置标题
fig.suptitle('bold figure suptitle', fontsize=14, fontweight='bold')
ax.set_title('axes title')
# 设置x和y轴标签
ax.set_xlabel('xlabel')
ax.set_ylabel('ylabel')
# 设置x和y轴显示范围均为0到10
ax.axis([0, 10, 0, 10])
# 在子图上添加文本
ax.text(3, 8, 'boxed italics text in data coords', style='italic',
bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10})
# 在画布上添加文本,一般在子图上添加文本是更常见的操作,这种方法很少用
fig.text(0.4,0.8,'This is text for figure')
ax.plot([2], [1], 'o')
# 添加注解,第二第三个参数分别是箭头和文字的坐标
ax.annotate('annotate', xy=(2, 1), xytext=(3, 4),arrowprops=dict(facecolor='black', shrink=0.05));
plt.show()
1.2 text—子图上的文本
Axes.text(x, y, s, fontdict=None, **kwargs)
其中x
,y
为文本的位置,默认为当前坐标系下的坐标值,
s
为文本的内容,
fontdict
是可选参数,用于覆盖默认的文本属性,
**kwargs
为关键字参数,也可以用于传入文本样式参数
fontdict和* *kwargs参数,这两种方式都可以用于调整呈现的文本样式,最终效果是一样的,不仅text方法,其他文本方法如set_xlabel,set_title等同样适用这两种方式修改样式。通过一个例子演示这两种方法是如何使用的。
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure(figsize=(10,3))
axes = fig.subplots(1,2)
# 使用关键字参数修改文本样式
axes[0].text(0.3, 0.8, 'modify by **kwargs', style='italic',
bbox={'facecolor': 'red', 'alpha': 0.5, 'pad': 10});
# 使用fontdict参数修改文本样式
font = {'bbox':{'facecolor': 'red', 'alpha': 0.5, 'pad': 10}, 'style':'italic'}
axes[1].text(0.3, 0.8, 'modify by fontdict', fontdict=font)
plt.show()
1.3 xlabel和ylabel - 子图的x,y轴标签
xlabel的调用方式为Axes.set_xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)
ylabel方式类似。
其中xlabel
即为标签内容,
fontdict
和**kwargs
用来修改样式
labelpad
为标签和坐标轴的距离,默认为4,
loc
为标签位置,可选的值为’left’, ‘center’, 'right’之一,默认为居中
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
# 观察labelpad和loc参数的使用效果
fig = plt.figure(figsize=(10,6))
axes = fig.subplots(1,2)
axes[0].set_xlabel('xlabel',labelpad=20,loc='left')
# loc参数仅能提供粗略的位置调整,如果想要更精确的设置标签的位置,可以使用position参数+horizontalalignment参数来定位
# position由一个元组过程,第一个元素0.2表示x轴标签在x轴的位置,第二个元素对于xlabel其实是无意义的,随便填一个数都可以
# horizontalalignment='left'表示左对齐,这样设置后x轴标签就能精确定位在x=0.2的位置处
axes[1].set_xlabel('xlabel', position=(0.2, 0.2), horizontalalignment='left')
plt.show()
1.5 annotate(注释,注解) - 子图的注解
annotate的调用方式为Axes.annotate(text, xy, *args, **kwargs)
其中text
为注解的内容,
xy
为注解箭头指向的坐标,
其他常用的参数包括:
xytext
为注解文字的坐标,
xycoords
用来定义xy参数的坐标系,
textcoords
用来定义xytext参数的坐标系,
arrowprops
用来定义指向箭头的样式
annotate的参数非常复杂,这里仅仅展示一个简单的例子,更多参数可以查看官方文档中的annotate介绍
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure()
ax = fig.add_subplot()
ax.annotate("",
xy=(0.2, 0.2), xycoords='data',
xytext=(0.8, 0.8), textcoords='data',
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=0.2")
)
plt.show()
1.6 字体的属性设置
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
#该block讲述如何在matplotlib里面,修改字体默认属性,完成全局字体的更改。
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为新宋体。
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时 负号'-' 显示为方块和报错的问题。
#局部字体的修改方法1
x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
plt.plot(x, label='小示例图标签')
# 直接用字体的名字
plt.xlabel('x 轴名称参数', fontproperties='Microsoft YaHei', fontsize=16) # 设置x轴名称,采用微软雅黑字体
plt.ylabel('y 轴名称参数', fontproperties='Microsoft YaHei', fontsize=14) # 设置Y轴名称
plt.title('坐标系的标题', fontproperties='Microsoft YaHei', fontsize=20) # 设置坐标系标题的字体
plt.legend(loc='lower right', prop={"family": 'Microsoft YaHei'}, fontsize=10) ; # 小示例图的字体设置
plt.show()
2.Tick(刻度)上的文本
设置tick(刻度)和ticklabel(刻度标签)也是可视化中经常需要操作的步骤,matplotlib既提供了自动生成刻度和刻度标签的模式(默认状态),同时也提供了许多让使用者灵活设置的方式。
2.1 简单模式
使用set_ticks设置标签位置,set_ticklabels设置标签格式
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
#该block讲述如何在matplotlib里面,修改字体默认属性,完成全局字体的更改。
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为新宋体。
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时 负号'-' 显示为方块和报错的问题。
x1 = np.linspace(0.0, 5.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
# 使用axis的set_ticks方法手动设置标签位置的例子,该案例中由于tick设置过大,所以会影响绘图美观,不建议用此方式进行设置tick
fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True)
axs[0].plot(x1, y1)
axs[1].plot(x1, y1)
axs[1].xaxis.set_ticks(np.arange(0., 10.1, 2.))
plt.show()
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
#该block讲述如何在matplotlib里面,修改字体默认属性,完成全局字体的更改。
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为新宋体。
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时 负号'-' 显示为方块和报错的问题。
# 使用axis的set_ticklabels方法手动设置标签格式的例子
fig, axs = plt.subplots(2, 1, figsize=(5, 3), tight_layout=True)
axs[0].plot(x1, y1)
axs[1].plot(x1, y1)
ticks = np.arange(0., 8.1, 2.)
tickla = [f'{tick:1.2f}' for tick in ticks]
axs[1].xaxis.set_ticks(ticks)
axs[1].xaxis.set_ticklabels(tickla)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
#该block讲述如何在matplotlib里面,修改字体默认属性,完成全局字体的更改。
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为新宋体。
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时 负号'-' 显示为方块和报错的问题。
#一般绘图时会自动创建刻度,而如果通过上面的例子使用set_ticks创建刻度可能会导致tick的范围与所绘制图形的范围不一致的问题。
#所以在下面的案例中,axs[1]中set_xtick的设置要与数据范围所对应,然后再通过set_xticklabels设置刻度所对应的标签
import numpy as np
import matplotlib.pyplot as plt
fig, axs = plt.subplots(2, 1, figsize=(6, 4), tight_layout=True)
x1 = np.linspace(0.0, 6.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
axs[0].plot(x1, y1)
axs[0].set_xticks([0,1,2,3,4,5,6])
axs[1].plot(x1, y1)
axs[1].set_xticks([0,1,2,3,4,5,6])#要将x轴的刻度放在数据范围中的哪些位置
axs[1].set_xticklabels(['zero','one', 'two', 'three', 'four', 'five','six'],#设置刻度对应的标签
rotation=30, fontsize='small')#rotation选项设定x刻度标签倾斜30度。
axs[1].xaxis.set_ticks_position('bottom')#set_ticks_position()方法是用来设置刻度所在的位置,常用的参数有bottom、top、both、none
print(axs[1].xaxis.get_ticklines())
plt.show()
2.2 Tick Locators and Formatters
除了上述的简单模式,还可以使用Tick Locators and Formatters
完成对于刻度位置和刻度标签的设置。 其中Axis.set_major_locator和Axis.set_minor_locator方法用来设置标签的位置,Axis.set_major_formatter和Axis.set_minor_formatter方法用来设置标签的格式。这种方式的好处是不用显式地列举出刻度值列表。
set_major_formatter和set_minor_formatter这两个formatter格式命令可以接收字符串格式(matplotlib.ticker.StrMethodFormatter)或函数参数(matplotlib.ticker.FuncFormatter)来设置刻度值的格式 。
A Tick Formatters
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
#该block讲述如何在matplotlib里面,修改字体默认属性,完成全局字体的更改。
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为新宋体。
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时 负号'-' 显示为方块和报错的问题。
x1 = np.linspace(0.0, 6.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
# 接收字符串格式的例子
fig, axs = plt.subplots(2, 2, figsize=(8, 5), tight_layout=True)
for n, ax in enumerate(axs.flat):
ax.plot(x1*10., y1)
formatter = mpl.ticker.FormatStrFormatter('%1.1f')
axs[0, 1].xaxis.set_major_formatter(formatter)
formatter = mpl.ticker.FormatStrFormatter('-%1.1f')
axs[1, 0].xaxis.set_major_formatter(formatter)
formatter = mpl.ticker.FormatStrFormatter('%1.5f')
axs[1, 1].xaxis.set_major_formatter(formatter)
plt.show()
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
#该block讲述如何在matplotlib里面,修改字体默认属性,完成全局字体的更改。
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为新宋体。
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时 负号'-' 显示为方块和报错的问题。
x1 = np.linspace(0.0, 6.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
# 接收函数的例子
def formatoddticks(x, pos):
"""Format odd tick positions."""
if x % 2:
return f'{x:1.2f}'
else:
return ''
fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True)
ax.plot(x1, y1)
ax.xaxis.set_major_formatter(formatoddticks)
plt.show()
B Tick Locators
在普通的绘图中,我们可以直接通过上图的set_ticks进行设置刻度的位置,缺点是需要自己指定或者接受matplotlib默认给定的刻度。当需要更改刻度的位置时,matplotlib给了常用的几种locator的类型。如果要绘制更复杂的图,可以先设置locator的类型,然后通过axs.xaxis.set_major_locator(locator)绘制即可
locator=plt.MaxNLocator(nbins=7)
locator=plt.FixedLocator(locs=[0,0.5,1.5,2.5,3.5,4.5,5.5,6])#直接指定刻度所在的位置
locator=plt.AutoLocator()#自动分配刻度值的位置
locator=plt.IndexLocator(offset=0.5, base=1)#面元间距是1,从0.5开始
locator=plt.MultipleLocator(1.5)#将刻度的标签设置为1.5的倍数
locator=plt.LinearLocator(numticks=5)#线性划分5等分,4个刻度
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
#该block讲述如何在matplotlib里面,修改字体默认属性,完成全局字体的更改。
plt.rcParams['font.sans-serif'] = ['SimSun'] # 指定默认字体为新宋体。
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像时 负号'-' 显示为方块和报错的问题。
x1 = np.linspace(0.0, 6.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
# 接收各种locator的例子
fig, axs = plt.subplots(2, 2, figsize=(8, 5), tight_layout=True)
for n, ax in enumerate(axs.flat):
ax.plot(x1*10., y1)
locator = mpl.ticker.AutoLocator()
axs[0, 0].xaxis.set_major_locator(locator)
locator = mpl.ticker.MaxNLocator(nbins=10)
axs[0, 1].xaxis.set_major_locator(locator)
locator = mpl.ticker.MultipleLocator(5)
axs[1, 0].xaxis.set_major_locator(locator)
locator = mpl.ticker.FixedLocator([0,7,14,21,28])
axs[1, 1].xaxis.set_major_locator(locator)
plt.show()
3.legend(图例)
在具体学习图例之前,首先解释几个术语:
legend entry(图例条目)
每个图例由一个或多个legend entries组成。一个entry包含一个key和其对应的label。
legend key(图例键)
每个legend label左面的colored/patterned marker(彩色/图案标记)
legend label(图例标签)
描述由key来表示的handle的文本
legend handle(图例句柄)
用于在图例中生成适当图例条目的原始对象
以下面这个图为例,右侧的方框中的共有两个legend entry;两个legend key,分别是一个蓝色和一个黄色的legend key;两个legend label,一个名为‘Line up’和一个名为‘Line Down’的legend label
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig, ax = plt.subplots()
line_up, = ax.plot([1, 2, 3], label='Line 2')
line_down, = ax.plot([3, 2, 1], label='Line 1')
ax.legend(handles = [line_up, line_down], labels = ['Line Up', 'Line Down'])
plt.show()
图例的绘制同样有OO模式和pyplot模式两种方式,写法都是一样的,使用legend()即可调用。
以下面的代码为例,在使用legend方法时,我们可以手动传入两个变量,句柄和标签,用以指定条目中的特定绘图对象和显示的标签值。
当然通常更简单的操作是不传入任何参数,此时matplotlib会自动寻找合适的图例条目。
legend其他常用的几个参数如下:
设置图例位置
loc参数接收一个字符串或数字表示图例出现的位置
ax.legend(loc=‘upper center’) 等同于ax.legend(loc=9)
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 |
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig,axes = plt.subplots(1,4,figsize=(10,4))
for i in range(4):
axes[i].plot([0.5],[0.5])
axes[i].legend(labels='a',loc=i) # 观察loc参数传入不同值时图例的位置
fig.tight_layout()
plt.show()
设置图例边框及背景
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig = plt.figure(figsize=(10,3))
axes = fig.subplots(1,3)
for i, ax in enumerate(axes):
ax.plot([1,2,3],label=f'ax {i}')
axes[0].legend(frameon=False) #去掉图例边框
axes[1].legend(edgecolor='blue') #设置图例边框颜色
axes[2].legend(facecolor='gray'); #设置图例背景颜色,若无边框,参数无效
plt.show()
设置图例标题
import numpy as np
import matplotlib.pyplot as plt
import matplotlib as mpl
fig,ax =plt.subplots()
ax.plot([1,2,3],label='label')
ax.legend(title='legend title');
plt.show()