Progress Bar

#| standalone: true
#| components: [viewer]
#| viewerHeight: 200

import asyncio

from shiny import App, reactive, render, ui

app_ui = ui.page_fluid(
    ui.input_action_button("button", "Compute"),
    ui.output_ui("compute"),
)

def server(input, output, session):
    @output
    @render.ui
    @reactive.event(input.button)
    async def compute():
        with ui.Progress(min=1, max=15) as p:
            p.set(message="Calculation in progress", detail="This may take a while...")

            for i in range(1, 15):
                p.set(i, message="Computing")
                await asyncio.sleep(0.1)

        return "Done computing!"

app = App(app_ui, server)
import asyncio

from shiny import reactive, render
from shiny.express import input, ui

ui.input_action_button("do_compute", "Compute")

@render.ui
@reactive.event(input.do_compute)
async def compute():
    with ui.Progress(min=1, max=15) as p:
        p.set(message="Calculation in progress", detail="This may take a while...")

        for i in range(1, 15):
            p.set(i, message="Computing")
            await asyncio.sleep(0.1)

    return "Done computing!"
import asyncio

from shiny import App, reactive, render, ui

app_ui = ui.page_fluid(
    ui.input_action_button("button", "Compute"),
    ui.output_ui("compute"),
)

def server(input, output, session):
    @output
    @render.ui
    @reactive.event(input.button)
    async def compute():
        with ui.Progress(min=1, max=15) as p:
            p.set(message="Calculation in progress", detail="This may take a while...")

            for i in range(1, 15):
                p.set(i, message="Computing")
                await asyncio.sleep(0.1)

        return "Done computing!"

app = App(app_ui, server)
No matching items

Relevant Functions

No matching items

Details

With Shiny, you can display a progress bar while a computation runs by running the computation bar within a special computation manager. Here’s how:

  1. Use ui.Progress() to create a computation manager, and use with to run the computation within the manager. For example, you might set up a progress bar like this:
def compute():
  with ui.Progress(min=1, max=15) as p:
      #  computation

ui.Progress() creates a progress bar object that you can use to update the progress bar that is displayed during the computation.

  1. Set the minimum and maximum values of the progress bar when you call ui.Progress(). These provide the outer bounds for the progress to display. For example, in the code above, when the bar is at 1, it would appear empty. When it is at 8, it would appear half full. When it is at 15, it would appear complete.

  2. Update the progress bar object as the computation runs. Updating the object is simple: you can call its set() method to change the location of the progress bar, as well as the message it displays. For example the code below would update the progress bar above to half finished, and change the message that accompanies the bar to “Almost there!”.

p.set(8, message="Almost there")

Finding opportunities to update the bar while the computation runs is more tricky. To have a responsive bar, you will need to interlace set() calls with the computation that runs. If the computation is a function from an external package, you may only be able to alert the user when the computation begins and when it finishes, which is unlikely to be satisfying:

async def compute():
with ui.Progress(min=1, max=15) as p:
    p.set(1, message="Here we go")
    # computation()
    p.set(15, message="Finished!")

If the computation involves separate functions run in sequence, you can update the progress bar after each function:

async def compute():
with ui.Progress(min=1, max=15) as p:
    p.set(1, message="Here we go")
    # computation1()
    p.set(5, message="Working hard")
    # computation2()
    p.set(10, message="Almost there")
    # computation3()
    p.set(15, message="Finished!")

If the computation is a function that you have written, you can write the function to accept a progress bar object to update as it runs.