Search code examples
canvasjupyter-notebookdrawipycanvas

when is ipycanvas drawing on the canvas? Or how to force it?


I try to write something like a minigame in Jupyter for my students, where they learn like in Swift playgrounds how a figure is behaving when applying different commands. I wrote the following:

from ipywidgets import Image
from ipycanvas import *
import time 

char = Image.from_file("Bilder/charRight.png")

bg = Image.from_file("Bilder/map.png")

xchar=150
ychar=170
tilesize = 48

canvas = Canvas(height=800, width=800)
canvas.draw_image(bg,0,0 )
canvas.draw_image(char, xchar, ychar)

def step():
    time.sleep(3)
    global xchar
    global ychar
    global char
    canvas.draw_image(bg,0,0 )
    xchar = xchar+tilesize
    canvas.draw_image(char, xchar, ychar)

step()
print("yay")
step()
print("yay")
canvas

But i do not understand, why it is not showing each step individually, but all at the end? If you want to suggest other modules, the environment i would like to use can only work with modules that are written in python. Otherwise i would have tried pygame.

i tried including canvas at several points, thinking it would force it to draw, didn't do that.


Solution

  • I think this works in a full Python kernel in that it doesn't wait until end to show anything and that it moves the char image over. (Session from the 'launch binder' badge here.) I think part of the issue is you aren't using Jupyter's display() or ipywidgets out handling correctly. The former one being the main issue so that the canvas wasn't displaying until the final line of the code was encountered in your code block. My suggestion is below:

    from ipywidgets import Image
    from ipycanvas import *
    import time 
    
    char = Image.from_file("single_document_mode_in_JupyterLab.png")
    
    bg = Image.from_file("ClassicNb_interface.png")
    
    xchar=150
    ychar=170
    tilesize = 48
    
    canvas = Canvas(height=800, width=800)
    canvas.draw_image(bg,0,0 )
    canvas.draw_image(char, xchar, ychar)
    
    display(canvas)
    
    def step():
        time.sleep(3)
        canvas.clear()
        global xchar
        global ychar
        global char
        canvas.draw_image(bg,0,0 )
        xchar = xchar+tilesize
        canvas.draw_image(char, xchar, ychar)
    
    step()
    print("yay")
    step()
    print("yay")
    

    I also added a 'clearing' step. Maybe that isn't what you wanted?

    As for the print(), I left it alone because I wasn't sure why you were using it. I think you were probably just using it as a monitor and didn't care exactly where it printed to? You don't really want just print() if you want the text going anywhere near the canvas. And to properly use it with ipywidgets you probably want to use it within a context manager. Feel free to update if you want something differently done with the print("yay") in regards to where it goes relative the images and output area.