-
Notifications
You must be signed in to change notification settings - Fork 100
Add busy indicators (aka spinners) #918
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
Merged
Changes from 61 commits
Commits
Show all changes
70 commits
Select commit
Hold shift + click to select a range
b5dfe7e
Add function for including loading spinners in apps.
nstrayer fb0e218
Fix documentation formatting
nstrayer 80c38b4
Add option for delay on the spinner animation. Also simplify animatio…
nstrayer fc69915
Refactor server function to control sleep behavior
nstrayer 77deff3
Add TODO for toggling spinner growing
nstrayer 2e076b9
Disable grow animation by default.
nstrayer 11a4726
Add two new loading spinners and add always-on spinner to demo app
nstrayer dd54ced
Use literals for typing of type and format docstrings
nstrayer 54a7f0d
Make disc spinner more balanced
nstrayer 6733696
Remove set width and heights from svg as they are never actually used
nstrayer 1fbb479
Add option for page-level spinner and modularize css a bit
nstrayer 95a8df2
make the page-level spinner have a smaller default size
nstrayer 14cbdc0
Add spinners as on by default and add response to classes to turn off…
nstrayer 4a8a91e
Add ability to target a specific output with a spinner.
nstrayer b0f8576
Remove the no-longer-used spinners-common.css file.
nstrayer 30ce38c
Merge branch 'main' into spinners
cpsievert bef3ae8
Fix small doc issues
cpsievert 7977393
Bundle HTMLDependency() with shiny's core dependencies
cpsievert 10cbc90
Update example to demonstrate some current problems better
cpsievert 8bd3513
Return tag instead of HTMLDependency; simplify API
cpsievert b4f5cef
Fix/improve element level spinner behavior. Provide a disable()/enabl…
cpsievert f98e30e
Merge branch 'main' into spinners
cpsievert ff93b4a
Fix plot tasks effects other plots
cpsievert 2826e34
Get rid of blur effect in favor of opacity dim
cpsievert f21f5ae
Introduce concept of indicator modes; leverage build-time Sass and tr…
cpsievert b5a268e
Execute the extended tasks concurrently
cpsievert 7862ce1
Add page-level spinner when shiny is busy, and nothing in the UI is r…
cpsievert ce4760a
Add spinner mode
cpsievert 5f38b79
Merge branch 'main' into spinners
cpsievert 924ed38
rm yarn.lock
cpsievert 93ef45b
Rename loading-indicators -> busy-indicators
cpsievert dfa0ab7
Activate page-level spinner up until the 1st idle.
cpsievert 1cbe237
Add submodule to express
cpsievert 618278c
Remove example commited by mistake
cpsievert 391be77
Embed svgs in the css; simplify further
cpsievert dadf49a
Revert changes to package json since plugin is no longer needed
cpsievert eae88cb
Add to API reference, with an example
cpsievert ae9994a
Merge branch 'main' into spinners
cpsievert df4e90b
Increase delay to 0.5s
cpsievert afdb8d7
Introduce the concept of a pulsing page (instead of a page-wide spinner)
cpsievert cf3c5f6
Move example to more sensible location
cpsievert 9279dc3
Remove disable spinner classes and just document size=0px as a way to…
cpsievert 3fb4975
Merge branch 'main' into spinners
cpsievert 684b25e
Remove example commited by mistake
cpsievert a40e0cd
Code review
cpsievert bbe4e1d
Improve pulse effect; add pulse_options()
cpsievert 0f64d90
Small tweaks to pulse from Greg
cpsievert 707f521
Bring in multi-color gradient
cpsievert f21d5c3
Merge branch 'main' into spinners
cpsievert ffad902
Merge branch 'main' into spinners
cpsievert 520045b
Export pulse_options()
cpsievert e883193
Avoid inline script
cpsievert edb2245
Show output busy state on 1st draw; disable pulse when spinners are v…
cpsievert f646b9e
Fix lint
cpsievert 2497552
Merge branch 'main' into spinners
cpsievert 816a1ac
Update express example
cpsievert 4a46170
Decrease default size; do more to avoid clipping; fix example
cpsievert 698cae2
Clean up event handling logic
cpsievert 4efa58b
Add more commentary
cpsievert 7d833f1
Merge branch 'main' into spinners
cpsievert b822ee1
Bring in JS/CSS source from RShiny repo
cpsievert 1285798
Add back spinner selector option
cpsievert 77755ea
Merge branch 'main' into spinners
cpsievert 335f059
Port over latest from RShiny
cpsievert 2949437
Update
cpsievert b242cb0
Update
cpsievert 1125f43
Fix base64 encoding
cpsievert 23d526e
Fix/improve example
cpsievert 63191a6
Update changelog
cpsievert 86ca109
Better naming
cpsievert File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
# pyright:basic | ||
import asyncio | ||
import concurrent.futures | ||
import time | ||
|
||
import matplotlib.pyplot as mpl | ||
import numpy as np | ||
import seaborn as sns | ||
from faicons import icon_svg | ||
|
||
from shiny import App, module, reactive, render, ui | ||
|
||
# Execute each extended task on a different thread. | ||
pool = concurrent.futures.ThreadPoolExecutor() | ||
|
||
# Use Agg backend for matplotlib so that it doesn't try to open a window. | ||
mpl.switch_backend("Agg") | ||
|
||
|
||
# -- Reusable card module -- | ||
@module.ui | ||
def card_ui(): | ||
return ui.card( | ||
ui.card_header( | ||
"A plot", | ||
ui.input_task_button("simulate", "Simulate", icon=icon_svg("shuffle")), | ||
class_="d-flex justify-content-between align-items-center", | ||
), | ||
ui.output_plot("plot"), | ||
) | ||
|
||
|
||
@module.server | ||
def card_server(input, output, session, length, simulate_all): | ||
|
||
def do_plot(wait_time=0.5): | ||
time.sleep(wait_time) | ||
|
||
# Without ax, seaborn works through side effects, so supply the ax to avoid | ||
# one figure from affecting another. | ||
fig, ax = mpl.subplots(1, 1) | ||
sns.lineplot(x=np.arange(100), y=np.random.randn(100), ax=ax) | ||
return fig | ||
|
||
@ui.bind_task_button(button_id="simulate") | ||
@reactive.extended_task | ||
async def plot_task(wait_time=1): | ||
loop = asyncio.get_event_loop() | ||
return await loop.run_in_executor(pool, do_plot, wait_time) | ||
|
||
@reactive.effect | ||
@reactive.event(input.simulate, ignore_none=False) | ||
def _(): | ||
plot_task(1 if input.simulate() == 0 else length()) | ||
|
||
@reactive.effect | ||
@reactive.event(simulate_all) | ||
def _(): | ||
plot_task(length()) | ||
|
||
@render.plot | ||
def plot(): | ||
return plot_task.result() | ||
|
||
|
||
# -- Main app -- | ||
app_ui = ui.page_sidebar( | ||
ui.sidebar( | ||
ui.input_task_button("simulate_all", "Simulate all", icon=icon_svg("shuffle")), | ||
ui.input_selectize( | ||
"indicator_types", | ||
"Busy indicator types", | ||
["spinners", "pulse"], | ||
multiple=True, | ||
selected=["spinners", "pulse"], | ||
), | ||
ui.input_slider("length", "Simulation length", 0, 500, 5), | ||
), | ||
ui.layout_columns( | ||
card_ui("a"), | ||
card_ui("b"), | ||
card_ui("c"), | ||
card_ui("d"), | ||
col_widths=[6, 6], | ||
), | ||
card_ui("e"), | ||
ui.output_ui("indicator_types_ui"), | ||
fillable=True, | ||
title="Busy indicators + extended tasks = ❤️", | ||
) | ||
|
||
|
||
def server(input, output, session): | ||
|
||
@render.ui | ||
def indicator_types_ui(): | ||
return ui.busy_indicators.use( | ||
spinners="spinners" in input.indicator_types(), | ||
pulse="pulse" in input.indicator_types(), | ||
) | ||
|
||
card_server("a", length=input.length, simulate_all=input.simulate_all) | ||
card_server("b", length=input.length, simulate_all=input.simulate_all) | ||
card_server("c", length=input.length, simulate_all=input.simulate_all) | ||
card_server("d", length=input.length, simulate_all=input.simulate_all) | ||
card_server("e", length=input.length, simulate_all=input.simulate_all) | ||
|
||
|
||
app = App(app_ui, server) | ||
app.on_shutdown(pool.shutdown) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import os | ||
import time | ||
|
||
import numpy as np | ||
import seaborn as sns | ||
|
||
from shiny import App, render, ui | ||
|
||
app_ui = ui.page_sidebar( | ||
ui.sidebar( | ||
ui.input_selectize( | ||
"indicator_types", | ||
"Busy indicator types", | ||
["spinners", "pulse"], | ||
multiple=True, | ||
selected=["spinners", "pulse"], | ||
), | ||
ui.busy_indicators.options(spinner_color="orange"), | ||
ui.download_button("download", "Download source"), | ||
), | ||
ui.card( | ||
ui.card_header( | ||
"Plot that takes a few seconds to render", | ||
ui.input_task_button("simulate", "Simulate"), | ||
class_="d-flex justify-content-between align-items-center", | ||
), | ||
ui.output_plot("plot"), | ||
), | ||
ui.output_ui("indicator_types_ui"), | ||
title="Busy indicators demo", | ||
) | ||
|
||
|
||
def server(input): | ||
|
||
@render.plot | ||
def plot(): | ||
input.simulate() | ||
time.sleep(3) | ||
sns.lineplot(x=np.arange(100), y=np.random.randn(100)) | ||
|
||
@render.ui | ||
def indicator_types_ui(): | ||
return ui.busy_indicators.use( | ||
spinners="spinners" in input.indicator_types(), | ||
pulse="pulse" in input.indicator_types(), | ||
) | ||
|
||
@render.download | ||
def download(): | ||
time.sleep(3) | ||
path = os.path.join(os.path.dirname(__file__), "app-core.py") | ||
return path | ||
|
||
|
||
app = App(app_ui, server) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import os | ||
import time | ||
|
||
import numpy as np | ||
import seaborn as sns | ||
|
||
from shiny.express import input, render, ui | ||
|
||
ui.page_opts(title="Busy spinner demo") | ||
|
||
with ui.sidebar(): | ||
ui.input_selectize( | ||
"indicator_types", | ||
"Busy indicator types", | ||
["spinners", "pulse"], | ||
multiple=True, | ||
selected=["spinners", "pulse"], | ||
) | ||
ui.busy_indicators.spinner_options(color="orange") | ||
|
||
@render.download | ||
def download(): | ||
time.sleep(3) | ||
path = os.path.join(os.path.dirname(__file__), "app-express.py") | ||
return path | ||
|
||
|
||
with ui.card(): | ||
ui.card_header( | ||
"Plot that takes a few seconds to render", | ||
ui.input_task_button("simulate", "Simulate"), | ||
class_="d-flex justify-content-between align-items-center", | ||
) | ||
|
||
@render.plot | ||
def plot(): | ||
input.simulate() | ||
time.sleep(3) | ||
sns.lineplot(x=np.arange(100), y=np.random.randn(100)) | ||
|
||
|
||
@render.ui | ||
def indicator_types_ui(): | ||
return ui.busy_indicators.use( | ||
spinners="spinners" in input.indicator_types(), | ||
pulse="pulse" in input.indicator_types(), | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.