创作背景
今天在群里看到有群有问问题,如下图所示
正好巩固一下上上一篇利用 Matplotlib
制作动图的知识,再学习一下制作动态柱状图,写下此篇以记录。
如果觉得我这篇文章写的好的话,能不能给我 点个赞
,评论
、收藏
一条龙(*▽*)。如果要点个 关注
的话也不是不可以。
请各位参加一下文末的 投票
哦,如果 有什么不足之处,还 请各位大佬在评论区提出,不胜感激。
知识回顾
回顾一下使用 FuncAnimation
制作曲线动图的步骤(详情请见这篇文章):
- 设置画布。
- 创建列表以保存点坐标。
- 构建更新函数。
- 使用
FuncAnimation
启动动画。
新的知识
上一篇是 曲线绘图 ,这次要加上 柱状图 ,于是我来到了 这里 学习一波。
这个代码的思路是:记录一连串路径点的坐标 ,通过 移动到指定点 、两点间绘制直线 来绘制柱子,可以借鉴这个思路。
从代码中可得,我们要使用 matplotlib.path.Path
记录绘制矩形的路径及方法,使用 matplotlib.patches.PathPatch
将路径绘制出来,最后使用 ax.add_patch()
将其在画布上显示出来。
我的思路
-
首先还是要导入需要的包。
import numpy as np import matplotlib.path as path import matplotlib.pyplot as plt import matplotlib.patches as patches from matplotlib.animation import FuncAnimation
其中,
numpy
用来生成点数据,path
是用来生成路径,patches
通过路径绘制图像。 -
然后还是设置一下画布,设置
x
和y
轴的范围。fig, ax = plt.subplots() ax.set_xlim(0, 1.1) ax.set_ylim(0, 3)
-
初始化曲线和数据,以保存点的坐标和路径动作。
ln = plt.plot([], [], 'ro') codes = [] verts = np.empty((0, 2), np.float64) points = np.empty((0, 2), np.float64)
其中,
codes
保存路径动作,verts
保存路径点坐标,points
保存曲线点坐标。 -
设置更新函数。
func = lambda x: x**3 + 1 def update(frame): global points, verts, codes points = np.append(points, [[frame, func(frame)]], axis=0) verts = np.append(verts, [[frame, 0], [frame, func(frame)], [frame+1/50, func(frame)], [frame+1/50, 0]], axis=0) ln[0].set_data(list(zip(*points))) codes.extend([path.Path.MOVETO] + [path.Path.LINETO] * 3) barpath = path.Path(verts, codes) patch = patches.PathPatch(barpath, facecolor='blue', edgecolor='yellow', alpha=0.5) ax.add_patch(patch) return patch, ln[0],
其中,
verts
要添加4
个点的坐标,分别是矩形的四个顶点坐标,codes
也同样添加四个动作。然后生成路径并显示。
-
启动动画
ani = FuncAnimation(fig, update, frames=np.linspace(0, 1, 50), repeat=False, blit=True) # 保存 # ani.save('test.gif', writer='imagemagick', fps=10) plt.show()
参数就不细讲了,详见 上一篇文章 ,如果在
jupyter
中绘制的话,记得要在代码框最前边加上%matplotlib notebook
哦。
最后看一下效果:
看起来还不错。
封装一下
可以看到,代码是可以进行封装的,封装后的函数可以实现 绘制任一函数的积分动画 。
(当然,因为我的代码能力限制,这是简陋版,如果有大佬能修改修改,能否让我拜读一下)
代码如下:
%matplotlib notebook
import numpy as np
import matplotlib.path as path
import matplotlib.pyplot as plt
import matplotlib.patches as patches
from matplotlib.animation import FuncAnimation
def create_gif(func, interval=[-1, 1, -1, 1], bins=50):
if not isinstance(interval, (list, np.array)):
raise ValueError(f'Input data "{
interval}" is invalid.')
def update(frame):
global points, verts, codes
dx = (interval[1] - interval[0]) / bins
points = [[frame, func(frame)]]
verts = [[frame, 0], [frame, func(frame)], [frame+dx, func(frame)], [frame+dx, 0]]
ln[0].set_data(list(zip(*points)))
codes = [path.Path.MOVETO] + [path.Path.LINETO] * 3
barpath = path.Path(verts, codes)
patch = patches.PathPatch(barpath, facecolor='blue', edgecolor='yellow', alpha=0.5)
ax.add_patch(patch)
return patch, ln[0],
fig, ax = plt.subplots()
ax.axis(interval)
global points, verts, codes
codes = []
verts = np.empty((0, 2), np.float64)
points = np.empty((0, 2), np.float64)
ln = plt.plot([], [], 'ro')
global ani
ani = FuncAnimation(fig, update, frames=np.linspace(*interval[:2], bins), repeat=False, blit=True)
# ani.save('test.gif', writer='imagemagick', fps=10)
plt.show()
其中:
func
就是要绘制动图的函数。interval
是坐标轴范围。bins
是要绘制的柱子个数。
测试一下:
func = lambda x: x**3+1
create_gif(func, [0, 1.1, 0, 3])
和上图结果一样,大家也可以自行尝试。
结尾
有想要一起学习 python
的小伙伴可以 私信我
进群哦。
以上就是我要分享的内容,因为 学识尚浅,会有不足,还 请各位大佬指正。
有什么问题也可在评论区留言。
文章评论