Python / Matplotlib – Actualizando rápidamente el texto en los ejes

Tengo una figura / canvas de matplotlib en una ventana de wxpython. Quiero actualizar algo de información sobre la ttwig mientras el ratón se mueve. Me conecté a ‘motion_notify_event’ para obtener esta información.

En el código a continuación, se trazan muchos datos aleatorios y luego la ubicación x, y del cursor se muestra en la barra de estado de la ventana. Esto es muy suave y funciona bien. Sin embargo, realmente quiero mostrar esta información en la parte superior de la ttwig. El comportamiento que deseo se muestra si usted elimina el comentario de las dos últimas líneas de cbUpdateCursor. Sin embargo, cuando se hace esto, el tiempo de respuesta para mover el cursor es terriblemente lento (porque se llama a draw y hay muchos datos, pero se debe llamar a draw o el texto no se actualiza).

¿Cómo puedo acelerar esto para que la posición del cursor se pueda mostrar en la ttwig, pero no la desacelere tanto? Creo que podría necesitar hacer algo con bbox?

Código:

import wx import numpy as np import matplotlib matplotlib.use('WXAgg') from matplotlib.figure import Figure from matplotlib.widgets import Cursor from matplotlib.backends.backend_wxagg import \ FigureCanvasWxAgg as FigCanvas, \ NavigationToolbar2WxAgg as NavigationToolbar class wxPlotting(wx.Frame): title = 'Test' def __init__(self): wx.Frame.__init__(self, None, -1, self.title) self.time = np.arange(10000) self.data = np.random.random(10000) self.sb = self.CreateStatusBar() self.create_main_panel() self.axes.plot(self.time, self.data) self.canvas.draw() def create_main_panel(self): self.panel = wx.Panel(self) self.fig = Figure((5.0, 4.0), dpi=100) self.canvas = FigCanvas(self.panel, -1, self.fig) self.axes = self.fig.add_subplot(111) self.text = self.axes.text(0., 1.005, '', transform = self.axes.transAxes) self.cursor = Cursor(self.axes, useblit=True, color='red') self.canvas.mpl_connect('motion_notify_event', self.cbUpdateCursor) self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.panel.SetSizer(self.vbox) self.vbox.Fit(self) def cbUpdateCursor(self, event): if event.inaxes: text = 'x = %5.4f, y = %5.4f' % (event.xdata, event.ydata) self.sb.SetStatusText(text) #self.text.set_text(text) #self.canvas.draw() if __name__ == '__main__': app = wx.PySimpleApp() app.frame = wxPlotting() app.frame.Show() app.MainLoop() 

Básicamente, quiero algo similar al texto que se muestra usando pyplot, es decir, la esquina inferior derecha cuando se ejecuta el código siguiente:

Código:

 import matplotlib.pyplot as plt plt.plot(range(10000), range(10000)) plt.show() 

EDITAR :

En mi progtwig real, quiero que el texto estático esté dentro de los ejes de matplotlib, no muy por encima de él. Así que no creo que solo pueda usar un texto estático wxpython para mostrarlo.

Podrías usar blitting, similar a los ejemplos de animación aquí .

Esto supone una gran diferencia de rendimiento en este caso, ya que solo se necesita volver a dibujar una pequeña parte de la ventana.

Desafortunadamente, no puedo encontrar la forma de obtener un fondo gris detrás del texto cuando se vuelve a dibujar, para que coincida con el fondo predeterminado de la figura detrás de él … Sin embargo, el rendimiento es excelente.

Como un ejemplo independiente basado en su código anterior:

 import wx import numpy as np import matplotlib matplotlib.use('WXAgg') from matplotlib.figure import Figure from matplotlib.widgets import Cursor from matplotlib.backends.backend_wxagg import \ FigureCanvasWxAgg as FigCanvas, \ NavigationToolbar2WxAgg as NavigationToolbar class wxPlotting(wx.Frame): title = 'Test' def __init__(self): wx.Frame.__init__(self, None, -1, self.title) self.time = np.arange(10000) self.data = np.random.random(10000) self.sb = self.CreateStatusBar() self.create_main_panel() self.axes.plot(self.time, self.data) self.background = self.canvas.copy_from_bbox(self.fig.bbox) self.canvas.draw() def create_main_panel(self): self.panel = wx.Panel(self) self.fig = Figure((5.0, 4.0), dpi=100) self.canvas = FigCanvas(self.panel, -1, self.fig) self.axes = self.fig.add_subplot(111) self.text = self.axes.text(0., 1.005, '', transform = self.axes.transAxes, animated=True) self.cursor = Cursor(self.axes, useblit=True, color='red') self.canvas.mpl_connect('motion_notify_event', self.cbUpdateCursor) self.vbox = wx.BoxSizer(wx.VERTICAL) self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.panel.SetSizer(self.vbox) self.vbox.Fit(self) def cbUpdateCursor(self, event): if event.inaxes: text = 'x = %5.4f, y = %5.4f' % (event.xdata, event.ydata) self.sb.SetStatusText(text) self.canvas.restre_region(self.background) self.text.set_text(text) self.axes.draw_artist(self.text) self.canvas.blit(self.text.get_window_extent()) if __name__ == '__main__': app = wx.PySimpleApp() app.frame = wxPlotting() app.frame.Show() app.MainLoop() 

Podría agregar un cuadro de texto estático en la parte superior, y simplemente actualizar su etiqueta:

 import wx import numpy as np import matplotlib matplotlib.use('WXAgg') from matplotlib.figure import Figure from matplotlib.widgets import Cursor from matplotlib.backends.backend_wxagg import \ FigureCanvasWxAgg as FigCanvas, \ NavigationToolbar2WxAgg as NavigationToolbar class wxPlotting(wx.Frame): title = 'Test' def __init__(self): wx.Frame.__init__(self, None, -1, self.title) self.time = np.arange(10000) self.data = np.random.random(10000) self.sb = self.CreateStatusBar() self.create_main_panel() self.axes.plot(self.time, self.data) self.canvas.draw() def create_main_panel(self): self.panel = wx.Panel(self) self.fig = Figure((5.0, 4.0), dpi=100) self.canvas = FigCanvas(self.panel, -1, self.fig) self.axes = self.fig.add_subplot(111) self.text = self.axes.text(0., 1.005, '', transform = self.axes.transAxes) self.cursor = Cursor(self.axes, useblit=True, color='red') self.canvas.mpl_connect('motion_notify_event', self.cbUpdateCursor) self.vbox = wx.BoxSizer(wx.VERTICAL) self.cursor_pos = wx.StaticText(self.panel,-1, label="") self.vbox.Add(self.cursor_pos, 0, wx.LEFT | wx.TOP | wx.GROW) self.vbox.Add(self.canvas, 1, wx.LEFT | wx.TOP | wx.GROW) self.panel.SetSizer(self.vbox) self.vbox.Fit(self) def cbUpdateCursor(self, event): if event.inaxes: text = 'x = %5.4f, y = %5.4f' % (event.xdata, event.ydata) self.sb.SetStatusText(text) self.cursor_pos.SetLabel(text) #self.text.set_text(text) #self.canvas.draw() if __name__ == '__main__': app = wx.PySimpleApp() app.frame = wxPlotting() app.frame.Show() app.MainLoop()