Python开发工具集之可视化包Matplotlib(上)

Table of Contents

Python开发工具集之可视化包Matplotlib

  • matplotlib是常用的Python的2D绘图包,可以对Python中的数据进行快速可视化,并以多种格式输出
  • 在matplotlib面向对象的绘图库中,pyplot是一个很好的API
  • pyplot与pylab的功能基本相同,pyplab包含许多NumPy和pyplot模块中常用的函数,十分适合在IPython交互式环境中使用
  • Pylab combines pyplot with numpy into a single namespace. This is convenient for interactive work, but for programming it is recommended that the namespaces be kept separate.

配置依赖环境

导入依赖模块

In [61]:
import matplotlib
import matplotlib.pyplot as plt
import numpy as np

导入中文依赖模块

In [62]:
from matplotlib.font_manager import *

# 解决中文显示问题
# 使用场景:在text()、label()、title()中添加:fontproperties=myfont1
myfont1 = FontProperties(
    fname='/usr/share/fonts/truetype/arphic/ukai.ttc'
)
# 第二种解决图例中文显示问题,配置:plt.legend(prop=myfont2)
myfont2 = matplotlib.font_manager.FontProperties(
      fname='/home/jw/etl/venv/lib/python3.6/site-packages/matplotlib/mpl-data/fonts/ttf/simhei.ttf'
    , size = 14
)
# 解决不显示负号的问题
matplotlib.rcParams['axes.unicode_minus'] = False
# 解决 cannot find sans-serif family 问题
matplotlib.rcParams.update({    
    'font.family':'sans-serif',
    'font.sans-serif':['Liberation Sans'],
    })

# 有时配置后需要清除一下缓存才能正确显示
# rm -rf ~/.matplotlib/*.cache

plot 基础制图

  • matplotlib plot提供了很多 API 函数. 本节从 plot 基础制图开始
In [63]:
# 先上一副最基本的图表
# 如果仅向plot()命令提供单个列表或数组
# 则matplotlib假定它是一个y值序列
# 并自动生成x值
plt.plot([1, 2, 3, 4])
# 显示图表
plt.show()

添加 x, y 值

In [64]:
plt.plot(
      [1, 2, 3, 4]    # x 值(list)
    , [1, 4, 16, 64]  # x 值(list)
)
plt.show()

配置图形颜色和形状

颜色字符 说明 颜色字符 说明 颜色字符 说明
‘b’ 蓝色 ‘m’ 洋红色 magenta ‘0.8’ 灰度值字符串
‘g’ 绿色 ‘y’ 黄色 ‘#008000’ RGB某颜色
‘r’ 红色 ‘k’ 黑色 ‘w’ 白色
‘c’ 青绿色 cyan
标记字符 说明 标记字符 说明 标记字符 说明
‘-‘ 实线 ’s’ 实心方形标记 ‘^’ 上三角标记
‘–’ 破折线 ‘p’ 实心五角标记 ‘>’ 右三角标记
‘-.’ 点划线 '*' 星形标记 ‘<’ 左三角标记
‘:’ 虚线 '竖线' 垂直线标记 ‘h’ 竖六边形标记
‘.’ 点标记 ‘1’ 下花三角标记 ‘H’ 横六边形标记
‘,’ 像素标记(极小点) ‘2’ 上花三角标记 ‘+’ 十字标记
‘o’ 实心圈标记 ‘3’ 左花三角标记 ‘x’ x标记
‘v’ 倒三角标记 ‘4’ 右花三角标记 ‘d’ 瘦菱形标记
‘D’ 菱形标记
In [121]:
plt.plot(
      [1, 2, 3, 4]      # x 值(list)
    , [1, 4, 16, 64]    # x 值(list)
    , 'r:'              # r 表示红色,: 表示虚线
)
plt.show()

添加关键字 plt.plot(x, y, format_string, **kwargs)

In [122]:
plt.plot(
      [1, 2, 3, 4]           # x 值(list)
    , [1, 4, 16, 64]         # x 值(list)
    , 'r:'                   # r 表示红色,: 表示虚线. 是关键字中color和linestyle的简化写法. 相同配置中生效的写法是后面的代码
    , color = 'm'            # 线条颜色.与前述 r 功能相同
    , linestyle = 'dashdot'  # 线条类型,与前述 : 功能相同,选择项包括: [‘solid’ | ‘dashed’, ‘dashdot’, ‘dotted’ | (offset, on-off-dash-seq) | '-' | '--' | '-.' | ':' | 'None' | ' ' | '']
    , linewidth = 5.0        # 线条宽度
    , marker ='o'            # 标记点形状
    , markersize = '10'      # 标记点大小
    , markerfacecolor ='k'   # 标记点颜色
)
plt.show()

配置两个线条

In [123]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
plt.plot(
      x, y1, 'r-'
    , x, y2, 'g--'
)
plt.show()

配置两个线条的第二种方法

In [68]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
plt.plot(x, y1, 'r-')
plt.plot(x, y2, 'g--')
plt.show()

控制线条属性-使用set方法

In [69]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
plt.plot(x, y1, 'r-')
line, = plt.plot(x, y2, 'g--', lw = 5)
line.set_antialiased(False)  # antialised代表字体抗锯齿,False为关闭
plt.show()

控制线条属性-使用setp()命令

In [70]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
plt.plot(x, y1, 'r-')
line, = plt.plot(x, y2, 'g--')
plt.setp(line, color='b', linewidth=1)
plt.show()

添加标题 title

In [71]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
plt.plot(x, y1, 'r-')
plt.plot(x, y2, 'g--')
plt.title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=18) # 植入硬广告
plt.show()

添加 x,y 轴的标签 plt.xlabel(), plt.ylabel()

In [72]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
plt.plot(x, y1, 'r-')
plt.plot(x, y2, 'g--')
plt.title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=18) # 植入硬广告
# 如有中文,配置字体为之前设定的 myfont
# fontsize=14 配置字体大小
plt.ylabel('y 轴标签', fontproperties=myfont1, fontsize=14) 
plt.xlabel('x 轴标签', fontproperties=myfont1, fontsize=14)
plt.show()

配置图例 plt.legend()

loc 数值代表的位置
'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
In [73]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
l1, = plt.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = plt.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
plt.title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=18) # 植入硬广告
# 如有中文,配置字体为之前设定的 myfont1
# fontsize=14 配置字体大小
plt.ylabel('y 轴标签', fontproperties=myfont1, fontsize=14) 
plt.xlabel('x 轴标签', fontproperties=myfont1, fontsize=14)
# 如前导入中文依赖模块,此处引用 prop=myfont2
# frameon=True 为配置图例是否使用外框
# 图例的 loc 配置项见下表列出
# 如果此处使用porp, 则字体大小只能由myfont2中配置的size=14起作用
# 如果此处没有使用porp, 则字体大小由fontsize=xxx生效, 但这样无法显示中文
plt.legend(handles=[l1, l2], loc = 0, frameon=False, prop=myfont2)
# plt.legend(handles=[l1, l2], loc = 0, frameon=False, fontsize=14) 

plt.show()

添加文本 text()

  • text()命令可用于在任意位置添加文本
  • xlabel(), ylabel() 和 title() 用于在指定的位置添加文本
In [74]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
l1, = plt.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = plt.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
plt.title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=18) # 植入硬广告
plt.ylabel('y 轴标签', fontproperties=myfont1, fontsize=14) 
plt.xlabel('x 轴标签', fontproperties=myfont1, fontsize=14)
plt.legend(handles=[l1, l2], loc = 0, frameon=False, prop=myfont2)
# 前两个参数是text的x和y的位置
plt.text(-2.7, 2.5, ' www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=14, color='b') # 植入硬广告
plt.show()

添加网格 grid()

In [75]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
l1, = plt.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = plt.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
plt.title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=18) # 植入硬广告
plt.ylabel('y 轴标签', fontproperties=myfont1, fontsize=14) 
plt.xlabel('x 轴标签', fontproperties=myfont1, fontsize=14)
plt.legend(handles=[l1, l2], loc = 0, frameon=False, prop=myfont2)
# 前两个参数是text的x和y的位置
plt.text(-2.7, 2.5, ' www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=14, color='b') # 植入硬广告
# 添加网格
plt.grid(color='m', linestyle='--', linewidth=1, alpha=0.3)  # 配置网格的颜色, 线条类型和宽度,以及透明度等等
plt.show()

标注特殊点之 annotate()

In [76]:
def funy(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,5, endpoint=True) # endpoint为True包含终止点
print('x = ', x)
print('~'*70)
y=funy(x)
print('y = ', y)
print('~'*70)
plt.plot(x, y, 'r-', label="www.jasper.wang", marker='o')
# zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成元组
# zip() 函数返回由元组组成的列表
for i, xy in enumerate(zip(x, y)):
    print('xy[', i, '] = ', xy)
    plt.annotate(
          "(%s,%s)" % xy               # 使用 (%s,%s) % (s1,s2) 格式化文本的方式提供标注点文本
        , xy=xy                        # 标记的位置即循环变量 xy 的当前值
        , xytext=(-10, 10)             # 标注文本的偏移量
        , textcoords='offset points'   # 确定以标注点的偏移量位置显示文本
    )
plt.show()
x =  [-5.  -2.5  0.   2.5  5. ]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
y =  [ 3.85  0.1   0.1   3.85 11.35]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
xy[ 0 ] =  (-5.0, 3.85)
xy[ 1 ] =  (-2.5, 0.1)
xy[ 2 ] =  (0.0, 0.1)
xy[ 3 ] =  (2.5, 3.85)
xy[ 4 ] =  (5.0, 11.35)

标注特殊点之 plt.scatter()

  • 两个点之间的连接路径的创建由connectionstyle键控制,可以使用以下样式:
名称 属性
angle angleA=90,angleB=0,rad=0.0
angle3 angleA=90,angleB=0
arc angleA=0,angleB=0,armA=None,armB=None,rad=0.0
arc3 rad=0.0
bar armA=0.0,armB=0.0,fraction=0.3,angle=None
In [77]:
x = np.linspace(0,np.pi,20)
y = np.sin(x)

# 前后添加"$"符号 表示数学公式
plt.plot(x, y, label='$cos(x)$', color='red', linewidth=1.0, linestyle='--') 

# 添加标注点
x0 = np.pi/2
y0 = np.sin(x0) 

# 显示一个点
plt.scatter(x0, y0, color='black')

# 在一条点到x轴画出垂直线
plt.plot([x0, x0], [0, y0],'b--') 

# 标注方法1
plt.annotate(
      'y = %s' % y0
    , xy=(x0, y0)
    , xycoords='data'
    , xytext=(+80,-30)
    , textcoords='offset points'
    , arrowprops=dict(
          arrowstyle='->'
        , connectionstyle='arc3, rad=-0.8'  # 两个点之间的连接路径的创建由connectionstyle键控制, 样式选择arc3:rad=-0.8
    )
)

# 标注方法2
plt.text(x0+0.3, y0, 'this is a sin(x) line')

plt.show()

将 x,y 轴坐标转换成字符坐标 plt.xticks(), plt.yticks()

In [78]:
# 使用 np.linspace 创建等差数列,三个参数分别代表起止和分隔数
x = np.linspace(-4, 4, 50)
y = np.cos(x)

# 作图 
plt.plot(x, y)

# 使用 ticks 将相应坐标数转换成字符坐标
plt.xticks(
      [-np.pi, -np.pi/2, 0, np.pi/2, np.pi]               # x 配置坐标刻度线
    , ['$-\pi$', '$-\pi/2$',  '$0$', '$\pi/2$','$\pi$']   # x 配置坐标刻度线对应的显示文本
    , fontsize=14
) 
plt.yticks(
      [-1, 0, 1]                                          # y 配置坐标刻度线
    , ['- one','zero','+ one']                            # y 配置坐标刻度线对应的显示文本
    , fontsize=14
)

plt.show()

配置x轴和y轴范围 plt.xlim(), plt.ylim()

In [79]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
l1, = plt.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = plt.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
plt.title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=18) # 植入硬广告
plt.ylabel('y 轴标签', fontproperties=myfont1, fontsize=14) 
plt.xlabel('x 轴标签', fontproperties=myfont1, fontsize=14)
plt.legend(handles=[l1, l2], loc = 0, frameon=False, prop=myfont2)
# 前两个参数是text的x和y的位置
plt.text(-2.7, 2.5, ' www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=14, color='b') # 植入硬广告
# 添加网格
plt.grid(True)
# 配置x轴和y轴范围
# 范围变大了,曲线图相对变小了
# 但 title, text, label, legend等等都没有变小
plt.xlim(-10.0, 10.0)
plt.ylim(-5, 15)

plt.show()

配置x轴和y轴范围的第二种方法 x.min(), x.max()

In [80]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
l1, = plt.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = plt.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
plt.title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=18) # 植入硬广告
plt.ylabel('y 轴标签', fontproperties=myfont1, fontsize=14) 
plt.xlabel('x 轴标签', fontproperties=myfont1, fontsize=14)
plt.legend(handles=[l1, l2], loc = 0, frameon=False, prop=myfont2)
plt.text(-2.7, 2.5, ' www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1, fontsize=14, color='b') # 植入硬广告
plt.grid(True)
# 根据 min, max动态配置最大最小值
plt.xlim(x.min()*1.1, x.max()*1.1)
plt.ylim(y2.min()*3, y2.max()*1.1)
print('y2的最小值是:', y2.min())
plt.show()
y2的最小值是: -0.3166666666666669

在 plot 中绘制横线, 竖线, 块

  • axhline: 在轴上添加一条水平线
  • axhspan: 在轴上添加水平跨度(矩形)
  • axvline: 在轴上添加垂直线
  • axvspan: 在轴上添加垂直跨度(矩形)
In [81]:
t = np.arange(-1, 2, .01)
s = np.sin(2*np.pi*t)
plt.plot(t, s, 'k:')
# draw a thick red hline at y=0 that spans the xrange
l = plt.axhline(linewidth=8, color='r')
# draw a default hline at y=1 that spans the xrange
l = plt.axhline(y=0.8, color='b')
# draw a default hline at y=.5 that spans the middle half of the axes
# xmin: Should be between 0 and 1, 0 being the far left of the plot, 1 the far right of the plot.
# xmax: Should be between 0 and 1, 0 being the far left of the plot, 1 the far right of the plot.
l = plt.axhline(y=.6, xmin=0.2, xmax=0.6)
# draw a default vline at x=1 that spans the yrange
l = plt.axvline(x=0.8, linewidth=8)
# draw a thick blue vline at x=0 that spans the upper quadrant of the yrange
l = plt.axvline(x=0.7, ymin=0.75, ymax=0.25, linewidth=1, color='b')
p = plt.axhspan(0.2, 0.38, facecolor='0.5', alpha=0.5)
p = plt.axvspan(0.05, 0.25, facecolor='g', alpha=0.5)
plt.axis([0, 1, 0, 1])
plt.show()

使用示例 可用于二元对比的柱形图 plt.bar

In [82]:
n = 10
X = np.arange(n)
male = (1-X/float(n)) * np.random.uniform(0.5, 1.0, n)
female = (1-X/float(n)) * np.random.uniform(0.5, 1.0, n)
plt.bar(X, +male, facecolor='green', edgecolor='white')
plt.bar(X, -female, facecolor='blue', edgecolor='white')
for x,y in zip(X,male):
    plt.text(x, y, '%.2f' % y, ha='center', va= 'bottom', fontsize=12)
for x,y in zip(X,female):
    plt.text(x, -y-0.02, '%.2f' % y, ha='center', va= 'top', fontsize=12)
plt.xlim(-1.1, n*1.1)
plt.xticks([])
plt.ylim(-1.1, +1.1)
plt.yticks([])
plt.show()

Matplotlib组件

  • 以上基础制图操作,是直接在plot中实现快速绘图, 是一种面向函数的方法
  • matplotlib可以使用 figure,subplot 和 axes 配置布局
    • figure 是 matplotlib 中面向用户的界面,在 figure 内部配置 subplots
    • subplot 指定 plots 在 figure 中的位置
    • axes 是被指定位置后的的 plots

术语表

英文 中文
Annotation 标注
Axes 轴域
Axis 轴/坐标轴
Coordinate 坐标
Figure 图形
Handle 句柄
Legend 图例
Line 线条
Patch 补丁
Path 路径
Subplot 子图
Text 文本
Tick 刻度
Tick Label 刻度标签

Figure, Subplot, Axes的关系

  • 一个Figure是一个空白的画板
  • Figure可以切割为一个或多个Sublots
  • 切割后, 每一个Subplot也是一个空白的画板
  • Axes是布局在画板上的轴域(包含纵轴xaxix, 横轴yaxis等信息)
  • Axes可以直接布局在Figure之上, 也可以布局在每一个Subplot之上
  • 一个Figure(或subplot)上可以包含一个或多个Axes
  • Subplots的位置, 只能按照既定规则排列显示在Figure之上, 不可重叠和交叉
  • Axes的位置, 可以在任意位置显示, 还可以跨Subplots显示

plot 和 axes 的选择

  • matplotlib的函数式编程是通过封装对象实现的
  • matplotlib本质上是构建对象来构建图像, 但函数式编程将构建对象的过程封装在函数中方便调用
  • matplotlib的函数式编程存在的不足
    • 操作"对象"时,函数调用降低了效率
    • 函数掩盖Figure, subplot, axes的隶属关系, 容易导致知其然而不知其所以然
    • plot函数力有不逮,有时处理图像仍然需要对对象进行操作
    • 针对不同对象的操作实现相同的绘图效果容易导致混淆
  • 对于程序猿(媛)来说, Axes可能是更好的选择

Figure, Subplot, Axes关系演示

  • 面对对象是指在轴域上对axes进行操作, 但是画板的切割,使用subplot还是更为规范
  • 查看对象基本类型
    • fig1: class 'matplotlib.figure.Figure'
    • ax1: class 'matplotlib.axes._axes.Axes', 直接配置在Figure之上的axes
    • ax3: class 'matplotlib.axes._subplots.AxesSubplot', 配置在subplot之上的axes

声明一个空白Figure

In [83]:
fig = plt.figure()
print(type(fig))
# 可以发现对象类型为: <class 'matplotlib.figure.Figure'>
<class 'matplotlib.figure.Figure'>
<Figure size 432x288 with 0 Axes>

声明2行1列subplots fig.add_subplot()

In [84]:
fig = plt.figure()
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
print(type(ax1))
# 可以发现对象类型为: <class 'matplotlib.axes._subplots.AxesSubplot'>
<class 'matplotlib.axes._subplots.AxesSubplot'>

声明2行,第一行2列,第二行1列的subplots(第二种声明方法) plt.subplot()

In [85]:
ax1 = plt.subplot(221) # 第一行的左图
ax2 = plt.subplot(222) # 第一行的右图
ax3 = plt.subplot(212) # 第二整行
print(type(ax1))
# 可以发现对象类型为: <class 'matplotlib.axes._subplots.AxesSubplot'>
<class 'matplotlib.axes._subplots.AxesSubplot'>

声明三个轴域(直接在Figure之上),第二个和第三个重叠(且都覆盖在第一个之上) fig.add_axes()

In [86]:
fig = plt.figure()
ax1 = fig.add_axes([0.1, 0.1, 0.8, 0.8]) # 四个参数分别代表起点的x,y值和终点的x,y值
ax2 = fig.add_axes([0.4, 0.4, 0.4, 0.4])
ax3 = fig.add_axes([0.2, 0.2, 0.4, 0.4])
print(type(ax1))
# 可以发现对象类型为: <class 'matplotlib.axes._axes.Axes'>
<class 'matplotlib.axes._axes.Axes'>

同时声明 Axes 和 Subplot

In [87]:
fig1=plt.figure(figsize=(8, 5))
# 在fig1中配置一个轴域
# 隐式声明了一个subplot(111)
ax1 = plt.Axes(fig1,[0.2, 0.2, 0.4, 0.4])
# 需要执行add操作将其添加到fig中
fig1.add_axes(ax1)
# 清除axes的方法
# ax1.set_axis_off()
# 如果使用plt.subplot方法配置,会清除上一段代码中配置的axes
# ax1=plt.subplot(221)
# ax3=plt.subplot(223)
# 将Figure切割为2行2列,配置其中的第一个和第四个
ax1=fig1.add_subplot(221)
ax2=fig1.add_subplot(224)

Subplot画板切片 GridSpec

In [88]:
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(3, 3)   # 切分为3行3列
ax1 = plt.subplot(gs[0, :2])   # 行列均以0为开始下标 第1行到第2列
ax2 = plt.subplot(gs[1, 0])    # 第2行, 第1列
ax3 = plt.subplot(gs[1, 1])    # 第2行, 第2列
ax4 = plt.subplot(gs[0:2, 2])  # 第1到第2行, 第3列
ax5 = plt.subplot(gs[2:, :])   # 第3行, 第1到第3列
plt.tight_layout(pad=0.4, w_pad=0.5, h_pad=1.0) # 调整布局
plt.show()

声明一个带有ax的非空白Figure

In [89]:
fig, ax = plt.subplots()
print(type(ax))
# 可以发现ax对象类型为: <class 'matplotlib.axes._subplots.AxesSubplot'>
<class 'matplotlib.axes._subplots.AxesSubplot'>

声明Axes后为每一个subplot(ax数组中的列表中的成员)配置轴域信息

In [90]:
t=np.arange(0.0,2.0,0.1)
s=np.sin(t*np.pi)
figure, ax=plt.subplots(2,2)
ax[0][0].plot(t,s,'r*')       # 配置第1个plot
ax[0][1].plot(t*2,-s,'b--')   # 配置第2个plot
ax[1][0].grid(color='r', linestyle='--', linewidth=1, alpha=0.3) # 配置第3个plot网格
ax[1][1].plot(s,t,'k*')       # 配置第4个plot
print(type(ax))
ax
# 可以发现ax对象类型为: <class 'numpy.ndarray'>, 表示ax是一个包含Subplot之上的Axes的列表的数组
<class 'numpy.ndarray'>
Out[90]:
array([[<matplotlib.axes._subplots.AxesSubplot object at 0x7f2c5dcaa588>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x7f2c58015518>],
       [<matplotlib.axes._subplots.AxesSubplot object at 0x7f2c5da5c128>,
        <matplotlib.axes._subplots.AxesSubplot object at 0x7f2c57eaf780>]],
      dtype=object)

Figures 语法

figure(num = None, figsize = None, dpi = None, facecolor = None, edgecolor = None, frameon = True)

参数 默认值 描述
num 1 图像编号或名称,数字为编号 ,字符串为名称
figsize figure.figsize 指定figure的宽和高,单位为英寸
dpi figure.dpi 指定绘图对象的分辨率,即每英寸多少个像素,缺省值为80
facecolor figure.facecolor 背景颜色
edgecolor figure.edgecolor 边框颜色
frameon True 是否显示边框

Subplot 语法

subplot(nrows, ncols, sharex, sharey, subplot_kw, **fig_kw)

参数 描述
nrows subplot的行数
ncols subplot的列数
sharex 共享的x轴
sharey 共享的y轴
subplot_kw subplot关键字
**fig_kw figure关键字,如plt.subplots(2, 2, figsize=(8, 6))

Axes 语法

  • Axes(fig, rect, facecolor=None, frameon=True, sharex=None, sharey=None, label='', xscale=None, yscale=None, **kwargs)
  • rect = [left, bottom, width, height] in Figure coordinates
  • 针对axes操作可以得到与subplot相同的显示效果, 但所使用的函数形式不同
  • plt.xlabel() 设置的是当前坐标系的X坐标,默认是suplot(111)
  • ax.set_xlabel() 则是利用坐标系"对象"在轴域axes上设置X坐标
  • 四大坐标系
数据坐标系 说明(x轴范围,y轴范围)
子图坐标系 描述子图中位置的坐标系,左下角为(0,0),右上角为(1,1)
图表坐标系 左下角为(0,0),右上角为(1,1)
窗口坐标系 左下角坐标为(0,0),右上角坐标为(width,height). 以像素为单位的坐标系,不包含标题栏、工具条及状态栏部分
  • 两大对象
类别 对象
axes对象(1) transData为数据坐标变换对象
axes对象(2) transAxes为子图坐标变换对象
Figure对象 transFigure为图表变换对象
  • 注释
    • 在python模板中提供的绘制文字的函数为text()和figtext().
      • text():调用当前Axes对象的text()方法进行绘图,默认在数据坐标系中添加文字
      • figtext():调用当前figure对象的text()方法进行绘图,默认在图表坐标系中添加文字
    • 可通过transform参数改变文字所在的坐标系

声明fig和ax figure, ax=plt.subplots()

In [91]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
figure, ax=plt.subplots()
l1, = ax.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = ax.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
ax.set_xlabel("www.jasper.wang")   # 设定x轴的标签
ax.set_ylabel("www.jasper.wang")   # 设定y轴的标签
ax.set_xlim(x.min()*1.1, x.max()*1.1)         # 设定x轴范围
ax.set_ylim(y2.min()*3, y2.max()*1.1)         # 设定y轴范围
ax.set_title('www.jasper.wang')
ax.grid(color='m', linestyle='--', linewidth=1, alpha=0.3)
ax.legend(handles=[l1, l2], loc = 0, frameon=False, prop=myfont2, shadow=True)
plt.show()

隐藏边框 spines[].set_color()

In [92]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
figure, ax=plt.subplots()
l1, = ax.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = ax.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
ax.set_xlabel("www.jasper.wang")   # 设定x轴的标签
ax.set_ylabel("www.jasper.wang")   # 设定y轴的标签
ax.set_xlim(x.min()*1.1, x.max()*1.1)         # 设定x轴范围
ax.set_ylim(y2.min()*3, y2.max()*1.1)         # 设定y轴范围
ax.set_title('www.jasper.wang')
ax.grid(color='m', linestyle='--', linewidth=1, alpha=0.3)
ax.legend(handles=[l1, l2], loc = 0, frameon=False, prop=myfont2, shadow=True)
# ax.spines['left'].set_color('none')    # 隐藏左边的y轴
ax.spines['right'].set_color('none')   # 隐藏右边的y轴
ax.spines['top'].set_color('none')     # 隐藏顶部的x轴
# ax.spines['bottom'].set_color('none')  # 隐藏底部的x轴
plt.show()

移动坐标轴与刻度 set_ticks_position()

In [93]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
figure, ax=plt.subplots()
l1, = ax.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = ax.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
ax.set_xlabel("www.jasper.wang")              # 设定x轴的标签
ax.set_ylabel("www.jasper.wang")              # 设定y轴的标签
ax.set_xlim(x.min()*1.1, x.max()*1.1)         # 设定x轴范围
ax.set_ylim(y2.min()*3, y2.max()*1.1)         # 设定y轴范围
ax.set_title('www.jasper.wang')
ax.grid(color='m', linestyle='--', linewidth=1, alpha=0.3)
ax.legend(handles=[l1, l2], loc = 0, frameon=False, prop=myfont2, shadow=True)
ax.spines['left'].set_color('none')           # 隐藏左边的y轴
ax.spines['top'].set_color('none')            # 隐藏顶部的x轴
# ax.xaxis.set_ticks_position('bottom')
ax.xaxis.set_ticks_position('bottom')         # 配置刻度是标注在坐标的上面还是下面
ax.spines['bottom'].set_position(('data', 6))
ax.yaxis.set_ticks_position('right')          # 配置刻度是标注在坐标的左侧还是右侧
ax.spines['right'].set_position(('data', x.max()*1.1)) # 配置右侧坐标,在x数据最大值的1.1的位置

plt.show()

配置x,y轴范围 plt.axis([xmin,xmax,ymin,ymax])

In [94]:
def funy1(x):
    return x*0.75+5
def funy2(x):
    return x**2*0.3+x*0.75+0.1
x = np.linspace(-5,5,10)
y1=funy1(x)
y2=funy2(x)
figure, ax=plt.subplots()
l1, = ax.plot(x, y1, 'r-', label="www.jasper.wang")
l2, = ax.plot(x, y2, 'g--', label="土豪哥我们做朋友吧")
ax.set_xlabel("www.jasper.wang")               # 设定x轴的标签
ax.set_ylabel("www.jasper.wang")               # 设定y轴的标签
ax.set_xlim(x.min()*1.1, x.max()*1.1)          # 设定x轴范围
ax.set_ylim(y2.min()*3, y2.max()*1.1)          # 设定y轴范围
ax.set_title('www.jasper.wang')
ax.grid(color='m', linestyle='--', linewidth=1, alpha=0.3)
ax.legend(handles=[l1, l2], loc = 2, frameon=False, prop=myfont2, shadow=True)
ax.spines['left'].set_color('none')            # 隐藏左边的y轴
ax.spines['top'].set_color('none')             # 隐藏顶部的x轴
# ax.xaxis.set_ticks_position('bottom')
ax.xaxis.set_ticks_position('bottom')          # 配置刻度是标注在坐标的上面还是下面
ax.spines['bottom'].set_position(('data', 12.5))
ax.yaxis.set_ticks_position('right')           # 配置刻度是标注在坐标的左侧还是右侧
ax.spines['right'].set_position(('data', x.max()*2.2)) # 配置右侧坐标,在x数据最大值的1.1的位置
# 指定轴域的可视区域
# axis()命令接收[xmin,xmax,ymin,ymax]列表
plt.axis([-10, 10, -2, 18])
plt.show()

嵌入式Axes,使用句柄 fig.add_axes([left, bottom, width, height])

In [95]:
#新建figure
fig = plt.figure()
# 定义数据
x = [1, 2, 3, 4, 5, 6, 7]
y = [1, 3, 4, 2, 5, 8, 6]

# 新建区域ax1
# figure的百分比,从figure 10%的位置开始绘制, 宽高是figure的80%
left, bottom, width, height = 0.1, 0.1, 0.85, 0.85
# 获得绘制的句柄
ax1 = fig.add_axes([left, bottom, width, height])
ax1.plot(x, y, 'r')
ax1.set_title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1)  # 植入硬广告

# 新增区域ax2, 嵌套在ax1内
left, bottom, width, height = 0.25, 0.5225, 0.26, 0.26
# 获得绘制的句柄
ax2 = fig.add_axes([left, bottom, width, height])
ax2.plot(x,y, 'b')
ax2.set_title('www.jasper.wang\n土豪哥我们做朋友吧', fontproperties=myfont1)  # 植入硬广告
# plt.title('jasper.wang')    # 针对当前axes,即ax2,配置title
plt.xticks([])                # 针对当前axes,即ax2,配置隐藏 x 坐标
plt.yticks([])                # 针对当前axes,即ax2,配置隐藏 y 坐标

plt.show() 

子图共享坐标轴

In [96]:
t = np.arange(0.01, 5.0, 0.01)
s1 = np.sin(2*np.pi*t)
s2 = np.exp(-t)
s3 = np.sin(4*np.pi*t)

ax1 = plt.subplot(311)
plt.plot(t, s1)
plt.setp(ax1.get_xticklabels(), fontsize=14)
plt.setp(ax1.get_yticklabels(), fontsize=14)

# ax2共享ax1的x轴
ax2 = plt.subplot(312, sharex=ax1)
plt.plot(t, s2)

# 隐藏ax2的x坐标刻度
plt.setp(ax2.get_xticklabels(), visible=False)

# ax3共享ax1的x轴和y轴
ax3 = plt.subplot(313, sharex=ax1, sharey=ax1)
plt.plot(t, s3)

plt.xlim(0.01, 5.0)
plt.show()