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)
Relevant Functions
-
ui.Progress
ui.Progress(self, min=0, max=1, session=None)
-
ui.Progress.close
ui.Progress.close(self)
-
ui.Progress.inc
ui.Progress.inc(self, amount=0.1, message=None, detail=None)
-
ui.Progress.set
ui.Progress.set(self, value=None, message=None, detail=None)
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:
- Use
ui.Progress()
to create a computation manager, and usewith
to run the computation within the manager. For example, you might set up a progress bar like this:
ui.Progress()
creates a progress bar object that you can use to update the progress bar that is displayed during the computation.
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.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!”.
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.