如何将数据驱动的d3JS图与Shiny集成?

时间:2015-03-30 19:56:41

标签: r d3.js shiny

昨天 I asked 如何将带有自包含数据的d3js javacript文件放入Shiny中以绘制强制网络图。现在我正在寻找下一步:server.R将读取JSON数据文件以在图中显示。我一直在尝试调整使用messageHandlers的this example 来将数据传递到d3JS。这超出了我的专业知识,所以我正在寻求一些帮助。我很确定它在messageHandler中出现问题。

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

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

1 个答案:

答案 0 :(得分:1)

你很亲密。它只需稍加修改即可使用; twoNodes.js中的第3行应为

var dataset = message;