Skip to content

Updating in a for or while loop #49

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kushalkolar opened this issue Dec 25, 2024 · 4 comments · May be fixed by #89
Open

Updating in a for or while loop #49

kushalkolar opened this issue Dec 25, 2024 · 4 comments · May be fixed by #89

Comments

@kushalkolar
Copy link
Contributor

Finally catching up with all this! Taking a look at the examples and wondering if this would be the right way to update the canvas in a for or while loop. It works but I'm not sure if this is the way it's intended to be used, without an event loop running.

import numpy as np
from rendercanvas.auto import RenderCanvas, loop

canvas = RenderCanvas(update_mode="ondemand")
context = canvas.get_context("bitmap")

for i in range(100):
    w, h = canvas.get_logical_size()
    shape = int(h) // 4, int(w) // 4

    bitmap = np.random.uniform(0, 255, shape).astype(np.uint8)
    context.set_bitmap(bitmap)
    canvas.force_draw()

related: pygfx/pygfx#667

I'm starting to think about how to implement this for fastplotlib, might help to have a mode where the canvas is updated only when an event occurs or when any buffer in the scene changes? Anyways that will be a separate issue which I'll think about later.

@almarklein
Copy link
Member

Yes, the way to go is to use force_draw(), also see the demo.py example:

elif event["key"] in " f":
# Force draw for 2 secs
print("force-drawing ...")
etime = time.time() + 2
i = 0
while time.time() < etime:
i += 1
canvas.force_draw()
print(f"Drew {i} frames in 2s.")

However, it is meant to be used only in special scenarios because it bypasses the normal event loop and scheduling, which means that there will also be no updates, unless you also flush the events etc. and then you are basically creating your own scheduler ...

In use-cases where you are running a simulation like pygfx/pygfx#667, I think it would be better to use something like:

async def do_my_simulation():
    for .... 
         do whatever you want to do
         but from time to time call
         asyncio.sleep(0)  # allow the window to stay active

and then run that together with the rendercanvas.asyncio.loop.

Would be good to cover this in an example! 🤔

might help to have a mode where the canvas is updated only when an event occurs or when any buffer in the scene changes?

No, that's what the "ondemand" mode is for.

@clewis7
Copy link

clewis7 commented May 12, 2025

Hi Almar,

Kushal and I are revisiting this to see how we can expose the "ondemand" render mode features in fastplotlib.

Our two primary use cases to start would be:

  1. Every so often, write a frame to a video file
  2. Running a simulation where you need a for-loop for updates/computations

I just wanted to get some clarification on some of the things you mentioned above. It seems like you are saying we should avoid calling force_draw and instead use rendercanvas.asyncio.loop.

Do you have an example of this somewhere?

@almarklein
Copy link
Member

Every so often, write a frame to a video file

In this case, I imagine you either have an offscreen canvas, so you just use canvas.draw(). Or you have a regular canvas/renderer and you grab a screenschot from that every somany frames.

Running a simulation where you need a for-loop for updates/computations

I will create one or two examples for this.

@almarklein almarklein linked a pull request May 13, 2025 that will close this issue
@almarklein
Copy link
Member

See #89

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants