这是一个Python的科学绘图库的使用心得,涉及平面绘制、子图绘制、格点、三维(3D)绘制以及动态绘图。
http://matplotlib.org/
基本绘制
直接导入库后,提供数组进行绘制即可:
基础
import matplotlib.pyplot as plt
x = [1, 2, 3]
y = [1, 2, 3]
# 绘制线图
plt.plot(x, y, color, ...)
# 绘制散点图
plt.scatte()
plt.show()
还可以绘制别的图像,详见官网。
进阶
子图
可以添加多张子图进行绘制,并且修改图像的标题和坐标轴等:
plt.subplot(2, 2, 1)
plt.title("子图像1")
plt.subplot(2, 2, 2)
plt.title("子图像2")
plt.subplot(2, 2, 3)
plt.title("子图像3")
plt.subplot(2, 2, 4)
plt.title("子图像4")
面向对象
除了这种类似于matlab的用法,还可以用面向对象的用法来进行绘制:
import matplotlib.pyplot as plt
fig = plt.figure()
axi = fig.add_subplot(2, 2, 1)
axi.set_title("子图1")
axi.set_xlabel("x轴")
axi.set_ylabel("y轴")
ax.set_xlim(min(0, 10)
ax.set_ylim(0, 10)
......
细化分隔
也可以进一步细化控制每一个子图所占区域范围:
import matplotlib.gridspec as gridspec
gs = gridspec.GridSpec(2, 2)
fig = plt.figure(1, figsize=(16, 9), dpi=72)
fig.suptitle("Distance offset from start")
ax1 = fig.add_subplot(gs[:, 0])
ax1.set_title("Total")
ax1.set_xlabel("X(m)")
ax1.set_ylabel("Y(m)")
ax2 = fig.add_subplot(gs[0, 1])
ax2.set_title("X")
ax2.set_xlabel("t(s)")
ax2.set_ylabel("0m")
ax3 = fig.add_subplot(gs[1, 1])
ax3.set_title("Y")
ax3.set_xlabel("t(s)")
ax3.set_ylabel("0m")
这种情况下,第一张子图将占据第一行,第二张子图占据第二行的第一列,第三张则是第二行的第二列。
三维
三维图的绘制也是被支持的,只需要导入一个模块便可以在绘制的时候加上z轴的参数:
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
fig = plt.figure(1, figsize=(16, 9), dpi=72)
ax1 = fig.add_subplot(1, 1, 1, projection="3d")
ax1.set_title("三维图")
ax1.set_xlabel("X")
ax1.set_ylabel("Y")
ax1.set_zlabel("Z")
ax1.scatter([1, 2, 3], [1, 2, 3], [1, 2, 3])
动画
动画也是被支持的,其核心在于一个模块和一个方法,以下是我常用的方案更详细可以看这里:
导入核心库和使用核心方法:
# 核心库
import matplotlib.animation as animation
# 生成动画对象
ani = animation.FuncAnimation(fig_p, draw_distances_run, draw_distances_data_gen, interval=200)
其中draw_distances_run
方法是绘制每一帧更新时用于绘制的方法,draw_distances_data_gen
方法用于在绘制中修改绘制数据,而interval
参数则是一个毫秒的时间,是每两帧之间的间隔。
那么如何具体的来使用呢?
我此处选择的是一个并非那么合理但是快速的方法,当然,其实外面用个类包起来其实就好,满足需求就行。。。
初始化数据
def draw_distances_start():
fig = plt.figure(1, figsize=(16, 9), dpi=120)
fig.suptitle("Distance offset from start")
ax1 = fig.add_subplot(1, 1, 1, projection="3d")
ax1.set_title("图1")
ax1.set_xlabel("X")
ax1.set_ylabel("Y")
ax1.set_zlabel("Z")
data1 = ax1.scatter([], [], [])
return fig, ax1, data1
# 全局变量
fig, ax1, data1 = draw_distances_start()
data_now = ["x": [], "y": [], "z": []]
data_new = ["x": [], "y": [], "z": []]
更新数据
def draw_distances_data_gen():
for key in data_now:
data_now[key].extend(data_new[key])
yield data_now
更新绘制
def draw_distances_run(d):
x, y, z = d["x"], d["y"], d["z"]
data1.set_offsets([(x[-1], y[-1])])
data1.set_3d_properties([z[-1]], "z")
ax1.set_xlim(min(x), max(x))
ax1.set_ylim(min(y), max(y))
ax1.set_zlim(min(z), max(z))
return data1
注意,这里更新x和y用的是set_offsets
方法,而更新z用的是set_3d_properties
方法。
提供新数据
以上代码中,一个全局的data_now
变量用于存储当前要绘制的数据,而data_new
则是该帧的新数据。在实际使用中,为了防止卡顿,一般选择用一个新的线程来更新data_new
的数据:
def refresh():
while True:
data_new = get_new_data()
thread.start_new(refresh, ())
一切准备就绪后,调用plt.show()
即可开始绘制动画。