我在重画这个图形时有问题。我允许用户指定时间尺度(x轴)中的单位,然后重新计算并调用此函数plots()。我希望简单地更新图形,而不是将另一个图形添加到图形中。
def plots():
global vlgaBuffSorted
cntr()
result = collections.defaultdict(list)
for d in vlgaBuffSorted:
result[d['event']].append(d)
result_list = result.values()
f = Figure()
graph1 = f.add_subplot(211)
graph2 = f.add_subplot(212,sharex=graph1)
for item in result_list:
tL = []
vgsL = []
vdsL = []
isubL = []
for dict in item:
tL.append(dict['time'])
vgsL.append(dict['vgs'])
vdsL.append(dict['vds'])
isubL.append(dict['isub'])
graph1.plot(tL,vdsL,'bo',label='a')
graph1.plot(tL,vgsL,'rp',label='b')
graph2.plot(tL,isubL,'b-',label='c')
plotCanvas = FigureCanvasTkAgg(f, pltFrame)
toolbar = NavigationToolbar2TkAgg(plotCanvas, pltFrame)
toolbar.pack(side=BOTTOM)
plotCanvas.get_tk_widget().pack(side=TOP)
你基本上有两个选择:
Do exactly what you're currently doing, but call graph1.clear() and graph2.clear() before replotting the data. This is the slowest, but most simplest and most robust option.
Instead of replotting, you can just update the data of the plot objects. You'll need to make some changes in your code, but this should be much, much faster than replotting things every time. However, the shape of the data that you're plotting can't change, and if the range of your data is changing, you'll need to manually reset the x and y axis limits.
举一个第二个选项的例子:
import matplotlib.pyplot as plt
import numpy as np
x = np.linspace(0, 6*np.pi, 100)
y = np.sin(x)
# You probably won't need this if you're embedding things in a tkinter plot...
plt.ion()
fig = plt.figure()
ax = fig.add_subplot(111)
line1, = ax.plot(x, y, 'r-') # Returns a tuple of line objects, thus the comma
for phase in np.linspace(0, 10*np.pi, 500):
line1.set_ydata(np.sin(x + phase))
fig.canvas.draw()
fig.canvas.flush_events()
如果有人看到这篇文章寻找我正在寻找的东西,我在这里找到了例子
如何可视化标量二维数据与Matplotlib?
and
http://mri.brechmos.org/2009/07/automatically-update-a-figure-in-a-loop
(web.archive.org)
然后将它们修改为使用imshow和帧的输入堆栈,而不是动态生成和使用轮廓。
从形状图像的3D数组(nBins, nBins, nBins)开始,称为帧。
def animate_frames(frames):
nBins = frames.shape[0]
frame = frames[0]
tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
for k in range(nBins):
frame = frames[k]
tempCS1 = plt.imshow(frame, cmap=plt.cm.gray)
del tempCS1
fig.canvas.draw()
#time.sleep(1e-2) #unnecessary, but useful
fig.clf()
fig = plt.figure()
ax = fig.add_subplot(111)
win = fig.canvas.manager.window
fig.canvas.manager.window.after(100, animate_frames, frames)
我还找到了一个更简单的方法来处理整个过程,尽管不那么健壮:
fig = plt.figure()
for k in range(nBins):
plt.clf()
plt.imshow(frames[k],cmap=plt.cm.gray)
fig.canvas.draw()
time.sleep(1e-6) #unnecessary, but useful
注意,这两个选项似乎都只适用于ipython——pylab=tk,也就是backend = TkAgg
谢谢你对我的帮助。
我发布了一个名为python-drawnow的包,它提供了让图形更新的功能,通常在for循环中调用,类似于Matlab的drawnow。
用法示例:
from pylab import figure, plot, ion, linspace, arange, sin, pi
def draw_fig():
# can be arbitrarily complex; just to draw a figure
#figure() # don't call!
plot(t, x)
#show() # don't call!
N = 1e3
figure() # call here instead!
ion() # enable interactivity
t = linspace(0, 2*pi, num=N)
for i in arange(100):
x = sin(2 * pi * i**2 * t / 100.0)
drawnow(draw_fig)
此包可用于任何matplotlib图,并提供了在每个图更新或放入调试器后等待的选项。
这对我很管用。重复调用一个函数,每次更新图形。
import matplotlib.pyplot as plt
import matplotlib.animation as anim
def plot_cont(fun, xmax):
y = []
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
def update(i):
yi = fun()
y.append(yi)
x = range(len(y))
ax.clear()
ax.plot(x, y)
print i, ': ', yi
a = anim.FuncAnimation(fig, update, frames=xmax, repeat=False)
plt.show()
"fun"是一个返回整数的函数。
FuncAnimation会重复调用"update"它会做"xmax"次。
根据其他答案,我将图形的更新包装在python装饰器中,以将图形的更新机制与实际的图形分开。这样,就更容易更新任何情节。
def plotlive(func):
plt.ion()
@functools.wraps(func)
def new_func(*args, **kwargs):
# Clear all axes in the current figure.
axes = plt.gcf().get_axes()
for axis in axes:
axis.cla()
# Call func to plot something
result = func(*args, **kwargs)
# Draw the plot
plt.draw()
plt.pause(0.01)
return result
return new_func
使用的例子
然后你可以像使用其他装饰器一样使用它。
@plotlive
def plot_something_live(ax, x, y):
ax.plot(x, y)
ax.set_ylim([0, 100])
唯一的限制是你必须在循环之前创建图形:
fig, ax = plt.subplots()
for i in range(100):
x = np.arange(100)
y = np.full([100], fill_value=i)
plot_something_live(ax, x, y)