Skip to content
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

Status update for slow functions, which don't require manipulation with mo.output #3718

Open
mrdobalina2k opened this issue Feb 7, 2025 · 3 comments
Labels
enhancement New feature or request

Comments

@mrdobalina2k
Copy link

Description

I like to build my UI based on components, and to show my UI as a single page, rather than stacked output cells (in vertical mode). I'm doing a lot of longer calculations which are triggered by e.g. a run button. When a long calculation takes place, I want to show a status spinner.

The current solution proposed is something like this, assuming the slow function is triggered by a run button:

mo.output.replace(main_ui)
if run.value:    
        mo.output.replace(spinner)
        result=await slow_function()
        mo.output.replace(mo.vstack([main_ui, result]))

Besides being very verbose, this method breaks down if we want to control the number of outputs inside our app: each of these cells which use a spinner will have it's own output, meaning we cannot use the vertical display mode in the app run mode, if we to control the layout using the vstack, or hstack methods, based on the UIElement of each returned by each cell. Instead we're forced to use the grid-mode, and place the outputs manually.

Moreover, and more critically, we cannot use this method when we want to place the output on an tab, because a tab requires us to pass the UIElement, which we don't have in this case (we only have the cell output).

Therefore I think, the current implementation is insufficient, for the more advanced user.

Suggested solution

We need a function similar to mo.lazy, let's call it mo.slow, but which gets re-rendered when triggered.

e.g.

import marimo

__generated_with = "0.11.0"
app = marimo.App(width="medium")


@app.cell
def _():
    import marimo as mo
    import asyncio
    return asyncio, mo


@app.cell
def _(mo):
    run_button = mo.ui.run_button()
    return (run_button,)


@app.cell
def _(asyncio, mo):
    async def slow_function():
        await asyncio.sleep(5)
        return mo.md("Results...")
    return (slow_function,)


@app.cell
def _(mo, run_button, slow_function):
    slow_function_output = mo.md("No results yet")
    if run_button.value:
        slow_function_output=mo.slow(slow_function, show_loading_indicator=True) # mo.lazy only renders a spinner once
    return (slow_function_output,)


@app.cell
def _(mo, run_button, slow_function_output):
    main_ui = mo.ui.tabs({"configure": mo.md("Configuration"), "results": mo.vstack([run_button, slow_function_output])})
    return (main_ui,)


@app.cell
def _(main_ui):
    main_ui
    return


if __name__ == "__main__":
    app.run()

mo.lazy does the job almost (showing a spinner), but it's purpose is different (delay rendering of ui components).

The function mo.slow could take as arguments what type of status update to show (spinner, bar, wave. etc.)

Alternative

No response

Additional context

No response

@mrdobalina2k mrdobalina2k added the enhancement New feature or request label Feb 7, 2025
@dmadisetti
Copy link
Collaborator

What about a context manager?

with mo.output.context(mo.spinner()): # Show output
    sleep(10)
# On exit, it disappears

Also, you may be interested in mo.cache? If you'd like to hold on to runs.

At risk of overstuffing the api:

with mo.persistent_cache("my_cache", loading_indicator=True): # Start the spinner
    sleep(10)
# On exit, it disappears

@mrdobalina2k
Copy link
Author

mrdobalina2k commented Feb 7, 2025

Not sure you're suggestion something that exists, or proposing a new feature, but mo.output.context does not exist. If you mean

with mo.output.spinner() as _spinner:
    results = await slow_function()

that shows the spinner in the cell which holds the context manager.

Also, I don't think this works for the proposed use-case (tabs)?

@dmadisetti
Copy link
Collaborator

Sorry, I should have specified- this does not exist. I was suggesting apis that might be useful

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

No branches or pull requests

2 participants