-
Notifications
You must be signed in to change notification settings - Fork 100
Maintain calculation results in session state #740
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
Comments
@gshotwell mentioned the idea of saving models, which I really liked. Being able to load them back in + show output and create additional plots, diagnostics, etc. would also be really interesting. You could do that with a separate app designed just to evaluate a particular type of saved models. However, to be able to do it in the same estimation app would be really nice (i.e., restore input values, reactive.Calc state, and output). |
I encountered the same issue. I would like to ask if there have been any recent developments about the |
Just curious if there are any updates on this, or people have any workarounds. Is there a Python equivalent of R's My use case is that I have to hit an external web API, and that API request will be the same for each user of the app. So I would prefer to cache it, and include a time component in the key to invalidate the cached result after X minutes. I've read the docs but based on what I can tell there isn't currently this type of functionality supported in Shiny for Python? |
@sambrilleman I bet you could get this behaviour by using a reactive outside of the server function. This will let all of the users of the app share the same API call, which you could invalidate on a schedule with https://github.com/posit-dev/py-shiny-templates/blob/main/monitor-database/shared.py#L26 |
Legend! Thanks @gshotwell , we'll give that approach a go 😀 I guess I didn't realise we can use a reactive outside of the context of a server. I guess if it's out there on its own, not part of the server, it just forms its own reactive dependency graph or something like that 🤔 (i.e. only linked to the invalidation/polling like you mention). Interesting that it still fires on start up as part of the App though. I guess because its still called from the server (even if not declared there) so must be called/loaded by the app atleast once. Anyhow ignore me if I'm talking some gibberish, pretty new to Shiny. I'll take a closer look at your example, and we can just copy that behaviour, thanks! |
The reactive graph actually works the same way, it's just that when you put it outside of the server function it's shared across all users. So it's instantiated once when the app starts up, and all users share that reactive. When it invalidates it also invalidates all of the session objects that depend on it. The one thing that I'd be careful of with this pattern is altering the global reactive from within a session. I think it's better to just have a rule that global reactives are a kind of one-way trip and send data to sessions, but aren't modified by them. |
Yeah epic, that sounds reasonable. Thanks again!
…On Thu, 19 Sept 2024, 10:33 pm Gordon Shotwell, ***@***.***> wrote:
The reactive graph actually works the same way, it's just that when you
put it outside of the server function it's shared across all users. So it's
instantiated once when the app starts up, and all users share that
reactive. When it invalidates it also invalidates all of the session
objects that depend on it.
The one thing that I'd be careful of with this pattern is altering the
global reactive from within a session. I think it's better to just have a
rule that global reactives are a kind of one-way trip and send data to
sessions, but aren't modified by them.
—
Reply to this email directly, view it on GitHub
<#740 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AEVECTCD53HGSSXMIHMNCSDZXLABDAVCNFSM6AAAAAA5IF4TWGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDGNRQHA3DINJYHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Related: Bookmarking demo app from #1870 from starlette.requests import Request
from shiny import App, Inputs, Outputs, Session, reactive, render, ui
from shiny.bookmark import BookmarkState
# App UI **must** be a function to ensure that each user restores their own UI values.
def app_ui(request: Request):
return ui.page_fluid(
ui.markdown(
"Directions: "
"\n1. Change the radio buttons below"
"\n2. Refresh your browser."
"\n3. The radio buttons should be restored to their previous state."
"\n4. Check the console messages for bookmarking events."
),
ui.hr(),
ui.input_radio_buttons(
"letter",
"Choose a letter (Store in Bookmark 'input')",
choices=["A", "B", "C"],
),
ui.input_radio_buttons(
"letter_values",
"Choose a letter (Stored in Bookmark 'values' as lowercase)",
choices=["A", "B", "C"],
),
"Selection:",
ui.output_code("letters"),
)
def server(input: Inputs, output: Outputs, session: Session):
# Exclude `"letter_values"` from being saved in the bookmark as we'll store it manually for example's sake
# Append or adjust this list as needed.
session.bookmark.exclude.append("letter_values")
lowercase_letter = reactive.value()
@reactive.effect
@reactive.event(input.letter_values)
async def _():
lowercase_letter.set(input.letter_values().lower())
@render.code
def letters():
return str([input.letter(), lowercase_letter()])
# When the user interacts with the input, we will bookmark the state.
@reactive.effect
@reactive.event(input.letter, lowercase_letter, ignore_init=True)
async def _():
await session.bookmark()
# Before saving state, we can adjust the bookmark state values object
@session.bookmark.on_bookmark
async def _(state: BookmarkState):
print("Bookmark state:", state.input, state.values, state.dir)
with reactive.isolate():
state.values["lowercase"] = lowercase_letter()
# After saving state, we will update the query string with the bookmark URL.
@session.bookmark.on_bookmarked
async def _(url: str):
print("Bookmarked url:", url)
await session.bookmark.update_query_string(url)
@session.bookmark.on_restore
def _(state: BookmarkState):
print("Restore state:", state.input, state.values, state.dir)
# Update the radio button selection based on the restored state.
if "lowercase" in state.values:
uppercase = state.values["lowercase"].upper()
# This may produce a small blip in the UI as the original value was restored on the client's HTML request, _then_ a message is received by the client to update the value.
ui.update_radio_buttons("letter_values", selected=uppercase)
@session.bookmark.on_restored
def _(state: BookmarkState):
# For rare cases, you can update the UI after the session has been fully restored.
print("Restored state:", state.input, state.values, state.dir)
# Make sure to set the bookmark_store to `"url"` (or `"server"`)
# to store the bookmark information/key in the URL query string.
app = App(app_ui, server, bookmark_store="url") |
@vnijs had a request to have the results of a long-running reactive calculation "persist" even through navigating away and back. In talking this through in person, maybe the equivalent of Shiny for R's
bindCache
(combined with bookmarkable state) would do it.The text was updated successfully, but these errors were encountered: