在类中放置具有可控制参数的动画图形


import matplotlib.gridspec as gridspec
import numpy as np
from matplotlib import animation
from matplotlib import pyplot as plt
from matplotlib.widgets import Slider, CheckButtons
PI = np.pi
sliderDataList = [{'name': 'Left amplitude', 'min': 0.1, 'max': 8.0, 'init': 2, 'step': 0.01}]
checkboxDataList = [{'name': 'Left wave', 'init': True}]

class CollidingWaves:
def __init__(self, timeFactor=5, x_range=4 * PI, x_offset=0, y_range=4, y_offset=0, sliderData=[],
checkboxData=[], tension=1, massDensity=1):
self.x_range = x_range
self.x_offset = x_offset
self.y_range = y_range
self.y_offset = y_offset
self.sliderData = sliderData
self.checkboxData = checkboxData
self.tension = tension
self.massDensity = massDensity
self.timeFactor = timeFactor
self.showWave = []
self.amplitude = 0
self.fig = plt.figure()
self.mainGrid = gridspec.GridSpec(2, 1)
self.graphCell = plt.subplot(self.mainGrid[0, :])
self.graphCell.set(xlim=(-self.x_range - self.x_offset, self.x_range - self.x_offset),
ylim=(-self.y_range - self.y_offset, self.y_range - self.y_offset))
self.x_data = np.linspace(-self.x_range - self.x_offset, self.x_range - self.x_offset, 512)
self.y_data = []
self.lines = [plt.plot([], [])[0] for _ in range(2)]
self.patches = self.lines
self.controlCell = self.mainGrid[1, :]
self.controlGrid = gridspec.GridSpecFromSubplotSpec(1, 7, self.controlCell)
self.checkboxCell = self.controlGrid[0, 0]
self.checkboxGrid = gridspec.GridSpecFromSubplotSpec(1, 1, self.checkboxCell)
self.checkboxes = []
self.checkboxAx = plt.subplot(self.checkboxGrid[0, 0:1])
self.checkbox = CheckButtons(self.checkboxAx, tuple(x["name"] for x in self.checkboxData),
tuple(x["init"] for x in self.checkboxData))
self.checkboxes.append(self.checkbox)
self.sliderCell = self.controlGrid[0, 2:6]
self.sliderGrid = gridspec.GridSpecFromSubplotSpec(len(self.sliderData), 1, self.sliderCell)
self.sliders = []
for i in range(0, len(self.sliderData)):
self.sliderAx = plt.subplot(self.sliderGrid[i, 0])
self.slider = Slider(self.sliderAx, self.sliderData[i]["name"], self.sliderData[i]["min"],
self.sliderData[i]["max"], valinit=self.sliderData[i]["init"],
valstep=self.sliderData[i]["step"])
self.sliders.append(self.slider)
for slider in self.sliders:
slider.on_changed(self.update)
for checkbox in self.checkboxes:
checkbox.on_clicked(self.update)
def update(self):
self.amplitude = self.sliders[0].val
self.showWave = self.checkboxes[0].val
def init(self):
for line in self.lines:
line.set_data([], [])
return self.patches
def animate(self, i):
self.y_data[0] = [1] * 512
self.y_data[1] = [2] * 512
self.lines[0].set_data(self.x_data, self.y_data[0])
self.lines[1].set_data(self.x_data, self.y_data[1])
return self.patches
def start(self):
animation.FuncAnimation(self.fig, self.animate, init_func=self.init, frames=600, repeat=True, interval=20, blit=True)
plt.show()

graph = CollidingWaves(sliderData=sliderDataList, checkboxData=checkboxDataList)
graph.start()

上面剪切的想法是有一个动画图形和一组控制其参数的小部件。更改参数应该会更改正在显示的图形。

话虽如此,上面的代码并没有做到这一点。这是一个不改变的动画图和两个改变对象内变量的小部件。然而,该程序并没有按预期运行。

首先,根本不显示图形。我不明白为什么。其次,更改这两个小部件中任何一个的状态都会抛出一个TypeError:

Traceback (most recent call last):
File "C:ProgramsPython37libsite-packagesmatplotlibcbook__init__.py", line 215, in process
func(*args, **kwargs)
File "C:ProgramsPython37libsite-packagesmatplotlibwidgets.py", line 417, in _update
self.set_val(val)
File "C:ProgramsPython37libsite-packagesmatplotlibwidgets.py", line 438, in set_val
func(val)
TypeError: update() takes 1 positional argument but 2 were given

我在这里做错了什么?

这里似乎只有四个问题:

  • update以事件作为参数进行调用。你需要确保它确实接受了这个论点,即使你没有使用它
  • 该复选框没有val属性。您可以通过.get_status获取复选框的状态
  • y_data被分配了两个元素。因此,它从一开始就需要两个要素
  • 动画需要留在内存中。因此,您可以将其分配给一个变量

总的来说,这是可行的:

import matplotlib.gridspec as gridspec
import numpy as np
from matplotlib import animation
from matplotlib import pyplot as plt
from matplotlib.widgets import Slider, CheckButtons
PI = np.pi
sliderDataList = [{'name': 'Left amplitude', 'min': 0.1, 'max': 8.0, 'init': 2, 'step': 0.01}]
checkboxDataList = [{'name': 'Left wave', 'init': True}]

class CollidingWaves:
def __init__(self, timeFactor=5, x_range=4 * PI, x_offset=0, y_range=4, y_offset=0, sliderData=[],
checkboxData=[], tension=1, massDensity=1):
self.x_range = x_range
self.x_offset = x_offset
self.y_range = y_range
self.y_offset = y_offset
self.sliderData = sliderData
self.checkboxData = checkboxData
self.tension = tension
self.massDensity = massDensity
self.timeFactor = timeFactor
self.showWave = []
self.amplitude = 0
self.fig = plt.figure()
self.mainGrid = gridspec.GridSpec(2, 1)
self.ax = plt.subplot(self.mainGrid[0, :])
self.ax.set(xlim=(-self.x_range - self.x_offset, self.x_range - self.x_offset),
ylim=(-self.y_range - self.y_offset, self.y_range - self.y_offset))
self.x_data = np.linspace(-self.x_range - self.x_offset, self.x_range - self.x_offset, 512)
self.y_data = [[],[]]
self.lines = [self.ax.plot([], [])[0] for _ in range(2)]
self.patches = self.lines
self.controlCell = self.mainGrid[1, :]
self.controlGrid = gridspec.GridSpecFromSubplotSpec(1, 7, self.controlCell)
self.checkboxCell = self.controlGrid[0, 0]
self.checkboxGrid = gridspec.GridSpecFromSubplotSpec(1, 1, self.checkboxCell)
self.checkboxes = []
self.checkboxAx = plt.subplot(self.checkboxGrid[0, 0:1])
self.checkbox = CheckButtons(self.checkboxAx, tuple(x["name"] for x in self.checkboxData),
tuple(x["init"] for x in self.checkboxData))
self.checkboxes.append(self.checkbox)
self.sliderCell = self.controlGrid[0, 2:6]
self.sliderGrid = gridspec.GridSpecFromSubplotSpec(len(self.sliderData), 1, self.sliderCell)
self.sliders = []
for i in range(0, len(self.sliderData)):
self.sliderAx = plt.subplot(self.sliderGrid[i, 0])
self.slider = Slider(self.sliderAx, self.sliderData[i]["name"], self.sliderData[i]["min"],
self.sliderData[i]["max"], valinit=self.sliderData[i]["init"],
valstep=self.sliderData[i]["step"])
self.sliders.append(self.slider)
for slider in self.sliders:
slider.on_changed(self.update)
for checkbox in self.checkboxes:
checkbox.on_clicked(self.update)
def update(self, event=None):
self.amplitude = self.sliders[0].val
self.showWave = self.checkboxes[0].get_status()
def init(self):
for line in self.lines:
line.set_data([], [])
return self.patches
def animate(self, i):
self.y_data[0] = [1] * 512
self.y_data[1] = [2] * 512
self.lines[0].set_data(self.x_data, self.y_data[0])
self.lines[1].set_data(self.x_data, self.y_data[1])
return self.patches
def start(self):
self.ani = animation.FuncAnimation(self.fig, self.animate, init_func=self.init, frames=600, repeat=True, interval=20, blit=True)
plt.show()

graph = CollidingWaves(sliderData=sliderDataList, checkboxData=checkboxDataList)
graph.start()

最新更新