Tout d'abord, je ne suis pas assez familier avec javascript et sa bibliothèque d3.js, mais je connais R. La création de tableaux de bord à l'aide de Shiny a été amusante et facile (grâce à stackoverflow). Maintenant, je veux l'étendre en y connectant des éléments d3.
Je recherche des sources d'informations sur la façon de lier réellement javascript à Shiny (tableau de bord R) et d'expliquer ce qui se passe réellement.
Contexte: J'ai fait le tutoriel sur js et jquery sur w3schools et j'ai appris (un peu) sur d3 en utilisant le livre de Scott Murray (visualisation interactive des données pour le web). J'espérais que ce serait suffisant pour me faire comprendre les exemples et les explications sur la façon de créer des liaisons d'entrée/sortie personnalisées sur le site Web de Shiny:
http://shiny.rstudio.com/articles/building-inputs.html
Mais malheureusement, je ne le fais pas et je n'arrive pas à trouver d'exemples qui sont en code de travail minimal. De nombreux exemples sur github sont trop complexes à disséquer, probablement à cause de ma petite expérience avec javascript. Voici un exemple de liaison d'entrée personnalisée avec javascript:
https://github.com/jcheng5/shiny-js-examples/tree/master/input
Voici un exemple de liaison d'entrée et de sortie que j'essaie de déplier:
<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>
Où "d3io" est un élément div dans l'interface utilisateur, updateView () est une fonction. Voici l'interface utilisateur:
#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
)
))
Voici le fichier serveur:
# 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);
}
})
})
Questions spécifiques:
1) Le server.r semble obtenir une entrée appelée "d3io" (entrée $ d3io) car cela n'est pas défini dans ui.r, j'ai pensé que cela devait provenir du fichier javascript. À quel élément se réfère-t-il réellement?
2) J'ai du mal à comprendre la partie reliure personnalisée:
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);
Ma compréhension est:
Créez une nouvelle liaison de sortie brillante, recherchez d'abord la classe .d3io (élément div), si erreur, puis écrivez sur la console "Foe" (est-ce ce code spécial?), Sinon erreur, alors renderValue en utilisant la fonction updateView en utilisant les données (où reçoit-il cette valeur de?) et écrivez sur la console "Friend". Enfin enregistrez la sortie.
J'espère que vous pouvez aider! Je crée un document avec les étapes sur "Les étapes nécessaires pour apprendre à implémenter javascript en brillant quand vous ne connaissez pas javascript", j'adorerais ça! :)
À la vôtre, longue
Salut Sweetbabyjesus (tellement amusant à dire). Vous aviez deux questions:
1) Le server.r semble obtenir une entrée appelée "d3io" (entrée $ d3io) car cela n'est pas défini dans ui.r, j'ai pensé que cela devait provenir du fichier javascript. À quel élément se réfère-t-il réellement?
Cette phrase input$d3io
A les composants suivants:
input
est un paramètre transmis à la fonction - c'est une liste qui stocke les valeurs actuelles de tous les widgets de l'application.$
Est le sélecteur de membres.d3io
Fait référence au contenu de l'élément div avec cet id ('d3IO ("d3io")') dans le panneau principal de l'interface utilisateur.2) J'ai du mal à comprendre la partie reliure personnalisée:
var d3OutputBinding = new Shiny.OutputBinding();
C'est vrai, cela crée une instance de Shiny.OutputBinding et l'affecte à la variable d3OutputBinding.
$.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");
}
});
Ce code étend le comportement de d3OutputBinding avec trois fonctions appelées find
, renderError
et renderValue
. Ces trois fonctions sont requises pour un Shiny.OutputBinding.
find
est la clé car elle retourne une liste d'éléments qui doivent être passés dans les deux fonctions de rendu via leur paramètre el
. Notez qu'il renvoie des éléments dont la classe css est "d3io" - c'est le même div mentionné plus haut.
Notez que extend()
est une fonction de la bibliothèque javascript jQuery et que $
Dans ce contexte est un alias pour l'objet jQuery.
Shiny.outputBindings.register(d3OutputBinding);
Permet à Shiny de savoir que cet objet nouvellement configuré doit être utilisé maintenant.
À la vôtre, Nick
Je vais prendre du recul et supposer que vous voulez les résultats étonnants dont D3 est capable, mais que vous n'êtes pas nécessairement liés à D3. Essentiellement, je répondrai à cette question:
Quelles sont les étapes nécessaires pour apprendre à implémenter JavaScript dans Shiny lorsque vous ne connaissez pas JavaScript?
Bien que D3 soit incroyablement puissant, il est également notoirement difficile à maîtriser - même pour de nombreuses personnes qui sont assez à l'aise avec JavaScript. Bien que j'adore le D3 et que je l'utilise presque tous les jours, je le déconseille dans ce cas. Au lieu de cela, il y a une bibliothèque appelée Plotly , qui utilise D3 en arrière-plan, mais est conçue spécifiquement pour la communauté scientifique et les scientifiques des données, elle est donc très conviviale pour la communauté R.
Ils ont un tutoriel complet pour se connecter à Shiny et même un convertisseur ggplot2 si vous êtes déjà familier avec cette syntaxe, comme beaucoup dans le monde R le sont. À moins que vos besoins ne soient très inhabituels, Plotly répondra probablement à vos besoins tout en écrivant directement en D3, avec une courbe d'apprentissage beaucoup plus conviviale.
Très occupé par le travail, je n'ai pas eu la chance de le poster. Notez qu'il s'agit d'une solution de contournement utilisant le customMessageHandler (et je n'utilise pas de liaison d'entrée/sortie personnalisée). Voici:
Objectif: envoyer des données à partir du bloc de données pour créer une arborescence D3JS à l'aide de customMessageHandler.
Chemin: j'ai réussi à envoyer des données au format data.frame vers une arborescence d3js. Après avoir cliqué sur le bouton d'action, il modifie les données dans le bloc de données au format JSON, puis les envoie au fichier js qui crée l'arborescence. Les données de l'arborescence sont codées en dur sur "server.r".
Où est le code? Sur mon github! https://github.com/SweetBabyJesus/shiny-d3js-simple-binding
Original: J'ai créé un algorithme d'arbre basé sur CHAID pour créer des informations à partir de grands ensembles de données. Les gens peuvent télécharger leur csv sur le tableau de bord qui crache ensuite l'arbre d3js :) Le code est un peu long, donc je l'ai coupé pour vous et créé un exemple de code minimal.
J'espère que vous aimez.
À la vôtre, longue
Connaissez-vous le package rCharts ? Cela peut très bien fonctionner avec Shiny et la plupart des options de sortie sont basées sur des variantes D3. Deuxexemples .