Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Drag and drop data into shiny app

How can I drag and drop data into a shiny app? I can drag and drop into an area and read it with javascript, but I'm not sure how to have shiny register it so I can process it on the server. Here is an example setup -- it's kinda long b/c I don't think there is a javascript function builtin to deal with drag-n-drop.

It currently should look like the following when run and a dataset "dat.csv" is dragged in. The goal is register the data that has been drag-n-dropped into a variable in input so it can be processed in R. enter image description here

ui.R

library(shiny)  ui <- shinyUI(   fluidPage(     tags$head(tags$link(rel="stylesheet", href="css/styles.css", type="text/css"),       tags$script(src="getdata.js")),     h3(id="data-title", "Drop Datasets"),     div(class="col-xs-12", id="drop-area", ondragover="dragOver(event)",        ondrop="dropData(event)"),     tableOutput('table'),  # doesn't do anything now      ## debug     div(class="col-xs-12",       tags$hr(style="border:1px solid grey;width:150%"),       tags$button(id="showData", "Show", class="btn btn-info",          onclick="printData('dat.csv')")),     div(id="data-output")  # print the data   ) ) 

server.R

## Make a sample dataset # write.csv(data.frame(a=1:10, b=letters[1:10]), "dat.csv", row.names=FALSE) server <- function(input, output, session) {   output$table <- renderTable(input$data)  # this variable doesn't exist } 

www/getdata.js

var datasets = {}; var dragOver = function(e) { e.preventDefault(); }; var dropData = function(e) {     e.preventDefault();     handleDrop(e.dataTransfer.files); }; var handleDrop = function(files) {     for (var i = 0, f; f = files[i]; i++) {     var reader = new FileReader();      reader.onload = (function(file) {         return function(e) {         datasets[file.name.toLowerCase()] = e.target.result;         var div = document.createElement("div");         var src = "https://cdn0.iconfinder.com/data/icons/office/512/e42-512.png";         div.id = "datasets";         div.innerHTML = [             "<img class='thumb' src='", src, "' title='", encodeURI(file.name),             "'/>", "<br>", file.name, "<br>"].join('');         document.getElementById("drop-area").appendChild(div);         };     })(f);     reader.readAsText(f);     } }; // debug var printData = function(data) {     var div = document.createElement("div");     div.innerHTML = datasets[data];     document.getElementById("data-output").appendChild(div); }; 

www/css/styles.css

#data-title {     text-align:center; }  #drop-area {     background-color:#BCED91;     border:2px solid #46523C;     border-radius:25px;     height:90px;     overflow:auto;     padding:12px; }  #drop-area #datasets {     display:inline-block;     font-size:small;     margin-right:8px;     text-align:center;     vertical-align:top; }  .thumb {     height:45px; } 
like image 323
Rorschach Avatar asked Mar 19 '16 23:03

Rorschach


People also ask

How do you enter Shiny data?

To add an input in a Shiny app, we need to place an input function *Input() in the ui object. Each input function requires several arguments. The first two are inputId , an id necessary to access the input value, and label which is the text that appears next to the input in the app.

Can you save Shiny app as HTML?

You need an R server in order to execute a shiny app. There is no way to convert it into "pure HTML" and run the interactivity via javascript. The reason for that is that shiny apps will have to execute R code at runtime and javascript does not know how to deal with that.

Can you run Shiny app locally?

You might be eager to deploy your Shiny app to a remote server. But the simplest way to run a Shiny app is to run it locally. You only need the shiny R package installed, and you can run the app in your browser.


1 Answers

You just need to add the following line into the js file

datasets[file.name.toLowerCase()] = e.target.result; # Add this line Shiny.onInputChange("mydata", datasets); 

Then you can use input$mydata in the server code. Note that it's a list, so you'll need to iterate through it (also necessary if you plan to drop several files).

Complete code (that also displays multiple csv files, note that if you drop multiple files with the same name, only one will be displayed):

getdata.js (add one line as above)

styles.css (no change)

ui.R

library(shiny)  ui <- shinyUI(   fluidPage(     tags$head(tags$link(rel="stylesheet", href="css/styles.css", type="text/css"),               tags$script(src="getdata.js")),     sidebarLayout(       sidebarPanel(         h3(id="data-title", "Drop Datasets"),         div(class="col-xs-12", id="drop-area", ondragover="dragOver(event)",              ondrop="dropData(event)")       ),       mainPanel(         uiOutput('tables')       )     )    ) ) 

server.R

server <- function(input, output, session) {   observeEvent(input$mydata, {     len = length(input$mydata)     output$tables <- renderUI({       table_list <- lapply(1:len, function(i) {         tableName <- names(input$mydata)[[i]]         tableOutput(tableName)       })       do.call(tagList, table_list)     })     for (name in names(input$mydata)) {       output[[name]] <- renderTable(read.csv(text=input$mydata[[name]]))     }   }) } 
like image 148
Xiongbing Jin Avatar answered Oct 11 '22 20:10

Xiongbing Jin