I am learning about modules and found that looping an input component is relatively straightforward using examples. However, looping output components like downloads or images can be tricky. I would like to know the best ways to loop such components.
from shiny import App, module, render, ui
import os
num_extra_rows = 5
extra_ids = [f"row_{i}" for i in range(1, 2 + num_extra_rows)]
@module.ui
def row_ui(row_id):
return ui.layout_columns(
ui.input_text("text_in", f'Enter text {row_id}'),
ui.output_text("text_out"),
ui.download_button("download_data", "Download CSV")
)
@module.server
def row_server(input, output, session, row_id):
input_id = f"text_in_{row_id}"
@output
@render.text
def text_out():
return f'You entered "{input.text_in()}"'
@output
@render.download(
filename=lambda: f"report.csv"
)
def download_data():
path = os.path.join(os.path.dirname(__file__), "../image/report/", f"report{row_id}.csv")
return path
app_ui = ui.page_fluid(
[row_ui(x, x) for x in extra_ids]
)
def server(input, output, session):
[row_server(x, x) for x in extra_ids]
app = App(app_ui, server)
For example, I want to generate six rows as defined in extra_ids. The input_text and output_text are auto-binded using {row_id}. However, the download_data function always downloads the report with the last row_id, i.e ., reportrow_6.csv. Here is a screenshot:
Every “Download CSV” button outputs reportrow_6.csv instead of the intended reportrow_1.csv, reportrow_2.csv, etc.
I have also tried this for @render.images and encountered the same issue: the last image in the loop is shown for every entry, even though I specify the dynamic {name} like this:
I might be doing something wrong, but I have not managed to implement dynamic looping for download and image components successfully. In Shiny R, I can use lapply for this purpose with ease. However, I am deeply invested in using Shiny for Python.
Thank you very much in advance for any assistance with this issue.
Hello,
I am learning about modules and found that looping an input component is relatively straightforward using examples. However, looping output components like downloads or images can be tricky. I would like to know the best ways to loop such components.
For example, I want to generate six rows as defined in extra_ids. The input_text and output_text are auto-binded using {row_id}. However, the download_data function always downloads the report with the last row_id, i.e ., reportrow_6.csv. Here is a screenshot:
Every “Download CSV” button outputs reportrow_6.csv instead of the intended reportrow_1.csv, reportrow_2.csv, etc.
I have also tried this for @render.images and encountered the same issue: the last image in the loop is shown for every entry, even though I specify the dynamic {name} like this:
ImgData = {"src": str(dir / "./image/upload_image" / {name}), "width": "100px"}
I might be doing something wrong, but I have not managed to implement dynamic looping for download and image components successfully. In Shiny R, I can use lapply for this purpose with ease. However, I am deeply invested in using Shiny for Python.
Thank you very much in advance for any assistance with this issue.