我正在尝试在类中封装matplotlib绘图更新。想法是调度信号(即事件),并且监听实例应该更新绘图。我目前正在使用dispatcher,但我也尝试使用PyDispatcher,结果相同。
以下是我想要做的简化代码,包括哪些有效,哪些无效:
from time import sleep
from random import random
import matplotlib.pyplot as plt
import dispatch
plt.ion()
# define signal to be dispatched
plot_update = dispatch.Signal(providing_args=["y"])
# non-encapsulated update (this works alright)
fig = plt.figure('This Works')
ax = fig.add_subplot(111)
line1, = ax.plot([1], [0], 'ko')
ax.axis((0, 2, 0, 1))
def update_callback(sender, **kwargs):
line1.set_ydata(kwargs['y'])
fig.canvas.draw()
plot_update.connect(update_callback)
# class to encapsulate plot update behavior
class DynamicPlot(object):
def __init__(self, fid_name):
self.fig = plt.figure(fid_name)
self.ax = self.fig.add_subplot(111)
self.line1, = self.ax.plot([1], [0], 'ko')
self.ax.axis((0, 2, 0, 1))
self.fig.canvas.draw()
def _update_callback(sender, **kwargs):
self.line1.set_ydata(kwargs['y'])
self.fig.canvas.draw()
# I'd expect this to connect _update_callback to be triggered
# when the `plot_update` signal is dispatched, but that's not
# happening
plot_update.connect(_update_callback)
# Calling this method, will update the plot, but this
# is not what I need (is just here for testing)
def update(self, y):
self.line1.set_ydata(y)
self.fig.canvas.draw()
# test code
if __name__ == "__main__":
# this one should update by listening to events (signal)
d1 = DynamicPlot("This Won't Work")
# this instance is here just for testing, to make sure
# the class can update a plot via a different mechanism
d2 = DynamicPlot("This Will Work Too")
# mocked signal dispatcher
while(True):
plot_update.send(sender=None, y=[random()])
d2.update([random()])
sleep(0.1)
非封装版本按预期工作。当我使用该类时,我可以调用更新方法,它可以完成它应该做的事情。但我真正需要的是能够更新绘图而无需显式调用更新方法(以避免不希望的耦合)。因此调度包。
我已经测试过并且正在调用_update_callback
。我知道事件正在被调度(否则,非封装版本将不起作用),所以我能想到的唯一解释是plot_update.connect(_update_callback)
没有做它应该做的事情,但我不知道为什么?
关于为什么这不能按预期工作的任何想法?更好的是,关于如何实现理想行为的任何想法?
答案 0 :(得分:0)
经过一些进一步的研究后,我意识到问题是connect()
dispatcher.Signal
方法默认情况下会尝试将弱引用用于回调函数。我的问题的解决方案是将weak=false
传递给connect()
。这就是我在代码中所说的内容(问题中的示例,但删除了测试和非封装代码):
from time import sleep
from random import random
import matplotlib.pyplot as plt
import dispatch
plot_update = dispatch.Signal(providing_args=["y"])
plt.ion()
class DynamicPlot(object):
def __init__(self, fid_name):
self.fig = plt.figure(fid_name)
plt.clf()
self.ax = self.fig.add_subplot(111)
self.line1, = self.ax.plot([1], [0], 'ko')
self.ax.axis((0, 2, 0, 1))
self.fig.canvas.draw()
plt.show()
def _update_callback(sender, **kwargs):
self.line1.set_ydata(kwargs['y'])
self.fig.canvas.draw()
plot_update.connect(_update_callback, weak=False)
# plot_update.connect(tmp(self))
if __name__ == "__main__":
d1 = DynamicPlot("Not it Works!")
while(True):
plot_update.send_robust(sender=None, y=[random()])
sleep(0.1)
希望这有助于其他人!