3

I have created a FigureCanvaswhich allows drag and drop on all Textinstances. This works great for text within the axes, but for text outside the axes (such s axis labels), when the text is being picked, it leaves behind a 'trail' of text where ever you move it. Once the mouse is released, the trail dissapears and the text is in it's desired positions, but I am trying to understand why this would occur (and why it would occur outside the axes, but not inside?)

BTW this only occurs if I try to introduce 'blitting' for performance. So I assume I am making some mistake in the blitting.

The code for the drag n drop functionality is below. Any ideas?

import logging
import sys
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
from PySide import QtGui
logger = logging.getLogger('colorpicker_example')
logger.setLevel(logging.DEBUG)

class JFigureCanvas(FigureCanvas):
    def __init__(self):
        self.figure = Figure()
        self.axes = self.figure.add_subplot(111)

        self._draggedArtist = None

        self.mpl_connect("pick_event", self.pck_event)
        self.mpl_connect("motion_notify_event", self.motion_event)
        self.mpl_connect("button_release_event", self.release_event)

    def pck_event(self, event):
        """ Pick event handler for text objects. If a pick event occurs, grab the artist and position."""
        if isinstance(event.artist, text.Text):
            self._draggedArtist = event.artist   

            #Get the x y position and transform it to display coords   
            x, y = self._draggedArtist.get_transform().transform_point(
                            (self._draggedArtist._x, self._draggedArtist._y))  
            self.startPos = (x, y, event.mouseevent.x, event.mouseevent.y)

            # draw everythin but the selected text and store the pixel buffer
            self._draggedArtist.set_animated(True)
            self.draw()
            self.background = self.copy_from_bbox(self.figure.bbox)

            # redraw the text
            self.figure.draw_artist(self._draggedArtist)

            # blit the redrawn area
            self.blit(self.figure.bbox)

    def motion_event(self, event):
        """ Motion event handler. If there is an artist stored, moved it with the mouse and redraw"""
        if self._draggedArtist:
            x0, y0, xpress, ypress = self.startPos
            dx = event.x - xpress
            dy = event.y - ypress
            canvasLoc = (x0 + dx, y0 + dy)
            newPos = self._draggedArtist.get_transform().inverted().transform_point(canvasLoc)
            self._draggedArtist.set_position(newPos)

            # Restore the background
            self.restore_region(self.background)

            #redraw the text
            self.figure.draw_artist(self._draggedArtist)

            # blit the redrawn area 
            self.blit(self.figure.bbox)

    def release_event(self, event):
        " If the mouse is released, release any artist"
        if self._draggedArtist:
            self._draggedArtist.set_animated(False)
        self.background = None
        self._draggedArtist = None
        self.draw()

class MainWindow(QtGui.QMainWindow):

    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)

        chart = JFigureCanvas()

        # Put some text in the axes
        chart.axes.text(0.5, 0.5, "Test", picker = True)

        self.setCentralWidget(chart)

if __name__ == '__main__':

    logging.basicConfig()
    app = QtGui.QApplication(sys.argv)
    main = MainWindow()
    main.show()
    app.exec_()

Screenshot of the problem in action (you can see the 'trail' left behind when moving outside the axes in the top left):

Blitting problem

jramm
  • 6,415
  • 4
  • 34
  • 73
  • What `FigureCanvas` are you subclassing? What backend are you using? It would be helpful if you could turn this into a runnable example. – ali_m Aug 17 '14 at 10:12
  • 1
    +1 for getting a runnable example. Nothing is jumping out at me as immediately wrong (from the prose my guess was using the wrong bbox, but that looks right). If this doesn't get sorted out in the near future, can you create an issue on gh for this (smells like a bug with blitting outside axes). – tacaswell Aug 17 '14 at 16:51
  • a naive guess would be to just use `set_visible(False)` to manually hide the text before you grab the blit background. The `animated` framework is doing a bunch of stuff underneath, there might be a subtle bug in there.... – tacaswell Aug 17 '14 at 17:34
  • I've added code to make it runnable. I'll try the set_visible – jramm Aug 18 '14 at 07:19
  • Tried various combinations with `set_visible`. All I've managed to do is make the text disappear when dragging and re-appear when the mouse is released, which is not ideal. – jramm Aug 18 '14 at 07:25

0 Answers0