2014-10-30 15 views
36

In primo luogo, sono abbastanza poco pratico con javascript e la sua libreria d3.js, ma ho familiarità con R. La creazione di cruscotti con Shiny è stata divertente e facile (grazie allo stackoverflow). Ora voglio espanderlo collegando elementi d3 ad esso.Collegamento javascript (d3.js) a lucido

Sto cercando fonti di informazione su come effettivamente associare javascript a Shiny (dashboard R) e spiegare cosa sta realmente accadendo.

Sfondo: Ho fatto il tutorial su js e jquery su w3schools e ho imparato (un po ') su d3 usando il libro di Scott Murray (Visualizzazione di dati interattivi per il web). Speravo che questo sarebbe sufficiente a farmi capire gli esempi e spiegazioni riguardo a come costruire attacchi di input/output personalizzati sul sito Shiny:

http://shiny.rstudio.com/articles/building-inputs.html

Ma purtroppo non e io non riesco a trova degli esempi che sono in codice di lavoro minimo. Molti esempi su github sono complessi per me da sezionare, molto probabilmente a causa della mia piccola esperienza con javascript. Ecco un esempio di input personalizzato vincolanti con javascript:

https://github.com/jcheng5/shiny-js-examples/tree/master/input

Ecco un esempio di un ingresso & uscita vincolante provo a spiegare:

<script src="http://d3js.org/d3.v3.js"></script> 
<script type="text/javascript"> 
(function(){ 
    // Probably not idiomatic javascript. 

    this.countValue=0; 

    // BEGIN: FUNCTION 
    updateView = function(message) { 

    var svg = d3.select(".d3io").select("svg") 

    svg.append("text") 
     .transition() 
     .attr("x",message[0]) 
     .attr("y",message[1]) 
     .text(countValue) 
     .each("end",function(){ 
     if(countValue<100) { 
      countValue+=1; 
      $(".d3io").trigger("change"); 
     } 
     }) 
    } 
    // END: FUNCTION 

    //BEGIN: OUTPUT BINDING 
    var d3OutputBinding = new Shiny.OutputBinding(); 
    $.extend(d3OutputBinding, { 
    find: function(scope) { 
     return $(scope).find(".d3io"); 
    }, 
    renderError: function(el,error) { 
     console.log("Foe"); 
    }, 
    renderValue: function(el,data) { 
     updateView(data); 
     console.log("Friend"); 
    } 
    }); 
    Shiny.outputBindings.register(d3OutputBinding); 
    //END: OUTPUT BINDING 

    //BEGIN: INPUT BINDING 
    var d3InputBinding = new Shiny.InputBinding(); 
    $.extend(d3InputBinding, { 
    find: function(scope) { 
     return $(scope).find(".d3io"); 
    }, 
    getValue: function(el) { 
     return countValue; 
    }, 
    subscribe: function(el, callback) { 
     $(el).on("change.d3InputBinding", function(e) { 
     callback(); 
     }); 
    } 
    }); 
    Shiny.inputBindings.register(d3InputBinding); 
//END: OUTPUT BINDING 

})() 
</script> 

Dove "d3io" è un elemento div Nell'interfaccia utente, updateView() è una funzione. Ecco l'ui:

#UI 
library(shiny) 

d3IO <- function(inputoutputID) { 
    div(id=inputoutputID,class=inputoutputID,tag("svg","")) #; eerst zat ; erbij, maar werkt blijkbaar ook zonder 
} 

# Define UI for shiny d3 chatter application 
shinyUI(pageWithSidebar(

    # Application title 
    headerPanel("D3 Javascript chatter", 
       "Demo of how to create D3 I/O and cumulative data transfer"), 

    sidebarPanel(
    tags$p("This widget is a demonstration of how to wire shiny direct to javascript, without any input elements."), 
    tags$p("Each time a transition ends, the client asks the server for another packet of information, and adds it 
      to the existing set"), 
    tags$p("I can't claim this is likely to be idiomatic javascript, because I'm a novice, but it allows d3 apps 
      to do progressive rendering. In real use, a more complex request/response protocol will probably be 
      required. -AlexBBrown") 
), 

    mainPanel(
    includeHTML("d3widget.js"), 
    d3IO("d3io") #Creates div element that d3 selects 
    ) 
)) 

Ecco il file server:

# SERVER 
library(shiny) 
# Define server logic required to respond to d3 requests 
shinyServer(function(input, output) { 

    # Generate a plot of the requested variable against mpg and only 
    # include outliers if requested 
    output$d3io <- reactive(function() { 
    if (is.null(input$d3io)) { 
     0; 
    } else { 
     list(rnorm(1)*400+200,rnorm(1)*400+200); 
    } 
    }) 
}) 

Domande specifiche:

1) La server.r sembra per ricevere input chiamato "d3io" (ingresso $ d3io) poiché non è definito in ui.r, ho pensato che debba provenire dal file javascript. A quale elemento si riferisce effettivamente?

2) Ho difficoltà a capire la parte personalizzata di rilegatura:

var d3OutputBinding = new Shiny.OutputBinding(); 
    $.extend(d3OutputBinding, { 
    find: function(scope) { 
     return $(scope).find(".d3io"); 
    }, 
    renderError: function(el,error) { 
     console.log("Foe"); 
    }, 
    renderValue: function(el,data) { 
     updateView(data); 
     console.log("Friend"); 
    } 
    }); 
    Shiny.outputBindings.register(d3OutputBinding); 

mia comprensione è:

Creare un nuovo outputbinding lucido, prima trovare il .d3io classe (div elemento), se l'errore allora scrivere alla console "Foe" (è questo codice speciale?), se non l'errore, allora renderValue usando la funzione updateView usando i dati (da dove riceve questo valore da?) e scrivi alla console "Friend". Infine registra l'output.

Spero che voi ragazzi potete aiutare! Sto creando un documento con le istruzioni su "Le misure necessarie per imparare come implementare javascript in lucido quando non si conosce alcun javascript", mi piacerebbe che! :)

Cheers, lungo

+0

+1 su "I passi necessari per imparare come implementare javascript in lucido quando non si conosce alcun javascript" – Vincent

+0

Sei ancora interessato a una guida su come scrivere associazioni personalizzate incl. d3.js? – BigDataScientist

risposta

11

Ciao Sweetbabyjesus (così divertente da dire). Hai avuto due domande:

1) La server.r sembra per ricevere input chiamato "d3io" (ingresso $ d3io) dal momento che questo non è definito in ui.r, ragionavo deve venire dal file javascript. A quale elemento si riferisce effettivamente?

Quella frase input$d3io ha i seguenti componenti:

  • input è un parametro passato alla funzione - si tratta di una lista che memorizza i valori correnti di tutti i widget in app.
  • $ è il selettore membri.
  • d3io si riferisce al contenuto dell'elemento div con quell'id ('d3IO ("d3io")') nel mainPanel dell'interfaccia utente.

2) ho difficoltà a capire la parte vincolante personalizzato:

var d3OutputBinding = new Shiny.OutputBinding(); 

Proprio così, questo crea un'istanza di Shiny.OutputBinding e lo assegna alla d3OutputBinding variabile.

$.extend(d3OutputBinding, { 
    find: function(scope) { 
    return $(scope).find(".d3io"); 
    }, 
    renderError: function(el,error) { 
    console.log("Foe"); 
    }, 
    renderValue: function(el,data) { 
    updateView(data); 
    console.log("Friend"); 
    } 
}); 

Questo codice estende il comportamento di d3OutputBinding con tre funzioni chiamate find, renderError e renderValue. Queste tre funzioni sono necessarie per un Shiny.OutputBinding.

find è la chiave perché restituisce un elenco di elementi che devono essere passati nelle due funzioni di rendering tramite il loro parametro el. Si noti che sta restituendo elementi la cui classe css è "d3io" - questo è lo stesso div citato in precedenza.

Nota che extend() è una funzione della libreria jQuery javascript e lo $ in questo contesto è un alias per l'oggetto jQuery.

Shiny.outputBindings.register(d3OutputBinding); 

Consente a Shiny di sapere che questo oggetto appena configurato deve essere messo in uso ora.

Cheers, Nick

8

Farò un passo indietro e presumo che tu voglia i risultati sorprendenti di cui è capace D3, ma che non sono necessariamente legati a D3. In sostanza, risponderò a questa domanda:

Quali sono i passaggi necessari per imparare come implementare JavaScript in Shiny quando non si conosce JavaScript?

Mentre D3 è incredibilmente potente, è anche notoriamente difficile da padroneggiare - anche per molte persone che sono abbastanza a proprio agio con JavaScript. Mentre io amo D3 e lo uso quasi tutti i giorni, in questo caso lo consiglierei contro di esso. Invece, c'è una libreria chiamata Plotly, che usa D3 in background, ma è costruita specificatamente per la comunità scientifica e i data scientist, quindi è molto amichevole con la comunità R.

Hanno un thorough tutorial for connecting to Shiny e hanno anche un ggplot2 converter se si ha già familiarità con quella sintassi, come molti nel mondo R sono. A meno che le tue necessità siano molto insolite, Plotly probabilmente servirà le tue necessità così come scrivere direttamente in D3, con una curva di apprendimento molto più amichevole.

+0

Plotly sembra molto user friendly, buon suggerimento. Piuttosto che creare immagini D3, sto cercando la risposta su come associare D3.js a lucido in modo da poter sfruttare l'impressionante pool esistente di immagini D3 (senza la necessità di crearle effettivamente), che è maggiore di quello che offre . Preferisco fare uso della fonte diretta (che è ambiziosa). – Sweetbabyjesus

+0

@warship Sembra che la domanda non esista più. : -/ –

+0

Ciao Chris, eccolo: http://stackoverflow.com/questions/34426202/downloadbutton-for-html-output-in-shiny – warship

3

Hai familiarità con lo rCharts package? Può funzionare molto bene con Shiny e la maggior parte delle opzioni di output sono basate su varianti D3. Twoexamples.

3

molto occupato con il lavoro, non ho avuto la possibilità di post-it. Si noti che questa è una soluzione alternativa che utilizza customMessageHandler (e non sto utilizzando il binding di input/output personalizzato). Ecco:

Obiettivo: inviare dati dal riquadro dati per creare un albero D3JS utilizzando customMessageHandler.

Percorso: sono riuscito a inviare dati nel formato data.frame a un albero d3js. Dopo aver fatto clic sul pulsante di azione, modifica i dati nel frame di dati in formato JSON, quindi li invia al file js che crea l'albero. I dati dell'albero sono hardcoded su "server.r".

Dov'è il codice? Sul mio github! https://github.com/SweetBabyJesus/shiny-d3js-simple-binding

Originale: ho creato un algoritmo ad albero basato su CHAID per creare approfondimenti da dataset di grandi dimensioni. Le persone possono caricare il loro csv nella dashboard che poi sputa l'albero d3js :) Il codice è piuttosto lungo, quindi l'ho tagliato per te e ho creato un esempio di codice minimo.

Spero che ti piaccia.

Cheers, lungo