Animated Line2D

I am reposting my problem since I have not been able to solve it myself.
I guess my original question has been buried deeply in this list.

I modified the path_editor.py example in order to make a line editor, as
attached. The path_editor.py worked fine on Qt4Agg. However, in the
line editor, the line was not draggable on the same backend. The
printout showed that the line (nodal coordinates) had been updated but
it was not redrawn in the axes. I also tested the line editor on WXAgg
and TkAgg and it did not work either. I am using Windows 7.

John Hunter tested this line editor on his system and found it was
working properly. I wonder whether this is a issue of backend/os. I
would like invite people to simply run this script and report your
successfulness and your backend/os. It will be especially useful for me
if you are using Qt4Agg on Windows 7.

Thank you very much.

line_editor.py (3.83 KB)

···

--
Jinsuo

From: Nie, Jinsuo [mailto:jnie@…3141…]
Sent: Tuesday, June 22, 2010 09:33

...

I modified the path_editor.py example in order to make a line editor, as
attached. The path_editor.py worked fine on Qt4Agg. However, in the
line editor, the line was not draggable on the same backend.

...

The problem seems to stem from the line not being marked invalid when its
set_data method is called. This can be seen by modifying your
motion_notify_callback method as follows; I removed the previous print
statements and inserted a new one:

    def motion_notify_callback(self, event):
        'on mouse movement'
        if not self.showverts: return
        if self._ind is None: return
        if event.inaxes is None: return
        if event.button != 1: return
        x,y = self.line.get_data()
        x[self._ind] = event.xdata
        y[self._ind] = event.ydata
        self.line.set_data(x, y)
        print self.line._invalid
        self.canvas.restore_region(self.background)
        self.ax.draw_artist(self.line)
        self.canvas.blit(self.ax.bbox)

The x returned by get_data is the same object as line._xorig (a private
attribute of the line object), so the changes you make to elements of x also
apply to _xorig. Then, set_data compares the incoming x with _xorig, sees
that they are the same object, and doesn't set the _invalid attribute to True.
With _invalid still False, the line is not redrawn.

I tested on Windows 7 with matplotlib 0.99.1 (and saw the same behavior you
did). The relevant code in matplotlib's lines.py was changed in revision 8054
(if I'm interpreting correctly), and that's why John saw the animation using
more recent matplotlib code. I checked the last released version (0.99.3) and
found the same code for set_data as in 0.99.1, so updating to 0.99.3 won't
help.

However, I see two alternative easy solutions. (1) After calling
self.line.set_data, call self.line.recache, which is what would happen
automatically if the _invalid attribute were True. (2) Call set_data with
different objects than the ones you received from get_data. For example:

        vertices = zip(*self.line.get_data())
        vertices[self._ind] = event.xdata, event.ydata
        self.line.set_data(zip(*vertices))

The set_data method will then set _invalid to True, enabling the line to be
redrawn.

Super. I will need to study your solution tomorrow.

···

--
Jinsuo

-----Original Message-----
From: Stan West [mailto:stan.west@…706…]
Sent: Tuesday, June 22, 2010 4:41 PM
To: Nie, Jinsuo; matplotlib-users@lists.sourceforge.net
Subject: RE: [Matplotlib-users] Animated Line2D

From: Nie, Jinsuo [mailto:jnie@…3141…]
Sent: Tuesday, June 22, 2010 09:33

...

I modified the path_editor.py example in order to make a line editor,

as

attached. The path_editor.py worked fine on Qt4Agg. However, in the
line editor, the line was not draggable on the same backend.

...

The problem seems to stem from the line not being marked invalid when
its
set_data method is called. This can be seen by modifying your
motion_notify_callback method as follows; I removed the previous print
statements and inserted a new one:

    def motion_notify_callback(self, event):
        'on mouse movement'
        if not self.showverts: return
        if self._ind is None: return
        if event.inaxes is None: return
        if event.button != 1: return
        x,y = self.line.get_data()
        x[self._ind] = event.xdata
        y[self._ind] = event.ydata
        self.line.set_data(x, y)
        print self.line._invalid
        self.canvas.restore_region(self.background)
        self.ax.draw_artist(self.line)
        self.canvas.blit(self.ax.bbox)

The x returned by get_data is the same object as line._xorig (a private
attribute of the line object), so the changes you make to elements of x
also
apply to _xorig. Then, set_data compares the incoming x with _xorig,
sees
that they are the same object, and doesn't set the _invalid attribute to
True.
With _invalid still False, the line is not redrawn.

I tested on Windows 7 with matplotlib 0.99.1 (and saw the same behavior
you
did). The relevant code in matplotlib's lines.py was changed in
revision 8054
(if I'm interpreting correctly), and that's why John saw the animation
using
more recent matplotlib code. I checked the last released version
(0.99.3) and
found the same code for set_data as in 0.99.1, so updating to 0.99.3
won't
help.

However, I see two alternative easy solutions. (1) After calling
self.line.set_data, call self.line.recache, which is what would happen
automatically if the _invalid attribute were True. (2) Call set_data
with
different objects than the ones you received from get_data. For
example:

        vertices = zip(*self.line.get_data())
        vertices[self._ind] = event.xdata, event.ydata
        self.line.set_data(zip(*vertices))

The set_data method will then set _invalid to True, enabling the line to
be
redrawn.