2017-01-14 37 views
-1

我试图给颜色的边缘,但愿望的结果是不符合我的愿望。颜色方案每改变一次JSON文件改变。如何为d3js图形的边缘赋予颜色?

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="D3js_edges_connected_by_nodes_id.WebForm1" %> 

<!DOCTYPE html> 

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <script type="text/javascript" src="http://d3js.org/d3.v2.min.js"></script> 
    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8/jquery.min.js"></script> 
    <title>Weighted Citation Graph</title> 
    <style> 
     path.link { 
      fill: none; 
      stroke: #666; 
      stroke-width: 1.5px; 
     } 

     circle { 
      fill: #ccc; 
      stroke: #333; 
      stroke-width: 1.5px; 
     } 

     text { 
      font: 10px sans-serif; 
      pointer-events: none; 
     } 

      text.shadow { 
       stroke: #fff; 
       stroke-width: 3px; 
       stroke-opacity: .8; 
      } 

     body { 
      background-color: white; 
      margin: 0px; 
     } 

     .graphContainer { 
      text-shadow: -1px -1px 0 white, 1px -1px 0 white, -1px 1px 0 white, 1px 1px 0 white; 
     } 
    </style> 
    <script> 
     function load_graph(text) { 

      var color = d3.scale.category20(); 
      try{ 
       //var data = JSON.parse(text); 
      } catch (e) { 
       window.alert("sometext: "+e); 
      } 

      var data = { "nodes": [{ "id": 127230, "name": "Optimization of query evaluation algorithms", "citation": 26, "group": 7 }, { "id": 127254, "name": "Flow algorithms for parallel query optimization", "citation": 22, "group": 7 }, { "id": 127380, "name": "Randomized approximation algorithms for query optimization problems on two processors", "citation": 14, "group": 7 }, { "id": 127438, "name": "Optimization algorithms for simultaneous multidimensional queries in OLAP environments", "citation": 12, "group": 7 }, { "id": 127063, "name": "Query optimization in database systems", "citation": 230, "group": 7 }, { "id": 127158, "name": "Query optimization in a memory-resident domain relational calculus database system", "citation": 41, "group": 7 }, { "id": 129760, "name": "An Overview of TQuel", "citation": 22, "group": 7 }, { "id": 129867, "name": "ADVISORS", "citation": 10, "group": 7 }, { "id": 129872, "name": "Tellabs and THRIP through the Telkom Centre of Excellence at Rhodes University.", "citation": 10, "group": 7 }, { "id": 127412, "name": "Optimal service ordering in decentralized queries over web services", "citation": 13, "group": 7 }, { "id": 130856, "name": "Queries over Web Services", "citation": 10, "group": 7 }, { "id": 130959, "name": "Exploiting Parallelism to Accelerate Keyword Search On Deep-web Sources", "citation": 10, "group": 7 }, { "id": 131199, "name": "Contents lists available at ScienceDirect Future Generation Computer Systems", "citation": 10, "group": 7 }, { "id": 131211, "name": "Flow Algorithms for Parallel Query Optimization", "citation": 10, "group": 7 }, { "id": 127373, "name": "Multi-query Optimization for On-Line Analytical Processing", "citation": 14, "group": 7 }, { "id": 133379, "name": "Concise descriptions of subsets of structured sets", "citation": 21, "group": 7 }], "links": [{ "source": 127230, "target": 127063, "name": "Most Similar", "value": 100, "grouo": "#1A4876" }, { "source": 127230, "target": 127158, "name": "71 %", "value": 71, "grouo": "#1F75FE" }, { "source": 127230, "target": 129760, "name": "Nothing Matched", "value": 10, "grouo": "#EE204D" }, { "source": 127230, "target": 129867, "name": "Nothing Matched", "value": 10, "grouo": "#EE204D" }, { "source": 127230, "target": 129872, "name": "Nothing Matched", "value": 10, "grouo": "#EE204D" }, { "source": 127230, "target": 127063, "name": "Most Similar", "value": 100, "grouo": "#1A4876" }, { "source": 127230, "target": 127158, "name": "71 %", "value": 71, "grouo": "#1F75FE" }, { "source": 127230, "target": 129760, "name": "Nothing Matched", "value": 10, "grouo": "#EE204D" }, { "source": 127230, "target": 129867, "name": "Nothing Matched", "value": 10, "grouo": "#EE204D" }, { "source": 127230, "target": 129872, "name": "Nothing Matched", "value": 10, "grouo": "#EE204D" }, { "source": 127254, "target": 127412, "name": "5 %", "value": 5, "grouo": "#1F75FE" }, { "source": 127254, "target": 130856, "name": "2 %", "value": 2, "grouo": "#1F75FE" }, { "source": 127254, "target": 130959, "name": "Least Similar", "value": 10, "grouo": "#ACE5EE" }, { "source": 127254, "target": 131199, "name": "Nothing Matched", "value": 10, "grouo": "#EE204D" }, { "source": 127254, "target": 131211, "name": "Most Similar", "value": 100, "grouo": "#1A4876" }, { "source": 127254, "target": 127412, "name": "5 %", "value": 5, "grouo": "#1F75FE" }, { "source": 127254, "target": 130856, "name": "2 %", "value": 2, "grouo": "#1F75FE" }, { "source": 127254, "target": 130959, "name": "Least Similar", "value": 10, "grouo": "#ACE5EE" }, { "source": 127254, "target": 131199, "name": "Nothing Matched", "value": 10, "grouo": "#EE204D" }, { "source": 127254, "target": 131211, "name": "Most Similar", "value": 100, "grouo": "#1A4876" }, { "source": 127438, "target": 127373, "name": "Most Similar", "value": 100, "grouo": "#1A4876" }, { "source": 127438, "target": 133379, "name": "3 %", "value": 3, "grouo": "#1F75FE" }, { "source": 127438, "target": 127373, "name": "Most Similar", "value": 100, "grouo": "#1A4876" }, { "source": 127438, "target": 133379, "name": "3 %", "value": 3, "grouo": "#1F75FE" }] }; 
      // used to store the number of links between two nodes. 
      // mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex; 
      var mLinkNum = {}; 

      // sort links first 
      // sortLinks(); 

      data.links.sort(function (a, b) { 
       if (a.source > b.source) { return 1; } 
       else if (a.source < b.source) { return -1; } 
       else { 
        if (a.target > b.target) { return 1; } 
        if (a.target < b.target) { return -1; } 
        else { return 0; } 
       } 
      }) 

      // set up linkIndex and linkNumer, because it may possible multiple links share the same source and target node 
      setLinkIndexAndNum(); 

      var w = 1345, 
       h = 1000; 

      //var w = 3000, 
      // h = 3000; 

      var force = d3.layout.force() 
      .size([w, h]) 
      .linkDistance(200) 
      .charge(-800) 
      .on("tick", tick); 

      var svg = d3.select(".graphContainer").append("svg:svg") 
      .attr("width", w) 
      .attr("height", h); 

      var color = d3.scale.category10() 
      var edges = []; 
      data.links.forEach(function (e) { 
       var sourceNode = data.nodes.filter(function (n) { 
        return n.id === e.source; 
       })[0], 
        targetNode = data.nodes.filter(function (n) { 
         return n.id === e.target; 
        })[0]; 

       edges.push({ 
        source: sourceNode, 
        target: targetNode, 
        name: e.name, 
        value: e.value, 
        linkindex: e.linkindex, 
        grouo: e.grouo 
       }); 
      }); 

      console.log(edges) 
      force 
       .nodes(data.nodes) 
       .links(edges) 
       .start(); 

      var path = svg.append("svg:g") 
      .selectAll("line") 
      .data(edges) 
      .enter().append("svg:path") 
      .attr("class", "link") 
      .style("stroke-width", function (d, i) { 
       console.log(d.value) 
       return Math.sqrt(d.value); 
      }).style('stroke', function (d) { 
       return color(d.grouo); 
      }); 

      //path.append("title").text(function (d) { return d.name }); 

      var circle = svg.append("svg:g") 
      .selectAll("circle") 
      .data(force.nodes()) 
      .enter().append("svg:circle") 
      .attr("r", function (d) { 
       return (Math.sqrt(d.citation)); 
      }) 
      .style("fill", function (d) { 
       return color(d.group); 
      }) 
      .call(force.drag); 

      circle.append("title").text(function (d) { return d.name }); 

      //circle.on("click", function() { 
      // d3.select(this) 
      // .attr("r", function (d) { 
      //  return (Math.sqrt(d.citation) * 2); 
      // }) 
      // .style("fill", "lightsteelblue"); 
      //}); 

      circle.on("click", function (d) { 
       var thisNode = d.id 
       var connected = data.links.filter(function (e) { 
        return e.source === thisNode || e.target === thisNode 
       }); 
       circle.attr("opacity", function (d) { 
        return (connected.map(d => d.source).indexOf(d.id) > -1 || connected.map(d => d.target).indexOf(d.id) > -1) ? 1 : 0.1 
       }); 

       path.attr("opacity", function (d) { 
        return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 0.1 
       }); 
      }) 

      circle.on("dblclick", function (d) { 
       var thisNode = d.id 
       var connected = data.links.filter(function (e) { 
        return e.source === thisNode || e.target === thisNode 
       }); 
       circle.attr("opacity", function (d) { 
        return (connected.map(d => d.source).indexOf(d.id) > -1 || connected.map(d => d.target).indexOf(d.id) > -1) ? 1 : 1 
       }); 

       path.attr("opacity", function (d) { 
        return (d.source.id == thisNode || d.target.id == thisNode) ? 1 : 1 
       }); 
      }) 

      var text = svg.append("svg:g") 
      .selectAll("g") 
      .data(force.nodes()) 
      .enter().append("svg:g"); 
      console.log('test'); 
      //A copy of the text with a thick white stroke for legibility. 
      //text.append("svg:text") 
       //.attr("x", 8) 
       //.attr("y", ".31em") 
       //.attr("class", "shadow") 
       //.text(function (d) { 
        //return d.name; 
       //}); 

      text.append("svg:text") 
       .attr("x", 8) 
       .attr("y", ".31em") 
       .text(function (d) { 
       // return d.name; 
       }); 



      // Use elliptical arc path segments to doubly-encode directionality. 
      function tick() { 
       path.attr("d", function (d, i) { 
        var dx = d.target.x - d.source.x, 
         dy = d.target.y - d.source.y, 
         dr = 75 * d.linkindex; //linknum is defined above 
        var output = "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; 
        //console.log(d) 
        return "M" + d.source.x + "," + d.source.y + "A" + dr + "," + dr + " 0 0,1 " + d.target.x + "," + d.target.y; 
       }); 

       // Add tooltip to the connection path 
       path.append("svg:title") 
        .text(function (d, i) { 
         return d.name; 
        }); 

       circle.attr("transform", function (d) { 
        return "translate(" + d.x + "," + d.y + ")"; 
       }); 

       text.attr("transform", function (d) { 
        return "translate(" + d.x + "," + d.y + ")"; 
       }); 
      } 

      // sort the links by source, then target 
      function sortLinks1() { 
       data.links.sort(function (a, b) { 
        if (a.source > b.source) { 
         return 1; 
        } else if (a.source < b.source) { 
         return -1; 
        } else { 
         if (a.target > b.target) { 
          return 1; 
         } 
         if (a.target < b.target) { 
          return -1; 
         } else { 
          return 0; 
         } 
        } 
       }); 
      } 



      //any links with duplicate source and target get an incremented 'linknum' 
      function setLinkIndexAndNum1() { 
       for (var i = 0; i < data.links.length; i++) { 
        if (i != 0 && 
         data.links[i].source == data.links[i - 1].source && 
         data.links[i].target == data.links[i - 1].target) { 
         data.links[i].linkindex = data.links[i - 1].linkindex + 1; 
         console.log(data.links[i].linkindex) 
        } else { 
         data.links[i].linkindex = 1; 
         console.log(data.links[i].linkindex) 
        } 
        // save the total number of links between two nodes 
        if (mLinkNum[data.links[i].target + "," + data.links[i].source] !== undefined) { 
         mLinkNum[data.links[i].target + "," + data.links[i].source] = data.links[i].linkindex; 
        } else { 
         mLinkNum[data.links[i].source + "," + data.links[i].target] = data.links[i].linkindex; 
        } 
       } 
      } 


      function setLinkIndexAndNum() { 

       for (var i = 0; i < data.links.length; i++) { 
        if (i != 0 && 
         data.links[i].source == data.links[i - 1].source && 
         data.links[i].target == data.links[i - 1].target) { 
         data.links[i].linkindex = data.links[i - 1].linkindex + 1; 
        } 
        else { 
         data.links[i].linkindex = 1; 
        }; 
       }; 
      } 
     } 
    </script> 
</head> 
<body> 
    <form id="form1" runat="server"> 
    <div> 
    <script src="//d3js.org/d3.v3.min.js"></script> 
     <%--<textarea runat="server" id="textarea" cols="80" rows="20"></textarea> 
     <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label>--%> 
    </div> 
     <div id="graphContainer" class="graphContainer"></div> 
    </form> 
</body> 
</html> 

任何人都可以帮助我。谢谢! 如果你看看数据变量,我已经根据“name”属性的描述为每个边赋予了不同的颜色。

+0

'我想给颜色的边缘,但愿望的结果不符合我的愿望:什么你的愿望是? – Mark

+0

如果名称属性包含“不匹配”,则链接的颜色应为红色。 如果name属性包含“最不相似”,则链接的颜色应该是浅蓝色。 如果name属性包含“最相似”,则链接的颜色应该是深蓝色。 –

回答

2

您看到不同颜色的原因是因为颜色比例d3.scale.category10() - 与所有d3序数比例(至少在v3中)一样 - 按先到先得的原则分配其颜色。

https://github.com/d3/d3-3.x-api-reference/blob/master/Ordinal-Scales.md#_ordinal

所以,如果你用组改变了你的JSON所以节点'是第一次遇到,那么它和随后的组“A”的节点将被赋予在规模第一的颜色。如果以前它是首先遇到的具有组“B”的节点,则具有组“B”的所有节点都将获得该颜色。

避免这种情况的一种方法是在设置单个节点的颜色之前,先对数据进行整理,排序,然后将它们作为域传递给您的色阶。这样A,B等每次都会以相同的顺序。

但是,这对于数据发生变化意味着特定组完全缺失的情况无效,您仍会看到颜色分配发生变化。为此,您需要提供所有可能组的固定列表以分配给色标,即使这些组并非全部位于当前数据中。

PS。您将color分配到category20颜色比例,然后再将其重新分配到category10。这对你为什么看到你所看到的没有任何影响,因为直到事后才使用color

PPS。我注意到的另一件事是,如.grouo数据所定义的链接颜色已经是十六进制颜色字符串。我怀疑你不打算通过他们的color规模和意味着使用它们,因为它们是,即style ("stroke", function(d) { return d.grouo; ]);

+0

感谢兄弟...我已经得到它! –