问题描述
我正在使用 matplotlib
来交互式
绘制一些补丁
和点
.
I am using matplotlib
to interactively
plot some patches
and points
.
我通过队列从一个单独的进程接收数据并将它们发送到我的绘图进程.代码的那部分工作正常,点显示在图形上,并按预期在图中不断更新.
I receive the data from a separate process via a queue and send them to my plot-process. That part of the code works fine and points are shown on the graph and continuously updated in the plot as expected.
应用户要求,我想删除图中的所有旧补丁并替换为新补丁.
Upon request from the user I would like to remove all the old patches in the plot and replace with new ones.
我认为执行就足够了
# remove the old patch
patch.remove()
# I also tried ax.cla() without any success
# create a new patch
monitor_box = path.Path([(305, 500), (11, -213), (300, -220), (500, 1734)])
patch = patches.PathPatch(monitor_box, facecolor='black', lw=1)
# add the patch to the axis
ax.add_patch(patch)
然后在下一次迭代中,应该使用新补丁更新绘图:
and then during the next iteration, the plot should be updated with new patch:
canvas.draw()
但是当我使用上面的代码时,补丁仍然保留在窗口中并且没有任何变化.(我仍然得到了情节中的点,因此至少仍在不断更新)
but when I use the above code, the patch still remains in the window and nothing changes. (I am still getting the points in the plot so that is at-least still being continuously updated)
下面我提供了该问题的最小工作示例.运行代码时,您可以看到绘制了不同的点,但从未删除补丁.
Below I have provided a minimal working example of the issue. When you run the code, you can see that different points get plotted but the patches are never removed.
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import multiprocessing
from Tkinter import *
import matplotlib.path as path
import matplotlib.patches as patches
import sys, thread, time
from random import randint
#Create a window
window=Tk()
sendProximityInfo = True
latest_published_msg = ""
def erasePatchesAndCreateNew_A():
print "erasePatchesAndCreateNew_A"
global line, ax, canvas
global monitor_box
global patch
patch.remove()
ax.cla()
monitor_box = path.Path([(35, 1677), (11, -213), (652, -220), (500, 1734)])
patch = patches.PathPatch(monitor_box, facecolor='black', lw=1)
ax.add_patch(patch)
def erasePatchesAndCreateNew_B():
print "erasePatchesAndCreateNew_B"
global line, ax, canvas
global monitor_box
global patch
patch.remove()
ax.cla()
monitor_box = path.Path([(35, 500), (11, -213), (300, -220), (500, 1734)])
patch = patches.PathPatch(monitor_box, facecolor='red', lw=1)
ax.add_patch(patch)
monitor_box = path.Path([(35, 1677), (111, -213), (62, -220), (800, 1734)])
fig = matplotlib.figure.Figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlim(-1500,2000)
ax.set_ylim(-1500,2000)
patch = patches.PathPatch(monitor_box, facecolor='black', lw=1)
ax.add_patch(patch)
def main():
erasePatchesAndCreateNew_B()
#Create a queue to share data between process
q = multiprocessing.Queue()
#Create and start the simulation process
simulate = multiprocessing.Process(None, simulation,args=(q,))
simulate.start()
#Create the base plot
plot()
#Call a function to update the plot when there is new data
updateplot(q)
window.mainloop()
print 'Done'
simulate.join() # wait for the other process to finish as well
def plot(): #Function to create the base plot, make sure to make global the lines, axes, canvas and any part that you would want to update later
global line, ax, canvas
global monitor_box
global patch
fig = matplotlib.figure.Figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlim(-1500,2000)
ax.set_ylim(-1500,2000)
patch = patches.PathPatch(monitor_box, facecolor='black', lw=1)
ax.add_patch(patch)
ax.invert_yaxis()
canvas = FigureCanvasTkAgg(fig, master=window)
canvas.show()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
line, = ax.plot([], [], 'ro')
def updateplot(q):
try: #Try to check if there is data in the queue
result = q.get_nowait()
if result != 'Q':
x, y = result
line.set_data(x, y)
ax.draw_artist(line)
canvas.draw()
window.after(1,updateplot,q)
else:
print 'done'
except:
window.after(1,updateplot,q)
def simulation(q):
try:
while True:
for i in range(10):
q.put( (randint(0,1500), randint(0,1500)) )
time.sleep(1)
erasePatchesAndCreateNew_A()
time.sleep(1)
for i in range(10):
q.put( (randint(0,1500), randint(0,1500)) )
time.sleep(1)
erasePatchesAndCreateNew_B()
time.sleep(1)
except KeyboardInterrupt:
print "received KeyboardInterrupt"
finally:
print "simulation ended"
sys.exit()
if __name__ == '__main__':
main()
下面是该程序的屏幕截图,红点在图中移动,但色块(黑色形状)永不改变.
Below is a screenshot from the program, the red dot moves around in the graph but the patch (black shape) never changes.
推荐答案
我设法解决了这个问题,或者确切地说,我找到了解决该问题的方法.我在下面添加了它,也许将来会对其他人有帮助.我基本上是使用队列来交流何时应在主线程中更新图形.
I managed to solve this issue, or to be exact I figured out a around for this issue. I am adding it below and maybe it will help someone else in the future.I am basically using the queue to communicate when the graph should be updated in the main thread.
import matplotlib
matplotlib.use('TkAgg')
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
import multiprocessing
from Tkinter import *
import matplotlib.path as path
import matplotlib.patches as patches
import matplotlib.pyplot as plt
import sys, thread, time
from random import randint
#Create a window
window=Tk()
sendProximityInfo = True
latest_published_msg = ""
monitor_box = path.Path([(1000, -1000), (111, -213), (62, -220), (800, 1734)])
fig = matplotlib.figure.Figure()
ax = fig.add_subplot(1,1,1)
ax.set_xlim(-1500,2000)
ax.set_ylim(-1500,2000)
patch = patches.PathPatch(monitor_box, facecolor='black', lw=1)
ax.add_patch(patch)
def main():
#Create a queue to share data between process
q = multiprocessing.Queue()
#Create and start the simulation process
simulate = multiprocessing.Process(target=simulation,args=(q,))
simulate.start()
#Create the base plot
plot()
#Call a function to update the plot when there is new data
updateplot(q)
window.mainloop()
print 'Done'
simulate.join() # wait for the other process to finish as well
def plot(): #Function to create the base plot, make sure to make global the lines, axes, canvas and any part that you would want to update later
global line, ax, canvas, fig, monitor_box, patch
patch.remove()
monitor_box = path.Path([(500, -500), (111, -213), (62, -220), (800, 1734)])
patch = patches.PathPatch(monitor_box, facecolor='pink', lw=1)
ax.add_patch(patch)
canvas = FigureCanvasTkAgg(fig, master=window)
canvas.show()
canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
canvas._tkcanvas.pack(side=TOP, fill=BOTH, expand=1)
line, = ax.plot([], [], 'ro')
def erasePatchesAndCreateNew_A():
print "erasePatchesAndCreateNew_A"
global ax, monitor_box, patch
patch.remove()
monitor_box = path.Path([(35, 1677), (11, -213), (652, -220), (500, 1734)])
patch = patches.PathPatch(monitor_box, facecolor='red', lw=1)
ax.add_patch(patch)
def erasePatchesAndCreateNew_B():
print "erasePatchesAndCreateNew_B"
global ax, monitor_box, patch
patch.remove()
monitor_box = path.Path([(-2000, 2000), (11, -213), (300, -220), (500, 1734)])
patch = patches.PathPatch(monitor_box, facecolor='blue', lw=1)
ax.add_patch(patch)
def updateplot(q):
try: #Try to check if there is data in the queue
result = q.get_nowait()
if result != 'A' and result != 'B':
x, y = result
line.set_data(x, y)
ax.draw_artist(line)
canvas.draw()
window.after(10,updateplot,q)
elif result == 'A':
erasePatchesAndCreateNew_A()
canvas.draw()
window.after(10,updateplot,q)
elif result == 'B':
erasePatchesAndCreateNew_B()
canvas.draw()
window.after(10,updateplot,q)
except:
window.after(10,updateplot,q)
def simulation(q):
try:
while True:
for i in range(5):
q.put( (randint(0,1500), randint(0,1500)) )
time.sleep(0.5)
#erasePatchesAndCreateNew_A()
q.put('A')
time.sleep(1)
for i in range(5):
q.put( (randint(0,1500), randint(0,1500)) )
time.sleep(0.5)
#erasePatchesAndCreateNew_B()
q.put('B')
time.sleep(1)
except KeyboardInterrupt:
print "received KeyboardInterrupt"
finally:
print "simulation ended"
sys.exit()
if __name__ == '__main__':
main()
这篇关于matplotlib:从图中删除补丁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!