Line update: set_data vs recache issue

Hi to all,

I'm doing a simple animation like this:

···

--
ion()
x = arange(0,2,0.01)
y = zeros_like(x)
y[45:55]=1
l, = plot(x,y)

D = 0.1
h = x[1]-x[0]
dt = 0.0001;

def nabla(v,h):
    na = zeros_like(v)
    na[1:-1] = (v[2:]-2*v[1:-1]+v[:-2])
    na[0],na[-1] = 0,0
    return na/(h**2)

for i in range(1000):
    y = y + D*nabla(y,h)*dt
    if i%10 == 0:
        l.set_ydata(y)
        draw()
--

however, changing the line

    y = y + D*nabla(y,h)*dt with

in

    y += D*nabla(y,h)*dt

the plot is not updated anymore. I have to replace l.set_ydata(y) with
y.recache() to make the the animation work again.

I think this is a bug since the line should be updated even using the
+= operator.

Regards,
Antonio

I just filed a bug related with this.

https://sourceforge.net/tracker/?func=detail&aid=2917758&group_id=80706&atid=560720

I think the possible solution could be

1) we keep the copied version of the input data as a cache, and
provide a api to access the cache.
2) Or forsce set_[x|y]data to always update.

My current inclination is the option 1.
If there is any other opinion, I'll go ahead and make a change in a few days.

-JJ

···

On Tue, Dec 15, 2009 at 9:12 AM, Antonino Ingargiola <tritemio@...287...> wrote:

Hi to all,

I'm doing a simple animation like this:

--
ion()
x = arange(0,2,0.01)
y = zeros_like(x)
y[45:55]=1
l, = plot(x,y)

D = 0.1
h = x[1]-x[0]
dt = 0.0001;

def nabla(v,h):
na = zeros_like(v)
na[1:-1] = (v[2:]-2*v[1:-1]+v[:-2])
na[0],na[-1] = 0,0
return na/(h**2)

for i in range(1000):
y = y + D*nabla(y,h)*dt
if i%10 == 0:
l.set_ydata(y)
draw()
--

however, changing the line

y = y + D*nabla(y,h)*dt with

in

y += D*nabla(y,h)*dt

the plot is not updated anymore. I have to replace l.set_ydata(y) with
y.recache() to make the the animation work again.

I think this is a bug since the line should be updated even using the
+= operator.

Regards,
Antonio

------------------------------------------------------------------------------
Return on Information:
Google Enterprise Search pays you back
Get the facts.
http://p.sf.net/sfu/google-dev2dev
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

Jae-Joon Lee wrote:

I just filed a bug related with this.

https://sourceforge.net/tracker/?func=detail&aid=2917758&group_id=80706&atid=560720

I think the possible solution could be

1) we keep the copied version of the input data as a cache, and
provide a api to access the cache.
2) Or forsce set_[x|y]data to always update.

My current inclination is the option 1.
If there is any other opinion, I'll go ahead and make a change in a few days.

-JJ

Jae-Joon,

I wonder whether things are getting more and more complicated here, for no real benefit. The logic even of some of the present code in set_data and recache is not immediately clear upon casual inspection. What are the circumstances under which one would call set_data() and not want or need an update?

Eric

···

On Tue, Dec 15, 2009 at 9:12 AM, Antonino Ingargiola <tritemio@...287...> wrote:

Hi to all,

I'm doing a simple animation like this:

--
ion()
x = arange(0,2,0.01)
y = zeros_like(x)
y[45:55]=1
l, = plot(x,y)

D = 0.1
h = x[1]-x[0]
dt = 0.0001;

def nabla(v,h):
   na = zeros_like(v)
   na[1:-1] = (v[2:]-2*v[1:-1]+v[:-2])
   na[0],na[-1] = 0,0
   return na/(h**2)

for i in range(1000):
   y = y + D*nabla(y,h)*dt
   if i%10 == 0:
       l.set_ydata(y)
       draw()
--

however, changing the line

   y = y + D*nabla(y,h)*dt with

in

   y += D*nabla(y,h)*dt

the plot is not updated anymore. I have to replace l.set_ydata(y) with
y.recache() to make the the animation work again.

I think this is a bug since the line should be updated even using the
+= operator.

Regards,
Antonio

------------------------------------------------------------------------------
Return on Information:
Google Enterprise Search pays you back
Get the facts.
http://p.sf.net/sfu/google-dev2dev
_______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

------------------------------------------------------------------------------
This SF.Net email is sponsored by the Verizon Developer Community
Take advantage of Verizon's best-in-class app development support
A streamlined, 14 day to market process makes app distribution fast and easy
Join now and get one step closer to millions of Verizon customers
http://p.sf.net/sfu/verizon-dev2dev _______________________________________________
Matplotlib-users mailing list
Matplotlib-users@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/matplotlib-users

If you ask me, I'm +1 to update the plot always. But, apparently, the
original author of this code wanted to do some checks to avoid
unnecessary recaching. So, I'm not sure which is better.

On the other hand, I think there is a general issue of whether the
current behavior of the cache is broken or not. In the code below,
the function test_cache() gives different results depending on the
input is a list or a numpy array. And, to me, this is something that
needs to be fixed despite it may add a little bit of complication into
the code.

I did not want to step into this issue as I didn't write the code, but
there has been no responses from other developers while this issue (I
mean, the original issue of set_data not updating the plot) has been
raised a few times in the mailing list.

So, if Eric and others have any other thoughts, please speak.
Regards,

-JJ

from matplotlib.pyplot import subplot, show
import numpy as np
import matplotlib.lines as mlines

def test_cache(ax, yy):
    l = mlines.Line2D([0, 1], yy)
    yy[1]=0.7
    ax.add_line(l)

ax = subplot(111)
a1 = [0, 1]
test_cache(ax, a1)
a2 = np.array([0, 1], dtype="d")
test_cache(ax, a2)

show()

···

On Sun, Dec 27, 2009 at 2:37 PM, Eric Firing <efiring@...202...> wrote:

What are the circumstances under which one would call set_data() and not
want or need an update?

Jae-Joon Lee wrote:

What are the circumstances under which one would call set_data() and not
want or need an update?

If you ask me, I'm +1 to update the plot always. But, apparently, the
original author of this code wanted to do some checks to avoid
unnecessary recaching. So, I'm not sure which is better.

On the other hand, I think there is a general issue of whether the
current behavior of the cache is broken or not. In the code below,
the function test_cache() gives different results depending on the
input is a list or a numpy array. And, to me, this is something that
needs to be fixed despite it may add a little bit of complication into
the code.

I did not want to step into this issue as I didn't write the code, but
there has been no responses from other developers while this issue (I
mean, the original issue of set_data not updating the plot) has been
raised a few times in the mailing list.

I'm glad you called attention to it; I agree that it needed to be addressed.

So, if Eric and others have any other thoughts, please speak.

I went ahead and committed (svn rev 8054) changes that I think address the problem, and that should slightly improve speed as well in some cases, without slowing anything down in other reasonable cases--unless there are subtleties I am missing. Or maybe I am missing something blatant. In any case, if I have fouled it up, I trust it will soon be evident and the commit can be reverted or fixed.

I don't understand what your script, below, is intended to do or show. I haven't run it with mpl prior to my change. With the change, it simply draws a single line, or at least that is all I see on the plot.

Eric

···

On Sun, Dec 27, 2009 at 2:37 PM, Eric Firing <efiring@...202...> wrote:

Regards,

-JJ

from matplotlib.pyplot import subplot, show
import numpy as np
import matplotlib.lines as mlines

def test_cache(ax, yy):
    l = mlines.Line2D([0, 1], yy)
    yy[1]=0.7
    ax.add_line(l)

ax = subplot(111)
a1 = [0, 1]
test_cache(ax, a1)
a2 = np.array([0, 1], dtype="d")
test_cache(ax, a2)

show()

I went ahead and committed (svn rev 8054) changes that I think address the problem, and that should slightly improve speed as well in some cases, without slowing anything down in other reasonable cases--unless there are subtleties I am missing. Or maybe I am missing something blatant. In any case, if I have fouled it up, I trust it will soon be evident and the commit can be reverted or fixed.

Sure enough, the buildbot came up with a problem: it looks like there is a test where my change is causing a line to disappear. I will look into it.

Eric

Eric Firing wrote:

I went ahead and committed (svn rev 8054) changes that I think address the problem, and that should slightly improve speed as well in some cases, without slowing anything down in other reasonable cases--unless there are subtleties I am missing. Or maybe I am missing something blatant. In any case, if I have fouled it up, I trust it will soon be evident and the commit can be reverted or fixed.

Sure enough, the buildbot came up with a problem: it looks like there is a test where my change is causing a line to disappear. I will look into it.

Fixed in 8055.

Eric

Before your change, it draws two different lines.

Anyhow, another example,

import matplotlib.pyplot as plt

ax = plt.subplot(111)
a = [0, 1]
l1, = ax.plot(a)
l1.set_ydata(a)
a[1] = 0.5

plt.show()

The above code draws a line from (0,0) to (1, 0.5), not (0,0) to
(1,1). And my question is whether we want this behavior.

I think the issue is more subtle. If the recaching is done somehow
before the mutable data changes, the change has no effect. On the
other hand, if the recaching is done after the change (as in the above
example), the change is effective.

Regards,

-JJ

···

On Sun, Dec 27, 2009 at 7:31 PM, Eric Firing <efiring@...202...> wrote:

I don't understand what your script, below, is intended to do or show. I
haven't run it with mpl prior to my change. With the change, it simply
draws a single line, or at least that is all I see on the plot.

Jae-Joon Lee wrote:

I don't understand what your script, below, is intended to do or show. I
haven't run it with mpl prior to my change. With the change, it simply
draws a single line, or at least that is all I see on the plot.

Before your change, it draws two different lines.

So, which way is better? I assume the change is an improvement, because the behavior with a list should be the same as with an ndarray.

Anyhow, another example,

import matplotlib.pyplot as plt

ax = plt.subplot(111)
a = [0, 1]
l1, = ax.plot(a)
l1.set_ydata(a)
a[1] = 0.5

plt.show()

The above code draws a line from (0,0) to (1, 0.5), not (0,0) to
(1,1). And my question is whether we want this behavior.

I don't think it matters much. The present behavior is not unreasonable.

I think the issue is more subtle. If the recaching is done somehow
before the mutable data changes, the change has no effect. On the
other hand, if the recaching is done after the change (as in the above
example), the change is effective.

We could split the recaching up into parts that can be done independently on x and y, and the part that has to be done when x and y are both set; this would permit the separate x and y parts to be done by set_xdata and set_ydata, which would freeze the data at that point, so that later changes to the original arrays' contents would not affect the plot. (This would also require forcing a copy instead of using asarray; this has a performance penalty, but perhaps a negligible one.)

Is it really worth fiddling with this, though? Unless there is a compelling reason to change it, I am inclined to leave the present behavior alone until the larger design is overhauled, so that unit-handling--which is the cause of most of the fuss--is clearly and uniformly confined to a single layer of the mpl stack.

Eric

···

On Sun, Dec 27, 2009 at 7:31 PM, Eric Firing <efiring@...202...> wrote:

Regards,

-JJ

So, which way is better? I assume the change is an improvement, because
the behavior with a list should be the same as with an ndarray.

I agree with you.

We could split the recaching up into parts that can be done independently on
x and y, and the part that has to be done when x and y are both set; this
would permit the separate x and y parts to be done by set_xdata and
set_ydata, which would freeze the data at that point, so that later changes
to the original arrays' contents would not affect the plot. (This would
also require forcing a copy instead of using asarray; this has a performance
penalty, but perhaps a negligible one.)

This is similar to what I meant with option 1 in my previous post.

Is it really worth fiddling with this, though? Unless there is a compelling
reason to change it, I am inclined to leave the present behavior alone until
the larger design is overhauled, so that unit-handling--which is the cause
of most of the fuss--is clearly and uniformly confined to a single layer of
the mpl stack.

I don't think I can make any compelling case here (I think this is
more like a design choice and not something that need to be fixed).
And I'm completely fine with leaving it as is.
Anyhow, how about adding some words about this behavior in set_data.

    def set_data(self, *args):
        """
        Set the x and y data.

        ACCEPTS: 2D array (rows are x, y) or two 1D arrays

        Note that a Line2D instatnce keeps a reference to the
        input. If the input is mutable (.e.g, list, numpy array) and
        its content changes after the set_data call, the plot may
        reflect the changes. A following meth:`recache` call will
        prevent it.
        """

Anyhow, the current code looks much cleaner than before,
Thanks.

-JJ

···

On Mon, Dec 28, 2009 at 12:39 AM, Eric Firing <efiring@...202...> wrote:

Eric