Reputation: 27
Update: the problem of linking json to d3 is sovled. The codes are updated. Now shiny just doesn't render d3 code. (I read this post but didn't understand anything)
I'm new to shiny and of course new to D3. I have developed a program that simulates the evolution of species of organisms (actually there are 4 species), and would like to build a shiny app that takes the parameters from user and renders an interactive plot that illustrates their evolution over time.
The problem is that my .js file doesn't seem to want to get integrated to my app, or if it does, I just don't know how to link the JSON object created in the source code to the .js file. I'm afraid but I think it's a good idea to copy the whole app files here.
Here is the link to my source code.
Below is the ui.R file:
library(plotly)
shinyUI(fluidPage(
titlePanel(h1("Language Game")),
sidebarLayout(
sidebarPanel(
h2("Parameters"),
checkboxInput("wealth.reset", label = h5("Reset wealth of replicated organisms"),value = FALSE),
actionButton("start", label = h5("Start")),
actionButton("reset", label = h5("Reset")),
sliderInput("n", label = h5("Number of organisms"), min = 50, max = 200, value = 100,step = 50),
sliderInput("iter", label = h5("Number of Iterations"), min = 10, max = 500,value = 200, step = 10),
sliderInput("memSpan", label = h5("Memory Span"),min = 1,max = 50,value = 5, step = 5),
sliderInput("dial_change_rate (in percentage)", label = h5("Dialect Update Probability"), min = 0, max = 100, value = 1, step= 1),
sliderInput("repr_rate", label = h5("Reproduction Rate"), min= 1, max= 20, value = 20, step = 1),
sliderInput("Beta", label = h5("Decay Factor"), min = 1, max = 1.05, value = 1.029), step = 0.005),
mainPanel(
position = "left",
h3("About the Game"),
p("This game simulates interactions between the members of a population of organisms that are assigned some randome characteristics.
Organims are distributed randomly on a linear space, and interact with their neighbours.
The nature of the interactions is defined by the strategies of organisms."),
plotlyOutput("encounter"),
plotOutput("d3outplot"),
tags$head(tags$link(rel = "stylesheet", type = "text/css", href = "style.css")),
tags$script(src="https://d3js.org/d3.v3.min.js"),
tags$script(src="shinyd3.js"),
tags$div(id="body")
)
)
)
)
And here is the server.R:
#source("global.R")
shinyServer(function(input, output, session){
val <- reactiveValues(doPlot = FALSE)
observeEvent(input$start, {
val$doPlot <- input$start
output$d3outplot <- renderPlot({
var_json <- reactive({
lang.game(
input$iter,
input$n,
input$repr_rate,
input$Beta)
})
session$sendCustomMessage(type="jsondata",message= var_json)
})
})
observeEvent(input$reset, {
val$doPlot <- FALSE
})
output$encounter <- renderPlotly({
p("The plot below illustrates the number of encounters for each organism. By hoovering on the points you can see the identity (assign by position in linear space), and the number of encounters")
if (val$doPlot == FALSE) return()
isolate({
data <- reactive({
lang.game(
input$iter,
input$n,
input$repr_rate,
input$Beta
)
})
OrganismID <- c(1:input$n)
Encounters <- rowSums(encounter.mat(input$n, input$Beta))
q <- qplot(OrganismID,
Encounters,
data = data.frame(encounter.mat(input$n, input$Beta)),
main = "Encounter Probability",
xlab = "Organisms", ylab="Number of encounters", alpha = 0)
ply <- ggplotly(q,kwargs=list(layout=list(hovermode="closest")))
})
})
})
As for the .js file, the problem is that I just don't know how to link the JSON file created in the source code to .js. I used shiny message handler and session but it only shows the d3 codes as text. My source code at the other hand doesn't seem to be able to save the json file somewhere in the directory. I hope I made the problem clear, and will highly appreciate any suggestion.
(The d3 code: I'd like to build something like this)
Shiny.addCustomMessageHandler("jsondata",
function(message){
var JS = message;
function truncate(str, maxLength, suffix) { if(str.length > maxLength) {
str = str.substring(0, maxLength + 1);
str = str.substring(0, Math.min(str.length, str.lastIndexOf(" ")));
str = str + suffix;
}
return str;
};
var margin = {top: 20, right: 20, bottom: 0, left: 200},
width = 300,
height = 650;
var c = d3.scale.category20c();
var x = d3.scale.linear()
.range([0, width]);
var xAxis = d3.svg.axis()
.scale(x)
.orient("top");
var formatCy = d3.format("0");
xAxis.tickFormat(formatCy);
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.style("margin-right", margin.right + "px")
.append("g")
.attr("transform", "translate(" + margin.right + "," + margin.bottom + ")");
d3.json(JS, function(jsondata) {
x.domain(jsondata["Cycle"]);
var xScale = d3.scale.linear()
.domain(jsondata["Cycle"])
.range([0, width]);
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + 0 + ")")
.call(xAxis);
for (var j = 0; j < jsondata.length; j++) {
var g = svg.append("g").attr("class","variable");
var circles = g.selectAll("circle")
.jsondata(jsondata[j]['variable'])
.enter()
.append("circle");
var text = g.selectAll("text")
.jsondata(jsondata[j]['variable'])
.enter()
.append("text");
var rScale = d3.scale.linear()
.domain([0, d3.max(jsondata[j]['variable'], function(d) { return d[1]; })])
.range([0, 100]);
circles
.attr("cx", function(d, i) { return xScale(d[0]); })
.attr("cy", j*20+20)
.attr("r", function(d) { return rScale(d[1]); })
.style("fill", function(d) { return c(j); });
text
.attr("y", j*20+25)
.attr("x",function(d, i) { return xScale(d[0])-5; })
.attr("class","value")
.text(function(d){ return d[1]; })
.style("fill", function(d) { return c(j); })
.style("display","none");
g.append("text")
.attr("y", j*20+25)
.attr("x",width+20)
.attr("class","label")
.text(truncate(jsondata[j]['name'],30,"..."))
.style("fill", function(d) { return c(j); })
.on("mouseover", mouseover)
.on("mouseout", mouseout);
};
function mouseover(p) {
var g = d3.select(this).node().parentNode;
d3.select(g).selectAll("circle").style("display","none");
d3.select(g).selectAll("text.value").style("display","block");
}
function mouseout(p) {
var g = d3.select(this).node().parentNode;
d3.select(g).selectAll("circle").style("display","block");
d3.select(g).selectAll("text.value").style("display","none");
}
});
})
Upvotes: 0
Views: 730
Reputation: 136
I'm not a D3-expert and don't have the full answer to this question. But I believe that you don't want to use the d3.json function in this case, because you already have the JSON present (in the JS variable). Instead, I think you can d3.select the DOM element in which your plot wil be rendered, selectAll all the circles and use data to enter and exit the data into new element.
Upvotes: 1