5

In the following shiny app, the plotly package is used to create an interactive correlation heat map. When individual tiles are clicked, the corresponding scatter plot appears. One can then download the individual scatters by clicking download plot as png. But is there a way to download all the possible scatter plots at once without having to click each individual tile and save each individual one? Thank you

library(plotly)
library(shiny)

# compute a correlation matrix
correlation <- round(cor(mtcars), 3)
nms <- names(mtcars)

ui <- fluidPage(
  mainPanel(
    plotlyOutput("heat"),
    plotlyOutput("scatterplot")
  ),
  verbatimTextOutput("selection")
)

server <- function(input, output, session) {
  output$heat <- renderPlotly({
    plot_ly(x = nms, y = nms, z = correlation, 
            key = correlation, type = "heatmap", source = "heatplot") %>%
      layout(xaxis = list(title = ""), 
             yaxis = list(title = ""))
  })

  output$selection <- renderPrint({
    s <- event_data("plotly_click")
    if (length(s) == 0) {
      "Click on a cell in the heatmap to display a scatterplot"
    } else {
      cat("You selected: \n\n")
      as.list(s)
    }
  })

  output$scatterplot <- renderPlotly({
    s <- event_data("plotly_click", source = "heatplot")
    if (length(s)) {
      vars <- c(s[["x"]], s[["y"]])
      d <- setNames(mtcars[vars], c("x", "y"))
      yhat <- fitted(lm(y ~ x, data = d))
      plot_ly(d, x = ~x) %>%
        add_markers(y = ~y) %>%
        add_lines(y = ~yhat) %>%
        layout(xaxis = list(title = s[["x"]]), 
               yaxis = list(title = s[["y"]]), 
               showlegend = FALSE)
    } else {
      plotly_empty()
    }
  })

}

shinyApp(ui, server)
MLavoie
  • 9,671
  • 41
  • 36
  • 56
J.Con
  • 4,101
  • 4
  • 36
  • 64
  • Does it need to run only locally or in the browser? – Maximilian Peters May 11 '18 at 08:32
  • @MaximilianPeters The app runs in the browser, but the scatter plots are saved as png files locally. – J.Con May 11 '18 at 09:53
  • You don't have to do it with plotly. You could use a loop that would produce all the plots you want and you can download them with an `actionButton` or `download` button. – MLavoie May 11 '18 at 11:11
  • @MLavoie I’m intrigued. Could you elaborate, please? – J.Con May 11 '18 at 11:12
  • 1
    here is an [example](https://stats.stackexchange.com/questions/177129/ggplot-and-loops) of what I had in mind. [This](https://stackoverflow.com/questions/14810409/save-plots-made-in-a-shiny-app) could download the plots. It is not easy but it might be possible :-) – MLavoie May 11 '18 at 11:29
  • Is it possible that the 2nd graph appears only after the click event in heatmap and uses the data from the heatmap to plot another graph?(Only appearing after the click in heatmap)? @MLavoie – rahul yadav Jul 13 '18 at 12:21

1 Answers1

4

You can use webshot to capture a static image of Plotly's HTML output using the instructions here: https://plot.ly/r/static-image-export/

An example for loop below generates random scatter plots from mtcars.

library(plotly)
library(webshot)

## You'll need to run the function the first time if you dont't have phantomjs installed
#webshot::install_phantomjs()
ColumnOptions <- colnames(mtcars)

for (i in seq_len(5)){
  xCol <- sample(ColumnOptions,1)
  yCol <- sample(ColumnOptions,1)
  ThisFileName <- paste0("Scatter_",xCol,"_vs_",yCol,".png")

  plot_ly(x = mtcars[[xCol]], y = mtcars[[yCol]], type = "scatter", mode = "markers") %>% 
    export(., file = ThisFileName)
}

However, if you're going to be potentially doing this dozens of times, the amount of computation required to go through the following steps really adds up.

  1. Generate a JSON plotly object from R
  2. Use htmlwidgets/htmltoolsto generate a self-contained HTML web page
  3. Render that HTML as a browser would see it with an external program --webshot
  4. Use webshot to render an image of that HTML and save it as a PNG

This isn't really a reflection of plotly being slow, but to make an analogy it's kind've like using an airplane to travel half a mile -- the plane gets you there, but if you need to make that trip more than a few times you should probably consider a car.

The plotly loop above takes 27 seconds to render 5 PNG images, but the alternative method below using ggplot2 takes 1.2 seconds.

library(ggplot2)

ColumnOptions <- colnames(mtcars)

for (i in seq_len(5)){
  xCol <- sample(ColumnOptions,1)
  yCol <- sample(ColumnOptions,1)
  ThisFileName <- paste0("ggplot2_Scatter_",xCol,"_vs_",yCol,".png")

  ggplot() + 
    geom_point(aes(x = mtcars[[xCol]], y = mtcars[[yCol]])) +
    labs(x = xCol, y = yCol) -> ThisPlot 

  ggsave(plot = ThisPlot, filename = ThisFileName)
}
Matt Summersgill
  • 4,054
  • 18
  • 47
  • Thank you very much for this info. However, I'm not sure it answers my question. This involves running separate scripts outside of the shiny app and also deals with the scatter plots alone. The example script provides a heat map first, with each scatter plot linked to a tile. I am looking for a way to quickly get each scatter plot that is linked to each tile. I hope that makes sense. – J.Con May 13 '18 at 22:12