总结
本系列是数据可视化基础与应用的第03篇,主要介绍基于matplotlib实现数据可视化。
参考
Matplotlib从入门到精通01-matplotlib简介与绘图基本流程
参考:
https://datawhalechina.github.io/fantastic-matplotlib/第一回:Matplotlib初相识/index.html
http://c.biancheng.net/matplotlib/data-visual.html
https://www.bookstack.cn/read/huaxiaozhuan-ai/333f5abdbabf383d.md
总结
本文主要是Matplotlib从入门到精通系列第1篇,本文介绍了Matplotlib的历史,绘图元素的概念以及Matplotlib的多个层级,同时介绍了较好的参考文档置于博客前面,读者可以重点查看参考链接。本系列的目的是可以完整的完成Matplotlib从入门到精通。
Matplotlib历史
MATLAB简介:
MATlAB是美国MathWorks公司出品的商业数学软件,用于数据分析、无线通信、深度学习、量化金融与风险管理、机器人,控制系统等领域。MATLAB在数值计算方面首屈一指,也是使用最广泛的科研绘图软件之一。优点:编程效率高 便于矩阵计算。缺点:循环效率低 封装性不好。
matplotlib简介
Matplotlib 是 Python 的绘图库。 Matplotlib 由 John D. Hunter 在 2002 年开始编写,提供了一个套面向绘图对象编程的 API 接口,能够很轻松地实现各种图像的绘制,并且它可以配合 Python GUI 工具(如 PyQt、Tkinter 等)在应用程序中嵌入图形。同时 Matplotlib 也支持以脚本的形式嵌入到 IPython shell、Jupyter 笔记本、web 应用服务器中使用。它可与 NumPy 一起使用,提供了一种有效的 MatLab 开源替代方案。
初开发的Matplotlib,仅支持绘制2d图形,后来随着版本的不断更新,Matplotlib在二维绘图的基础上,构建了一部分较为实用的3D绘图程序包,通过调用该程序包一些接口可以绘制3D散点图、3D曲面图、3D线框图等
seaborn简介
Seaborn是一种开源的数据可视化工具,它在Matplotlib的基础上进行了更高级的API封装,因此可以进行更复杂的图形设计和输出。Seaborn是Matplotlib的重要补充,可以自主设置在Matplotlib中被默认的各种参数,而且它能高度兼容NumPy与Pandas数据结构以及Scipy与statsmodels等统计模式。
Seaborn是一种开源的数据可视化工具,它在Matplotlib的基础上进行了更高级的API封装,因此可以进行更复杂的图形设计和输出。
Matplotlib特点
Matplotlib: Visualization with Python
Matplotlib is a comprehensive library for creating static, animated, and interactive visualizations in Python. Matplotlib makes easy things easy and hard things possible.
Create publication quality plots.
Make interactive figures that can zoom, pan, update.
Customize visual style and layout.
Export to many file formats .
Embed in JupyterLab and Graphical User Interfaces.
Use a rich array of third-party packages built on Matplotlib.
Matplotlib安装
Python 包管理器 pip 安装
bash
pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple
Linux安装
bash
·sudo apt-get install python-matplotlib
·sudo yum install python-matplotlib
Jupyter安装
bash
!pip install matplotlib -i https://pypi.tuna.tsinghua.edu.cn/simple
Python 编程环境
bash
import matplotlib
matplotlib.__version__
'3.7.0'
绘图元素
核心概念
一个完整的matplotlib图像通常会包括以下四个层级,这些层级也被称为容器(container)
Figure:顶层级,用来容纳所有绘图元素
Axes:matplotlib宇宙的核心,容纳了大量元素用来构造一幅幅子图,一个figure可以由一个或多个子图组成
Axis:axes的下属层级,用于处理所有和坐标轴,网格有关的元素
Tick:axis的下属层级,用来处理所有和刻度有关的元素
Figure:指整个图形,您可以把它理解成一张画布,它包括了所有的子元素Axes,一组特殊的Artists(如标题,图例,色彩,轴等),以及嵌套的子图;
The whole figure. The Figure keeps track of all the child Axes, a
group of 'special' Artists (titles, figure legends, colorbars, etc),
and even nested subfigures. The easiest way to create a new Figure is with pyplot:
python
fig = plt.figure() # an empty figure with no Axes
fig, ax = plt.subplots() # a figure with a single Axes
fig, axs = plt.subplots(2, 2) # a figure with a 2x2 grid of Axes
Axes:绘制 2D 图像的实际区域,也称为轴域区,或者绘图区;
An Axes is an Artist attached to a Figure that contains a region for
plotting data, and usually includes two (or three in the case of 3D)
Axis objects (be aware of the difference between Axes and Axis) that
provide ticks and tick labels to provide scales for the data in the
Axes. Each Axes also has a title (set via set_title()), an x-label
(set via set_xlabel()), and a y-label set via set_ylabel()). The Axes
class and its member functions are the primary entry point to working
with the OOP interface, and have most of the plotting methods defined on them (e.g. ax.plot(), shown above, uses the plot method)
Axis:指坐标系中的垂直轴与水平轴,包含轴的长度大小(图中轴长为 7)、轴标签(指 x 轴,y轴)和刻度标签;
These objects set the scale and limits and generate ticks (the marks on the Axis) and ticklabels (strings labeling the ticks). The location of the ticks is determined by a Locator object and the ticklabel strings are formatted by a Formatter. The combination of the correct Locator and Formatter gives very fine control over the tick locations and labels.
Artist:您在画布上看到的所有元素都属于 Artist 对象,比如文本对象(title、xlabel、ylabel)、Line2D 对象(用于绘制2D图像)等。
Basically, everything visible on the Figure is an Artist (even Figure, Axes, and Axis objects). This includes Text objects, Line2D objects, collections objects, Patch objects, etc. When the Figure is rendered, all of the Artists are drawn to the canvas. Most Artists are tied to an Axes; such an Artist cannot be shared by multiple Axes, or moved from one to another.
下面这幅图是如何设置对应的元素。
绘图接口
matplotlib提供了两种最常用的绘图接口
1.显式创建figure和axes,在上面调用绘图方法,也被称为OO模式(object-oriented style)
2.依赖pyplot自动创建figure和axes,并绘图
OO模式
python
from matplotlib import pyplot as plt
import matplotlib as mpl
import numpy as np
x = np.linspace(0, 2, 100)
fig, ax = plt.subplots()
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()
输出为:
依赖pyplot模式
python
from matplotlib import pyplot as plt
import matplotlib as mpl
import numpy as np
x = np.linspace(0, 2, 100)
# fig, ax = plt.subplots()
# 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.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()
基本流程:
1.导入依赖
python
from matplotlib import pyplot as plt
import matplotlib as mpl
import numpy as np
2.定义x轴和y轴数据
python
x = np.linspace(0,20,200) #等差数列
y = 0.5*np.cos(2*x)*x+2.5*x #x相关的函数
3.设置绘图样式
python
# 设置绘图样式,这一步不是必须的,样式也可以在绘制图像是进行设置
mpl.rc('lines', linewidth=4, linestyle='-.')
4.定义布局
python
# 定义布局, 这一模块的扩展参考第三章进一步学习
fig, ax = plt.subplots()
5.绘制图像
python
# 绘制图像, 这一模块的扩展参考第二章进一步学习
ax.plot(x, y, label='linear')
6.添加标签文字图例
python
# step6 添加标签,文字和图例,这一模块的扩展参考第四章进一步学习
ax.set_xlabel('x label')
ax.set_ylabel('y label')
ax.set_title("Simple Plot")
ax.set_xlim(15,20) # x轴的刻度范围
ax.set_ylim(30,60) # y轴的刻度范围
ax.legend(labels='p',loc = 'upper right') ;
plt.show() #
完整代码:
python
# 1.导入依赖定义x轴和y轴数据
from matplotlib import pyplot as plt
import matplotlib as mpl
import numpy as np
#2.定义x轴和y轴数据
x = np.linspace(0,20,200) #等差数列
y = 0.5*np.cos(2*x)*x+2.5*x #x相关的函数
#3.设置绘图样式
# 设置绘图样式,这一步不是必须的,样式也可以在绘制图像是进行设置
mpl.rc('lines', linewidth=4, linestyle='-.')
#4.定义布局
# 定义布局, 这一模块的扩展参考第三章进一步学习
fig, ax = plt.subplots()
#5.绘制图像
# 绘制图像, 这一模块的扩展参考第二章进一步学习
ax.plot(x, y, label='linear')
# 6.添加标签文字图例
# step6 添加标签,文字和图例,这一模块的扩展参考第四章进一步学习
ax.set_xlabel('x label')
ax.set_ylabel('y label')
ax.set_title("Simple Plot")
ax.set_xlim(15,20) # x轴的刻度范围
ax.set_ylim(30,60) # y轴的刻度范围
ax.legend(labels='p',loc = 'upper right')
plt.show() #
输出为:
Matplotlib从入门到精通02-层次元素和容器
参考:
https://datawhalechina.github.io/fantastic-matplotlib/第一回:Matplotlib初相识/index.html
http://c.biancheng.net/matplotlib/data-visual.html
https://www.bookstack.cn/read/huaxiaozhuan-ai/333f5abdbabf383d.md
总结
本文主要是Matplotlib从入门到精通系列第2篇,本文介绍了Matplotlib的历史,绘图元素的概念以及Matplotlib的多个层级,同时介绍了较好的参考文档置于博客前面,读者可以重点查看参考链接。本系列的目的是可以完整的完成Matplotlib从入门到精通。重点参考连接
Matplotlib三个层次
Matplotlib由三个不同的层次结构组成:
1)脚本层
Matplotlib结构中的最顶层。我们编写的绘图代码大部分代码都在该层运行,它的主要工作是负责生成图形与坐标系。
2)美工层
Matplotlib结构中的第二层,它提供了绘制图形的元素时的给各种功能,例如,绘制标题、轴标签、坐标刻度等。
3)后端层
Matplotlib结构最底层,它定义了三个基本类,首先是FigureCanvas(图层画布类),它提供了绘图所需的画布,其次是Renderer(绘图操作类),它提供了在画布上进行绘图的各种方法,最后是Event(事件处理类),它提供了用来处理鼠标和键盘事件的方法。
matplotlib.backend_bases.FigureCanvas 代表了绘图区,所有的图像都是在绘图区完成的
matplotlib.backend_bases.Renderer 代表了渲染器,可以近似理解为画笔,控制如何在 FigureCanvas 上画图。
matplotlib.artist.Artist 代表了具体的图表组件,即调用了Renderer的接口在Canvas上作图。
前两者处理程序和计算机的底层交互的事项,第三项Artist就是具体的调用接口来做出我们想要的图,比如图形、文本、线条的设定。所以通常来说,我们95%的时间,都是用来和matplotlib.artist.Artist类打交道
matplotlib的原理或者说基础逻辑是,用Artist对象在画布(canvas)上绘制(Render)图形。
就和人作画的步骤类似:
准备一块画布或画纸
准备好颜料、画笔等制图工具
作画
Artist的分类-primitives和containers
参考:https://datawhalechina.github.io/fantastic-matplotlib/第二回:艺术画笔见乾坤/index.html#id2
Artist有两种类型:primitives原生的
和containers容器
。
primitive
是基本要素,它包含一些我们要在绘图区作图用到的标准图形对象,如曲线Line2D,文字text,矩形Rectangle,图像image等。
container
是容器,即用来装基本要素的地方,包括图形figure、坐标系Axes和坐标轴Axis。他们之间的关系如下图所示:
artist类可以参考下图。
第一列表示matplotlib中子图上的辅助方法,可以理解为可视化中不同种类的图表类型,如柱状图,折线图,直方图等,这些图表都可以用这些辅助方法直接画出来,属于更高层级的抽象。
第二列表示不同图表背后的artist类,比如折线图方法plot在底层用到的就是Line2D这一artist类。
第三列是第二列的列表容器,例如所有在子图中创建的Line2D对象都会被自动收集到ax.lines返回的列表中。
基本元素 - primitives-01-Line2D
基本元素 - primitives。primitives 的几种类型:曲线-Line2D,矩形-Rectangle,多边形-Polygon,图像-image。
1)以Line2D为例
参考:https://matplotlib.org/stable/api/_as_gen/matplotlib.lines.Line2D.html
https://datawhalechina.github.io/fantastic-matplotlib/第一回:Matplotlib初相识/index.html
在matplotlib中曲线的绘制,主要是通过类 matplotlib.lines.Line2D
来完成的。
matplotlib中线-line的含义
:它表示的可以是连接所有顶点的实线样式,也可以是每个顶点的标记。此外,这条线也会受到绘画风格的影响,比如,我们可以创建虚线种类的线。
python
class matplotlib.lines.Line2D(xdata, ydata, *, linewidth=None,
linestyle=None, color=None, gapcolor=None, marker=None,
markersize=None, markeredgewidth=None, markeredgecolor=None,
markerfacecolor=None, markerfacecoloralt='none', fillstyle=None,
antialiased=None, dash_capstyle=None, solid_capstyle=None,
dash_joinstyle=None, solid_joinstyle=None, pickradius=5,
drawstyle=None, markevery=None, **kwargs)[
xdata:需要绘制的line中点的在x轴上的取值,若忽略,则默认为range(1,len(ydata)+1)
ydata:需要绘制的line中点的在y轴上的取值
linewidth:线条的宽度
linestyle:线型
color:线条的颜色
marker:点的标记,详细可参考markers API
markersize:标记的size
设置Line2D的属性的3种方法
有三种方法可以用设置线的属性。
直接在plot()函数中设置
通过获得线对象,对线对象进行设置
获得线属性,使用setp()函数设置
python
from matplotlib import pyplot as plt
# 设置x和y的值
x = range(0,5)
y = [2,5,7,8,10]
# 1) 直接在plot()函数中设置
plt.plot(x,y, linewidth=10); # 设置线的粗细参数为10
plt.show()
# 2) 通过获得线对象,对线对象进行设置
line, = plt.plot(x, y, ':') # 这里等号左边的line,是一个列表解包的操作,目的是获取plt.plot返回列表中的Line2D对象
line.set_antialiased(False); # 关闭抗锯齿功能
plt.show()
# 3) 获得线属性,使用setp()函数设置
lines = plt.plot(x, y)
plt.setp(lines, color='r', linewidth=10);
plt.show()
绘制直线line的2种方法:
介绍两种绘制直线line常用的方法:
plot方法绘制
Line2D对象绘制
- plot方法绘制
python
from matplotlib import pyplot as plt
# 1. plot方法绘制
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); # 通过直接使用辅助方法画线,打印ax.lines后可以看到在matplotlib在底层创建了两个Line2D对象
# <Axes.ArtistList of 2 lines>
plt.show()
输出为:
- Line2D对象绘制
python
from matplotlib import pyplot as plt
from matplotlib.lines import Line2D
# 2. 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')] # 显式创建Line2D对象
for line in lines:
ax.add_line(line) # 使用add_line方法将创建的Line2D添加到子图中
ax.set_xlim(0,4)
ax.set_ylim(2, 11);
plt.show()
2) errorbar绘制误差折线图
参考:
matplotlib基础绘图命令之errorbar
官方文档errorbar
pyplot里有个专门绘制误差线的功能,通过errorbar类实现,它的构造函数:
python
matplotlib.pyplot.errorbar(x, y, yerr=None, xerr=None, fmt='',
ecolor=None, elinewidth=None, capsize=None, barsabove=False,
lolims=False, uplims=False, xlolims=False, xuplims=False,
errorevery=1, capthick=None, *, data=None, **kwargs)
其中最主要的参数是前几个:
x:需要绘制的line中点的在x轴上的取值
y:需要绘制的line中点的在y轴上的取值
yerr:指定y轴水平的误差
xerr:指定x轴水平的误差
fmt:指定折线图中某个点的颜色,形状,线条风格,例如'co--'
ecolor:指定error bar的颜色
elinewidth:指定error bar的线条宽度
绘制errorbar
python
import numpy as np
import matplotlib.pyplot as plt
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.errorbar(x, y + 2, yerr=yerr, uplims=True, label='uplims=True')
plt.errorbar(x, y + 1, yerr=yerr, uplims=True, lolims=True,
label='uplims=True, lolims=True')
upperlimits = [True, False] * 5
lowerlimits = [False, True] * 5
plt.errorbar(x, y, yerr=yerr, uplims=upperlimits, lolims=lowerlimits,
label='subsets of uplims and lolims')
plt.legend(loc='lower right')
plt.show()
python
import numpy as np
import matplotlib.pyplot as plt
upperlimits = [True, False] * 5
lowerlimits = [False, True] * 5
fig = plt.figure()
x = np.arange(10) / 10
y = (x + 0.1)**2
plt.errorbar(x, y, xerr=0.1, xlolims=True, label='xlolims=True')
y = (x + 0.1)**3
plt.errorbar(x + 0.6, y, xerr=0.1, xuplims=upperlimits, xlolims=lowerlimits,
label='subsets of xuplims and xlolims')
y = (x + 0.1)**4
plt.errorbar(x + 1.2, y, xerr=0.1, xuplims=True, label='xuplims=True')
plt.legend()
plt.show()
基本元素 - primitives-02-patches¶
matplotlib.patches.Patch类是二维图形类,并且它是众多二维图形的父类,它的所有子类见matplotlib.patches API ,
Patches are Artists with a face color and an edge color.
Patch类的构造函数:
python
Patch(edgecolor=None, facecolor=None, color=None, linewidth=None,
linestyle=None, antialiased=None, hatch=None, fill=True,
capstyle=None, joinstyle=None, **kwargs)
本小节重点讲述三种最常见的子类,矩形,多边形和楔形。
a. Rectangle-矩形
A rectangle defined via an anchor point xy and its width and height.
Rectangle矩形类在官网中的定义是: 通过锚点xy及其宽度和高度生成。
Rectangle本身的主要比较简单,即xy控制锚点,width和height分别控制宽和高。它的构造函数:
python
class matplotlib.patches.Rectangle(xy, width, height, angle=0.0, **kwargs)
在实际中最常见的矩形图是hist直方图和bar条形图。
1) hist-直方图
基于hist
python
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)
下面是一些常用的参数:
x: 数据集,最终的直方图将对数据集进行统计
bins: 统计的区间分布
range: tuple, 显示的区间,range在没有给出bins时生效
density: bool,默认为false,显示的是频数统计结果,为True则显示频率统计结果,这里需要注意,频率统计结果=区间数目/(总数*区间宽度),和normed效果一致,官方推荐使用density
histtype: 可选{'bar', 'barstacked', 'step', 'stepfilled'}之一,默认为bar,推荐使用默认配置,step使用的是梯状,stepfilled则会对梯状内部进行填充,效果与bar类似
align: 可选{'left', 'mid', 'right'}之一,默认为'mid',控制柱状图的水平分布,left或者right,会有部分空白区域,推荐使用默认
log: bool,默认False,即y坐标轴是否选择指数刻度
stacked: bool,默认为False,是否为堆积状图
python
import numpy as np
import matplotlib.pyplot as plt
# hist绘制直方图
x=np.random.randint(0,100,100) #生成[0-100)之间的100个数据,即 数据集
bins=np.arange(0,101,10) #设置连续的边界值,即直方图的分布区间[0,10),[10,20)...
plt.hist(x,bins,color='fuchsia',alpha=0.5)#alpha设置透明度,0为完全透明
plt.xlabel('scores')
plt.ylabel('count')
plt.xlim(0,100); #设置x轴分布范围 plt.show()
plt.show()
输出为:
基于Rectangle绘制直方图
- 导入依赖
python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import re
- 初始化数据
python
# hist绘制直方图
x=np.random.randint(0,100,100) #生成[0-100)之间的100个数据,即 数据集
bins=np.arange(0,101,10) #设置连续的边界值,即直方图的分布区间[0,10),[10,20)...
# Rectangle矩形类绘制直方图
df = pd.DataFrame(columns = ['data'])
df.loc[:,'data'] = x
print("df-->\n",df)
print("--------------------------")
"""
df-->
data
0 93
1 22
2 75
3 44
4 59
.. ...
95 6
96 90
97 90
98 60
99 32
[100 rows x 1 columns]
--------------------------
"""
- 分组数据
python
df['fenzu'] = pd.cut(df['data'], bins=bins, right = False,include_lowest=True)
print("fenzu-->\n",df)
print("--------------------------")
"""
fenzu-->
data fenzu
0 93 [90, 100)
1 22 [20, 30)
2 75 [70, 80)
3 44 [40, 50)
4 59 [50, 60)
.. ... ...
95 6 [0, 10)
96 90 [90, 100)
97 90 [90, 100)
98 60 [60, 70)
99 32 [30, 40)
[100 rows x 2 columns]
--------------------------
"""
- 统计分组数量
python
df_cnt = df['fenzu'].value_counts().reset_index()
print("df_cnt-->\n",df_cnt)
print("--------------------------")
"""
df_cnt-->
index fenzu
0 [40, 50) 13
1 [70, 80) 13
2 [60, 70) 11
3 [20, 30) 10
4 [30, 40) 10
5 [50, 60) 10
6 [90, 100) 10
7 [0, 10) 9
8 [80, 90) 8
9 [10, 20) 6
--------------------------
"""
- 统计最小最大宽度的值
python
df_cnt.loc[:,'mini'] = df_cnt['index'].astype(str).map(lambda x:re.findall('\[(.*)\,',x)[0]).astype(int)
df_cnt.loc[:,'maxi'] = df_cnt['index'].astype(str).map(lambda x:re.findall('\,(.*)\)',x)[0]).astype(int)
df_cnt.loc[:,'width'] = df_cnt['maxi']- df_cnt['mini']
print("df_cnt_minmaxwidth-->\n",df_cnt)
print("--------------------------")
"""
df_cnt_minmaxwidth-->
index fenzu mini maxi width
0 [70, 80) 13 70 80 10
1 [10, 20) 12 10 20 10
2 [80, 90) 12 80 90 10
3 [30, 40) 11 30 40 10
4 [60, 70) 11 60 70 10
5 [20, 30) 10 20 30 10
6 [40, 50) 10 40 50 10
7 [0, 10) 9 0 10 10
8 [50, 60) 7 50 60 10
9 [90, 100) 5 90 100 10
--------------------------
"""
- 排序并重置索引
python
df_cnt.sort_values('mini',ascending = True,inplace = True)
print("df_cnt_sortvalues-->\n",df_cnt)
print("--------------------------")
"""
df_cnt_sortvalues-->
index fenzu mini maxi width
1 [0, 10) 13 0 10 10
0 [10, 20) 14 10 20 10
2 [20, 30) 11 20 30 10
6 [30, 40) 9 30 40 10
8 [40, 50) 7 40 50 10
9 [50, 60) 6 50 60 10
3 [60, 70) 11 60 70 10
5 [70, 80) 10 70 80 10
7 [80, 90) 8 80 90 10
4 [90, 100) 11 90 100 10
--------------------------
"""
df_cnt.reset_index(inplace = True,drop = True)
print("df_cnt_resetindex-->\n",df_cnt)
print("--------------------------")
"""
df_cnt_resetindex-->
index fenzu mini maxi width
0 [0, 10) 13 0 10 10
1 [10, 20) 14 10 20 10
2 [20, 30) 11 20 30 10
3 [30, 40) 9 30 40 10
4 [40, 50) 7 40 50 10
5 [50, 60) 6 50 60 10
6 [60, 70) 11 60 70 10
7 [70, 80) 10 70 80 10
8 [80, 90) 8 80 90 10
9 [90, 100) 11 90 100 10
--------------------------
"""
- 用Rectangle把hist绘制出来
python
#用Rectangle把hist绘制出来
fig = plt.figure()
ax1 = fig.add_subplot(111)
for i in df_cnt.index:
rect = plt.Rectangle((df_cnt.loc[i,'mini'],0),df_cnt.loc[i,'width'],df_cnt.loc[i,'fenzu'])
print('rect-->',rect)
ax1.add_patch(rect)
"""
rect--> Rectangle(xy=(0, 0), width=10, height=10, angle=0)
rect--> Rectangle(xy=(10, 0), width=10, height=14, angle=0)
rect--> Rectangle(xy=(20, 0), width=10, height=11, angle=0)
rect--> Rectangle(xy=(30, 0), width=10, height=6, angle=0)
rect--> Rectangle(xy=(40, 0), width=10, height=12, angle=0)
rect--> Rectangle(xy=(50, 0), width=10, height=10, angle=0)
rect--> Rectangle(xy=(60, 0), width=10, height=13, angle=0)
rect--> Rectangle(xy=(70, 0), width=10, height=8, angle=0)
rect--> Rectangle(xy=(80, 0), width=10, height=5, angle=0)
rect--> Rectangle(xy=(90, 0), width=10, height=11, angle=0)
"""
ax1.set_xlim(0, 100)
ax1.set_ylim(0, 16)
plt.show()
完整代码
python
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import re
# hist绘制直方图
x=np.random.randint(0,100,100) #生成[0-100)之间的100个数据,即 数据集
bins=np.arange(0,101,10) #设置连续的边界值,即直方图的分布区间[0,10),[10,20)...
# Rectangle矩形类绘制直方图
df = pd.DataFrame(columns = ['data'])
df.loc[:,'data'] = x
df['fenzu'] = pd.cut(df['data'], bins=bins, right = False,include_lowest=True)
df_cnt = df['fenzu'].value_counts().reset_index()
df_cnt.loc[:,'mini'] = df_cnt['index'].astype(str).map(lambda x:re.findall('\[(.*)\,',x)[0]).astype(int)
df_cnt.loc[:,'maxi'] = df_cnt['index'].astype(str).map(lambda x:re.findall('\,(.*)\)',x)[0]).astype(int)
df_cnt.loc[:,'width'] = df_cnt['maxi']- df_cnt['mini']
df_cnt.sort_values('mini',ascending = True,inplace = True)
df_cnt.reset_index(inplace = True,drop = True)
#用Rectangle把hist绘制出来
fig = plt.figure()
ax1 = fig.add_subplot(111)
for i in df_cnt.index:
rect = plt.Rectangle((df_cnt.loc[i,'mini'],0),df_cnt.loc[i,'width'],df_cnt.loc[i,'fenzu'])
ax1.add_patch(rect)
ax1.set_xlim(0, 100)
ax1.set_ylim(0, 16)
plt.show()
输出为:
2) bar-柱状图
python
matplotlib.pyplot.bar(left, height, alpha=1, width=0.8, color=,
edgecolor=, label=, lw=3)
下面是一些常用的参数:
left:x轴的位置序列,一般采用range函数产生一个序列,但是有时候可以是字符串
height:y轴的数值序列,也就是柱形图的高度,一般就是我们需要展示的数据;
alpha:透明度,值越小越透明
width:为柱形图的宽度,一般这是为0.8即可;
color或facecolor:柱形图填充的颜色;
edgecolor:图形边缘颜色
label:解释每个图像代表的含义,这个参数是为legend()函数做铺垫的,表示该次bar的标签
有两种方式绘制柱状图
bar绘制柱状图
Rectangle矩形类绘制柱状图
python
import numpy as np
import matplotlib.pyplot as plt
# bar绘制柱状图
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=3);
plt.show()
python
import matplotlib.pyplot as plt
# Rectangle矩形类绘制柱状图
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()
b. Polygon-多边形
参考:https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.Polygon.html
matplotlib.patches.Polygon类是多边形类。它的构造函数:
python
class matplotlib.patches.Polygon(xy, closed=True, **kwargs)
xy是一个N×2的numpy array,为多边形的顶点。
closed为True则指定多边形将起点和终点重合从而显式关闭多边形。
matplotlib.patches.Polygon类中常用的是fill类,它是基于xy绘制一个填充的多边形,它的定义:
python
matplotlib.pyplot.fill(*args, data=None, **kwargs)
参数说明 : 关于x、y和color的序列,其中color是可选的参数,每个多边形都是由其节点的x和y位置列表定义的,后面可以选择一个颜色说明符。您可以通过提供多个x、y、[颜色]组来绘制多个多边形。
python
import matplotlib.pyplot as plt
import numpy as np
# 用fill来绘制图形
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()
python
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.patches import Polygon
def func(x):
return (x - 3) * (x - 5) * (x - 7) + 85
a, b = 2, 9 # integral limits
x = np.linspace(0, 10)
y = func(x)
fig, ax = plt.subplots()
ax.plot(x, y, 'r', linewidth=2)
ax.set_ylim(bottom=0)
# Make the shaded region
ix = np.linspace(a, b)
iy = func(ix)
verts = [(a, 0), *zip(ix, iy), (b, 0)]
poly = Polygon(verts, facecolor='0.9', edgecolor='0.5')
ax.add_patch(poly)
ax.text(0.5 * (a + b), 30, r"$\int_a^b f(x)\mathrm{d}x$",
horizontalalignment='center', fontsize=20)
fig.text(0.9, 0.05, '$x$')
fig.text(0.1, 0.9, '$y$')
ax.spines[['top', 'right']].set_visible(False)
ax.set_xticks([a, b], labels=['$a$', '$b$'])
ax.set_yticks([])
plt.show()
输出为:
c. Wedge-契形¶
matplotlib.patches.Wedge类是楔型类。其基类是matplotlib.patches.Patch,它的构造函数:
python
class matplotlib.patches.Wedge(center, r, theta1, theta2, width=None, **kwargs)
一个Wedge-楔型 是以坐标x,y为中心,半径为r,从θ1扫到θ2(单位是度)。
如果宽度给定,则从内半径r -宽度到外半径r画出部分楔形。wedge中比较常见的是绘制饼状图。
matplotlib.pyplot.pie语法:
python
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:饼状图开始的绘制的角度。
pie绘制饼状图
python
import matplotlib.pyplot as plt
# pie绘制饼状图
labels = 'Frogs', 'Hogs', 'Dogs', 'Logs'
sizes = [15, 30, 45, 10]
explode = (0, 0.1, 0, 0)
fig1, ax1 = plt.subplots()
ax1.pie(sizes, explode=explode, labels=labels, autopct='%1.1f%%', shadow=True, startangle=90)
ax1.axis('equal'); # Equal aspect ratio ensures that pie is drawn as a circle.
plt.show()
wedge绘制饼图
python
from matplotlib.collections import PatchCollection
from matplotlib.patches import Wedge
import matplotlib.pyplot as plt
import numpy as np
# wedge绘制饼图
fig = plt.figure(figsize=(5,5))
ax1 = fig.add_subplot(111)
theta1 = 0
sizes = [15, 30, 45, 10]
patches = []
patches += [
Wedge((0.5, 0.5), .4, 0, 54),
Wedge((0.5, 0.5), .4, 54, 162),
Wedge((0.5, 0.5), .4, 162, 324),
Wedge((0.5, 0.5), .4, 324, 360),
]
colors = 100 * np.random.rand(len(patches))
p = PatchCollection(patches, alpha=0.8)
p.set_array(colors)
ax1.add_collection(p);
plt.show()
基本元素 - primitives-03-collections
参考:https://matplotlib.org/devdocs/api/collections_api.html#
collections类是用来绘制一组对象的集合,collections有许多不同的子类,如RegularPolyCollection, CircleCollection, Pathcollection, 分别对应不同的集合子类型。其中比较常用的就是散点图,它是属于PathCollection子类,scatter方法提供了该类的封装,根据x与y绘制不同大小或颜色标记的散点图。 它的构造方法:
python
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: 标记的类型
python
import matplotlib.pyplot as plt
# 用scatter绘制散点图
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()
参考:制作量角器
python
import matplotlib.pyplot as plt
from matplotlib.patheffects import withStroke
from matplotlib.collections import LineCollection
import numpy as np
fig=plt.figure(figsize=(10,8),dpi=100)
ax = fig.add_subplot(111, projection='polar')
# 设置坐标系为0到180度,半径为10,去掉刻度标签和网格线,量角器的形状就出来了
ax.set_thetamin(0)
ax.set_thetamax(180)
ax.set_rlim(0, 10)
ax.set_xticklabels([])
ax.set_yticklabels([])
ax.grid(False)
# 因为要画的线比较多,用for循环plot来画会比较慢,这里使用LineCollection来画。先用数组创建出线的坐标。
# 再用ax.add_collection方法一次性画出来
scale = np.zeros((181, 2, 2))
scale[:, 0, 0] = np.linspace(0, np.pi, 181) # 刻度线的角度值
scale[:, 0, 1] = 9.6 # 每度的刻度线起始点r值
scale[::5, 0, 1] = 9.3 # 每5度的刻度线起始点r值
scale[::10, 0, 1] = 2 # 每10度的刻度线起始点r值
scale[::90, 0, 1] = 0 # 90度的刻度线起始点r值
scale[:, 1, 0] = np.linspace(0, np.pi, 181)
scale[:, 1, 1] = 10
line_segments = LineCollection(scale, linewidths=[1, 0.5, 0.5, 0.5, 0.5],
color='k', linestyle='solid')
ax.add_collection(line_segments)
# 接下来再画两个半圆和45度刻度线。再加上数字。大功告成。
c = np.linspace(0, np.pi, 500)
ax.plot(c, [7]*c.size, color='k', linewidth=0.5)
ax.plot(c, [2]*c.size, color='k', linewidth=0.5)
ax.plot([0, np.deg2rad(45)], [0, 10],
color='k', linestyle='--', linewidth=0.5)
ax.plot([0, np.deg2rad(135)], [0, 10],
color='k', linestyle='--', linewidth=0.5)
text_kw = dict(rotation_mode='anchor',
va='top', ha='center', color='black', clip_on=False,
path_effects=[withStroke(linewidth=5, foreground='white')])
for i in range(10, 180, 10):
theta = np.deg2rad(i)
if theta == np.pi/2:
ax.text(theta, 8.7, i, fontsize=18, **text_kw)
continue
ax.text(theta, 8.9, i, rotation=i-90, fontsize=12, **text_kw)
ax.text(theta, 7.9, 180-i, rotation=i-90, fontsize=12, **text_kw)
plt.show()
基本元素 - primitives-04-images
images是matplotlib中绘制image图像的类,
AxesImage
BboxImage
FigureImage
NonUniformImage
PcolorImage
composite_images()
imread()
imsave()
pil_to_array()
thumbnail()
支持基本的图像加载、缩放和显示操作。其中最常用的imshow可以根据数组绘制成图像,它的构造函数:
python
class matplotlib.image.AxesImage(ax, cmap=None, norm=None,
interpolation=None, origin=None, extent=None, filternorm=True,
filterrad=4.0, resample=False, **kwargs)
imshow根据数组绘制图像
python
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参数可以设置不同的差值方法,具体效果如下。
python
import matplotlib.pyplot as plt
import numpy as np
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()
容器-container-01-Figure容器
对象容器 - Object container,容器会包含一些primitives,并且容器还有它自身的属性。
比如Axes Artist,它是一种容器,它包含了很多primitives,比如Line2D,Text;同时,它也有自身的属性,比如xscal,用来控制X轴是linear还是log的。
- Figure容器
python
from matplotlib import pyplot as plt
from matplotlib.lines import Line2D
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)
print(ax1)
print(fig.axes) # fig.axes 中包含了subplot和axes两个实例, 刚刚添加的
# Axes(0.125,0.53;0.775x0.35)
# [<Axes: >, <Axes: >]
plt.show()
由于Figure维持了current axes,因此你不应该手动的从Figure.axes列表中添加删除元素,而是要通过Figure.add_subplot()、Figure.add_axes()来添加元素,通过Figure.delaxes()来删除元素。但是你可以迭代或者访问Figure.axes中的Axes,然后修改这个Axes的属性。
python
from matplotlib import pyplot as plt
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实例列表
容器-container-02-Axes容器
matplotlib.axes.Axes是matplotlib的核心。
The Axes class represents one (sub-)plot in a figure. It contains the plotted data, axis ticks, labels, title, legend, etc. Its methods are the main interface for manipulating the plot.
Axes类表示图形中的一个(子)图。它包含绘制的数据、轴刻度、标签、标题、图例等。它的方法是操纵情节的主要界面。
大量的用于绘图的Artist存放在它内部,并且它有许多辅助方法来创建和添加Artist给它自己,而且它也有许多赋值方法来访问和修改这些Artist。
和Figure容器类似,Axes包含了一个patch属性,对于笛卡尔坐标系而言,它是一个Rectangle;对于极坐标而言,它是一个Circle。这个patch属性决定了绘图区域的形状、背景和边框。
python
from matplotlib import pyplot as plt
fig = plt.figure()
ax1 = fig.add_subplot(121)
rect = ax1.patch # axes的patch是一个Rectangle实例
rect.set_facecolor('green')
ax2 = fig.add_subplot(122,polar=True)
rect = ax2.patch # axes的patch是一个Circle实例
rect.set_facecolor('red')
plt.show()
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 实例
容器-container-03- Axis容器
参考:https://matplotlib.org/devdocs/api/axis_api.html
matplotlib.axis.Axis实例处理tick line、grid line、tick label以及axis label的绘制,它包括坐标轴上的刻度线、刻度label、坐标网格、坐标轴标题。通常你可以独立的配置y轴的左边刻度以及右边的刻度,也可以独立地配置x轴的上边刻度以及下边的刻度。
刻度包括主刻度和次刻度,它们都是Tick刻度对象
python
from matplotlib import pyplot as plt
fig, ax = plt.subplots()
x = range(0,5)
y = [2,5,7,8,10]
plt.plot(x, y, '-')
axis = ax.xaxis # axis为X轴对象
print(axis.get_ticklocs()) # 获取刻度线位置
print(axis.get_ticklabels()) # 获取刻度label列表(一个Text实例的列表)。 可以通过minor=True|False关键字参数控制输出minor还是major的tick label。
print(axis.get_ticklines()) # 获取刻度线列表(一个Line2D实例的列表)。 可以通过minor=True|False关键字参数控制输出minor还是major的tick line。
print(axis.get_data_interval())# 获取轴刻度间隔
print(axis.get_view_interval())# 获取轴视角(位置)的间隔
plt.show()
输出为:
[-0.5 0. 0.5 1. 1.5 2. 2.5 3. 3.5 4. 4.5]
[Text(-0.5, 0, '−0.5'), Text(0.0, 0, '0.0'), Text(0.5, 0, '0.5'), Text(1.0, 0, '1.0'),
Text(1.5, 0, '1.5'), Text(2.0, 0, '2.0'), Text(2.5, 0, '2.5'), Text(3.0, 0, '3.0'), Text(3.5, 0, '3.5'), Text(4.0, 0, '4.0'), Text(4.5, 0, '4.5')]
<a list of 22 Line2D ticklines objects>
[0. 4.]
[-0.2 4.2]
python
from matplotlib import pyplot as plt
fig = plt.figure() # 创建一个新图表
rect = fig.patch # 矩形实例并将其设为黄色
rect.set_facecolor('lightgoldenrodyellow')
ax1 = fig.add_axes([0.1, 0.3, 0.4, 0.4]) # 创一个axes对象,从(0.1,0.3)的位置开始,宽和高都为0.4,
rect = ax1.patch # ax1的矩形设为灰色
rect.set_facecolor('lightslategray')
for label in ax1.xaxis.get_ticklabels():
# 调用x轴刻度标签实例,是一个text实例
label.set_color('red') # 颜色
label.set_rotation(45) # 旋转角度
label.set_fontsize(16) # 字体大小
for line in ax1.yaxis.get_ticklines():
# 调用y轴刻度线条实例, 是一个Line2D实例
line.set_markeredgecolor('green') # 颜色
line.set_markersize(25) # marker大小
line.set_markeredgewidth(2)# marker粗细
plt.show()
容器-container-04-Tick容器
Abstract base class for the axis ticks, grid lines and labels.
Ticks mark a position on an Axis. They contain two lines as markers and two labels; one each for the bottom and top positions (in case of an
.XAxis
) or for the left and right positions (in case of a.YAxis
).轴刻度、网格线和标签的抽象基类。刻度标记轴上的位置。它们包含两行作为标记和两个标签;底部和顶部位置各一个' . xaxis ')或用于左右位置(如果是' . yaxis ')。
matplotlib.axis.Tick是从Figure到Axes到Axis到Tick中最末端的容器对象。
Tick包含了tick、grid line实例以及对应的label。
python
from matplotlib import pyplot as plt
import numpy as np
import matplotlib
fig, ax = plt.subplots()
ax.plot(100*np.random.rand(20))
# 设置ticker的显示格式
formatter = matplotlib.ticker.FormatStrFormatter('$%1.2f')
ax.yaxis.set_major_formatter(formatter)
# 设置ticker的参数,右侧为主轴,颜色为绿色
ax.yaxis.set_tick_params(which='major', labelcolor='green',
labelleft=False, labelright=True);
plt.show()
Matplotlib从入门到精通03-布局格式定方圆
参考:
https://datawhalechina.github.io/fantastic-matplotlib/第一回:Matplotlib初相识/index.html
https://matplotlib.org/stable/index.html
http://c.biancheng.net/matplotlib/data-visual.html
总结
本文主要是Matplotlib从入门到精通系列第3篇,本文介绍了Matplotlib的子图布局,同时介绍了较好的参考文档置于博客前面,读者可以重点查看参考链接。本系列的目的是可以完整的完成Matplotlib从入门到精通。重点参考连接
Matplotlib从入门到精通03-布局格式定方圆
导入依赖设置中文坐标轴负号
python
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 #用来正常显示负号
Matplotlib绘制子图
1. 使用 plt.subplots 绘制均匀状态下的子图¶
参考:https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.subplots.html
python
matplotlib.pyplot.subplots(nrows=1, ncols=1, *, sharex=False, sharey=False, squeeze=True, width_ratios=None,
height_ratios=None, subplot_kw=None, gridspec_kw=None, **fig_kw)
第一个数字为行,
第二个为列,不传入时默认值都为1
figsize 参数可以指定整个画布的大小
sharex 和 sharey 分别表示是否共享横轴和纵轴刻度
tight_layout 函数可以调整子图的相对大小使字符不会重叠
返回元素分别是画布和子图构成的列表,
fig:Figure
ax:Axes or array of Axes
返回值案例
python
# using the variable ax for single a Axes
fig, ax = plt.subplots()
# using the variable axs for multiple Axes
fig, axs = plt.subplots(2, 2)
# using tuple unpacking for multiple Axes
fig, (ax1, ax2) = plt.subplots(1, 2)
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
绘制多个整齐排列的子图
python
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))
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()
# fig.show()
# plt.pause(0)
subplots是基于OO模式的写法,显式创建一个或多个axes对象,然后在对应的子图对象上进行绘图操作。
2.使用subplot这样基于pyplot模式绘制子图
还有种方式是使用subplot这样基于pyplot模式的写法,每次在指定位置新建一个子图,并且之后的绘图操作都会指向当前子图,本质上subplot也是Figure.add_subplot的一种封装。
Add an Axes to the current figure or retrieve an existing Axes.
This is a wrapper of Figure.add_subplot which provides additional behavior when working with the implicit API (see the notes section).
python
matplotlib.pyplot.subplot(*args, **kwargs)
调用subplot案例
python
subplot(nrows, ncols, index, **kwargs)
subplot(pos, **kwargs)
subplot(**kwargs)
subplot(ax)
在调用subplot时一般需要传入三位数字,分别代表总行数,总列数,当前子图的index
python
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')
plt.show()
除了常规的直角坐标系,也可以通过projection方法创建极坐标系下的图表
python
import copy
N = 150
r = copy.deepcopy(2 * np.random.rand(N))
theta = copy.deepcopy(2 * np.pi * np.random.rand(N))
print('theta.size:{}--theta[0:5]{}\n'.format(theta.size,theta[0:5],theta.max()))
print('theta.max:{}\n'.format(theta.max()))
# theta.size:150--theta[0:5][4.79750376 4.7365522 4.15253206 5.10639503 2.18095445]
# theta.max:6.277904493717284
area = copy.deepcopy(200 * r**2)
print('area.size:{}--area[0:5]{}\n'.format(area.size,area[0:5],area.max()))
print('area.max:{}\n'.format(area.max()))
# area.size:150--area[0:5][659.7790882 179.13939507 219.69376541 39.21408373 82.3782166 ]
# area.max:790.7976635649974
colors = theta
plt.subplot(projection='polar')
plt.scatter(theta, r, c=colors, s=area, cmap='hsv', alpha=0.75)
plt.show()
请思考如何用极坐标系画出类似的玫瑰图
python
fig = plt.figure(figsize=(10, 6))
ax = plt.subplot(111, projection='polar')
ax.set_theta_direction(-1) # 顺时针
ax.set_theta_zero_location('N') # NSWE
r = np.arange(100, 800, 20)
theta = np.linspace(0, np.pi * 2, len(r), endpoint=False)
print(theta,"--------------")
"""
[0. 0.17951958 0.35903916 0.53855874 0.71807832 0.8975979
1.07711748 1.25663706 1.43615664 1.61567622 1.7951958 1.97471538
2.15423496 2.33375454 2.51327412 2.6927937 2.87231328 3.05183286
3.23135244 3.41087202 3.5903916 3.76991118 3.94943076 4.12895034
4.30846992 4.48798951 4.66750909 4.84702867 5.02654825 5.20606783
5.38558741 5.56510699 5.74462657 5.92414615 6.10366573] --------------
"""
ax.bar(theta, r, width=0.18, color=np.random.random((len(r), 3)),
align='edge', bottom=100)
ax.text(np.pi * 3 / 2 - 0.2, 90, '极坐标玫瑰', fontsize=8)
for angle, height in zip(theta, r):
ax.text(angle + 0.03, height + 120, str(height), fontsize=height / 80)
plt.axis('off')
plt.tight_layout()
plt.show()
3. 使用 GridSpec 绘制非均匀子图¶
参考:https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.figure.html
所谓非均匀包含两层含义,第一是指图的比例大小不同但没有跨行或跨列,第二是指图为跨列或跨行状态
利用 add_gridspec 可以指定相对宽度比例 width_ratios 和相对高度比例参数 height_ratios
python
fig = plt.figure(figsize=(10, 4))
spec = fig.add_gridspec(nrows=2, ncols=5, width_ratios=[1,2,3,4,3], height_ratios=[1,3])
print(spec) # GridSpec(2, 5, height_ratios=[1, 3], width_ratios=[1, 2, 3, 4, 5])
print(spec[9]) # GridSpec(2, 5, height_ratios=[1, 3], width_ratios=[1, 2, 3, 4, 5])[1:2, 4:5]
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] 的用法,事实上通过切片就可以实现子图的合并而达到跨图的功能
python
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()
二子图上的方法¶
补充介绍一些子图上的方法
常用直线的画法为: axhline, axvline, axline (水平、垂直、任意方向)
python
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()
使用 set_xscale 可以设置坐标轴的规度(指对数坐标等)
python
fig, axs = plt.subplots(1, 2, figsize=(10, 4))
for j in range(2):
axs[j].plot(list('abcd'), [10**i for i in range(4)])
if j==0:
axs[j].set_yscale('log') # 'linear', 'log', 'symlog', 'asinh', 'logit', 'function', 'functionlog'
else:
pass
fig.tight_layout()
plt.show()
思考题
用 np.random.randn(2, 150) 生成一组二维数据,使用两种非均匀子图的分割方法,做出该数据对应的散点图和边际分布图
解题办法:
参考:https://blog.csdn.net/YangTinTin/article/details/122592342
方法1,不跨行:
python
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import gridspec
data=np.random.randn(2, 150)
fig = plt.figure(figsize=(6,6))
spec = gridspec.GridSpec(nrows=2, ncols=2, width_ratios=[5,1], height_ratios=[1,5])
## 使用过fig.add_gridspec 报错,,就没使用
#子图1
ax=fig.add_subplot(spec[0,0])
ax.hist(data[0,:],bins=10,rwidth=0.8,color='b',alpha=0.5) # rwidth=0.8 设置柱子宽度百分比,防止挨在一起
for word in ['right','left','top','bottom']:
ax.spines[word].set_visible(False) #边框不可见
ax.get_xaxis().set_visible(False) # x轴不可见
ax.get_yaxis().set_visible(False) # y轴不可见
#子图3
ax=fig.add_subplot(spec[1,0])
# 设置点的形状、大小,颜色
area=200*np.random.rand(150)
colors=np.random.rand(150)
#ax.scatter(data[0,:],data[1,:],color='r',marker='*',s=area) # 只有一种颜色时,用c或color都可,多种颜色,用参数c
ax.scatter(data[0,:],data[1,:],c=colors,marker='o',s=area,cmap='hsv',alpha=0.75)#cmap 色谱
ax.grid(True)
ax.set_xlabel('my_data_x')
ax.set_ylabel('my_data_y')
#子图4
ax=fig.add_subplot(spec[1,1])
ax.hist(data[1,:],orientation='horizontal',bins=10,rwidth=0.8,color='b',alpha=0.5)
for word in ['right','left','top','bottom']:
ax.spines[word].set_visible(False)
ax.get_xaxis().set_visible(False) # x轴不可见
ax.get_yaxis().set_visible(False) # y轴不可见
plt.tight_layout()
plt.show()
方法2 跨行
python
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import gridspec
data=np.random.randn(2, 150)
fig = plt.figure(figsize=(6,6))
spec = gridspec.GridSpec(nrows=6, ncols=6, width_ratios=[1,1,1,1,1,1], height_ratios=[1,1,1,1,1,1])
## 使用过fig.add_gridspec 报错,,就没使用
#子图1
ax=fig.add_subplot(spec[0,:5])
ax.hist(data[0,:],bins=10,rwidth=0.8,color='b',alpha=0.5) # rwidth=0.8 设置柱子宽度百分比,防止挨在一起
for word in ['right','left','top','bottom']:
ax.spines[word].set_visible(False) #边框不可见
ax.get_xaxis().set_visible(False) # x轴不可见
ax.get_yaxis().set_visible(False) # y轴不可见
#子图3
ax=fig.add_subplot(spec[1:,:5])
# 设置点的形状、大小,颜色
area=200*np.random.rand(150)
colors=np.random.rand(150)
#ax.scatter(data[0,:],data[1,:],color='r',marker='*',s=area) # 只有一种颜色时,用c或color都可,多种颜色,用参数c
ax.scatter(data[0,:],data[1,:],c=colors,marker='o',s=area,cmap='hsv',alpha=0.75)#cmap 色谱
ax.grid(True)
ax.set_xlabel('my_data_x')
ax.set_ylabel('my_data_y')
#子图4
ax=fig.add_subplot(spec[1:,5:6])
ax.hist(data[1,:],orientation='horizontal',bins=10,rwidth=0.8,color='b',alpha=0.5)
for word in ['right','left','top','bottom']:
ax.spines[word].set_visible(False)
ax.get_xaxis().set_visible(False) # x轴不可见
ax.get_yaxis().set_visible(False) # y轴不可见
plt.tight_layout()
plt.show()
Matplotlib从入门到精通04-文字图例尽眉目
参考:
https://datawhalechina.github.io/fantastic-matplotlib/第一回:Matplotlib初相识/index.html
https://matplotlib.org/stable/index.html
http://c.biancheng.net/matplotlib/data-visual.html
总结
本文主要是Matplotlib从入门到精通系列第4篇,本文介绍了Matplotlib的Figure和Axes上的文本设置,Tick的文本设置,legend图例设置,同时介绍了较好的参考文档置于博客前面,读者可以重点查看参考链接。本系列的目的是可以完整的完成Matplotlib从入门到精通。重点参考连接
Matplotlib从入门到精通04-文字图例尽眉目
导入依赖设置中文坐标轴负号
python
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
import datetime
plt.rcParams['font.sans-serif'] = ['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False #用来正常显示负号
一.Figure和Axes上的文本
Matplotlib具有广泛的文本支持,包括对数学表达式的支持、对栅格和矢量输出的TrueType支持、具有任意旋转的换行分隔文本以及Unicode支持。
1.文本API示例¶
下面的命令是介绍了通过pyplot API和objected-oriented API分别创建文本的方式。
通过一个综合例子,以OO模式展示这些API是如何控制一个图像中各部分的文本,在之后的章节我们再详细分析这些api的使用技巧
python
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()
2.text - 子图上的文本¶
参考:https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.text.html#matplotlib.axes.Axes.text
text的用方式为
python
Axes.text(x, y, s, fontdict=None, **kwargs)
其中x,y为文本出现的位置,默认状态下即为当前坐标系下的坐标值,
s为文本的内容,
fontdict是可选参数,用于覆盖默认的文本属性,
**kwargs为关键字参数,也可以用于传入文本样式参数
重点解释下fontdict和**kwargs参数,这两种方式都可以用于调整呈现的文本样式,最终效果是一样的,不仅text方法,其他文本方法如set_xlabel,set_title等同样适用这两种方式修改样式。通过一个例子演示这两种方法是如何使用的。
python
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()
text的参数可参考官方文档
3.xlabel和ylabel - 子图的x,y轴标签¶
参考:https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.set_xlabel.html
xlabel的调用方式为
python
Axes.set_xlabel(xlabel, fontdict=None, labelpad=None, *, loc=None, **kwargs)
ylabel方式类似,这里不重复写出。
其中xlabel即为标签内容,
fontdict和**kwargs用来修改样式,上一小节已介绍,
labelpad为标签和坐标轴的距离,默认为4,
loc为标签位置,可选的值为'left', 'center', 'right'之一,默认为居中
python
# 观察labelpad和loc参数的使用效果
fig = plt.figure(figsize=(10,3))
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), horizontalalignment='left');
plt.show()
4.title和suptitle - 子图和画布的标题¶
title的调用方式为
python
Axes.set_title(label, fontdict=None, loc=None, pad=None, *, y=None, **kwargs)
其中label为子图标签的内容,fontdict,loc,**kwargs和之前小节相同不重复介绍
pad是指标题偏离图表顶部的距离,默认为6
y是title所在子图垂向的位置。默认值为1,即title位于子图的顶部。
suptitle的调用方式为figure.suptitle(t, **kwargs)
其中t为画布的标题内容
python
fig, ax = plt.subplots(1,2)
fruits = ['apple', 'blueberry', 'cherry', 'orange']
counts = [40, 100, 30, 55]
bar_labels = ['red', 'blue', '_red', 'orange']
bar_colors = ['tab:red', 'tab:blue', 'tab:red', 'tab:orange']
ax[0].bar(fruits, counts, label=bar_labels, color=bar_colors)
ax[0].set_ylabel('fruit supply')
ax[0].set_title('Fruit supply by kind and color')
ax[0].legend(title='Fruit color')
ax[1].set_title('空的title')
plt.show()
5.annotate - 子图的注解¶
annotate的调用方式为
python
Axes.annotate(text, xy, *args, **kwargs)
其中text为注解的内容,
xy为注解箭头指向的坐标,
其他常用的参数包括:
xytext为注解文字的坐标,
xycoords用来定义xy参数的坐标系,
textcoords用来定义xytext参数的坐标系,
arrowprops用来定义指向箭头的样式
annotate的参数非常复杂,这里仅仅展示一个简单的例子,更多参数可以查看官方文档中的annotate介绍
python
fig, ax = plt.subplots(figsize=(3, 3))
x = [1, 3, 5, 7, 9]
y = [2, 4, 6, 8, 10]
annotations = ["A", "B", "C", "D", "E"]
ax.scatter(x, y, s=20)
for xi, yi, text in zip(x, y, annotations):
ax.annotate(text,
xy=(xi, yi), xycoords='data',
xytext=(1.5, 1.5), textcoords='offset points')
plt.show()
6.字体的属性设置¶
字体设置一般有全局字体设置和自定义局部字体设置两种方法。
为方便在图中加入合适的字体,可以尝试了解中文字体的英文名称,该链接告诉了常用中文的英文名称
python
#该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='KaiTi', fontsize=16) # 设置x轴名称,采用楷体
plt.ylabel('y 轴名称参数-幼园', fontproperties='YouYuan', fontsize=14) # 设置Y轴名称 采用幼园
plt.title('坐标系的标题-微软雅黑', fontproperties='Microsoft YaHei', fontsize=20) # 设置坐标系标题的字体 采用微软雅黑
plt.legend(loc='lower right', prop={"family": 'SimHei'}, fontsize=10) ; # 小示例图的字体设置 采用黑体
plt.show()
二、Tick上的文本¶
设置tick(刻度)和ticklabel(刻度标签)也是可视化中经常需要操作的步骤,matplotlib既提供了自动生成刻度和刻度标签的模式(默认状态),同时也提供了许多让使用者灵活设置的方式。
1.简单模式¶
可以使用axis的set_ticks方法手动设置标签位置,使用axis的set_ticklabels方法手动设置标签格式
python
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()
python
x1 = np.linspace(0.0, 5.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
# 使用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()
python
#一般绘图时会自动创建刻度,而如果通过上面的例子使用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.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
python
# 接收字符串格式的例子
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 = matplotlib.ticker.FormatStrFormatter('%1.1f')
axs[0, 1].xaxis.set_major_formatter(formatter)
formatter = matplotlib.ticker.FormatStrFormatter('-%1.1f')
axs[1, 0].xaxis.set_major_formatter(formatter)
formatter = matplotlib.ticker.FormatStrFormatter('%1.5f')
axs[1, 1].xaxis.set_major_formatter(formatter);
plt.show()
python
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)#自动选择合适的位置,并且刻度之间最多不超过7(nbins)个间隔
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个刻度
python
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 = matplotlib.ticker.AutoLocator()
axs[0, 0].xaxis.set_major_locator(locator)
locator = matplotlib.ticker.MaxNLocator(nbins=3)
axs[0, 1].xaxis.set_major_locator(locator)
locator = matplotlib.ticker.MultipleLocator(5)
axs[1, 0].xaxis.set_major_locator(locator)
locator = matplotlib.ticker.FixedLocator([0,7,14,21,28])
axs[1, 1].xaxis.set_major_locator(locator);
plt.show()
此外matplotlib.dates 模块还提供了特殊的设置日期型刻度格式和位置的方式
python
x1 = np.linspace(0.0, 6.0, 100)
y1 = np.cos(2 * np.pi * x1) * np.exp(-x1)
# 特殊的日期型locator和formatter
locator = mdates.DayLocator(bymonthday=[1,15,25])
formatter = mdates.DateFormatter('%b %d')
fig, ax = plt.subplots(figsize=(5, 3), tight_layout=True)
ax.xaxis.set_major_locator(locator)
ax.xaxis.set_major_formatter(formatter)
base = datetime.datetime(2017, 1, 1, 0, 0, 1)
time = [base + datetime.timedelta(days=x) for x in range(len(x1))]
ax.plot(time, y1)
ax.tick_params(axis='x', rotation=70);
plt.show()
输出为:
三、legend(图例)¶
legend组成即案例
在具体学习图例之前,首先解释几个术语:
legend entry(图例条目)
每个图例由一个或多个legend entries组成。一个entry包含一个key和其对应的label。
legend key(图例键)
每个legend label左面的colored/patterned marker(彩色/图案标记)
legend label(图例标签)
描述由key来表示的handle的文本
legend handle(图例句柄)
用于在图例中生成适当图例条目的原始对象
图例的绘制同样有OO模式和pyplot模式两种方式,写法都是一样的,使用legend()即可调用。
以下面的代码为例,在使用legend方法时,我们可以手动传入两个变量,句柄和标签,用以指定条目中的特定绘图对象和显示的标签值。
当然通常更简单的操作是不传入任何参数,此时matplotlib会自动寻找合适的图例条目。
python
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()
以上图为例,右侧的方框中的共有两个legend entry;两个legend key,分别是一个蓝色和一个黄色的legend key;两个legend label,一个名为'Line up'和一个名为'Line Down'的legend label
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
python
fig,axes = plt.subplots(2,4,figsize=(10,4))
for i in range(4):
axes[0][i].plot([0.5],[0.5])
axes[0][i].legend(labels='a',loc=i) # 观察loc参数传入不同值时图例的位置
for i in range(4,8):
t=i%4
axes[1][t].plot([0.5],[0.5])
axes[1][t].legend(labels='a',loc=i) # 观察loc参数传入不同值时图例的位置
fig.tight_layout()
plt.show()
设置图例边框及背景
python
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()
设置图例标题
python
fig,ax =plt.subplots()
ax.plot([1,2,3],label='label')
ax.legend(title='legend title');
plt.show()
Matplotlib从入门到精通05-样式色彩秀芳华
参考:
https://datawhalechina.github.io/fantastic-matplotlib/第一回:Matplotlib初相识/index.html
https://matplotlib.org/stable/index.html
http://c.biancheng.net/matplotlib/data-visual.html
总结
本文主要是Matplotlib从入门到精通系列第5篇,本文介绍了Matplotlib的绘图样式和色彩设置,同时介绍了较好的参考文档置于博客前面,读者可以重点查看参考链接。本系列的目的是可以完整的完成Matplotlib从入门到精通。重点参考连接
Matplotlib从入门到精通05-样式色彩秀芳华
第五回详细介绍matplotlib中样式和颜色的使用,绘图样式和颜色是丰富可视化图表的重要手段,因此熟练掌握本章可以让可视化图表变得更美观,突出重点和凸显艺术性。
关于绘图样式,常见的有3种方法,分别是
修改预定义样式,自定义样式和rcparams。
关于颜色使用,本章介绍了
常见的5种表示单色颜色的基本方法,以及colormap多色显示的方法。
导入依赖
python
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
一、matplotlib的绘图样式(style)¶
在matplotlib中,要想设置绘制样式,最简单的方法是在绘制元素时单独设置样式。 但是有时候,当用户在做专题报告时,往往会希望保持整体风格的统一而不用对每张图一张张修改,因此matplotlib库还提供了四种批量修改全局样式的方式
1.matplotlib预先定义样式¶
matplotlib贴心地提供了许多内置的样式供用户使用,使用方法很简单,只需在python脚本的最开始输入想使用style的名称即可调用,尝试调用不同内置样式,比较区别
python
print(plt.style.available)
plt.style.use('default')
plt.plot([1,2,3,4],[2,3,4,5]);
plt.show()
['Solarize_Light2', '_classic_test_patch', '_mpl-gallery', '_mpl-gallery-nogrid', 'bmh', 'classic', 'dark_background', 'fast', 'fivethirtyeight', 'ggplot', 'grayscale', 'seaborn-v0_8', 'seaborn-v0_8-bright', 'seaborn-v0_8-colorblind', 'seaborn-v0_8-dark', 'seaborn-v0_8-dark-palette', 'seaborn-v0_8-darkgrid', 'seaborn-v0_8-deep', 'seaborn-v0_8-muted', 'seaborn-v0_8-notebook', 'seaborn-v0_8-paper', 'seaborn-v0_8-pastel', 'seaborn-v0_8-poster', 'seaborn-v0_8-talk', 'seaborn-v0_8-ticks', 'seaborn-v0_8-white', 'seaborn-v0_8-whitegrid', 'tableau-colorblind10']
python
plt.style.use('ggplot')
plt.plot([1,2,3,4],[2,3,4,5]);
plt.show()
2.用户自定义stylesheet¶
在任意路径下创建一个后缀名为mplstyle的样式清单,编辑文件添加以下样式内容
axes.titlesize : 24
axes.labelsize : 20
lines.linewidth : 5
lines.markersize : 10
xtick.labelsize : 10
ytick.labelsize : 20
引用自定义stylesheet后观察图表变化。
python
plt.style.use('a.mplstyle')
plt.plot([1,2,3,4],[2,3,4,5])
plt.show()
值得特别注意的是,matplotlib支持混合样式的引用,只需在引用时输入一个样式列表,若是几个样式中涉及到同一个参数,右边的样式表会覆盖左边的值。
python
plt.style.use(['dark_background', 'a.mplstyle'])
plt.plot([1,2,3,4],[2,3,4,5]);
plt.show()
3.设置rcparams¶
我们还可以通过修改默认rc设置的方式改变样式,所有rc设置都保存在一个叫做 matplotlib.rcParams的变量中。
修改过后再绘图,可以看到绘图样式发生了变化。
python
plt.style.use('default') # 恢复到默认样式
mpl.rcParams['lines.linewidth'] = 2
mpl.rcParams['lines.linestyle'] = '--'
# mpl.rc('lines', linewidth=2, linestyle='-.') # 一次修改多个,与上面等价
plt.plot([1,2,3,4],[2,3,4,5])
plt.show()
二、matplotlib的色彩设置(color)¶
在可视化中,如何选择合适的颜色和搭配组合也是需要仔细考虑的,色彩选择要能够反映出可视化图像的主旨。
从可视化编码的角度对颜色进行分析,可以将颜色分为色相、亮度和饱和度三个视觉通道。通常来说:
色相: 没有明显的顺序性、一般不用来表达数据量的高低,而是用来表达数据列的类别。
明度和饱和度: 在视觉上很容易区分出优先级的高低、被用作表达顺序或者表达数据量视觉通道。
具体关于色彩理论部分的知识,不属于本教程的重点,请参阅有关拓展材料学习。
学会这6个可视化配色基本技巧,还原数据本身的意义
在matplotlib中,设置颜色有以下几种方式:
1.RGB或RGBA¶
python
plt.style.use('default')
# 颜色用[0,1]之间的浮点数表示,四个分量按顺序分别为(red, green, blue, alpha),其中alpha透明度可省略
plt.plot([1,2,3],[4,5,6],color=(0.1, 0.2, 0.5))
plt.plot([4,5,6],[1,2,3],color=(0.1, 0.2, 0.5, 0.5))
plt.show()
2.HEX RGB 或 RGBA
python
# 用十六进制颜色码表示,同样最后两位表示透明度,可省略
plt.plot([1,2,3],[4,5,6],color='#0f0f0f')
plt.plot([4,5,6],[1,2,3],color='#0f0f0f80');
plt.show()
RGB颜色和HEX颜色之间是可以一一对应的,以下网址提供了两种色彩表示方法的转换工具。
参考:
https://www.fontke.com/tool/rgb/0f0f0f/
https://www.colorhexa.com/
3.灰度色阶¶
python
# 当只有一个位于[0,1]的值时,表示灰度色阶
plt.plot([1,2,3],[4,5,6],color='0.5');
plt.show()
4.单字符基本颜色
matplotlib有八个基本颜色,可以用单字符串来表示,分别是'b', 'g', 'r', 'c', 'm', 'y', 'k', 'w',对应的是blue, green, red, cyan, magenta, yellow, black, and white的英文缩写
5.颜色名称
matplotlib提供了颜色对照表,可供查询颜色对应的名称
6.使用colormap设置一组颜色¶
有些图表支持使用colormap的方式配置一组颜色,从而在可视化中通过色彩的变化表达更多信息。
在matplotlib中,colormap共有五种类型:
顺序(Sequential)。通常使用单一色调,逐渐改变亮度和颜色渐渐增加,用于表示有顺序的信息
plot_color_gradients('Perceptually Uniform Sequential',
['viridis', 'plasma', 'inferno', 'magma', 'cividis'])
plot_color_gradients('Sequential',
['Greys', 'Purples', 'Blues', 'Greens', 'Oranges', 'Reds',
'YlOrBr', 'YlOrRd', 'OrRd', 'PuRd', 'RdPu', 'BuPu',
'GnBu', 'PuBu', 'YlGnBu', 'PuBuGn', 'BuGn', 'YlGn'])
plot_color_gradients('Sequential (2)',
['binary', 'gist_yarg', 'gist_gray', 'gray', 'bone',
'pink', 'spring', 'summer', 'autumn', 'winter', 'cool',
'Wistia', 'hot', 'afmhot', 'gist_heat', 'copper'])
发散(Diverging)。改变两种不同颜色的亮度和饱和度,这些颜色在中间以不饱和的颜色相遇;当绘制的信息具有关键中间值(例如地形)或数据偏离零时,应使用此值。
plot_color_gradients('Diverging',
['PiYG', 'PRGn', 'BrBG', 'PuOr', 'RdGy', 'RdBu', 'RdYlBu',
'RdYlGn', 'Spectral', 'coolwarm', 'bwr', 'seismic'])
循环(Cyclic)。改变两种不同颜色的亮度,在中间和开始/结束时以不饱和的颜色相遇。用于在端点处环绕的值,例如相角,风向或一天中的时间。
plot_color_gradients('Cyclic', ['twilight', 'twilight_shifted', 'hsv'])
定性(Qualitative)。常是杂色,用来表示没有排序或关系的信息。
plot_color_gradients('Qualitative',
['Pastel1', 'Pastel2', 'Paired', 'Accent', 'Dark2',
'Set1', 'Set2', 'Set3', 'tab10', 'tab20', 'tab20b',
'tab20c'])
杂色(Miscellaneous)。一些在特定场景使用的杂色组合,如彩虹,海洋,地形等。
plot_color_gradients('Miscellaneous',
['flag', 'prism', 'ocean', 'gist_earth', 'terrain',
'gist_stern', 'gnuplot', 'gnuplot2', 'CMRmap',
'cubehelix', 'brg', 'gist_rainbow', 'rainbow', 'jet',
'turbo', 'nipy_spectral', 'gist_ncar'])
plt.show()
具体见:
https://matplotlib.org/stable/tutorials/colors/colormaps.html
完整代码:
python
import numpy as np
import matplotlib as mpl
import matplotlib.pyplot as plt
# from colorspacious import cspace_converter
cmaps = {}
gradient = np.linspace(0, 1, 256)
gradient = np.vstack((gradient, gradient))
def plot_color_gradients(category, cmap_list):
# Create figure and adjust figure height to number of colormaps
nrows = len(cmap_list)
figh = 0.35 + 0.15 + (nrows + (nrows - 1) * 0.1) * 0.22
fig, axs = plt.subplots(nrows=nrows + 1, figsize=(6.4, figh))
fig.subplots_adjust(top=1 - 0.35 / figh, bottom=0.15 / figh,
left=0.2, right=0.99)
axs[0].set_title(f'{category} colormaps', fontsize=14)
for ax, name in zip(axs, cmap_list):
ax.imshow(gradient, aspect='auto', cmap=mpl.colormaps[name])
ax.text(-0.01, 0.5, name, va='center', ha='right', fontsize=10,
transform=ax.transAxes)
# Turn off *all* ticks & spines, not just the ones with colormaps.
for ax in axs:
ax.set_axis_off()
# Save colormap list for later.
cmaps[category] = cmap_list
plot_color_gradients('Perceptually Uniform Sequential',
['viridis', 'plasma', 'inferno', 'magma', 'cividis'])
plt.show()