Search code examples
rshinyplotlyr-plotlyggplotly

How to download a ggplotly plot with R Shiny downloadHandler?


I'm making a Shiny app in R. I use plotly to make my ggplots interactive, thus I have lots of ggplotly plots in the app. I would like to be able to download each one through a button on the interface.

My download button works for normal ggplot objects but not for ggplotly objects. A simple reproducible example would be:

library(shiny)
library(ggplot2)
library(processx) # for orca()
library(plotly)

ui <- fluidPage(
  mainPanel(plotlyOutput("plot1"), downloadButton('download1', 'Download Graph'))
  )

server <- function(input,output){
  make_plot1 <- function(){
    p1 = ggplot(cars, aes(x = speed, y = dist)) + geom_point()
    return(ggplotly(p1))}

  output$plot1 <- renderPlotly({ make_plot1() }) 

  output$download1 <- downloadHandler(
    filename = function() {'plot1.png'},
    content = function(file) {
      # try 1
      png(file)
      print(make_plot1())

      # try 2
      #plotly_IMAGE(make_plot1(), format = "png", out_file = file)

      # try 3
      #orca(make_plot1(), file)

      #try 4
      #export(make_plot1(), file = file)

      dev.off()
      })
  }

shinyApp(ui, server)

Some things I've tried are commented out in that code.

Try 1 is based on how I would normally handle plot objects in a shiny app

Try 2 is based on this question and this post

Try 3 is based on some plotly documentation

Try 4 is based on this question

All of these attempts either download a blank .png (try 1) or simply fail to download anything (tries 2-4). I suspect I'm not quite using the download Handler correctly. Anybody have suggestions for getting this working?

EDIT: For this case I want .png files, but there are some good answers on this thread for downloading interactive .html files.


Solution

  • Do you need to accomplish this with a download button for some reason? If not, plotly has its own button in the modebar that downloads to a PNG.

    enter image description here

    Dashboard taken from https://plot.ly/r/dashboard/.

    From the plotly support forum (https://community.plot.ly/t/remove-options-from-the-hover-toolbar/130/3), you can use config() to remove the other components.

    make_plot1 <- function() {
      p1 = ggplot(cars, aes(x = speed, y = dist)) + geom_point()
      p1 = ggplotly(p1) %>%
        config(
          modeBarButtonsToRemove = list(
            "zoom2d",
            "pan2d",
            "zoomIn2d",
            "zoomOut2d",
            "autoScale2d",
            "resetScale2d",
            "hoverClosestCartesian",
            "hoverCompareCartesian",
            "sendDataToCloud",
            "toggleHover",
            "resetViews",
            "toggleSpikelines",
            "resetViewMapbox"
          ),
          displaylogo = FALSE
        )
      return(p1)
    }
    

    You can also move the modebar so that it doesn't cover the plot, using CSS.

    .modebar {
        top: -30px !important;
    }