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

Long Initialization time due to large number of ui.input_selectize options #1789

Closed
HarrisonWismer opened this issue Dec 3, 2024 · 3 comments

Comments

@HarrisonWismer
Copy link

Hello, I'm creating a shiny app to create an interface for biological data. For many of the pages I have, the user needs to select from a complete list of genes from the dataset which contains about 58,000 genes total. I can't really narrow down or have the user select other options to narrow down the gene list since the user could be interesting in any of the genes.

The problem is that this many input_selectize options makes the app take a couple of minutes to start up every time. Curious as to whether there is anything I can do to speed up initialization or potentially pre-render the UI to avoid this initializing every time? I'm self-hosting the app on shiny-server too if that makes any difference (hardware doesn't seem to be the bottleneck here). Any input or ideas would be greatly appreciated! Thanks!

@gadenbuie
Copy link
Collaborator

That's a lot of options! You can avoid the slowdown by using server-side selectize elements, which don't try to send all of the options to the browser at once and don't create a huge number of DOM elements.

Here's a simple example (that you can run in your browser on shinylive.io):

from shiny import App, Inputs, Outputs, Session, reactive, ui

app_ui = ui.page_fluid(
    ui.input_selectize("x", "Server side selectize", choices=[], multiple=True),
)


def server(input: Inputs, output: Outputs, session: Session):
    @reactive.effect
    def _():
        ui.update_selectize(
            "x",
            choices=[f"Gene {i:05}" for i in range(58000)],
            selected=["Gene 00011", "Gene 12345"],
            server=True,
        )


app = App(app_ui, server, debug=True)

The basic pattern is to:

  1. Initialize ui.input_selectize() in the UI with an empty list of choices that will be filled in later, along with any initial options.
  2. Send the final list of choices to the client from your server function with ui.update_selectize() and server=True.

@HarrisonWismer
Copy link
Author

This seems to do the trick! Initialization is much faster now. Quick question though: Do I need to add an individual

@reactive.effect
def _():
    ui.update_selectize(
        "x",
        choices=[f"Gene {i:05}" for i in range(58000)],
        selected=["Gene 00011", "Gene 12345"],
        server=True,
    ) 

block for each input_selectize element? Or can I put multiple under the same def_(): ?

@gadenbuie
Copy link
Collaborator

You could put them in the same @reactive.effect. Without being tied to a reactive event, the code in the effect function runs once on app startup.

If you have a few inputs with the same choices, you could use a for loop to walk through their IDs.

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

No branches or pull requests

2 participants