Ask Your Question
3

Fast show()? (for cached plots for @interact)

asked 2011-04-20 04:09:16 -0500

chaesloc gravatar image

Hello,

I need a fast (no noticeable delay) version of the following:

@interact
def _(a=(0,10)):
    time show(plot(lambda x:sin(a*x),plot_points=10000))

Time: CPU 2.65 s, Wall: 2.72 s


I can cache the plots, but showing them takes half a second:

@cached_function
def p(a):
    return plot(lambda x:sin(a*x),plot_points=10000)
for i in range(101):
    p(N(i/10))
@interact
def _(a=(0..100)):
    time p2=p(N(a/10))
    time show(p2)

Time: CPU 0.00 s, Wall: 0.00 s
Time: CPU 0.42 s, Wall: 0.43 s


Is there a faster way?

Thanks!

edit retag flag offensive close merge delete

2 answers

Sort by ยป oldest newest most voted
3

answered 2011-04-21 10:04:14 -0500

Jason Grout gravatar image

It still has to create the actual image each time. The graphics object is cached, but the actual image isn't. Also, if you are running from a web notebook, it also takes time to transfer the image to your browser. My guess is that the transfer time is taking most of that half second. Have you tried running that code locally on your own computer?

In the code below, I actually write all of the images out first and the interact just retrieves the right image. There is still a bit of lag, but it is a bit faster for me.

n=100
for i in range(n+1):
    f(x)=sin(N(i/10)*x)
    plot(f,plot_points=10000).save(DATA+'image%d.png'%i)

@interact
def _(a=(0..n)):
    html('<img src="data/image%d.png"/>'%a)
edit flag offensive delete link more

Comments

Also, notice that I don't use a lambda expression. That's so that the plot statement can optimize the function evaluation using the fast_callable framework.

Jason Grout gravatar imageJason Grout ( 2011-04-21 10:05:09 -0500 )edit

Thanks! Using your idea to save the plot as a file, I got lagless switching between two images using only javascript. It uses onMouseover instead of @interact in order not to contact the server at all. So I guess I could implement a slider as a row of tiny images, each of them triggering an onMouseover.

chaesloc gravatar imagechaesloc ( 2011-04-23 12:12:51 -0500 )edit

The slider should have the option of the images, though it would also be good to make sure that one could just use a regular sider as before. Nice!

kcrisman gravatar imagekcrisman ( 2011-04-25 04:55:31 -0500 )edit
3

answered 2011-04-24 19:09:54 -0500

chaesloc gravatar image

updated 2011-04-24 19:37:09 -0500

Building on Jason's idea, I made an interactive graph that does not contact the sage server, using javascript to change the frames. On my computer it does not lag at all. I find it so useful that I'm thinking of making a feature request for something with similar functionality. What do you think?

EDIT: The code below in a published worksheet: http://nt.sagenb.org/home/pub/36/

def jslider(f,start,end,num_steps):

    # Draw a tile for the slider
    import Image, ImageDraw
    img=Image.new("RGB",(3,20))
    draw = ImageDraw.Draw(img)
    draw.line(((2,0),(2,19)),(255,255,255))
    img.save("data/jslider_tile.png", "PNG")

    step_size=(end-start)/num_steps

    for i in range(num_steps+1):
        f(start+i*step_size).save(DATA+'jslider_%d.png'%i)

    html("""
        <script>
        function jslider_switch(n)
        {
              document.getElementsByClassName('jslider_image')[0].src='data/jslider_'+n+'.png';
        }
        </script>
        """)

    def tile_html(n): #Returns the html code for the (n)th tile of the slider
        return '<img src="data/jslider_tile.png" onMouseover="jslider_switch(%d)">'%n

    slider_html=""
    for i in range(num_steps+1):
        slider_html=slider_html+tile_html(i)

    html(slider_html)
    html('<img src="data/jslider_0.png" class="jslider_image">')

jslider(lambda a:plot(lambda x:sin(a*x),xmin=0,xmax=pi,ymin=-1,ymax=1),0,5,50) # This can take a minute or two.

Now refresh the notebook (the browser's reload/refresh button) for the html/javascript to work properly.

If you use a remote notebook, transferring the images will introduce significant lag. To avoid it, after running jslider run the following function. It will load all of the images once, so they will hopefully get stored in the browser's cache.

def load_images(num_steps):
    def frame_html(n):
        return '<img src="data/jslider_%d.png">'%n
    cmd=""
    for i in range(num_steps+1):
        cmd=cmd+frame_html(i)
    html(cmd)

load_images(50)

Do not run jslider in more than one cell - only the first cell's image will be interactive. And be aware that the code above saves .png files in the worksheet's data directory and does not clean them up.

edit flag offensive delete link more

Comments

Thanks! I had a similar problem with interact for 3d plots -- this looks like a great solution!

niles gravatar imageniles ( 2011-04-25 01:58:56 -0500 )edit

You should definitely file a feature request with this. Even if it isn't standard, having it as an easy-to-use option would be great; we really need more js magic stuff that doesn't require the round trip. The downside is, of course, creating all the images first. Actual use would be to put it in an %auto cell, and to talk to your audience while it's loading up :)

kcrisman gravatar imagekcrisman ( 2011-04-25 04:54:48 -0500 )edit

@kcrisman I will file one when I find out how (but this deserves its own question). Regarding your actual use, if you *prepare* a talk, you will create all the images before the talk - they get saved as files.

chaesloc gravatar imagechaesloc ( 2011-04-27 04:53:40 -0500 )edit

Right, that is what I meant with the %auto cell. At least, I am always making minute changes right up to the last second...

kcrisman gravatar imagekcrisman ( 2011-04-27 05:33:53 -0500 )edit

I answered your other question, by the way; hope it is what you were asking.

kcrisman gravatar imagekcrisman ( 2011-04-27 05:34:10 -0500 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

2 followers

Stats

Asked: 2011-04-20 04:09:16 -0500

Seen: 467 times

Last updated: Apr 24 '11