Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Download data from plotly graph via custom modebar button, coded in R

I have a plotly graph (in my case made in R / rmarkdown), and would like to download the data.

  • Option 1 is a download button outside the graph to a data object (e.g CSV, or a table). For example Download output file csv, or this. It works, but not that neat - using custom modebar would be neater.

Options 2 and 3 use a custom modebar button. plotly book - custom modebar button has a nice example with code to make the custom button.

  • Option 2, is a download button (e.g. to csv) as a plotly custom modebar button. Presumably this could be done in javascript (or html) and passed through, similar to example below in option 3? Suggestions for how to do this? There is some discussion on this option at Plotly forum, using Dash(?), but that is well over my pay grade.

  • Option 3 is a button that links to a table (possibly an appendix or other website with a datatable object), where that datatable has a download button. The last part, making a button for datatable that you can click is easy (see here). The javascript code for a website link should look something like this (javascript link to website). The default Plotly button in a plotly modebar does send you to a linked website when you click, but not sure how to replicate that html/javascript from R.

Am I missing something simple in this code?

Edit The icon web link below works, once opened in a browser - i.e. clicking on the icon wont open a website from the Rstudio viewer.

#devtools::install_github('cpsievert/plotly_book') #for octocat image
library(tidyverse)
library(DT)
library(plotly)

data(octocat_svg_path, package = "plotlyBook")

octocat <- list(
    name = "octocat",
    icon = list(
      path = octocat_svg_path,
      transform = 'matrix(1 0 0 1 -2 -2) scale(0.7)'
    ),
    click = htmlwidgets::JS(
      "function(gd) {window.location.href = 'http://www.google.com';
    }"
    )
  )
plot_ly() %>%
    config(modeBarButtonsToAdd = list(octocat))
like image 450
Mark Neal Avatar asked Dec 23 '22 20:12

Mark Neal


1 Answers

Using onRender from htmlwidgets you can add JS event handlers. This one will print the clicked data series to a window.

https://plotly-r.com/js-event-handlers.html

Here is an example in an Rmd file. Open this in RStudio and click [Knit to HTML] then [Open in Browser]. When you click one of the data series, a new windows will open containing the data in csv format.

---
title: "Export Plotly Data"
output: html_document
---

```{r echo = FALSE, message = FALSE}
library(plotly)
library(htmlwidgets)

plot_ly() %>%
    add_markers(x = c(0, 1), y = c(2, 3)) %>%
    add_markers(x = c(4, 5), y = c(6, 7)) %>%
    onRender("
    function(el) {
      el.on('plotly_click', function(d) {
        var newWindow = window.open();
        newWindow.document.write('x,', d.points[0].data.x, '<br>y,', d.points[0].data.y);
      });
    }
  ")

Update 1

Here is an example with ggplotly

https://community.plot.ly/t/returning-specific-data-element-with-plotly-click-function/5670

---
title: "Export Plotly Data"
output: html_document
---

```{r echo = FALSE, message = FALSE}
library(plotly)
library(htmlwidgets)
library(ggplot2)

data <- data.frame(
    Time = round(runif(10), 2), 
    Value = round(runif(10), 2),
    Type = rep(c("A", "B"), each = 5)
    )

gg <- ggplot(data = data) +
    geom_point(mapping = aes(x = Time, y = Value, colour = Type), size = 2)

ggplotly(gg) %>%
    onRender("
    function(el) {
      el.on('plotly_click', function(d) {
        var newWindow = window.open();
        newWindow.document.write(
          d.points[0].xaxis.title.text, ',',
          d.points[0].data.x, '<br>',
          d.points[0].data.name, ',',
          d.points[0].data.y
          );
      });
    }
  ")

Update 2

Here's an example using a custom modebar, as you originally had, that prints all data series. Icon svg data obtained from http://svgicons.sparkk.fr/

---
title: "Export Plotly Data"
output: html_document
---

```{r echo = FALSE, message = FALSE}
library(plotly)
library(htmlwidgets)
library(ggplot2)

data <- data.frame(
    Time = round(runif(10), 2),
    Value = round(runif(10), 2),
    Type = rep(c("A", "B"), each = 5)
    )

gg <- ggplot(data = data) +
    theme(legend.title = element_blank()) +
    geom_point(mapping = aes(x = Time, y = Value, colour = Type), size = 2)

# http://svgicons.sparkk.fr/
icon_svg_path = "M19.404,6.65l-5.998-5.996c-0.292-0.292-0.765-0.292-1.056,0l-2.22,2.22l-8.311,8.313l-0.003,0.001v0.003l-0.161,0.161c-0.114,0.112-0.187,0.258-0.21,0.417l-1.059,7.051c-0.035,0.233,0.044,0.47,0.21,0.639c0.143,0.14,0.333,0.219,0.528,0.219c0.038,0,0.073-0.003,0.111-0.009l7.054-1.055c0.158-0.025,0.306-0.098,0.417-0.211l8.478-8.476l2.22-2.22C19.695,7.414,19.695,6.941,19.404,6.65z M8.341,16.656l-0.989-0.99l7.258-7.258l0.989,0.99L8.341,16.656z M2.332,15.919l0.411-2.748l4.143,4.143l-2.748,0.41L2.332,15.919z M13.554,7.351L6.296,14.61l-0.849-0.848l7.259-7.258l0.423,0.424L13.554,7.351zM10.658,4.457l0.992,0.99l-7.259,7.258L3.4,11.715L10.658,4.457z M16.656,8.342l-1.517-1.517V6.823h-0.003l-0.951-0.951l-2.471-2.471l1.164-1.164l4.942,4.94L16.656,8.342z"

dl_button <- list(
    name = "Download data",
    icon = list(
        path = icon_svg_path,
        transform = "scale(0.84) translate(-1, 0)"
        ),
    click = htmlwidgets::JS("
          function(gd) {
            var html = '';
            for(var i = 0; i < gd.data.length; i++){
              html += gd.layout.xaxis.title.text + ' ' + gd.data[i].name + ',' + gd.data[i].x + '<br>';
              html += gd.layout.yaxis.title.text + ' ' + gd.data[i].name + ',' + gd.data[i].y + '<br>';
            }
            var newWindow = window.open();
            newWindow.document.write(html);
          }
   ")
)

ggplotly(gg) %>%
    layout(legend = list(y = 0.5)) %>%
    config(modeBarButtonsToAdd = list(dl_button))

Update 3

This version opens the Save As dialogue to write the data to a file.

Download .txt using JavaScript without dialog prompt

---
title: "Export Plotly Data"
output: html_document
---

```{r echo = FALSE, message = FALSE}
library(plotly)
library(htmlwidgets)
library(ggplot2)

data <- data.frame(
    Time = round(runif(10), 2),
    Value = round(runif(10), 2),
    Type = rep(c("A", "B"), each = 5)
    )

gg <- ggplot(data = data) +
    theme(legend.title = element_blank()) +
    geom_point(mapping = aes(x = Time, y = Value, colour = Type), size = 2)

# http://svgicons.sparkk.fr/
icon_svg_path = "M15.608,6.262h-2.338v0.935h2.338c0.516,0,0.934,0.418,0.934,0.935v8.879c0,0.517-0.418,0.935-0.934,0.935H4.392c-0.516,0-0.935-0.418-0.935-0.935V8.131c0-0.516,0.419-0.935,0.935-0.935h2.336V6.262H4.392c-1.032,0-1.869,0.837-1.869,1.869v8.879c0,1.031,0.837,1.869,1.869,1.869h11.216c1.031,0,1.869-0.838,1.869-1.869V8.131C17.478,7.099,16.64,6.262,15.608,6.262z M9.513,11.973c0.017,0.082,0.047,0.162,0.109,0.226c0.104,0.106,0.243,0.143,0.378,0.126c0.135,0.017,0.274-0.02,0.377-0.126c0.064-0.065,0.097-0.147,0.115-0.231l1.708-1.751c0.178-0.183,0.178-0.479,0-0.662c-0.178-0.182-0.467-0.182-0.645,0l-1.101,1.129V1.588c0-0.258-0.204-0.467-0.456-0.467c-0.252,0-0.456,0.209-0.456,0.467v9.094L8.443,9.553c-0.178-0.182-0.467-0.182-0.645,0c-0.178,0.184-0.178,0.479,0,0.662L9.513,11.973z"

dl_button <- list(
    name = "Download data",
    icon = list(
        path = icon_svg_path,
        transform = "scale(0.84) translate(-1, -1)"
        ),
    click = htmlwidgets::JS("
          function(gd) {
            var text = '';
            for(var i = 0; i < gd.data.length; i++){
              text += gd.layout.xaxis.title.text + gd.data[i].name + ',' + gd.data[i].x + '\\n';
              text += gd.layout.yaxis.title.text + gd.data[i].name + ',' + gd.data[i].y + '\\n';
            };
            var blob = new Blob([text], {type: 'text/plain'});
            var a = document.createElement('a');
            const object_URL = URL.createObjectURL(blob);
            a.href = object_URL;
            a.download = 'data.csv';
            document.body.appendChild(a);
            a.click();
            URL.revokeObjectURL(object_URL);
          }
   ")
)

ggplotly(gg) %>%
    layout(legend = list(y = 0.5)) %>%
    config(modeBarButtonsToAdd = list(dl_button))

like image 57
Simon Woodward Avatar answered Dec 28 '22 23:12

Simon Woodward