-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy patharc_diagram.R
185 lines (158 loc) · 6.35 KB
/
arc_diagram.R
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
arc_diagram<- function(){
fileConn <- file(paste("arc_diagram", Sys.Date(),".html", sep=""), "w")
igraph <- fetchFirstSelectedStoredIgraph()
if (is.null(igraph))
return()
dataset <- fetchFirstSelectedStoredDataset()
if (is.null(dataset))
return()
cat(sprintf("<!DOCTYPE html>
<meta charset=\"utf-8\">
<!-- Load d3.js -->
<script src=\"https://d3js.org/d3.v4.js\"></script>
<!-- Load color palette -->
<script src=\"https://d3js.org/d3-scale-chromatic.v1.min.js\"></script>
<!-- Create a div where the graph will take place -->
<div id=\"my_dataviz\"></div>
<script>
// set the dimensions and margins of the graph
var margin = {top: 0, right: 30, bottom: 50, left: 60},
width = 650 - margin.left - margin.right,
height = 400 - margin.top - margin.bottom;
// append the svg object to the body of the page
var svg = d3.select(\"#my_dataviz\")
.append(\"svg\")
.attr(\"width\", width + margin.left + margin.right)
.attr(\"height\", height + margin.top + margin.bottom)
.append(\"g\")
.attr(\"transform\",
\"translate(\" + margin.left + \",\" + margin.top + \")\");
"), file = fileConn)
cat(sprintf("\n// Read dummy data
var data= {\"nodes\":[\n"), file = fileConn)
dataset_with_numbers<- data.frame("Source"= c(dataset$Source)-1, "Target"=c(dataset$Target)-1)
dataset_with_numbers<- dataset_with_numbers[order(dataset_with_numbers$Source),]
unique_source<- unique(dataset$Source)
unique_target<- unique(dataset$Target)
nodes_names<- c(as.character(unique_source), as.character(unique_target))
nodes_names<- sort(unique(nodes_names))
nodes<- c(unique_source, unique_target)
unique_nodes<- sort(unique(nodes))
n<-5
for (i in 1:round((length(nodes_names)))) {
if(length(nodes_names)>200){
n<-3
}
if(i == round((length(nodes_names)))){
cat(sprintf(paste("\t{\"name\":","\"", nodes_names[i],"\",", "\"n\":", n, ",\"grp\":", 1,",\"id\":", "\"",nodes_names[i], "\"","}\n"), sep= ""), file = fileConn)
}else{
cat(sprintf(paste("\t{\"name\":","\"", nodes_names[i],"\",", "\"n\":", n, ",\"grp\":", 1,",\"id\":", "\"",nodes_names[i], "\"","},\n"), sep= ""), file = fileConn)
}
}
cat(sprintf("],
\"links\":[\n"), file = fileConn)
for (i in 1:nrow(dataset)) {
if(i == nrow(dataset)){
cat(sprintf(paste("\t{\"source\":", "\"" ,dataset$Source[i], "\"", ",\"target\":", "\"",dataset$Target[i],"\"" ,",\"value\":1}\n"), sep= ""), file = fileConn)
}
else{
cat(sprintf(paste("\t{\"source\":", "\"" ,dataset$Source[i], "\"", ",\"target\":", "\"",dataset$Target[i],"\"" ,",\"value\":1},\n"), sep= ""), file = fileConn)
}
}
cat(sprintf("\n
],
\"attributes\":{}}
\n"), file = fileConn)
cat(sprintf("// List of node names
var allNodes = data.nodes.map(function(d){return d.name})
// List of groups
var allGroups = data.nodes.map(function(d){return d.grp})
allGroups = [...new Set(allGroups)]
// A color scale for groups:
var color = d3.scaleOrdinal()
.domain(allGroups)
.range(d3.schemeSet3);
// A linear scale for node size
var size = d3.scaleLinear()
.domain([1,10])
.range([2,10]);
// A linear scale to position the nodes on the X axis
var x = d3.scalePoint()
.range([0, width])
.domain(allNodes)
// In my input data, links are provided between nodes -id-, NOT between node names.
// So I have to do a link between this id and the name
var idToNode = {};
data.nodes.forEach(function (n) {
idToNode[n.id] = n;
});"), file = fileConn)
cat(sprintf("\n// Add the links
var links = svg
.selectAll('mylinks')
.data(data.links)
.enter()
.append('path')
.attr('d', function (d) {
start = x(idToNode[d.source].name) // X position of start node on the X axis
end = x(idToNode[d.target].name) // X position of end node
return ['M', start, height-30, // the arc starts at the coordinate x=start, y=height-30 (where the starting node is)
'A', // This means we're gonna build an elliptical arc
(start - end)/2, ',', // Next 2 lines are the coordinates of the inflexion point. Height of this point is proportional with start - end distance
(start - end)/2, 0, 0, ',',
start < end ? 1 : 0, end, ',', height-30] // We always want the arc on top. So if end is before start, putting 0 here turn the arc upside down.
.join(' ');
})
.style(\"fill\", \"none\")
.attr(\"stroke\", \"grey\")
.style(\"stroke-width\", 1)"), file = fileConn)
cat(sprintf("\n// Add the circle for the nodes
var nodes = svg
.selectAll(\"mynodes\")
.data(data.nodes.sort(function(a,b) { return +b.n - +a.n }))
.enter()
.append(\"circle\")
.attr(\"cx\", function(d){ return(x(d.name))})
.attr(\"cy\", height-30)
.attr(\"r\", function(d){ return(size(d.n))})
.style(\"fill\", function(d){ return color(d.grp)})
.attr(\"stroke\", \"white\")
// And give them a label
var labels = svg
.selectAll(\"mylabels\")
.data(data.nodes)
.enter()
.append(\"text\")
.attr(\"x\", 0)
.attr(\"y\", 0)
.text(function(d){ return(d.name)} )
.style(\"text-anchor\", \"end\")
.attr(\"transform\", function(d){ return( \"translate(\" + (x(d.name)) + \",\" + (height-15) + \")rotate(-45)\")})
.style(\"font-size\", 6)
// Add the highlighting functionality
nodes
.on('mouseover', function (d) {
// Highlight the nodes: every node is green except of him
nodes
.style('opacity', .2)
d3.select(this)
.style('opacity', 1)
// Highlight the connections
links
.style('stroke', function (link_d) { return link_d.source === d.id || link_d.target === d.id ? color(d.grp) : '#b8b8b8';})
.style('stroke-opacity', function (link_d) { return link_d.source === d.id || link_d.target === d.id ? 1 : .2;})
.style('stroke-width', function (link_d) { return link_d.source === d.id || link_d.target === d.id ? 4 : 1;})
labels
.style(\"font-size\", function(label_d){ return label_d.name === d.name ? 16 : 2 } )
.attr(\"y\", function(label_d){ return label_d.name === d.name ? 10 : 0 } )
})
.on('mouseout', function (d) {
nodes.style('opacity', 1)
links
.style('stroke', 'grey')
.style('stroke-opacity', .8)
.style('stroke-width', '1')
labels
.style(\"font-size\", 6 )
})
</script>"), file = fileConn)
}