First time here? Check out the FAQ!

Ask Your Question
3

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

asked 13 years ago

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!

Preview: (hide)

2 Answers

Sort by » oldest newest most voted
3

answered 13 years ago

chaesloc gravatar image

updated 13 years ago

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.

Preview: (hide)
link

Comments

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

niles gravatar imageniles ( 13 years ago )

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 ( 13 years ago )

@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 ( 13 years ago )

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 ( 13 years ago )

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

kcrisman gravatar imagekcrisman ( 13 years ago )
3

answered 13 years ago

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)
Preview: (hide)
link

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 ( 13 years ago )

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 ( 13 years ago )

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 ( 13 years ago )

Your Answer

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

Add Answer

Question Tools

3 followers

Stats

Asked: 13 years ago

Seen: 1,227 times

Last updated: Apr 25 '11