【问题标题】:Search box in network Plot网络图中的搜索框
【发布时间】:2016-09-14 09:25:48
【问题描述】:

我使用networkD3 包的forceNetwork() 函数创建了一个蛋白质突变网络。它在 RStudio 的“查看器”窗格中呈现。

然后我可以将其保存为 HTML 文件以供共享,同时保留动态特性(如单击节点、突出显示连接等)。

我的网络图的 png 版本如下所示:

这是我原始数据中前 20% 的表示,完整的数据看起来更加庞大和复杂。

我需要能够向这个 forceNetwork 添加搜索,以便特定节点可以位于复杂网络中。通过编辑包networkD3的副本并重新打包,可以轻松实现其中的javascript或jquery部分。但我的主要挑战是添加包含搜索框的 html 代码。

我的主要 R 代码如下所示:

library(networkD3)
library(XLConnect)

wb <- loadWorkbook("input.xlsx")
nodes <- readWorksheet(wb, sheet="Node", startRow = 1, startCol = 1, header = TRUE)
links <- readWorksheet(wb, sheet="Edges", startRow = 1, startCol = 1, header = TRUE)


fn <- forceNetwork(Links = links, Nodes = nodes,
                   Source = "Source", Target = "ID", Value = "Combo",
                   NodeID = "Mutation", linkDistance = JS('function(d){return d.value * 50;}'), 
                   Nodesize = "IF", Group = "Combo", radiusCalculation = JS("d.nodesize+6"),
                   zoom = T, bounded = F, legend = T, 
                   opacity = 0.8,
                   fontSize = 16 )

fn

我的灵感来自 Simon Raper 的 jsfiddle。 在这种情况下包含搜索的最佳方式是什么?我想到的选项是首先将渲染保存为 html。然后阅读并编辑 html 并插入用于搜索的代码。 我尝试为此使用 Rhtml,但这似乎并不简单。任何指针将不胜感激。

【问题讨论】:

    标签: html r rhtml networkd3


    【解决方案1】:

    虽然我对这种交互性并不着迷,但我认为这将是一个展示如何将htmltoolshtmlwidgets 一起使用的好机会。稍后,我将使用crosstalk 重新创建,但现在,我将复制提供的示例。

    直接复制

    library(htmltools)
    library(networkD3)
    
    data(MisLinks)
    data(MisNodes)
    
    # make a forceNetwork as shown in ?forceNetwork
    fn <- forceNetwork(
      Links = MisLinks, Nodes = MisNodes, Source = "source",
      Target = "target", Value = "value", NodeID = "name",
      Group = "group", opacity = 0.4, zoom = TRUE
    )
    
    fn <- htmlwidgets::onRender(
      fn,
      '
    function(el,x){
    debugger;
      var optArray = [];
      for (var i = 0; i < x.nodes.name.length - 1; i++) {
        optArray.push(x.nodes.name[i]);
      }
    
      optArray = optArray.sort();
    
      $(function () {
        $("#search").autocomplete({
          source: optArray
        });
      });
    
      d3.select(".ui-widget button").node().onclick=searchNode;
    
      function searchNode() {
        debugger;
        //find the node
    
        var selectedVal = document.getElementById("search").value;
        var svg = d3.select(el).select("svg");
        var node = d3.select(el).selectAll(".node");
    
        if (selectedVal == "none") {
          node.style("stroke", "white").style("stroke-width", "1");
        } else {
          var selected = node.filter(function (d, i) {
            return d.name != selectedVal;
          });
          selected.style("opacity", "0");
          var link = svg.selectAll(".link")
          link.style("opacity", "0");
          d3.selectAll(".node, .link").transition()
            .duration(5000)
            .style("opacity", 1);
        }
      }
    }  
      '
    )
    
    browsable(
      attachDependencies(
        tagList(
          tags$head(
            tags$link(
              href="http://code.jquery.com/ui/1.11.0/themes/smoothness/jquery-ui.css",
              rel="stylesheet"
            )
          ),
          HTML(
      '
      <div class="ui-widget">
          <input id="search">
          <button type="button">Search</button>
      </div>
      '     
          ),
          fn
        ),
        list(
          rmarkdown::html_dependency_jquery(),
          rmarkdown::html_dependency_jqueryui()
        )
      )
    )
    

    串音版

    注意:串扰是实验性的,所以这可能会改变

    我没有花时间进行优化和完善,但这里有一个版本,它与示例执行相同的操作,但使用 crosstalk 而不是自定义代码和 jquery-ui 自动完成。

    library(htmltools)
    library(networkD3)
    
    
    # demonstrate with experimental crosstalk
    #  this will get much easier once we start converting
    #  htmlwidgets to work natively with crosstalk
    
    #devtoools::install_github("rstudio/crosstalk")
    library(crosstalk)
    
    data(MisLinks)
    data(MisNodes)
    
    # make a forceNetwork as shown in ?forceNetwork
    fn <- forceNetwork(
      Links = MisLinks, Nodes = MisNodes, Source = "source",
      Target = "target", Value = "value", NodeID = "name",
      Group = "group", opacity = 0.4, zoom = TRUE
    )
    
    sd <- SharedData$new(MisNodes, key=~name, group="grp1" )
    
    # no autocomplete so not the same
    #  but will use this instead of writing something new
    fs <- filter_select(
      id = "filter-node",
      label = "Search Nodes",
      sharedData = sd,
      group = ~name
    )
    
    fn <- htmlwidgets::onRender(
      fn,
    '
    function(el,x){
      // get the crosstalk group
      //  we used grp1 in the SharedData from R
      var ct_grp = crosstalk.group("grp1");
    debugger;
      ct_grp
        .var("filter")
        .on("change", function(val){searchNode(val.value)});
    
      function searchNode(filter_nodes) {
        debugger;
        //find the node
        var selectedVal = filter_nodes? filter_nodes : [];
        var svg = d3.select(el).select("svg");
        var node = d3.select(el).selectAll(".node");
    
        if (selectedVal.length===0) {
          node.style("opacity", "1");
          svg.selectAll(".link").style("opacity","1");
        } else {
          var selected = node.filter(function (d, i) {
            return selectedVal.indexOf(d.name) >= 0;
          });
          node.style("opacity","0");
          selected.style("opacity", "1");
          var link = svg.selectAll(".link").style("opacity", "0");
          /*
          svg.selectAll(".node, .link").transition()
            .duration(5000)
            .style("opacity", 1);
          */
        }
      }
    }  
    '
    )
    
    browsable(
      tagList(
        fs,
        fn
      )
    )
    

    【讨论】:

    • 第一个代码示例还在工作吗?当我搜索某些内容时,单击我希望网络似乎重新渲染的节点,但是没有选择节点
    • 没关系,这对于大型网络(>1000 个节点)来说不是那么有用,因为搜索不会放大节点
    • 两种解决方案在 R(3.6.3)、htmltools(0.4.0)、networkD3(0.4.9000)、crosstalk(1.0.0) 中都不显示搜索框
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-27
    • 1970-01-01
    • 2011-02-05
    • 1970-01-01
    • 1970-01-01
    • 2016-05-20
    相关资源
    最近更新 更多