0

https://matplotlib.org/stable/gallery/event_handling/cursor_demo.html

Im trying to make a cross hair cursor with a annotation on the right axis to show the Y-value

everything works fine except when the artist / annotation is drawn outside the axis

keeps drawing the figure will work but my chart has many data which will cause 0.5 - 0.7sec for each draw, which is quite laggy for a cursor function self.ax.figure.canvas.draw()

my guess is when i save the background , "self.ax.bbox" is only saving the image for the thing inside the axis, that's why when it blit it doesnt work outside the axis? self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.bbox)

I have many attempts but no luck...need some advices

below is the easy example (my plot will be a heavy one that i cannot keep calling the draw() on mousemove event) Im trying to make a smooth cross hair cursor with annotation on the right axis

import matplotlib.pyplot as plt
import numpy as np

class BlittedCursor:
    """
    A cross hair cursor using blitting for faster redraw.
    """
    def __init__(self, ax):
        self.ax = ax
        self.background = None
        self.horizontal_line = ax.axhline(color='k', lw=0.8, ls='--')
        self.vertical_line = ax.axvline(color='k', lw=0.8, ls='--')
        # text location in axes coordinates
        self.text = ax.text(0.95, 0, '', transform=ax.get_yaxis_transform())
        self._creating_background = False
        ax.figure.canvas.mpl_connect('draw_event', self.on_draw)

    def on_draw(self, event):
        self.create_new_background()

    def set_cross_hair_visible(self, visible):
        need_redraw = self.horizontal_line.get_visible() != visible
        self.horizontal_line.set_visible(visible)
        self.vertical_line.set_visible(visible)
        self.text.set_visible(visible)
        return need_redraw

    def create_new_background(self):
        if self._creating_background:
            # discard calls triggered from within this function
            return
        self._creating_background = True
        self.set_cross_hair_visible(False)
        self.ax.figure.canvas.draw()
        self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.bbox)
        self.set_cross_hair_visible(True)
        self._creating_background = False

    def on_mouse_move(self, event):
        if self.background is None:
            self.create_new_background()
        if not event.inaxes:
            need_redraw = self.set_cross_hair_visible(False)
            if need_redraw:
                self.ax.figure.canvas.restore_region(self.background)
                self.ax.figure.canvas.blit(self.ax.bbox)
        else:
            self.set_cross_hair_visible(True)
            # update the line positions
            x, y = event.xdata, event.ydata
            self.horizontal_line.set_ydata(y)
            self.vertical_line.set_xdata(x)
            self.text.set_text('y=%1.2f' % (y))
            self.text.set_y(y)

            self.ax.figure.canvas.restore_region(self.background)
            self.ax.draw_artist(self.horizontal_line)
            self.ax.draw_artist(self.vertical_line)
            self.ax.draw_artist(self.text)
            self.ax.figure.canvas.blit(self.ax.bbox)


x = np.arange(0, 1, 0.01)
y = np.sin(2 * 2 * np.pi * x)

fig, ax = plt.subplots()
ax.set_title('Blitted cursor')
ax.plot(x, y, 'o')
blitted_cursor = BlittedCursor(ax)
fig.canvas.mpl_connect('motion_notify_event', blitted_cursor.on_mouse_move)
plt.show()

1 Answers1

0

I actually solved the problem by changing below...but I still don't understand. Anyone can explain further? My guess is ax.get_figure() will get the image outside the axis as well? and ax.clipbox means the whole figure?

self.background = self.ax.figure.canvas.copy_from_bbox(self.ax.get_figure().bbox)
self.ax.figure.canvas.blit(self.ax.clipbox)
demonplus
  • 5,613
  • 12
  • 49
  • 68