shiny app reloading any time I download plot

I have a shiny app with a download button for a plot generated within the app. Whenever I download a plot, the entire app reloads, which would basically render the entire app useless. I might be mistaken but I don't think it was always doing this? Any idea for what I can try?

If it makes any difference, the app has not yet been hosted anywhere-- this is just when I'm opening it in my browser from VScode. Clearly I'm new to this whole process...

Thanks in advance for any help I can get!

I might be mistaken but I don't think it was always doing this?
It seems like you are either asking us if the application you wrote didnt use to do something ? or whether its standard for a downloadbutton in shiny to reload the entire app

  1. We cant know that.
  2. Absolutely not; you can run the downloadButton example included in the shiny documentation to see that.
library(shiny)
ui <- fluidPage(
  p("Choose a dataset to download."),
  selectInput("dataset", "Dataset", choices = c("mtcars", "airquality")),
  downloadButton("downloadData", "Download")
)

server <- function(input, output) {
  # The requested dataset
  data <- reactive({
    get(input$dataset)
  })

  output$downloadData <- downloadHandler(
    filename = function() {
      # Use the selected dataset as the suggested file name
      paste0(input$dataset, ".csv")
    },
    content = function(file) {
      # Write the dataset to the `file` that will be downloaded
      write.csv(data(), file)
    }
  )
}

shinyApp(ui, server)

Yes, I am asking if that is the standard behavior of the button. I was curious if anyone else had run into the same issues and if so what would be a good place to start troubleshooting, since my function mirrors that of the shiny for python documentation. When I run the sample session.download example the same way, I also run into the exact same issue, so wasn't sure if this was something that even has a possible workaround.

Have you possibly done anything "funky" such as nesting your output$downloadData inside some other structures aside from the root server content ?

I haven't done anything like that. This is the code my download was mirrored after (I'm working in python):

import asyncio
import io
import os
from datetime import date
from typing import Any

import matplotlib.pyplot as plt
import numpy as np

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


def make_example(id: str, label: str, title: str, desc: str, extra: Any = None):
    return ui.column(
        4,
        ui.div(
            {"class": "card mb-4"},
            ui.div(title, class_="card-header"),
            ui.div(
                {"class": "card-body"},
                ui.p(desc, class_="card-text text-muted"),
                extra,
                ui.download_button(id, label, class_="btn-primary"),
            ),
        ),
    )


app_ui = ui.page_fluid(
    ui.row(
        make_example(
            "download2",
            label="Download plot",
            title="Dynamic data generation",
            desc="Downloads a PNG that's generated on the fly.",
            extra=[
                ui.input_text("title", "Plot title", "Random scatter plot"),
                ui.input_slider(
                    "num_points", "Number of data points", min=1, max=100, value=50
                ),
            ],
        ),
    ))

def server(input: Inputs, output: Outputs, session: Session):
    @session.download()
    def download1():
        """
        This is the simplest case. The implementation simply returns the name of a file.
        Note that the function name (`download1`) determines which download_button()
        corresponds to this function.
        """

        path = os.path.join(os.path.dirname(__file__), "mtcars.csv")
        return path

    @session.download(filename="image.png")
    def download2():
        """
        Another way to implement a file download is by yielding bytes; either all at
        once, like in this case, or by yielding multiple times. When using this
        approach, you should pass a filename argument to @session.download, which
        determines what the browser will name the downloaded file.
        """

        print(input.num_points())
        x = np.random.uniform(size=input.num_points())
        y = np.random.uniform(size=input.num_points())
        plt.figure()
        plt.scatter(x, y)
        plt.title(input.title())
        with io.BytesIO() as buf:
            plt.savefig(buf, format="png")
            yield buf.getvalue()

    @session.download(
        filename=lambda: f"新型-{date.today().isoformat()}-{np.random.randint(100,999)}.csv"
    )
    async def download3():
        await asyncio.sleep(0.25)
        yield "one,two,three\n"
        yield "新,1,2\n"
        yield "型,4,5\n"

    @session.download(id="download4", filename="failuretest.txt")
    async def _():
        yield "hello"
        raise Exception("This error was caused intentionally")


app = App(app_ui, server)

That either works in Python or it doesnt, what can we learn from that about your R code that presumably doesnt work in the way you say it doesnt ?
I'm sorry but you aren't giving me any actionable information with which I can identify an issue and offer a correction.

To help us help you, could you please prepare a reproducible example (reprex) illustrating your issue? Please have a look at these resources, to see how to create one for a shiny app

I don't have any R code-- the shiny app in which I am having my issue is built in Python. This example from the documentation "works" in the sense that there is a file downloaded, although it also reloads the entire app. My app has the same behavior, which makes sense as it was modeled after the example I gave.

Shiny for python definitely lags behind its R counterpart, so I have learned not to assume that just because something is standard behavior or is possible in R that the same will be true for python. I think the most helpful answer I could get from this post is whether another shiny for python user has confirmation on whether this automatic reload is the default behavior of this framework when handling downloads.

I greatly appreciate you taking the time to attempt to troubleshoot with me! But I don't think creating a reproducible example in R will help me get closer to solving my issue in python. Thanks again for your input.

Thanks for clarifying that you are writing pyshiny code, rather than R Shiny which I'm personally more familiar with.

Does the documented example work as required, or does it result in buggy behaviour for you ?
source :

import asyncio
from datetime import date

import numpy as np

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

app_ui = ui.page_fluid(
    ui.download_button("downloadData", "Download"),
)


def server(input: Inputs, output: Outputs, session: Session):
    @session.download(
        filename=lambda: f"新型-{date.today().isoformat()}-{np.random.randint(100,999)}.csv"
    )
    async def downloadData():
        await asyncio.sleep(0.25)
        yield "one,two,three\n"
        yield "新,1,2\n"
        yield "型,4,5\n"


app = App(app_ui, server)

If it doesnt work also, then I would raise it as a bug with the pyshiny team on the github; otherwise if it works, you can hopefully build on that.

Yeah, that one is fine actually! Just trying to figure out why its different in the other example, which is also from the documentation examples on how to downloaded images. I'll keep researching, thanks for trying to help.

if thats the case; that a direct example from the documentation fails - I would raise it as a bug with the pyshiny team on the github - I think its here : Issues · posit-dev/py-shiny · GitHub

Hello, I have a similar issue. When I download a 'png' file, the app automatically reloads with this message: "WARNING: WatchFiles detected changes Reloading...".

Have you figured out what the issue was?

This topic was automatically closed 54 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.