我有以下代码生成可以交互式修改的绘图。单击/按住鼠标左键设置标记位置,按住右键并移动鼠标将绘制的数据沿x方向移动并使用鼠标滚轮放大/缩小。此外,调整窗口大小调用figure.tight_layout()
,以便轴的大小适应窗口大小。
# coding=utf-8
from __future__ import division
from Tkinter import *
import matplotlib
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from numpy import arange, sin, pi
matplotlib.use('TkAgg')
class PlotFrame(Frame):
def __init__(self, master, **ops):
Frame.__init__(self, master, **ops)
self.figure = Figure()
self.axes_main = self.figure.add_subplot(111)
for i in range(10):
t = arange(0, 300, 0.01)
s = sin(0.02 * pi * (t + 10 * i))
self.axes_main.plot(t, s)
self.plot = FigureCanvasTkAgg(self.figure, master=self)
self.plot.show()
self.plot.get_tk_widget().pack(fill=BOTH, expand=1)
self.dragging = False
self.dragging_button = None
self.mouse_pos = [0, 0]
self.marker = self.figure.axes[0].plot((0, 0), (-1, 1), 'black', linewidth=3)[0]
self.plot.mpl_connect('button_press_event', self.on_button_press)
self.plot.mpl_connect('button_release_event', self.on_button_release)
self.plot.mpl_connect('motion_notify_event', self.on_mouse_move)
self.plot.mpl_connect('scroll_event', self.on_mouse_scroll)
self.plot.mpl_connect("resize_event", self.on_resize)
def on_resize(self, _):
self.figure.tight_layout()
def axes_size(self):
pos = self.axes_main.get_position()
bbox = self.figure.get_window_extent().transformed(self.figure.dpi_scale_trans.inverted())
width, height = bbox.width * self.figure.dpi, bbox.height * self.figure.dpi
axis_size = [(pos.x1 - pos.x0) * width, (pos.y1 - pos.y0) * height]
return axis_size
def on_button_press(self, event):
# right mouse button clicked
if not self.dragging and event.button in (1, 3):
self.dragging = True
self.dragging_button = event.button
self.mouse_pos = [event.x, event.y]
# left mouse button clicked
if event.button == 1 and event.xdata is not None:
self.move_marker(event.xdata)
def on_button_release(self, event):
if self.dragging and self.dragging_button == event.button:
self.dragging = False
def on_mouse_move(self, event):
if self.dragging and self.dragging_button == 3:
dx = event.x - self.mouse_pos[0]
self.mouse_pos = [event.x, event.y]
x_min, x_max = self.figure.axes[0].get_xlim()
x_range = x_max - x_min
x_factor = x_range / self.axes_size()[0]
self.figure.axes[0].set_xlim([x_min - dx * x_factor, x_max - dx * x_factor])
self.plot.draw()
elif self.dragging and self.dragging_button == 1:
self.move_marker(event.xdata)
def on_mouse_scroll(self, event):
if event.xdata is None:
return
zoom_direction = -1 if event.button == 'up' else 1
zoom_factor = 1 + .4 * zoom_direction
x_min, x_max = self.figure.axes[0].get_xlim()
min = event.xdata + (x_min - event.xdata) * zoom_factor
max = event.xdata + (x_max - event.xdata) * zoom_factor
self.figure.axes[0].set_xlim([min, max])
self.plot.draw()
def move_marker(self, x_position):
y_min, y_max = self.figure.axes[0].get_ylim()
self.marker.set_data((x_position, x_position), (y_min, y_max))
self.plot.draw()
if __name__ == '__main__':
gui = Tk()
vf = PlotFrame(gui)
vf.pack(fill=BOTH, expand=1)
gui.mainloop()
实现工作正常,但在显示很多行时渲染非常慢。如何更快地渲染渲染?正如您在上面的实现中所看到的,每次发生任何不必要的更改时,都会完整绘制整个图。我对此的看法:
在调整大小/缩放时绘制所有内容对我来说很好,但我真的需要更快地绘制后两个修改。我已经查看了matplotlib的动画,但据我所知,它们对我的情况没有帮助。非常感谢任何帮助,谢谢!
答案 0 :(得分:1)
解决方案似乎是缓存重新绘制的元素,如你所说:
重新绘制的一个重要事项是背景:
# cache the background
background = fig.canvas.copy_from_bbox(ax.bbox)
缓存后使用restore region
恢复它,然后只需在每次呼叫时重新绘制点/线
# restore background
fig.canvas.restore_region(background)
# redraw just the points
ax.draw_artist(points)
# fill in the axes rectangle
fig.canvas.blit(ax.bbox)
答案 1 :(得分:0)
可以使用优化绘图blitting。只有给定的艺术家(那些被改变的)将被渲染而不是整个人物。
Motplotlib在animation模块内部使用该技术。您可以在其中使用Animation
类作为参考,以在代码中实现相同的行为。在源代码中查看_blit_draw()
及其后的几个相关函数。