在 class 中放置具有可控参数的动画图形
Placing animated graph with controlable parameters in a class
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()
上面截图的想法是有一个动画图形和一组控制它的参数的小部件。更改参数应该会更改正在显示的图表。
话虽如此,上面的代码确实 none 了。它是一个不会改变的动画图形和两个改变对象内变量的小部件。但是,该程序没有按预期运行。
首先,图表根本没有显示。我不明白为什么。
其次,改变两个小部件中的任何一个的状态都会抛出 TypeError
:
Traceback (most recent call last):
File "C:\Programs\Python37\lib\site-packages\matplotlib\cbook\__init__.py", line 215, in process
func(*args, **kwargs)
File "C:\Programs\Python37\lib\site-packages\matplotlib\widgets.py", line 417, in _update
self.set_val(val)
File "C:\Programs\Python37\lib\site-packages\matplotlib\widgets.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()
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()
上面截图的想法是有一个动画图形和一组控制它的参数的小部件。更改参数应该会更改正在显示的图表。
话虽如此,上面的代码确实 none 了。它是一个不会改变的动画图形和两个改变对象内变量的小部件。但是,该程序没有按预期运行。
首先,图表根本没有显示。我不明白为什么。
其次,改变两个小部件中的任何一个的状态都会抛出 TypeError
:
Traceback (most recent call last):
File "C:\Programs\Python37\lib\site-packages\matplotlib\cbook\__init__.py", line 215, in process
func(*args, **kwargs)
File "C:\Programs\Python37\lib\site-packages\matplotlib\widgets.py", line 417, in _update
self.set_val(val)
File "C:\Programs\Python37\lib\site-packages\matplotlib\widgets.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()