如何绘制论文中好看又高级的误差图,本文旨在解决如下类似的图的绘制
准备工具:Python
参考:https://zhuanlan.zhihu.com/p/147274030参考文章
首先是引入需要的库
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.axes_grid1.inset_locator import inset_axes # 用于创建具有给定宽度和高度的插入轴
from matplotlib.patches import ConnectionPatch #
from pylab import *
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 指定默认字体 还有仿宋、楷体、微软雅黑:'FangSong', 'KaiTi', 'Microsoft YaHei'
mpl.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
读取数据
# Data read
data1 = pd.read_csv('data1.csv', header= None) # 防止第一行被读作 header
data2 = pd.read_csv('data2.csv', index_col = 0) # 设置第一列为 index
关于读取数据的具体操作详解请见
绘制主图
t = range(800) # 绘制时间轴长度为 800
plt.rcParams['figure.figsize'] = (14.0, 6.0) # 图片大小设置为 14英寸,6英寸
fig, ax = plt.subplots() # fig is figure object, and ax is axes object
LW = 0.8 # 线宽
ca = plt.gca() # gca means "get current axis"
ca.spines['right'].set_linestyle('--') # 右侧轴的设置线形
ca.spines['right'].set_linewidth(1) # 右侧轴的设置线宽
ca.spines['right'].set_color('gray') # 右侧轴的设置线的颜色
ca.spines['top'].set_linestyle('--') # 顶部轴的
ca.spines['top'].set_linewidth(1)
ca.spines['top'].set_color('gray')
ca.spines['left'].set_linewidth(1.5) # 左侧轴
ca.spines['bottom'].set_linewidth(1.5) # 底部轴
ax.plot(t, data1.iloc[0,0:800], color = 'red', linewidth = LW , linestyle = '-' , label = '原始数据')
# 绘制颜色为红色,x轴为t,y轴为 data1.iloc[0,0:800] 的线宽为LW图,标签为原始数据。
ax.plot(t, data2[0,0:800], color = 'darkgreen', linewidth = LW , linestyle = '-' , label = '传统模型')
ax.plot(t, data3.iloc[0,0:800], color = 'darkred', linewidth = LW , linestyle = '-' , label = 'RBF')
ax.plot(t, data4.iloc[0,0:800], color = 'darkcyan', linewidth = LW , linestyle = '-' , label = 'GRNN')
ax.plot(t, data5.iloc[0:800,0], color = 'black', linewidth = LW , linestyle = '-' , label = 'GRU')
ax.plot(t, data6.iloc[0:800,0], color = 'royalblue', linewidth = LW , linestyle = '-' , label = 'LSTM')
ax.set_xlabel('时间/s') # 设置 x 轴标签
ax.set_ylabel('残差') # 设置 y 轴标签
ax.set_title('残差对比图') # 设置题目
ax.set_xlim((0,800)) # 设置 x 轴的范围
ax.set_ylim((-0.07,0.12)) # 设置 y 轴范围
ax.legend(loc = 'upper left', shadow = True, framealpha = 1, fontsize = 10, edgecolor = 'black')
# 加入legend 位置为左上,带阴影,框架透明度为1,字体大小为10,边框颜色为黑。
绘制子图
插入子图应用 ax.inset_axes((a, b, c, d))
,其中a, b
分别表示子图在主图 x 轴与 y 轴的起始位置(数值从0-1, 表示比例),c, d
表示子图占主图的 x, y 轴的长度比例。
axins = ax.inset_axes((0.45, 0.58, 0.45, 0.4)) # 插入子图的轴
zone_left = 550 # 子图的 x 轴左界
zone_right = 650 # 子图的 x 轴右界
t_ins = range(zone_left, zone_right) # 子图的 x 时间轴
# 绘制子图
axins.plot(t_ins, data1[0, zone_left : zone_right], color = 'darkcyan', linewidth = LW , linestyle = '-' , label = 'GRNN')
axins.plot(t_ins, data2.iloc[0, zone_left : zone_right], color = 'darkred', linewidth = LW , linestyle = '-' , label = 'RBF')
axins.plot(t_ins, data3.iloc[0, zone_left : zone_right], color = 'darkgreen', linewidth = LW , linestyle = '-' , label = '传统模型')
axins.plot(t_ins, data4.iloc[0, zone_left : zone_right], color = 'red', linewidth = LW , linestyle = '-' , label = '原始数据')
axins.plot(t_ins, data5.iloc[zone_left : zone_right, 0], color = 'black', linewidth = LW , linestyle = '-' , label = 'GRU')
axins.plot(t_ins, data6.iloc[zone_left : zone_right, 0], color = 'royalblue', linewidth = LW , linestyle = '-' , label = 'LSTM')
# 设置子图 x 轴与 y 轴区间
axins.set_xlim((zone_left, zone_right))
axins.set_ylim((-0.02,0.02))
主子图连接
主图中绘制方框就用正常的直线连接。
子图与主图的连接用 ConnectionPatch(xyA, xyB, coordsA="data", coordsB="data", axesA=axins, axesB=ax)
,这里xyA是子图里面的点(按子图的坐标输入),xyB是主图里面的点,coordsA和coordsB默认值"data",也不用改,然后就是axesA为子图轴对象,axesB为主图轴对象。
函数参考https://matplotlib.org/stable/api/_as_gen/matplotlib.patches.ConnectionPatch.html
axins.add_artist(connect_AB1)
用于添加连线。
# 在主图中绘制方框
ax.plot([zone_left, zone_left, zone_right, zone_right, zone_left], [-0.02, 0.02, 0.02, -0.02, -0.02], linestyle = '--', linewidth = 1, color = "black")
# 连接主图的方框与子图
connect_AB1 = ConnectionPatch((zone_left, -0.02),(zone_left, 0.02), coordsA="data",coordsB="data",
axesA=axins,axesB=ax)
axins.add_artist(connect_AB1)
connect_AB2 = ConnectionPatch((zone_right, -0.02),(zone_right, 0.02), coordsA="data",coordsB="data",
axesA=axins,axesB=ax)
axins.add_artist(connect_AB2)
# 保存图像 分辨率 dpi = 600 一般 600 已经很清楚了
plt.savefig('error.jpg', dpi = 600)
主图与子图之间还有另一种连接方式:
from mpl_toolkits.axes_grid1.inset_locator import mark_inset
mark_inset((parent_axes, inset_axes, loc1 = {1, 2, 3, 4}, loc2 = {1, 2, 3, 4}, alpha=0.5,fc='none',ec='r',ls='-.')
mark_inset意为插入图的标记
其中,parent_axes,inset_axes
分别代表主图与子图的轴,loc1,loc2
表示用于连接主图与子图轴区域的角,fc
即facecolor
,ec
表示 edgecolor
,其他参数与线状参数类似。
线型:
基础颜色:
标记:
位置参数:
进阶颜色: