赞
踩
项目背景
这个是一个金融建模比赛的题目,本人和队友拿了一等奖(感谢慷慨的金主爸爸)。该题目分析企业自身的主要数据,企业与企业、企业与个人、个人与个人之间的关系数据,建设企业的关联关系图谱,识别对公客户的关联关系,并找出关联关系中的风险点。
代码说明
以下代码将是我GitHub中的其中一个页面,主要目的是展示企业之间的担保关系,其他关系的代码可以以此进行推演。主要框架是D3.js
开源地址(有用的话记得follow一下并点个star哦)
https://github.com/lebron-li/Visualization-of-risk-control-based-on-Enterprise-Association-Graph.git
答辩ppt
很多效果和使用说明在PPT中
链接:https://pan.baidu.com/s/1Sl8EpcqTrQhiUrZH90wHzw
提取码:1984
复制这段内容后打开百度网盘手机App,操作更方便哦
其实还有很多特性没写出来,有兴趣的可以clone去跑一跑
//svg的元素g是用来组合对象的容器。添加到g元素上的变换会应用到其所有的子元素上。添加到g元素的属性会被其所有的子元素继承。 var svg = d3.select(".svg1"); //为指定的类型调用每个注册的回调,将指定的参数传递给回调,并将其作为 this 上下文 svg.call(d3.zoom() //对zoom这个事件进行链式调用绑定事件 .scaleExtent([0.1, 8])//使用scaleExtent来控制zoom的缩小和扩大范围 .on("zoom", function () {//在svg绑定zoom事件后,监听zoom事件,然后将缩放结果返回给绑定的g,直接给g绑定zoom会出现抖动情况,体验很差 $("g").attr("transform", d3.event.transform) }) ); //无论屏幕大小是多少,每次关联图谱的初始化中心都能在一个合适的位置 var svgCenterWidth=document.documentElement.clientWidth/3; var svgCenterHeight=document.documentElement.clientHeight/2; //利用d3.forcesimulation()定义关系图 //包括设置边link,排斥电荷charge,关系图中心点,表示如何展示 var simulation = d3.forceSimulation() .force("link", d3.forceLink().id(function (d) { return d.id; })) //使用默认参数创建新的多实体力 //API可参考https://github.com/d3/d3-force/blob/v2.1.1/README.md#forceManyBody .force("charge", d3.forceManyBody()) //使用指定的x和y坐标创建新的定心力 //API可参考https://github.com/d3/d3-force/blob/v2.1.1/README.md#forceCenter .force("center", d3.forceCenter(svgCenterWidth, svgCenterHeight));
对于forceSimulation的优化可参考D3.js 力导向图的显示优化
var graph; d3.json("../../res/json/guarantee_json/demo.json", function (error, data) { if (error) throw error; graph = data; //g用于绘制所有边,selectALL选中所有的line,并绑定数据data(graph.links) //enter().append("line")添加元素 var link = svg.append("g").attr("class", "links") .selectAll("line").data(graph.links)//数据驱动文档 .enter().append("line") .attr("stroke-width", function (d) { //这里设置边的粗细,d.amount是数据中一次担保关系的担保金额 //如果担保金额越大,边就越粗 //为了展示效果,调用了math.sqrt进行了两次开方 return Math.sqrt(Math.sqrt(d.amount))/20; }) //把担保金额显示在边上 var edgesText = svg.append("g") .selectAll('.linetext') .data(graph.links) .enter() // 对所有的links,可能是null元素 .append('text') .attr('class',"edgesTexts") .text((d) => { return d.amount; }) .attr("font-size", function (d) { return 5; }) .attr('fill','#f2f2f2') .attr('opacity','0.5') //由于是有向图,所以这里设置箭头属性 //marker元素定义了在特定的<path>元素、<line>元素、<polyline>元素或者<polygon>元素上绘制的箭头或者多边标记图形 var marker= svg.append("marker") .attr("id", "resolved") //userSpaceOnUse指定markerWidth和markerUnits属性以及<marker>元素的内容表示当前用户坐标系中引用标记的图形对象的值 //即通过标记、标记开始、标记中间、,或标记结束属性 .attr("markerUnits","userSpaceOnUse") .attr("viewBox", "0 -5 10 10") .attr("refX",26) .attr("refY", 0) .attr("markerWidth", 5) .attr("markerHeight", 6) .attr("orient", "auto") .attr("stroke-width",2) .append("path") .attr("d", "M0,-5L10,0L0,5") .attr('fill','#4e88af'); // <circle> SVG 元素是一个SVG的基本形状,用来创建圆,基于一个圆心和一个半径。 var node = svg.append("g").attr("class", "nodes") selectAll("circle")选中所有的圆并绑定数据 .selectAll("circle").data(graph.nodes) .enter().append("circle").attr("r", function (d) { return d.size/4+2; }).attr("fill", function (d) { return colors[d.group]; }) .attr("stroke", 'none') .attr("name", function (d) { return d.id; }).call( d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended)); //给每一个node设置texts,在texts模式下使用 var text = svg.append("g").attr("class", "texts") .selectAll("text").data(graph.nodes) .enter().append("text") //text的大小和每个节点的size正相关 //在之前的数据分析中,size和该节点的风险传播能力呈正相关 .attr("font-size", function (d) { return d.size/4+2; }).attr("fill", function (d) { return colors[d.group]; }).attr("name", function (d) { return d.id; }).text(function (d) { return d.id; }).attr("text-anchor", 'middle') //当拖动开始绑定dragstarted函数 //拖动进行时绑定dragstarted函数 //拖动结束绑定dragended函数 .call( d3.drag() .on("start", dragstarted) .on("drag", dragged) .on("end", dragended) ); node.append("title").text(function (d) { return d.id; }); //ticked数据初始化,生成每个结点的位置 //按指定的迭代次数手动逐步执行模拟,并返回模拟。 //对于每个迭代,它将当前alpha增加(alphaTarget-alpha)×alphaDecay;然后调用每个注册的力,传递新的alpha;然后将每个节点的速度减少 simulation //如果指定了节点,则将模拟的节点设置为指定的对象数组 //必要时初始化其位置和速度,然后重新初始化任何绑定力 .nodes(graph.nodes) //ticked是listener, //If listener is specified, sets the event listener for the specified typenames and returns this simulation. .on("tick", ticked); //力的强度与链接节点的距离和目标距离之间的差成比例,类似于弹簧力 simulation.force("link") .links(graph.links)
如果对以上代码还不好理解的同学,可以翻阅d3-force的官方文档
function ticked() { 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; }) .attr("marker-end", "url(#resolved)"); edgesText.attr('x', function (d) { return (d.source.x + d.target.x) / 2-1; }) edgesText.attr('y', function (d) { return (d.source.y + d.target.y) / 2 }) node .attr("cx", function (d) { return d.x; }) .attr("cy", function (d) { return d.y; }); text.attr('transform', function (d) { return 'translate(' + d.x + ',' + (d.y + d.size / 2) + ')'; }); }
var dragging = false; //开始拖动并更新相应的node //alpha大致类似于模拟退火中的温度。当模拟“冷却”时,它会随着时间的推移而减少。 function dragstarted(d) { if (!d3.event.active) simulation.alphaTarget(0.1).restart(); d.fx = d.x; d.fy = d.y; dragging = true; } //拖动进行中 function dragged(d) { d.fx = d3.event.x; d.fy = d3.event.y; } //拖动结束 //alphaTarget的值从0-1,控制nodes拖拽后返回的速度 function dragended(d) { if (!d3.event.active) simulation.alphaTarget(0); d.fx = null; d.fy = null; dragging = false; }
//点击circle的时候显示的是圆圈,点击text的时候显示结点中文信息
//我在css中将nodes和text默认显示设为隐藏,当类设置为active时就为显示
$('.mode span').click(function (event){
$('.mode span').removeClass('active');
$(this).addClass('active');
if ($(this).text()=='Circles'){
$('.texts text').hide();
$('.nodes circle').show();
}else{
$('.texts text').show();
$('.nodes circle').hide();
}
});
$('.svg1').on('mouseenter','.nodes circle', function (event){ var name =$(this).attr('name'); //每一个子图都会有一个id,标记为Gid //ctx_name为该节点的介绍或者说是详情 var Gid_name = $(this)['context'].__data__.Gid; var ctx_name= $(this)['context'].__data__.ctx; //当鼠标hover到某一个节点的时候,右上角会出现节点详情,在源代码body中为info类 //标题的填充色赋给了右上角的节点详情文字 $('.info h5').css('color', $(this).attr('fill')).text('id: '+name); $('.info h4').css('color', $(this).attr('fill')).text('type: '+ctx_name); $('.info p').remove(); //!dragging可以防止在拖动的过程中hover到其他nodes或texts if (!dragging) { d3.select(".svg1 .nodes").selectAll('circle').attr('class', function (d) { if (d.id == name) { return ''; } //只有是和hover的那个node或text同一个子图的才会保留 for (var i = 0; i < graph.links.length; i++) { if (graph.links[i]['source'].Gid == Gid_name && graph.links[i]['target'].Gid == d.Gid) { return ''; } if (graph.links[i]['target'].Gid == Gid_name && graph.links[i]['source'].Gid == d.Gid) { return ''; } } //否则给一个‘inactive’类将其隐藏,‘inactive’在css文件中有预设 return 'inactive'; });
$('.svg1').on('mouseleave', '.nodes circle', function(event) {
if (!dragging) {
d3.select('.svg1 .nodes').selectAll('circle').attr('class', '');
d3.select('.svg1 .links').selectAll('line').attr('class', '');
}
});
$('.search1 input').keyup(function(event) { if ($(this).val() == '') { d3.select('.svg1 .texts').selectAll('text').attr('class', ''); d3.select('.svg1 .nodes').selectAll('circle').attr('class', ''); d3.select('.svg1 .links').selectAll('line').attr('class', ''); } else { var name = $(this).val(); d3.select('.svg1 .nodes').selectAll('circle').attr('class', function(d) { if (d.id.toLowerCase().indexOf(name.toLowerCase()) >= 0) { return ''; } else { return 'inactive'; } }); d3.select('.svg1 .texts').selectAll('text').attr('class', function(d) { if (d.id.toLowerCase().indexOf(name.toLowerCase()) >= 0) { return ''; } else { return 'inactive'; } }); d3.select(".svg1 .links").selectAll('line').attr('class', function(d) { return 'inactive'; }); } });
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。