欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

D3临摹作业(西安交大国家艺术基金数据可视化培训第23天)

程序员文章站 2024-02-13 17:18:46
...

力导向算法

也称为弹簧算法,基于物理系统的引力斥力模型为图上的node和edge布局,用于解决重叠问题。


应用:

网络层级气泡蜂房、布匹


绘制过程:

数据(node/edge表示图或网络)-->d3.layout.force()计算节点的位置-->绘制节点(circle/rect)-->绘制边(line/path)


基本原理:

代码:

<html>
    <head>
        <meta charset="utf-8">
        <title>一个简单的力引导案例</title>
        <style>
            .node {
              stroke: #fff;
              stroke-width: 1.5px;
            }
            .link {
              stroke: #999;
              stroke-opacity: .6;
            }
        </style>
    </head>

    <body>
        <script src="d3.v3.min.js"></script>
        <script>
            var width=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)*0.98;
            var height=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)*0.9;
            
            var color = d3.scale.category20();


            var force = d3.layout.force()      //创建为力引导布局
                .charge(-120)
                .linkDistance(200)
                .size([width, height]);

            var svg = d3.select("body").append("svg")   //添加svg绘图区
                .attr("width", width)
                .attr("height", height);
            d3.json("a.json", function(error, graph) {
                  console.log(graph);                  
                  force.nodes(graph.nodes)             //绑定图的节点和数据
                       .links(graph.links)
                       .start();
                  
                  var node = svg.selectAll(".node")    //绘制圆形表示节点
                      .data(graph.nodes)
                      .enter().append("circle")
                      .attr("class", "node")
                      .attr("r", 16)
                      .style("fill", function(d) { return color(d.group); })
                      .call(force.drag);

                  var link = svg.selectAll(".link")       //绘制直线表示边
                      .data(graph.links)
                      .enter().append("line")
                      .attr("class", "link")
                      .style("stroke-width", function(d) { return Math.sqrt(d.value); });
                  force.on("tick", function() {
                    link.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; });

                    node.attr("cx", function(d) { return d.x; })
                        .attr("cy", function(d) { return d.y; });
                  });
                });

        </script>
    </body>
</html>

 

节点相关参数:

[D3]

  参数 特点 代码
基本配置参数 d3.layout.force()    
节点相关参数 force.node([nodes])    
force.size([width,height])    
force.friction([])    
force.charge([])    
force.chargeDistance([])    
force.gravity([])    
force.theta([])    
连线相关参数 force.links([])    
force.linkDistance([])    
force.linkStrength([])    
动画相关参数 force.alpha([])    
force.start()    
force.stop()    
force.tick()    
交互相关参数 force.drag() 与call一起使用 node.call(force.drag)


综合案例:

人物社会关系图(代码来源:《数据可视化原理与实例》)


<html>    
  <head>      
  <title>
    《人名的名义》人物关系
  </title>
     <style>
      path{
        fill: none;
        stroke: #666;
        stroke-width: 1.5px;
      }
      circle {
        stroke: #333;
        stroke-width: 1.5px;
      }
      text {
        font: 10px sans-serif;
        pointer-events: none;
      }
      .tooltip{  
        position: absolute;  
        width: 240px;  
        height: auto;  
        font-family: simsun;  
        font-size: 10px;
        text-align: left;  
        color: black;  
        border-width: 1px solid black;  
        background-color: 7FFF00;  
        border-radius: 3px;  
      }  
      .tooltip:after{   
        content: '';  
        position: absolute;  
        bottom: 100%;  
        left: 20%;  
        margin-left: -3px;  
        width: 0;  
        height: 0;  
        border-bottom: 12px solid black;  
        border-right: 12px solid transparent;  
        border-left: 12px solid transparent;  
      }  
  </style>  
  </head>   
  <body style=" opacity:1"> 
    <script src="d3.v3.min.js" charset="utf-8" ></script>  
  <script type="text/javascript">  
    var  width=(window.innerWidth||document.documentElement.clientWidth||document.body.clientWidth)*0.98;
    var  height=(window.innerHeight||document.documentElement.clientHeight||document.body.clientHeight)*0.9;
    var  img_h=50;
    var  img_w=50;
    var  radius=10;
    var svg=d3.select("body")  
                .append("svg")  
                .attr("width",width)  
                .attr("height",height);   
    var nodes=[{name:"侯亮平",image:"hlp.jpg",intro:"侯亮平是最高检反贪局侦查处处长,汉东省人民检察院副检察长兼反贪局局长。经过与腐败违法分子的斗争,最终将一批腐败分子送上了审判台,正义战胜邪恶,自己也迎来了成长。"},
        {name:"高育良",image:"gyl.jpg",intro:"高育良是汉东省省委副书记兼政法委书记。年近六十,是一个擅长太极功夫的官场老手。侯亮平、陈海和祁同伟都是其学生。"},
        {name:"祁同伟",image:"qtw.jpg",intro:"祈同伟是汉东省*厅厅长。出身农民,曾想凭自己的努力走上去,内心渴望成为一个胜天半子的人,但现实却沉重地打击了他,进而走上了不归路"},
        {name:"陈海",image:"ch.jpg",intro:"陈海是汉东省人民检察院反贪局局长。他不畏强权、裁决果断,一出场就与汉东官场权利正面交锋;他廉明正直、重情重义,与好兄弟侯亮平携手战斗在反腐第一线,他遭遇暗害惨出车祸而躺在医院。"},
        {name:"蔡成功",image:"ccg.jpg",intro:"蔡成功是汉东省大风厂董事长、法人代表,为人狡诈,为了招标成功而贿赂*官员,甚至连发小反贪局局长侯亮平也企图想去贿赂。"},
        {name:"高小琴",image:"gxq.jpg",intro:"高小琴是山水集团董事长,也是一位叱咤于政界和商界的风云人物,处事圆滑、精明干练。在与官员沟通时更是辩口利辞,沉稳大气,拥有高智商和高情商,并得到以“猴精”著称的反贪局长侯亮平冠以“美女蛇”的称号。"},
              {name:"高小凤",image:"gxf.jpg",intro:"高小凤是高小琴的孪生妹妹,高育良的情妇。"},
        {name:"陆亦可",image:"lyk.jpg",intro:"陆亦可是汉东省检察院反贪局的女检查官,表面冷峻决绝,内心重情重义。大龄未嫁的她面临着家庭逼婚的困境,而她抗婚是因为对反贪局长陈海一往情深。然而陈海惨遭横祸,她收起悲愤去探求真相拨云见雾,同时在*局长赵东来的追求中获得真爱。"},
        {name:"赵东来",image:"zdl.jpg",intro:"赵东来是汉东省京州市*局局长。看似直来直去,但却深谋远虑,智勇双全。为了保护正义的尊严,报着坚决整治恶*的决心,在与检察部门的合作中从最初的质疑到之后的通力配合,展现出现代执法机构的反腐决心。"},
        {name:"陈岩石",image:"cys.jpg",intro:"陈岩石是离休*、汉东省检察院前常务副检察长。充满正义,平凡而普通的*人。对大老虎赵立春,以各种形式执着举报了十二年。在这场关系*生死存亡的斗争中,老人家以耄耋高龄,义无反顾"},
        {name:"李达康",image:"ldk.jpg",intro:"李达康是汉东省省委常委,京州市市委书记,是一个正义无私的好官。但为人过于爱惜自己的羽毛,对待身边的亲人和朋友显得过于无情"},
        {name:"沙瑞金",image:"srj.jpg",intro:"沙瑞金是汉东省省委书记。刚至汉东便发生丁义珍出逃美国事件,又遇到大风厂案。深知汉东政治情况的沙瑞金支持侯亮平查案,要求他上不封顶。"},
        {name:"欧阳菁",image:"oyj.jpg",intro:"欧阳菁是汉东省京州市城市银行副行长,京州市市委书记李达康的妻子,后因感情不和离婚。她曾利用职务的便利贪赃枉法。"},
        {name:"丁义珍",image:"dyz.jpg",intro:"丁义珍英文名汤姆丁。汉东省京州市副市长兼光明区区委书记。贪污腐败,逃往国外。"},
        {name:"季昌明",image:"jcm.jpg",intro:"季昌明是汉东省省级检察院检察长。清廉负责,为人正直,性格温和,但也有些拘泥于教条。对初到汉东省的侯亮平提供了极大地帮助,为**案件起到了极大地作用。"},
        {name:"钟小艾",image:"zxa.jpg",intro:"钟小艾是侯亮平的妻子,中纪委调查组的委派员。"},
        {name:"赵瑞龙",image:"zrl.jpg",intro:"赵瑞龙是副国级人物赵立春的公子哥,官二代,打着老子的旗子,黑白两道通吃,权倾一时。把汉东省搅得天翻地覆。"}];
    var edges=[{source:0,target:1,relation:"师生"},{source:0,target:2,relation:"同门"},{source:0,target:3,relation:"同学&挚友"},
             {source:0,target:4,relation:"发小"},{source:0,target:7,relation:"同事"}, {source:0,target:15,relation:"夫妻"}, 
         {source:14,target:0,relation:"上下级"},{source:1,target:2,relation:"师生"},{source:1,target:3,relation:"师生"}, 
         {source:1,target:6,relation:"情人"}, {source:1,target:11,relation:"上下级"},{source:1,target:10,relation:"政敌"},
         {source:2,target:5,relation:"情人"}, {source:2,target:3,relation:"同门&陷害"},  {source:2,target:11,relation:"上下级"},
         {source:3,target:9,relation:"父子"},{source:4,target:5,relation:"商业对手"},{source:5,target:6,relation:"孪生姐妹"}, 
         {source:8,target:11,relation:"上下级"},{source:9,target:11,relation:"故交"},
         {source:10,target:11,relation:"上下级"},{source:10,target:12,relation:"夫妻"},{source:13,target:10,relation:"上下级"},
         {source:12,target:4,relation:"受贿关系"},{source:16,target:2,relation:"利益关系"},{source:16,target:5,relation:"利益关系"}];
         
    var force=d3.layout.force()
                .nodes(nodes)
        .links(edges)
        .size([width,height])
        .linkDistance(150)
        .charge(-1200)
                .start(); 
        //提示框部分
    var tooltip=d3.selectAll("body")  
                    .append("div")  
                    .attr("class","tooltip")  
                    .style("opacity",0.0); 

       //箭头绘制 
    var defs = svg.append("defs");
    var radius=10;
    var arrowMarker = defs.append("marker")
                .attr("id","arrow")
                .attr("markerUnits","strokeWidth")
                .attr("markerWidth","4")
                .attr("markerHeight","4")
                .attr("viewBox","0 0 4 4")
                .attr("refX",20+radius/8-2)   //实际是radius/strokeWidth
                .attr("refY",2)
                .attr("orient","auto");

    var arrow_path = "M0,1 L4,2 L0,3 L0,0";

    arrowMarker.append("path")
          .attr("d",arrow_path);          
    var color=d3.scale.category20();
    var path = svg.selectAll("path")
                  .data(edges)
                  .enter()
                  .append("path")
                  .attr("id", function(d,i) {
                     return "edgepath" +i;
                  })
                  .attr("class","edges")
                  .attr("marker-end","url(#arrow)");    
    var pathtext = svg.selectAll('.pathText')
          .data(edges)
          .enter()
          .append("text")
          .attr("class","pathText")
          .append('textPath')
          .attr("text-anchor", "middle")//居中
          .attr("startOffset","50%")
          .attr('xlink:href', function(d,i) { return "#edgepath" + i; })
          .text(function(d) { return d.relation; });              
    var  img_h=50;
    var  img_w=50;
    var  radius=23;               
    var  circles=svg.selectAll("forceCircle")
                 .data(nodes)
           .enter()
           .append("circle")
           .attr("class","forceCircle")
           .attr("r",radius)
           .style("stroke","DarkGray")
           .style("stroke-width","1.0px")
           .attr("fill", function(d, i){
                                    //创建圆形图片
                                    var defs = svg.append("defs").attr("id", "imgdefs");
                                    var catpattern = defs.append("pattern")
                                                         .attr("id", "catpattern" + i)
                                                         .attr("height", 1)
                                                         .attr("width", 1);
                                    catpattern.append("image")
                                            .attr("x", - (img_w / 2 - radius+5.8))
                                            .attr("y", - (img_h / 2 - radius+3.5))
                                            .attr("width", img_w+11)
                                            .attr("height", img_h+6)
                                            .attr("xlink:href","image/"+d.image);
                                    return "url(#catpattern" + i + ")";
                    })
          .on("mouseover",function(d,i){    //加入提示框
                        tooltip.html("角色简介:"+d.intro)
                               .style("left",(d3.event.pageX)+"px")  
                               .style("top",(d3.event.pageY+20)+"px")  
                               .style("opacity",1.0);  
          })
          .on("mousemove",function(d){            
                          tooltip.style("left",(d3.event.pageX)+"px")  
                                 .style("top",(d3.event.pageY+20)+"px"); })           
                   .on("mouseout",function(d){  
                        tooltip.style("opacity",0.0); })
           .call(force.drag);  
      var texts=svg.selectAll(".forceText")
                 .data(nodes)
         .enter()
         .append("text")
         .attr("class","forceText")
         .attr("x",function(d){return d.x;})
         .attr("y",function(d){return d.y;})
         .style("stroke", "#336666")
                 .attr("dx","-1.5em")
         .attr("dy","3em")
         .text(function(d){return d.name;});
          
    force.on("tick",function(){
          path.attr("d", function(d) {
          var dx = d.target.x - d.source.x;//增量
          var dy = d.target.y - d.source.y;
          return "M" + d.source.x + ","+ d.source.y + "L" + d.target.x + "," + d.target.y;
          });
        circles.attr("cx",function(d){return d.x;});
        circles.attr("cy",function(d){return d.y;});
        texts.attr("x",function(d){return d.x;});
        texts.attr("y",function(d){return d.y;});
    });
  </script>
  </body>
</html>

a.json

{"nodes":
    [   
        {"name":"@","group":0},
        {"name":"a","group":1},
        {"name":"b","group":2}
    ],
"links":
    [
        {"source":0,"target":1,"value":1},
        {"source":1,"target":2,"value":1},
        {"source":2,"target":0,"value":1}
    ]
}

参考文献:

李春芳 石民勇 数据可视化原理与实例 中国传媒大学出版社

相关标签: D3