带标签和加权边的Javascript网络
我已经搜索了很长一段时间,但我找不到一个简单的JS库来创建一个网络,其中:带标签和加权边的Javascript网络,javascript,graph,visualization,Javascript,Graph,Visualization,我已经搜索了很长一段时间,但我找不到一个简单的JS库来创建一个网络,其中: 节点具有标签 边缘厚度与重量成正比 能够分散节点,使其不会变得混乱 我在bl.ocks.org上找到了一个适合我需要的脚本,但是当我使用很多节点时,它变得非常混乱: 我使用它作为输入: target,source,weight woooooow,notgood,70.0 woooooow,gainzz,32.004950495049506 woooooow,test,33.86138613861386 wooooo
- 节点具有标签
- 边缘厚度与重量成正比
- 能够分散节点,使其不会变得混乱李>
我使用它作为输入:
target,source,weight
woooooow,notgood,70.0
woooooow,gainzz,32.004950495049506
woooooow,test,33.86138613861386
woooooow,peanutss,20.866336633663366
nicecode,woooooow,22.103960396039604
woooooow,oreo,20.742574257425744
bread,woooooow,37.945544554455445
jam,nutella,20.123762376237625
bread,nutsarelol,20.866336633663366
etc
问题我可以使用哪种代码/库来创建一个类似于上面的图但节点分布更广的图 JS代码
/*
Author: Corneliu S. (github.com/upphiminn)
This is a javascript implementation of the Louvain
community detection algorithm (http://arxiv.org/abs/0803.0476)
Based on https://bitbucket.org/taynaud/python-louvain/overview
*/
(function(){
jLouvain = function(){
//Constants
var __PASS_MAX = -1
var __MIN = 0.0000001
//Local vars
var original_graph_nodes;
var original_graph_edges;
var original_graph = {};
var partition_init;
//Helpers
function make_set(array){
var set = {};
array.forEach(function(d,i){
set[d] = true;
});
return Object.keys(set);
};
function obj_values(obj){
var vals = [];
for( var key in obj ) {
if ( obj.hasOwnProperty(key) ) {
vals.push(obj[key]);
}
}
return vals;
};
function get_degree_for_node(graph, node){
var neighbours = graph._assoc_mat[node] ? Object.keys(graph._assoc_mat[node]) : [];
var weight = 0;
neighbours.forEach(function(neighbour,i){
var value = graph._assoc_mat[node][neighbour] || 1;
if(node == neighbour)
value *= 2;
weight += value;
});
return weight;
};
function get_neighbours_of_node(graph, node){
if(typeof graph._assoc_mat[node] == 'undefined')
return [];
var neighbours = Object.keys(graph._assoc_mat[node]);
return neighbours;
}
function get_edge_weight(graph, node1, node2){
return graph._assoc_mat[node1] ? graph._assoc_mat[node1][node2] : undefined;
}
function get_graph_size(graph){
var size = 0;
graph.edges.forEach(function(edge){
size += edge.weight;
});
return size;
}
function add_edge_to_graph(graph, edge){
update_assoc_mat(graph, edge);
var edge_index = graph.edges.map(function(d){
return d.source+'_'+d.target;
}).indexOf(edge.source+'_'+edge.target);
if(edge_index != -1)
graph.edges[edge_index].weight = edge.weight;
else
graph.edges.push(edge);
}
function make_assoc_mat(edge_list){
var mat = {};
edge_list.forEach(function(edge, i){
mat[edge.source] = mat[edge.source] || {};
mat[edge.source][edge.target] = edge.weight;
mat[edge.target] = mat[edge.target] || {};
mat[edge.target][edge.source] = edge.weight;
});
return mat;
}
function update_assoc_mat(graph, edge){
graph._assoc_mat[edge.source] = graph._assoc_mat[edge.source] || {};
graph._assoc_mat[edge.source][edge.target] = edge.weight;
graph._assoc_mat[edge.target] = graph._assoc_mat[edge.target] || {};
graph._assoc_mat[edge.target][edge.source] = edge.weight;
}
function clone(obj){
if(obj == null || typeof(obj) != 'object')
return obj;
var temp = obj.constructor();
for(var key in obj)
temp[key] = clone(obj[key]);
return temp;
}
//Core-Algorithm Related
function init_status(graph, status, part){
status['nodes_to_com'] = {};
status['total_weight'] = 0;
status['internals'] = {};
status['degrees'] = {};
status['gdegrees'] = {};
status['loops'] = {};
status['total_weight'] = get_graph_size(graph);
if(typeof part == 'undefined'){
graph.nodes.forEach(function(node,i){
status.nodes_to_com[node] = i;
var deg = get_degree_for_node(graph, node);
if (deg < 0)
throw 'Bad graph type, use positive weights!';
status.degrees[i] = deg;
status.gdegrees[node] = deg;
status.loops[node] = get_edge_weight(graph, node, node) || 0;
status.internals[i] = status.loops[node];
});
}else{
graph.nodes.forEach(function(node,i){
var com = part[node];
status.nodes_to_com[node] = com;
var deg = get_degree_for_node(graph, node);
status.degrees[com] = (status.degrees[com] || 0) + deg;
status.gdegrees[node] = deg;
var inc = 0.0;
var neighbours = get_neighbours_of_node(graph, node);
neighbours.forEach(function(neighbour, i){
var weight = graph._assoc_mat[node][neighbour];
if (weight <= 0){
throw "Bad graph type, use positive weights";
}
if(part[neighbour] == com){
if (neighbour == node){
inc += weight;
}else{
inc += weight/2.0;
}
}
});
status.internals[com] = (status.internals[com] || 0) + inc;
});
}
}
function __modularity(status){
var links = status.total_weight;
var result = 0.0;
var communities = make_set(obj_values(status.nodes_to_com));
communities.forEach(function(com,i){
var in_degree = status.internals[com] || 0 ;
var degree = status.degrees[com] || 0 ;
if(links > 0){
result = result + in_degree / links - Math.pow((degree / (2.0*links)), 2);
}
});
return result;
}
function __neighcom(node, graph, status){
// compute the communities in the neighb. of the node, with the graph given by
// node_to_com
var weights = {};
var neighboorhood = get_neighbours_of_node(graph, node);//make iterable;
neighboorhood.forEach(function(neighbour, i){
if(neighbour != node){
var weight = graph._assoc_mat[node][neighbour] || 1;
var neighbourcom = status.nodes_to_com[neighbour];
weights[neighbourcom] = (weights[neighbourcom] || 0) + weight;
}
});
return weights;
}
function __insert(node, com, weight, status){
//insert node into com and modify status
status.nodes_to_com[node] = +com;
status.degrees[com] = (status.degrees[com] || 0) + (status.gdegrees[node]||0);
status.internals[com] = (status.internals[com] || 0) + weight + (status.loops[node]||0);
}
function __remove(node, com, weight, status){
//remove node from com and modify status
status.degrees[com] = ((status.degrees[com] || 0) - (status.gdegrees[node] || 0));
status.internals[com] = ((status.internals[com] || 0) - weight -(status.loops[node] ||0));
status.nodes_to_com[node] = -1;
}
function __renumber(dict){
var count = 0;
var ret = clone(dict); //deep copy :)
var new_values = {};
var dict_keys = Object.keys(dict);
dict_keys.forEach(function(key){
var value = dict[key];
var new_value = typeof new_values[value] =='undefined' ? -1 : new_values[value];
if(new_value == -1){
new_values[value] = count;
new_value = count;
count = count + 1;
}
ret[key] = new_value;
});
return ret;
}
function __one_level(graph, status){
//Compute one level of the Communities Dendogram.
var modif = true,
nb_pass_done = 0,
cur_mod = __modularity(status),
new_mod = cur_mod;
while (modif && nb_pass_done != __PASS_MAX){
cur_mod = new_mod;
modif = false;
nb_pass_done += 1
graph.nodes.forEach(function(node,i){
var com_node = status.nodes_to_com[node];
var degc_totw = (status.gdegrees[node] || 0) / (status.total_weight * 2.0);
var neigh_communities = __neighcom(node, graph, status);
__remove(node, com_node, (neigh_communities[com_node] || 0.0), status);
var best_com = com_node;
var best_increase = 0;
var neigh_communities_entries = Object.keys(neigh_communities);//make iterable;
neigh_communities_entries.forEach(function(com,i){
var incr = neigh_communities[com] - (status.degrees[com] || 0.0) * degc_totw;
if (incr > best_increase){
best_increase = incr;
best_com = com;
}
});
__insert(node, best_com, neigh_communities[best_com] || 0, status);
if(best_com != com_node)
modif = true;
});
new_mod = __modularity(status);
if(new_mod - cur_mod < __MIN)
break;
}
}
function induced_graph(partition, graph){
var ret = {nodes:[], edges:[], _assoc_mat: {}};
var w_prec, weight;
//add nodes from partition values
var partition_values = obj_values(partition);
ret.nodes = ret.nodes.concat(make_set(partition_values)); //make set
graph.edges.forEach(function(edge,i){
weight = edge.weight || 1;
var com1 = partition[edge.source];
var com2 = partition[edge.target];
w_prec = (get_edge_weight(ret, com1, com2) || 0);
var new_weight = (w_prec + weight);
add_edge_to_graph(ret, {'source': com1, 'target': com2, 'weight': new_weight});
});
return ret;
}
function partition_at_level(dendogram, level){
var partition = clone(dendogram[0]);
for(var i = 1; i < level + 1; i++ )
Object.keys(partition).forEach(function(key,j){
var node = key;
var com = partition[key];
partition[node] = dendogram[i][com];
});
return partition;
}
function generate_dendogram(graph, part_init){
if(graph.edges.length == 0){
var part = {};
graph.nodes.forEach(function(node,i){
part[node] = node;
});
return part;
}
var status = {};
init_status(original_graph, status, part_init);
var mod = __modularity(status);
var status_list = [];
__one_level(original_graph, status);
var new_mod = __modularity(status);
var partition = __renumber(status.nodes_to_com);
status_list.push(partition);
mod = new_mod;
var current_graph = induced_graph(partition, original_graph);
init_status(current_graph, status);
while (true){
__one_level(current_graph, status);
new_mod = __modularity(status);
if(new_mod - mod < __MIN)
break;
partition = __renumber(status.nodes_to_com);
status_list.push(partition);
mod = new_mod;
current_graph = induced_graph(partition, current_graph);
init_status(current_graph, status);
}
return status_list;
}
var core = function(){
var status = {};
var dendogram = generate_dendogram(original_graph, partition_init);
return partition_at_level(dendogram, dendogram.length - 1);
};
core.nodes = function(nds){
if(arguments.length > 0){
original_graph_nodes = nds;
}
return core;
};
core.edges = function(edgs){
if(typeof original_graph_nodes == 'undefined')
throw 'Please provide the graph nodes first!';
if(arguments.length > 0){
original_graph_edges = edgs;
var assoc_mat = make_assoc_mat(edgs);
original_graph = { 'nodes': original_graph_nodes,
'edges': original_graph_edges,
'_assoc_mat': assoc_mat };
}
return core;
};
core.partition_init = function(prttn){
if(arguments.length > 0){
partition_init = prttn;
}
return core;
};
return core;
}
})();
/*
作者:Corneliu S.(github.com/upphiminn)
这是Louvain的javascript实现
社区检测算法(http://arxiv.org/abs/0803.0476)
基于https://bitbucket.org/taynaud/python-louvain/overview
*/
(功能(){
jLouvain=函数(){
//常数
var uu PASS_MAX=-1
var\uu MIN=0.0000001
//局部变量
var原图节点;
var原图边;
var原_图={};
var-partition_init;
//助手
函数生成集合(数组){
变量集={};
forEach(函数(d,i){
设置[d]=真;
});
返回Object.key(set);
};
函数obj_值(obj){
var VAL=[];
for(obj中的var键){
if(对象hasOwnProperty(键)){
VAL.push(对象[键]);
}
}
返回VAL;
};
函数获取节点的度(图,节点){
var neights=graph.\u assoc\u mat[node]?Object.keys(graph.\u assoc\u mat[node]):[];
变量权重=0;
forEach(函数(邻居,i){
var值=图形。_assoc_mat[节点][邻居]| 1;
if(节点==邻居)
数值*=2;
重量+=价值;
});
返回重量;
};
函数get\u node的邻居(图,节点){
if(图形类型。\u assoc\u mat[node]=“未定义”)
返回[];
var neights=Object.keys(图.assoc\u mat[node]);
返回邻居;
}
函数获取边权重(图、节点1、节点2){
返回图._assoc_mat[node1]?图._assoc_mat[node1][node2]:未定义;
}
函数获取图大小(图){
变量大小=0;
graph.edges.forEach(函数(边){
尺寸+=边缘重量;
});
返回大小;
}
函数将边添加到图(图,边){
更新相关材料(图形、边缘);
var edge_index=graph.edges.map(函数(d){
返回d.source+“”+d.target;
}).indexOf(edge.source+“”“+”edge.target);
如果(边索引!=-1)
graph.edges[edge_index].weight=edge.weight;
其他的
图.边.推(边);
}
功能制作相关材料(边缘列表){
var mat={};
edge_list.forEach(函数(edge,i){
mat[edge.source]=mat[edge.source]|{};
mat[edge.source][edge.target]=edge.weight;
mat[edge.target]=mat[edge.target]|{};
mat[edge.target][edge.source]=edge.weight;
});
返回垫;
}
功能更新\u关联\u材料(图形、边缘){
图._assoc_mat[edge.source]=图._assoc_mat[edge.source]|{};
图._assoc_mat[edge.source][edge.target]=edge.weight;
graph._assoc_mat[edge.target]=graph._assoc_mat[edge.target]|{};
图._assoc_mat[edge.target][edge.source]=edge.weight;
}
功能克隆(obj){
if(obj==null | | typeof(obj)!='object')
返回obj;
var temp=obj.constructor();
for(obj中的var键)
temp[key]=克隆(obj[key]);
返回温度;
}
//核心算法相关
函数初始状态(图形、状态、零件){
状态['nodes_to_com']={};
状态['total_weight']=0;
状态['internals']={};
状态['degrees']={};
状态['gdegrees']={};
状态['loops']={};
状态['total_weight']=获取图形大小(图形);
如果(零件类型==‘未定义’){
graph.nodes.forEach(函数(node,i){
status.nodes_to_com[node]=i;
var deg=获取节点的度(图,节点);
如果(度<0)
抛出“错误的图形类型,使用正权重!”;
状态。度[i]=度;
状态.gdegrees[节点]=度;
status.loops[node]=get_edge_weight(图形、节点、节点)| 0;
status.internal[i]=status.loops[node];
});
}否则{
graph.nodes.forEach(函数(node,i){
var com=部件[节点];
status.nodes_to_com[node]=com;
var deg=获取节点的度(图,节点);
status.degrees[com]=(status.degrees[com]| | 0)+deg;
状态.gdegrees[节点]=度;
var inc=0.0;
var Neights=获取节点(图,节点)的\u Neights\u;
forEach(函数(邻居,i){
变量权重=图。关联矩阵[节点][邻居];
如果(重量0){
结果=结果+学位/链接-数学能力((学位/(2.0*链接)),2);
}
});
返回结果;
}
函数_neighcom(节点、图形、状态){
//计算社区