2015-03-30 62 views
4

昨天 I asked如何将带有自包含数据的d3js javacript文件转化为Shiny来绘制一个强制网络图。现在我正在寻找下一步:server.R将读取一个JSON数据文件以显示在图中。我一直在尝试改编使用messageHandlers的this example将数据传递给d3JS。这超出了我的专业知识,所以我正在寻求一些帮助。我很确定它是在messageHandler中出现错误的地方。如何使用Shiny集成数据驱动的d3JS图形?

我会很乐意发布完整的工作示例,因为这将使我对R,Shiny和d3JS集成有了新的了解。 PS:是的,我查看了networkD3和其他工具。我的d3JS图表比这里的简单例子复杂得多。 :)接下来的步骤还包括使图形在Shiny中选择输入,但我首先需要解决这个问题。 非常感谢! Tim

ui.R - 按下按钮,接收图形!

shinyUI(fluidPage(
    titlePanel("Shiny Binding to d3JS"), 
    sidebarLayout(
    sidebarPanel(
     tags$head(tags$link(rel = "stylesheet", type = "text/css", href = "twoNodes.css")), 
     actionButton("var_run",label="Create Graph!") 
    ), 
    mainPanel(
     h3("D3JS FN OUTPUT:"), 
     # load D3JS library 
     tags$script(src="d3.min.js"), 
     # load javascript 
     tags$script(src="twoNodes.js"), 
     # create div 
     tags$div(id="div_graph") 
    ) 
) 
)) 

server.R - 当前读入两个节点及其链接。 IRL它会查询数据存储。

library(shiny) 
library(rjson) 
# Read JSON from the file 
json_data <- fromJSON(file="twoNodes.JSON") 

shinyServer(
    function(input, output, session) { 
    # exception handler for when action button is clicked 
    # session$sendCustomMessage is where things start to fall apart 
    observe({ 
     if (input$var_run == 0){ 
     return() 
     } 
     session$sendCustomMessage(type="jsondata",json_data) 
     }) 
    } 
) 

twoNodes.JSON - 数据

{ 
     "nodes":[ 
      {"id":0,"name":"Observations","group":"1"}, 
      {"id":1,"name":"DataSet","group":"2"} 
      ], 
     "edges":[ 
      {"source":0,"target":1,"value":""} 
      ] 
    } 

twoNodes.css - 样式表

#nodegroup1{ 
    fill:#000000; 
    fon-family: Serif, Georgia; 
    font-size: 14px; 
    font-weight: bold; 
    }    
    .nodetext{ 
    font-size:8; 
    color: red; 
    } 
    .edgelabel{ 
    font-size:12px; 
    fill:darkblue; 
    } 
    .edges{ 
    stroke: #ccc; 
    stroke-width: 2; 
    } 

twoNodes.js - 在d3JS魔法我想利用

Shiny.addCustomMessageHandler("jsondata", 
    function(message){ 
    var dataset = [message]; 

    d3.select("#tempID").remove() 

    // lines from original d3JS follow 
    //Width and height for SVG area 
    var w = 300; 
    var h = 200; 
    // changed from body to #div_graph. Added tempID 
    var svg = d3.select("#div_graph").append("svg") 
       .attr("id","tempID") 
       .attr("width", w) 
       .attr("height", h); 

    svg.append("text") 
    .text("Two Nodes in a Force Network") 
    .attr("x",10) 
    .attr("y",15); 

// Data source - Now comes in with message handler 
// d3.json("/d3/CubeStructure/twoNodes.JSON", function(dataset) { 

    var force = d3.layout.force() 
       .nodes(dataset.nodes) 
       .links(dataset.edges) 
       .gravity(.05) 
       .charge(-180) 
       .linkDistance(100) 
       .size([w, h]) 
       .start(); 
    var drag = force.drag() 
        .on("dragstart", dragstart); 

    var edges = svg.selectAll("line") 
       .data(dataset.edges) 
       .enter() 
       .append("line") 
       .attr("id",function(d,i){return 'edge'+i}) 
       .attr("class", "edges") 
       .attr("marker-end", "url(#end)"); 

    var nodes = svg.selectAll("g.node") 
       .data(dataset.nodes) 
       .enter() 
       .append("g") 
       .attr("class", "node") 
       .on("dblclick", dblclick) 
       .call(drag); 
    nodes.append("circle") 
     .attr("r", 10) 
     .style("stroke", "black") 
     // Mousover Node - highlight node by fading the node colour during mouseover 
     .on('mouseover', function(d){ 
      var nodeSelection = d3.select(this).style({opacity:'0.5'}); 
     }) 
     //Mouseout Node - bring node back to full colour 
     .on('mouseout', function(d){ 
      var nodeSelection= d3.select(this).style({opacity:'1.0',}) 
     }) 

// Node label 
    nodes.append("text") 
     .attr("class", "nodetext") 
     .attr("dx", 12) 
     .attr("dy", ".35em") 
     .attr("id", function(d,i){return 'nodegroup1'}) // all get the same style 
     .text(function(d) { return d.name });   // Just the name 
    // Paths along which to apply the edge label 
    var edgepaths = svg.selectAll(".edgepath") 
        .data(dataset.edges) 
        .enter() 
        .append('path') 
        .attr({'d': function(d) {return 'M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y}, 
          'class':'edgepath', 
          'fill-opacity':0, 
          'stroke-opacity':0, 
          'fill':'blue', 
          'stroke':'red', 
          'id':function(d,i) {return 'edgepath'+i}}) 
        .style("pointer-events", "none"); 
    // dx : the starting distance of the label from the source node 
    var edgelabels = svg.selectAll(".edgelabel") 
         .data(dataset.edges) 
         .enter() 
         .append('text') 
         .style("pointer-events", "none") 
        .attr({'class':'edgelabel', 
          'id':function(d,i){return 'edgelabel'+i}, 
          'dx':40, 
          'dy':0 
          }) ; 
    force.on("tick", function() { 
      edges.attr("x1", function(d) { return d.source.x; }) 
            .attr("y1", function(d) { return d.source.y; }) 
            .attr("x2", function(d) { return d.target.x; }) 
            .attr("y2", function(d) { return d.target.y; }); 
    nodes.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; }); 

    edgepaths.attr('d', function(d) { var path='M '+d.source.x+' '+d.source.y+' L '+ d.target.x +' '+d.target.y; 
             //console.log(d) 
             return path});  
    // positioning of the label along the edge 
    edgelabels.attr('transform',function(d,i){ 
       if (d.target.x<d.source.x){ 
        bbox = this.getBBox(); 
        rx = bbox.x+bbox.width/2; 
        ry = bbox.y+bbox.height/2; 
        return 'rotate(180 '+rx+' '+ry+')'; 
       } 
       else { 
        return 'rotate(0)'; 
       } 
    }); 
    });  
    // }); // not needed due to msg handler End of reading in JSON from file 
    // Double click to 'unfix' the node and have forces start to act on it again. 
    function dblclick(d) { 
    d3.select(this).classed("fixed", d.fixed = false); 
    } 
    // Set the "fixed" property of the dragged node to TRUE when a dragstart event is initiated, 
    // - removes "forces" from acting on that node and changing its position. 
    function dragstart(d) { 
    d3.select(this).classed("fixed", d.fixed = true); 
    } 
    }); // end of new function 
+0

您是否找到解决方案? – Stophface 2016-07-14 09:11:09

回答

1

你相当接近。它稍作修改; twoNodes.js中的第3行应该是

var dataset = message;