jupyter-widgets-contrib / ipycanvas

Interactive Canvas in Jupyter
https://ipycanvas.readthedocs.io/en/latest/
BSD 3-Clause "New" or "Revised" License
686 stars 64 forks source link

to_file is unreliable #222

Open DangerMouseB opened 2 years ago

DangerMouseB commented 2 years ago

Firstly thank you for creating this - really helpful as a quick and dirty way to plot in jupyter when matplotlib etc are too cumbersome.

I'm having problems with to_file - as in not all the drawn elements that are displaying in the browser are being saved to file. I haven't been able to figure a reliable way of saving all the elements - I suppose it's acting a bit racy.

Any ideas of how to fix? (I've set sync_image_date to true and tried the callback method as well as the direct save).

martinRenou commented 2 years ago

Thank you for opening an issue.

This routine is indeed a bit unreliable, the big problem is that the rendering is done on the front-end (web-page) while your Python code runs on the server, so it's difficult to get in sync.

The callback method might be more reliable than a direct save. Though, for example, you have no certainty that you'll receive back all frames of an animations. We might be able to improve this though.

I can recommend to run your Python code in a separate Python thread, so that your Python code execution does not block any callback.

DangerMouseB commented 2 years ago

Do you happen to have some example code? - it's been 11 years since I did multithreading in python :)

A quick question to save some time, do I need to include all the rendering code, of if I have a canvas object do I just call the to_file method in a separate thread? (I'm hoping the latter).

martinRenou commented 2 years ago

I would put the rendering code in a separate thread... This example Notebook and this one both use threading so that the animation does not block any callback.

It might be possible to change the ipycanvas implementation so that we manually request image data, and making sure the Python callback gets called.

profhuster commented 1 year ago

I cannot get to_file to work at all. Can you give an example notebook that uses it?

martinRenou commented 1 year ago

@profhuster what code did you try?

Did you try something similar to here? https://ipycanvas.readthedocs.io/en/latest/retrieve_images.html#save-canvas-to-a-file

from ipycanvas import Canvas

canvas = Canvas(width=200, height=200, sync_image_data=True)

def save_to_file(*args, **kwargs):
    canvas.to_file("my_file.png")

# Listen to changes on the ``image_data`` trait and call ``save_to_file`` when it changes.
canvas.observe(save_to_file, "image_data")

# Perform some drawings...
profhuster commented 1 year ago

Yes. Parts of the image are missing in the file. It is weird because maybe on in ten runs it does have the full drawing. I cannot find any pattern

profhuster commented 1 year ago

I added canvas.flush() after drawing. That does not help.

DangerMouseB commented 1 year ago

That was my experience too - which is a shame because the api was nice and simple and I got some nice plots done using it but it was very hard to get them reliable into a png.

profhuster commented 1 year ago

I will look at pycairo. It is a more mature, and probably complex, package.

profhuster commented 1 year ago

Also Cairo and pycairo use vector drawing, so it scales without degradation.