forked from Pseudomanifold/Shakespeare
-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
224 lines (196 loc) · 9.04 KB
/
index.html
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
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="d3.min.js"></script>
</head>
<style>
.links line {
stroke: #999;
stroke-opacity: 0.6;
}
.nodes circle {
stroke: #fff;
stroke-width: 1.5px;
}
.node text {
font 10px serif;
}
</style>
<body>
<aside>
<select id="play">
<option value="A_Midsummer-Night's_Dream.json" >A Midsummer Night's Dream</option>
<option value="All's_Well_That_Ends_Well.json" >All's Well that Ends Well</option>
<option value="Anthony_and_Cleopatra.json" >Anthony and Cleopatra</option>
<option value="As_You_Like_It.json" >As You Like It</option>
<option value="Coriolanus.json" >Coriolanus</option>
<option value="Cymbeline.json" >Cymbeline</option>
<option value="Hamlet.json" >Hamlet, Prince of Denmark</option>
<option value="Henry_IV_Part_1.json" >Henry IV: Part I</option>
<option value="Henry_IV_Part_2.json" >Henry IV: Part II</option>
<option value="Henry_V.json" >Henry V</option>
<option value="Henry_VI_Part_1.json" >Henry VI: Part I</option>
<option value="Henry_VI_Part_2.json" >Henry VI: Part II</option>
<option value="Henry_VI_Part_3.json" >Henry VI: Part III</option>
<option value="Henry_VIII.json" >Henry VIII</option>
<option value="Julius_Caesar.json" >Julius Caesar</option>
<option value="King_Lear.json" >King Lear</option>
<option value="Love's_Labour's_Lost.json" >Love's Labour's Lost</option>
<option value="Macbeth.json" selected >Macbeth</option>
<option value="Measure_for_Measure.json" >Measure for Measure</option>
<option value="Much_Ado_about_Nothing.json" >Much Ado About Nothing</option>
<option value="Othello,_the_Moor_of_Venice.json" >Othello, the Moor of Venice</option>
<option value="Pericles,_Prince_of_Tyre.json" >Pericles, Prince of Tyre</option>
<option value="Richard_II.json" >Richard II</option>
<option value="Richard_III.json" >Richard III</option>
<option value="Romeo_And_Juliet.json" >Romeo and Juliet</option>
<option value="The_Comedy_of_Errors.json" >The Comedy of Errors</option>
<option value="The_Life_and_Death_of_King_John.json" >The Life and Death of King John</option>
<option value="The_Merchant_of_Venice.json" >The Merchant of Venice</option>
<option value="The_Merry_Wives_of_Windsor.json" >The Merry Wives of Windsor</option>
<option value="The_Taming_of_the_Shrew.json" >The Taming of the Shrew</option>
<option value="The_Tempest.json" >The Tempest</option>
<option value="The_Two_Gentlemen_of_Verona.json" >The Two Gentlement of Verona</option>
<option value="The_Winter's_Tale.json" >The Winter's Tale</option>
<option value="Timon_of_Athens.json" >Timon of Athens</option>
<option value="Titus_Andronicus.json" >Titus Andronicus</option>
<option value="Troilus_and_Cressida.json" >Troilus and Cressida</option>
<option value="Twelfth-Night;_or_What_You_Will.json" >Twelfth Night, or What You Will</option>
</select>
</aside>
<svg width="800" height="600"></svg>
<script>
function initialize(name)
{
var svg = d3.select("svg"), width = +svg.attr("width"), height = +svg.attr("height");
var simulation = d3.forceSimulation()
.force("link", d3.forceLink().id( function(d) { return d.id; } ))
.force("charge", d3.forceManyBody())
.force("center", d3.forceCenter(0.5*width, 0.5*height))
.force("collide", d3.forceCollide());
d3.json("JSON/"+name,
function(error, graph)
{
if (error)
throw error;
var getWeight = function(d) { return +d.weight; };
var minWeight = d3.min(graph.links, getWeight);
var maxWeight = d3.max(graph.links, getWeight);
var getDegree = function(d) { return +d.degree; };
var minDegree = d3.min(graph.nodes, getDegree);
var maxDegree = d3.max(graph.nodes, getDegree);
var link = svg.append("g")
.attr("class", "links")
.selectAll("line")
.data(graph.links)
.enter().append("line")
.attr("stroke-width", function(d) { return 2 * ( d.weight - minWeight ) / (maxWeight - minWeight ); });
// Calculates the radius of a given node based on its degree
// and scales it accordingly.
var getRadius = function(d)
{
var scale = d3.scaleLinear()
.domain([minDegree,maxDegree])
.range( [5,20] );
return scale(d.degree);
};
var node = svg.append("g")
.attr("class", "nodes")
.selectAll("circle")
.data(graph.nodes)
.enter()
.append("circle")
.attr("r", getRadius)
.attr("fill", function(d) { return 'black'; })
.call(d3.drag()
.on("start", dragstarted)
.on("drag", dragged)
.on("end", dragended)
);
node.append("title")
.text(function(d) { return d.id; });
var label = svg.append("g")
.attr("class", "labels")
.selectAll("text")
.data(graph.nodes)
.enter()
.append("text")
.attr("dx", "1em")
.attr("dy", ".35em")
.attr("stroke", "white")
.attr("stroke-width", "0.1")
.text(function(d) { return d.id; });
simulation
.nodes(graph.nodes)
.on("tick", ticked);
// TODO: better forces?
simulation.force("link")
.links(graph.links)
.distance(0.25*height)
.strength(function(link)
{
return link.weight / maxWeight;
}
);
simulation.force("collide")
.radius(getRadius);
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; });
node
.attr("cx", function(d) { return d.x; })
.attr("cy", function(d) { return d.y; });
label.attr("transform", function(d) { return "translate(" + d.x + "," + d.y + ")"; } );
}
}
);
function dragstarted(d)
{
if (!d3.event.active)
simulation.alphaTarget(0.3).restart();
d.fx = d.x;
d.fy = d.y;
}
function dragged(d)
{
d.fx = d3.event.x;
d.fy = d3.event.y;
}
function dragended(d)
{
if (!d3.event.active)
simulation.alphaTarget(0);
d.fx = null;
d.fy = null;
}
}
d3.select("#play").on("change",
function() {
// Remove old data completely and start with a fresh
// initialization of the page
d3.selectAll("svg > *").remove();
initialize(this.value);
}
);
initialize(document.getElementById("play").value);
</script>
<main>
<div style="width:600px; margin:0 auto">
<p>
This small demo shows co-occurrence networks for all of Shakespeare's plays. For more details on the <em>extraction</em> of these networks, please refer to the <a href="https://github.com/Submanifold/Shakespeare">GitHub repository</a> or the accompanying paper <a href="http://bastian.rieck.ru/research/Vis2016.pdf">Shall I compare thee to a network?—Visualizing the Topological Structure of Shakespeare's Plays</a>. The demo uses a force-directed graph layout. Nodes are scaled according to their degree.
</p>
<p>
More information about the data post-processing, including
a calculation of relevant network features, is available as
a <a
href="https://submanifold.github.io/Aleph/Rieck16b.html">Tutorial</a>
for <a href="https://submanifold.github.io/Aleph">Aleph,
a library for exploring persistent homology</a>.
</p>
</div>
</main>
</body>
</html>