python数据可视化之matplotlib(下)
-
matplotlib
import numpy as np import matplotlib as mpl import matplotlib.pyplot as plt # 解决坐标轴刻度负号乱码 plt.rcParams['axes.unicode_minus'] = False # 解决中文乱码问题 plt.rcParams['font.sans-serif'] = ['Simhei']
-
1、plt.plot() 绘图进阶
-
1.1 子图 plt.subplot()
plt.subplot(CRP):划分C行R列,从最左到右,从上到下,序号P依次增加
import matplotlib as mpl import matplotlib.pyplot as plt x = np.linspace(-2*np.pi,2*np.pi,200) y_01 = np.sin(x) y_02 = np.cos(x) y_03 = x y_04 = x**2 plt.subplot(221) # 设置子图的位置 plt.plot(x, y_01, label="sin(x)") plt.subplot(222) plt.plot(x, y_02, label="cos(x)") plt.subplot(223) plt.plot(x, y_03, label="x"); plt.subplot(224) plt.plot(x, y_04, label="x**2") plt.show()
结果为:

import matplotlib as mpl import matplotlib.pyplot as plt x = np.linspace(-2*np.pi,2*np.pi,200) y_01 = np.sin(x) y_02 = np.cos(x) y_03 = x**2 plt.subplot(221) plt.plot(x, y_01) plt.title("y=sin(x)") # 子图标题 plt.subplot(222) plt.plot(x, y_02) plt.title("y=cos(x)") plt.subplot(212) # 两行一列,占其第二行 plt.plot(x, y_03); plt.title("y=x^2") plt.suptitle("subplot()函数的实例展示") # 整体图的标题 plt.show()
结果为:

-
1.2 网格布局子图
plt.subplot2grid(shape, loc, colspan, rowspan)
- shape 如果是 (2,3) 的话,就是设置了一个2行3列的网格布局
- loc 表示元组的第一个和第二个数值的起点,如果 loc 为 (0,1) 就以为这图形从第1行第2列的位置开始绘制
- rowspan表示图形横跨多少行
- colspan表示图形横跨多少列
import matplotlib as mpl import matplotlib.pyplot as plt x = np.linspace(-2*np.pi,2*np.pi,200) y_01 = np.sin(x) y_02 = np.cos(x) y_03 = x**2 plt.subplot2grid((2,3), (0,0), colspan=2) #在一个2行3列的网格,从第1行第1列开始绘制,横跨2列 plt.plot(x, y_01) plt.title("y=sin(x)")
plt.subplot2grid((2,3), (0,2)) #在一个2行3列的网格,从第1行第3列开始绘制,横跨1列 plt.plot(x, y_02) plt.title("y=cos(x)") plt.subplot2grid((2,3), (1,0), colspan=2) #在一个2行3列的网格,从第2行第1列开始绘制,横跨2列 plt.plot(x, y_03); plt.title("y=x^2") plt.suptitle("subplot2grid()函数的实例展示") plt.show()
结果为:

-
2、面向对象接口绘图
-
2.1 简介

- 我们想一下,上面的图画完之后,如果此时想再画一条折线图,添加到“图一”中,实现起来就比较麻烦。因为此时两幅子图已经画完。那如何让Python再回到“图一”中去绘图呢?
- 另外一个问题就是,如果我想对图形的细节作进一步优化,比如上面图二的图标题,就和图一的横轴标签重叠了,有办法对这些小的细节作优化吗?
- 此时我们就需要引入另外一种绘图方式:通过面向对象绘图。我们首先阅读以下代码,对比上面的绘图方式,看看这种绘图方式的特点:
import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np fig, ax = plt.subplots(2,1) # 把fig想象成一块画板,ax想象成两张画纸 x = np.linspace(-2*np.pi,2*np.pi,200) y_01 = np.sin(x) y_02 = x**2 ax[0].plot(x, y_01, label="sin(x)") ax[0].legend() ax[0].set_title("图一") ax[1].plot(x, y_02, label="x**2") ax[1].legend() ax[1].set_title("图二") #如果在画完两幅子图之后,在这个时候想再往图一添加折线图y=x,可以直接通过实例ax[0].plot()来画: ax[0].plot(x, x, color="r", ls="--", alpha=0.3) plt.show()
结果为:

首先要说明的是 fig, ax = plt.subplots(2,1) 是什么意思:
- plt.subplots()其实会返回两个对象,一个是画板实例 figure,一个是坐标轴域实例 axes :
- figure 可以看做是一个图形实例,用来包含坐标轴、图形、文字标签等
- axes 表示一个坐标轴域实例,是一个带有刻度和标签的矩阵
- 先有了 figure、axes,就可以使用 ax.plot 来绘图了
- 因为 ax[0] 表示第一个子图的实例,ax[1] 表示第二个子图的实例,所以可以通过 ax[0] 回到第一个子图绘图,画出红色的折线图

或者将子图 plt.subplot(211) 和 plt.subplot(212) 赋值到对象中去,然后同样可以通过面向对象的调用方法实现追加画图操作:
import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np x = np.linspace(-2*np.pi,2*np.pi,200) y_01 = np.sin(x) y_02 = x**2 ax_01 = plt.subplot(211) ax_01.plot(x, y_01, label="sin(x)") ax_01.legend() ax_01.set_title("图一") ax_02 = plt.subplot(212) ax_02.plot(x, y_02, label="x**2") ax_02.legend() ax_02.set_title("图二") #如果在画完两幅子图之后,在这个时候想再往图一添加折线图y=x,可以直接通过实例ax[0].plot()来画: ax_01.plot(x, x, color="r", ls="--", alpha=0.3) plt.show()
结果为:

-
2.2 plt.figure 创建画板
plt.figure(num, figsize, dpi, facecolor, edgecolor, frameon)
- num:整数或字符串,可选,默认值:无
- 如果未提供,将创建新图形和图形编号,图形对象将此数字保存在“数字”中
- 如果提供了num,将在该编号的图形中绘图
- 如果num是一个字符串,该字符串作为图标题
- figsize:整数元组,可选,默认值:无
- [宽度,高度](英寸)
- 如果未提供,则默认为[6.4, 4.8]
- dpi:整数,可选,默认值:无
- 分辨率,如果未提供,则默认为100
- facecolor:背景颜色。如果未提供,则默认为白色
- edgecolor:边框颜色。如果未提供,则默认为白色
- frameon:布尔型,可选,默认值:True,如果为 False,则禁止绘制图框
import matplotlib.pyplot as plt import numpy as np fig_01 = plt.figure(1, figsize=[3,3]) # 建立“画板1” ax_01 = plt.axes() # 在“画板1”生成一张画纸,需配合figure对象使用,不然只是一个画板对象 fig_02 = plt.figure(2, figsize=[6,6]) # 建立“画板2” ax_02 = plt.axes() plt.show()
结果为:

-
2.3 plt.axes
plt.axes 用来创建一个新的全窗口轴域(画纸):
- plt.axes([left, bottom, width, height]...)
- 以左下角为原点,右上角为1,设置轴域的[左坐标,底坐标,宽度,高度]
- 上面的轴域取值范围是左下角(原点)为0,右上角为1
- 左坐标和底坐标两个参数对应的就是——该坐标轴的原点位置,为该图形宽度和高度比例
- 宽度和高度的参数就是——该坐标轴原点往外扩展,宽度和高度为图形的比例长度
import matplotlib.pyplot as plt import numpy as np x = np.linspace(-2*np.pi,2*np.pi,200) y = np.sin(x) fig = plt.figure(1, facecolor="gray") #建立“画板1”,颜色设置为灰色 ax_1 = plt.axes([0, 0, 0.4, 0.4], facecolor="w") # 建立轴域1(画纸),颜色设置成白色,起点原点,长宽均为整体长宽的0.4倍 ax_1.plot(x, y, ls="-.", color="r") ax_2 = plt.axes([0.4, 0.4, 0.6, 0.6], facecolor="g") # 建立轴域2(画纸),颜色设置成绿色,起点为0.4倍整体长宽的位置,长宽均为整体长宽的0.6倍 ax_2.plot(x, y, ls="-", color="c") plt.show()
结果为:

-
2.4 其他建立 figure 和 axes 的方法
-
2.4.1 通过 plt.subplots() 同时创建画板和画纸
import matplotlib.pyplot as plt import numpy as np x = np.linspace(0,10,1000) y_1 = np.sin(x) y_2 = np.cos(x) y_3 = x y_4 = x ** 3 fig, ((ax_01, ax_02), (ax_03, ax_04)) = plt.subplots(2,2) # 通过 plt.subplots() 返回“画板”和“画纸” ax_01.plot(x, y_1) ax_02.plot(x, y_2) ax_03.plot(x, y_3) ax_04.plot(x, y_4) plt.show()
结果为:

或者:
import matplotlib.pyplot as plt import numpy as np x = np.linspace(0,10,1000) y_1 = np.sin(x) y_2 = np.cos(x) y_3 = x y_4 = x ** 3 fig, ax = plt.subplots(2,2) # 通过 plt.subplots() 返回“画板”和“画纸” ax_01 = ax[0][0] # 或者ax_01 = ax[0,1]
ax_01.plot(x, y_1) ax_02 = ax[0][1] ax_02.plot(x, y_2) ax_03 = ax[1][0] ax_03.plot(x, y_3) ax_04 = ax[1][1] ax_04.plot(x, y_4) plt.show()
结果为:

-
2.4.2 通过 fig.add_subplot() 在已经创建好的画板上再追加创建画纸
import matplotlib.pyplot as plt import numpy as np x = np.linspace(0,10,1000) y_1 = np.sin(x) y_2 = np.cos(x) y_3 = x y_4 = x ** 3 fig = plt.figure() # 先创建“画板” ax_01 = fig.add_subplot(221) # 通过“画板”来调用“画纸” ax_01.plot(x, y_1) ax_02 = fig.add_subplot(222) # 通过“画板”来调用“画纸” ax_02.plot(x, y_2) ax_03 = fig.add_subplot(223) # 通过“画板”来调用“画纸” ax_03.plot(x, y_3) ax_04 = fig.add_subplot(224) # 通过“画板”来调用“画纸” ax_04.plot(x, y_4) plt.show()
结果为:

-
2.5 面向对象接口绘图举例
-
2.5.1 折线图 ax.plot()
import matplotlib.pyplot as plt import numpy as np x = np.linspace(-2*np.pi,2*np.pi,200) y = np.sin(x) fig = plt.figure() # 建立“画板” ax = plt.axes() # 建立“画纸” ax.plot(x, y, ls="-", lw=2, label="plot figure", color="c") ax.legend() # plt.plot(x,y,ls="-",lw=2,label="plot figure",color="c") # plt.legend() #将标签显示出来 plt.show()
结果为:

-
2.5.2 散点图 ax.scatter()
import matplotlib.pyplot as plt import numpy as np fig = plt.figure() ax = plt.axes() x = np.linspace(0.05,20,500) y = np.random.randint(1,100,500) ax.scatter(x,y,label="scatter figure") ax.legend() # plt.scatter(x,y,label="scatter figure") # plt.legend() plt.show()
结果为:

-
2.5.3 柱状图 ax.bar()
import matplotlib.pyplot as plt import numpy as np fig = plt.figure() ax = plt.axes() x = [i for i in range(1,6)] y = np.random.randint(45,100,5) z = ("小红","小明","小帅","小英","小晓") ax.set_ylabel("成绩") ax.grid(linestyle="-.", color="r", axis="y", alpha=0.15) ax.bar(x, y, align="center", color="c", tick_label=z, hatch="///") # plt.ylabel("成绩") # plt.grid(linestyle="-.",color="r",axis="y",alpha=0.15) # plt.bar(x,y,align="center",color="c",tick_label=z,hatch="///") plt.show()
结果为:

-
2.6 matplotlib 陷阱
- 绝大多数 plt 函数都可以直接转换成 ax 方法,比如 plt.plot() --> ax.plot()、plt.legend() --> ax.legend() 等
- 在设置坐标轴上下限、坐标轴标题和图形标题方面,会稍有不同:
- 设置坐标轴标题
- plt.xlabel() --> ax.set_xlabel()
- plt.ylabel() --> ax.set_ylabel()
- 设置坐标轴上下限
- plt.xlim() --> ax.set_xlim()
- plt.ylim() --> ax.set_ylim()
- 设置图形标题
- plt.title() --> ax.set_title()
- 设置坐标轴标题
- 用面向对象接口画图的另外一个好处就是,你可以使用 ax.set() 对图形的属性进行一次性定义
-
3、共享绘图区域
-
3.1 设置副坐标轴
共享x轴,y轴设置副坐标轴:
import matplotlib as mpl import matplotlib.pyplot as plt fig, ax_01 = plt.subplots() #生成一个画布对象fig,以及一个坐标轴实例数组ax_01 #通过实例ax_01绘制x、y坐标轴标签 x = np.linspace(0.0,4.0,100) y_01 = np.random.randn(100) ax_01.plot(x, y_01, c="c") #通过实例ax_01来绘图 ax_01.set_xlabel("x坐标轴") ax_01.set_ylabel("散点图的y轴") ax_01.tick_params("y", colors="b") # 绘制ax_01的y坐标轴的主刻度线和刻度标签颜色(蓝色) #通过ax.twins()来“克隆”ax_01的双胞胎轴域ax_02 ax_02 = ax_01.twinx() x = np.linspace(0.0,4.0,100) y_02 = x**2 ax_02.plot(x, y_02, c="r") ax_02.set_ylabel("折线图的y轴") ax_02.tick_params("y", colors="r") # 绘制ax_02的y坐标轴的主刻度线和刻度标签颜色(红色) plt.show()
结果为:

共享y轴,x轴设置副坐标轴:
import matplotlib as mpl import matplotlib.pyplot as plt fig, ax_01 = plt.subplots() #生成一个画布对象fig,以及一个坐标轴实例数组ax_01 #通过实例ax_01绘制x、y坐标轴标签 x = np.linspace(0.0,4.0,100) y_01 = np.random.randint(0, 10, 100) ax_01.plot(x, y_01, c="c") #通过实例ax_01来绘图 ax_01.set_xlabel("散点图的x轴") ax_01.set_ylabel("y坐标轴") ax_01.tick_params("x", colors="b") # 绘制ax_01的y坐标轴的主刻度线和刻度标签颜色(蓝色) #通过ax.twins()来“克隆”ax_01的双胞胎轴域ax_02 ax_02 = ax_01.twiny() x = np.linspace(5.0 , 10.0,100) y_02 = np.random.randint(0, 10, 100) ax_02.plot(x, y_02, c="r") ax_02.set_xlabel("折线图的x轴") ax_02.tick_params("x", colors="r") # 绘制ax_02的y坐标轴的主刻度线和刻度标签颜色(红色) plt.show()
结果为:

-
3.2 plt.subplots() 方法中全部子图共享某坐标轴
有时候,我们将多个子图放在一起显示,是想要某些子图之间做出对比,这个时候,我们可能想将子图的坐标轴设置得一样
- 此时我们可以通过修改 plt.subplots(shape, sharex, sharey) 里面的sharex,sharey两个参数,以sharex为例:
- sharex="all":所有的x轴都相同,以子图中 x 轴范围最大的作为共享 x 轴
- sharex="row":同一行的子图,所有的 x 轴都相同
- sharex="col":同一列的子图,所有的 x 轴都相同
- sharex="none":坐标轴不变
- sharex,sharey 两个参数都可以同时在 subplots() 中使用
import matplotlib as mpl import matplotlib.pyplot as plt fig, ax = plt.subplots(2, 2, sharex="all") #修改sharex,sharey ax_01 = ax[0,0] x_01 = np.linspace(0.0,10.0,100) y_01 = np.random.randn(100) ax_01.scatter(x_01, y_01, c="c") ax_01.set_xlabel("散点图") ax_02 = ax[0,1] x_02 = np.linspace(0.0,8.0,100) y_02 = x_02**2 ax_02.plot(x_02, y_02, c="c") ax_02.set_xlabel("折线图") ax_03 = ax[1,0] x_03 = np.linspace(0.0,12.0,100) y_03 = np.cos(x_03) ax_03.plot(x_03, y_03, lw=2, ls="-") ax_03.grid(True, ls=":", c="g") ax_03.set_xlabel("三角函数cos(x)") ax_04 = ax[1,1] x_04 = np.linspace(0.0,15.0,100) y_04 = (x_04+3)**2 ax_04.plot(x_04, y_04, lw=2, ls="-") ax_04.grid(True, ls=":", c="g") ax_04.set_xlabel("折线图") plt.suptitle("子图共享同一坐标的展示") plt.show()
结果为:

-
3.3 plt.subplot() 方法中与某子图共享坐标轴
在使用 plt.subplot() 制图方法的时候,创建子图轴域实例的时候,用 sharex 或 sharey 参数可以指定与哪个子图共享坐标轴
import matplotlib as mpl import matplotlib.pyplot as plt x = np.linspace(-2*np.pi,2*np.pi,200) y_01 = np.sin(x) y_02 = np.cos(x) y_03 = np.sin(x)+np.cos(x) y_04 = x**2 ax_01 = plt.subplot(221) ax_01.plot(x, y_01) ax_02 = plt.subplot(222) ax_02.plot(x, y_02) ax_03 = plt.subplot(223) ax_03.plot(x, y_03) ax_04 = plt.subplot(224, sharey=ax_02) #用sharex或sharey参数指定与哪个子图共享坐标轴,此时ax_02的y坐标轴与ax_04相同 ax_04.plot(x, y_04) plt.show()
结果为:

-
3.4 修改子图之间的空隙
通过 fig.subplots_adjust(wspace,hspace) 中的 wspace 和 hspace 修改子图之间的空隙距离
- wspace:子图之间的宽距
- hspace:子图之间的高距
import matplotlib as mpl import matplotlib.pyplot as plt fig, ax = plt.subplots(2,2) fig.subplots_adjust(hspace=0.55, wspace=0.2) #可以在开头就添加 ax_01 = ax[0,0] x_01 = np.linspace(0.0,10.0,100) y_01 = np.random.randn(100) ax_01.scatter(x_01, y_01, c="c") ax_01.set_xlabel("散点图") ax_02 = ax[0,1] x_02 = np.linspace(0.0,8.0,100) y_02 = x_02**2 ax_02.plot(x_02, y_02, c="c") ax_02.set_xlabel("折线图") ax_03 = ax[1,0] x_03 = np.linspace(0.0,12.0,100) y_03 = np.cos(x_03) ax_03.plot(x_03, y_03, lw=2, ls="-") ax_03.grid(True,ls=":",c="g") ax_03.set_xlabel("三角函数cos(x)") ax_04 = ax[1,1] x_04 = np.linspace(0.0,15.0,100) y_04 = (x_04+3)**2 ax_04.plot(x_04, y_04, lw=2, ls="-") ax_04.grid(True, ls=":", c="g") ax_04.set_xlabel("折线图") plt.suptitle("子图共享同一坐标的展示") plt.show()
结果为:

-
3.5 自动调整坐标轴范围
如果觉得调整坐标轴数据范围太麻烦,可以使用函数 autoscale() ,坐标轴范围会自适应调整
- ax.autoscale(enable=True, axis="both", tight=True)
- enable:对坐标轴范围进行自适应调整
- axis:使 x, y 轴都进行自适应调整
- tight:让坐标轴的范围调整到数据的范围上
import matplotlib as mpl import matplotlib.pyplot as plt import numpy as np np.random.seed(100) fig, ax = plt.subplots(2,1) x_01 = np.linspace(0.0,5.0,100) y_01 = np.random.randn(100) ax_01 = ax[0] ax_01.scatter(x_01, y_01, c="c") ax_01.set_xlabel("散点图") ax_02 = ax[1] ax_02.scatter(x_01, y_01, c="c") ax_02.set_xlabel("散点图") ax_02.autoscale(enable=True, axis="both", tight=True) # 想对子图2的坐标轴范围进行调整,可以将autoscale()函数放这里,此时坐标轴的范围会从图的边缘开始 plt.show()
结果为:


浙公网安备 33010602011771号