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

昨天 I asked 如何将带有自包含数据的d3js javacript文件带入Shiny中以绘制强制网络图.现在我正在寻找下一步:server.R将读取JSON数据文件以在图中显示.我一直在努力调整使用messageHandlers将数据传递到d3JS的 this example .这超出了我的专业知识,所以我正在寻求一些帮助.我很确定它出现在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",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',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',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

解决方法

你很近.它只需稍加修改即可使用; twoNodes.js中的第3行应该是

var dataset = message;

相关文章

前言 做过web项目开发的人对layer弹层组件肯定不陌生,作为l...
前言 前端表单校验是过滤无效数据、假数据、有毒数据的第一步...
前言 图片上传是web项目常见的需求,我基于之前的博客的代码...
前言 导出Excel文件这个功能,通常都是在后端实现返回前端一...
前言 众所周知,js是单线程的,从上往下,从左往右依次执行,...
前言 项目开发中,我们可能会碰到这样的需求:select标签,禁...