-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
411 lines (377 loc) · 23.4 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
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>StrmWrd: Seek Things that aRe coMmon While Reserving Differences</title>
<style type="text/css">
body {
margin: 1em 1.5em;
font-family: arial, lucinda, helvetica;
color: black;
background: white;
}
h1, h2, h3 {
text-align: center;
font-weight: normal;
}
h2, h3 {
text-align: left;
background: #00BA4A;
padding: 5px;
}
h3 {
background: #00DF59;
}
td {vertical-align:top;}
</style>
<script type="text/javascript" src="mydata.js"></script>
<script type="text/javascript" src="jscolor/jscolor.js"></script>
<script type="text/javascript" src="lib/jquery-1.7.2.min.js"></script>
<script type="text/javascript" src="lib/rgbcolor.js"></script>
<script type="text/javascript" src="lib/jquery.wordcloud.diffwordle.js"></script>
<script type="text/javascript" src="lib/d3/d3.js"></script>
<script type="text/javascript" src="lib/d3-cloud/d3.layout.cloud.js"></script>
<script type="text/javascript" src="lib/highcharts.js"></script>
<script type="text/javascript" src="wordle/wordanalyzer.js"></script>
<script type="text/javascript" src="wordle/diffwordle.js"></script>
<script type="text/javascript" src="wordle/stopwords.js"></script>
<script type="text/javascript" src="trends/difftrends.js"></script>
<script type="text/javascript" src="common.js"></script>
<script type="text/javascript">
var $I = function(id) {
return document.getElementById(id);
};
var difftrends = null;
var diffwordle1 = null, diffwordle2 = null;
var loadExamples = function() {
diffwordle1 = new DiffWordle('cloudcontainer', {'width':350, 'height':200, 'type':0, 'scale':'log'});
// http://www.thesportreview.com/tsr/2012/08/london-2012-olympics-womens-doubles-players-unfairly-punished/
addWordleText("The Sport Review: Subsequently one half of China’s world No1 doubles badminton team has announced her retirement from the sport such was her dismay at being disqualified from the Olympics. The 26-year-old Yu Yang took to her blog, saying: “What you’ve cancelled is not just a game, but my dream!” Meanwhile, Chinese Olympic officials distanced themselves from the whole saga, demanding that the players publically apologise. However, should the authorities have been so quick to judge the players’ actions and forever condemn them to Olympic infamy? Or should we instead sympathise to a degree with the Chinese, Indonesian and two South Korean pairs, who have possibly been punished for following coaches’ unsportsmanlike advice? Both reactions have their advocates but perhaps we should be sympathetic. Initially, there was outrage spread among the 4,500 strong Wembley Arena crowd at the farce and blatant nature of Tuesday’s events. Why should we have a change of heart? Well China’s badminton coach Li Yongbo, who has now stated that he should take the blame for the incident, which Chinese state media said “violates the Olympic spirit of fair competition”. There is no denying that purposely losing a match in order to gain an advantage violates the spirit of the Olympics as they aim to promote fair competition and athletic endeavour. The players have been made an example of, but in countries like China and Korea where the influence of governing bodies and the autocratic nature of the coaches’ rule, perhaps it is these individuals who should have been kicked out of the Games. This would have allowed the players to continue and would surely have been the most prominent demonstration of the Olympic spirit. It is notable that the International Olympic Committee (IOC) has in part recognised the coaches’ influence in the saga and has asked the national delegations of China, South Korea and Indonesia to investigate the role of their Coaches. “We want to see a positive result for the sport in the Olympics. And now we make sure they (the three national Olympic committees) also consider the entourage, to make sure it is not just the athletes who are punished for this. They are looking into this,” IOC spokesman Mark Adams said at briefing on Thursday.");
// http://edition.cnn.com/2012/08/01/sport/olympics-badminton-scandal/index.html
addWordleText("London (CNN) -- Eight female badminton players were disqualified from the Olympics on Wednesday for trying to lose matches the day before, the Badminton World Federation announced after a disciplinary hearing. The players from China, South Korea and Indonesia were accused of playing to lose so they could face easier opponents in future matches, drawing boos from spectators and warnings from match officials Tuesday night. All four pairs of players were charged with not doing their best to win a match and abusing or demeaning the sport. The Indonesian and South Korean pairs appealed the decision, the federation said. But the Chinese sporting authorities accepted the decision and the head badminton coach apologized for the players' behavior. The charges result from two lackluster contests in London that angered the watching crowds as the doubles pairs appeared to be serving into the net on purpose. The eight players concerned had all already qualified for the quarterfinals of the tournament before the final matches of the group stage Tuesday night. British sports fans going into the Olympic Park on Wednesday called the scandal \"shocking\" after seeing parts of the matches on television. \"It's not in the spirit of the thing,\" said Kevin Button of Ashford, in Kent, just outside London. \"And it's so disappointing for the people who came to see it,\" said his wife, Tina. \"It leaves a bit of a sour taste.\" The disqualifications mean the world's No. 1 pair, Wang Xiaoli and Yu Yang of China, are out of the competition. In the first of the Tuesday matches under scrutiny, Wang and Yu played South Korea's Jung Kyung-eun and Kim Ha-na in a game in which \"neither side seemed to be exerting themselves,\" the official Olympic news service said. After several serves by both pairs went into the net, the tournament referee, Torsten Berg, was called to the court, the news service reported, \"where he warned all four players amid a chorus of boos from the crowd.\"");
// http://europe.chinadaily.com.cn/opinion/2012-08/03/content_15647809.htm
addWordleText("China Daily: I feel sorry for the eight badminton players who were disqualified from the London Olympic Games for not giving off their best to win, because athletes get a chance to win an Olympic medal only once in four years or maybe once a lifetime. But that is the cost the eight doubles players have to pay for what they did - violated the Olympic spirit by intentionally losing their final group matches after they had already qualified for the knockout round. Some people say they wanted to lose to face weaker opponents in the knockout round. Whatever the reason, their action (or inaction) is a violation of all the rules of sportsmanship and an affront to the spectators who paid to watch them play. Others say the new rules were to blame for the scandal. If you can win a medal by losing rather than winning a match, what would you do? Maybe the new group format leaves much to be desired and has loopholes which players can take advantage of to save energy for the knockout round or avoid the rivals they don't want to meet. Still others argue that athletes take advantage of the rules to get the best result in all events. They say that it is natural for players to circumvent the rules to get medals. For example, swimmers will not go all out in the preliminary (or qualifying) rounds as long as they qualify for the next round. As long as there is a possibility, athletes will circumvent or try to circumvent the rules. There is nothing wrong in saving some energy when the competition is not that severe. But there is a bottom line. And teams, coaches and players should know that line. Many online postings allege that the Chinese badminton team \"fixed\" or \"manipulated\" matches to win a gold medal before. We are yet to know whether the team and coaches had arranged that. The Chinese delegation has said it will investigate the scandal. Whatever the result of the investigation, the World Badminton Federation's decision to disqualify the two Chinese players along with others provides food for thought. ");
$I('trendsdata').value = JSON.stringify(mydata);
updateTrends();
updateWordle();
};
var updateTrends = function() {
difftrends = new DiffTrends(JSON.parse($I('trendsdata').value), 'trendcontrols', 'trendcontainer', 'difftrends', function(graphdata) {
var texts = concattxtforwordle(graphdata);
diffwordle1.draw(texts);
});
};
var updateWordle = function() {
var wordletype = parseInt($I('wordletype').value);
var wordlescale = $I('wordlescale').value;
var wordleoptions = {'width':350, 'height':200, 'type':wordletype};
if (wordlescale == 'log' || wordlescale == 'sqrt') {
wordleoptions['scale'] = wordlescale;
}
diffwordle2 = new DiffWordle('cloudcontainer2', wordleoptions);
var textobj = [];
var contentnodes = $I('wordletablecontent').childNodes;
for (var idx = 0; idx < contentnodes.length; idx++) {
var nd = contentnodes[idx];
if (nd.nodeType == 1 && nd.id != null && nd.id.indexOf('wordletablecontent_') == 0) {
var num = nd.id.substring(nd.id.indexOf('_') + 1);
var color = '#' + $I('wordlecolor_' + num).value;
var text = $I('wordletext_' + num).value;
textobj.push({'color':color, 'weight':1, 'text':text});
}
}
diffwordle2.draw(textobj);
/*var str = $I('wordletext').value;
var text = "";
try {
text = JSON.parse(str);
} catch (err) {
text = str;
}
diffwordle2.draw(text);*/
};
// get the last child of node with that tag
var getLastChild = function(node, tag) {
var nd = node.lastChild;
while (nd != null) {
if (nd.nodeName.toLowerCase() == tag.toLowerCase())
return nd;
nd = nd.previousSibling;
}
return null;
};
var wordletextcount = 0;
var colorcandidates = ['#4572A7', '#AA4643', '#89A54E', '#80699B', '#3D96AE', '#DB843D', '#92A8CD', '#A47D7C', '#B5CA92'];
var addWordleText = function(text) {
// head
var head = document.createElement('th');
head.id = 'wordletablehead_' + wordletextcount;
var colorinput = document.createElement('input');
colorinput.className = 'color';
colorinput.style.width = '100px';
colorinput.id = 'wordlecolor_' + wordletextcount;
colorinput.value = colorcandidates[wordletextcount % colorcandidates.length];
head.appendChild(document.createTextNode('Text' + (wordletextcount + 1) + ': '));
head.appendChild(colorinput);
$I('wordletablehead').insertBefore(head, getLastChild($I('wordletablehead'), 'th'));
// content
var content = document.createElement('td');
content.id = 'wordletablecontent_' + wordletextcount;
var textarea = document.createElement('textarea');
textarea.id = 'wordletext_' + wordletextcount;
textarea.style.width = '350px';
textarea.style.height = '200px';
textarea.appendChild(document.createTextNode(text == null ? "" : text));
content.appendChild(textarea);
$I('wordletablecontent').insertBefore(content, getLastChild($I('wordletablecontent'), 'td'));
// foot
var foot = document.createElement('td');
foot.align = 'center';
foot.id = 'wordletablefoot_' + wordletextcount;
var delbtn = document.createElement('a');
delbtn.href = 'javascript:deleteWordleText("' + wordletextcount + '");';
delbtn.appendChild(document.createTextNode('Delete'));
foot.appendChild(delbtn);
$I('wordletablefoot').insertBefore(foot, getLastChild($I('wordletablefoot'), 'td'));
// increment the counter
wordletextcount++;
// add the color picker event
jscolor.bind();
};
var removeNode = function(node) {
node.parentNode.removeChild(node);
};
var deleteWordleText = function(num) {
removeNode($I('wordletablehead_' + num));
removeNode($I('wordletablecontent_' + num));
removeNode($I('wordletablefoot_' + num));
};
</script>
</head>
<body onload="loadExamples();">
<!-- leftcontent -->
<div id="leftcontent" style="position:fixed; background:none repeat scroll 0% 0% lightblue; padding:5px; left:5px; border:1px solid black;">
[ <a href="http://wing.comp.nus.edu.sg/">WING homepage</a> ]<br/>
[ <a href="http://wing.comp.nus.edu.sg/portal/web-services.html">WING web services</a> ] <br/>
<br/>
[ <a href="#top">StrmWrd</a> ]<br/>
[ <a href="#demo1">Demo1</a> ]<br/>
[ <a href="#demo2">Demo2</a> ]<br/>
[ <a href="#download">Download</a> ]<br/>
[ <a href="#license">License</a> ]</br/>
[ <a href="#usage">Usage</a> ]<br/>
[ <a href="#wordseg">Word Segmentation</a> ]<br/>
<!--[ <a href="#gm">Group Members</a> ]<br/>
[ <a href="#faq">FAQ</a> ]<br/>
[ <a href="#t">Troubleshooting</a> ]<br/> -->
</div>
<!-- centercontent -->
<script>
</script>
<div id="centercontent" style="position:absolute;left:200px;padding:10px;">
<a name='top'></a><h1>StrmWrd: Seek Things that aRe coMmon While Reserving Differences</h1>
<p>StrmWrd (pronounced as Stream-Word) is a visualization tool for trends and texts comparison among different resources, written in JavaScript with HTML5 techniques.</p>
<p>As the name suggests, StrmWrd has two components, used either individually or together:</p>
<ul>
<li>DiffTrends (Stream): A stacked area chart showing the trends among different resources.</li>
<li>DiffWordle (Word): A frequency-based word cloud, where the color of a word represents its resource.</li>
</ul>
<p>Note if you use the two components together, the DiffTrends will control the DiffWordle, i.e., DiffTrends is rendered before DiffWordle.</p>
<a name='demo1'></a><h2>Demo 1: DiffTrends + DiffWordle</h2>
<p>The advanced way to use the two components is input JavaScript objects to them. Here it shows most of the functionalities.</p>
<table border='0'>
<tr><th>DiffTrends data</th><th>DiffTrends</th><th>DiffWordle</th></tr>
<tr>
<td><textarea id='trendsdata' style='width:350px; height:200px; margin:0'></textarea></td><td><div id="trendcontrols"></div>
<div id="trendcontainer" style="width:350px; height:200px; margin:0"></div></td>
<td><div id="cloudcontainer"></div></td>
</tr>
<tr><td align='center'><input type='button' value='Update DiffTrends =>' onclick='updateTrends();'/></td><td colspan='2' align='center'><input type='button' value='Load Example' onclick='loadExample();'/></td></tr>
</table>
<a name='demo2'></a><h2>Demo 2: Plain Text DiffWordle</h2>
<p>DiffWordle accepts multi-series plain texts, where the words are colored according to their series color. Words that come from multiple series are colored in a mixed color.</p>
<table border='0'>
<tr id='wordletablehead'><th>DiffWordle</th><th></th></tr>
<tr id='wordletablecontent'>
<td><div id="cloudcontainer2"></div></td>
<td style='vertical-align:middle'><input type='button' value='Add more' style='width:50px;text-align:center;' onclick='addWordleText("Example text");'/></td>
</tr>
<tr id='wordletablefoot'>
<td align='center'>
Type: <select id='wordletype'><option value='0' selected>0</option><option value='1'>1</option></select>
Scale: <select id='wordlescale'><option value='n'>normal</option><option value='log'>log</option><option value='sqrt' selected>sqrt</option></select>
<input type='button' value='Update' onclick='updateWordle();'/>
</td>
<td></td>
</tr>
</table>
<p>The above examples come from the badminton disqualification event in London Olympics 2012, reported by three different media. Do you find how much they are different from each other?</p>
<a name='download'></a><h2>Download</h2>
<p>Currently on GitHub <a href='https://github.com/THUNUS/StrmWrd' target='_blank'>StrmWrd</a>.</p>
<a name='license'></a><h2>License and Third-party Libraries</h2>
We use several third-party libraries for the modules. Please follow their individual licenses. For our integrating part, use it as you like.
<ul>
<li><a href="http://www.highcharts.com/" target="_blank">Highcharts</a></li>
<li><a href="http://www.phpied.com/rgb-color-parser-in-javascript/" target="_blank">RGB color parser</a></li>
<li><a href="http://www.jasondavies.com/wordcloud" target="_blank">d3-cloud</a></li>
<li><a href="http://timc.idv.tw/wordcloud/en/" target="_blank">HTML5 word cloud</a></li>
</ul>
The name "wordle" comes from <a href='http://www.wordle.net/' target='_blank'>wordle.net</a>.
<a name='usage'></a><h2>Usage</h2>
<table border=1 width='100%'>
<tr>
<th width='50%'>DiffTrends</th>
<th width='50%'>DiffWordle</th>
</tr>
<tr><td colspan=2 align='center'>Script files</td></tr>
<tr>
<td>
<pre>
trends/difftrends.js
lib/highcharts.js
</pre>
</td>
<td>
<pre>
wordle/diffwordle.js
lib/rgbcolor.js
</pre>
Required if word segmentation is needed:
<pre>
wordle/wordanalyzer.js
wordle/stopwords.js
</pre>
Required for type-0 (default) cloud chart:
<pre>
lib/d3/d3.js
lib/d3-cloud/d3.layout.cloud.js
</pre>
Required for type-1 cloud chart:
<pre>
lib/jquery-1.7.2.min.js
lib/jquery.wordcloud.diffwordle.js
</pre>
Required if the trends data is later used for wordle:
<pre>
common.js
</pre>
</td>
</tr>
<tr><td colspan=2 align='center'>Containers</td></tr>
<tr>
<td>
<pre>
<div id="trendcontrols"></div>
<div id="trendcontainer" style="width:350px; height:200px; margin:0"></div>
</pre>
</td>
<td>
<pre>
<div id="cloudcontainer"></div>
</pre>
</td>
</tr>
<tr><td colspan=2 align='center'>Data format</td></tr>
<tr>
<td>
<pre>
var mydata = {
heads: ['datetime', 'source', 'freq', 'region', 'titleanddesc'],
x: 'datetime', y: 'freq', facets: ['source', 'region'],
text: 'titleanddesc', granularity: 'day',
options: {
selectClass: 'input-small',
facetColors: {'source':{'新浪网':'#4572A7',
'搜狐':'#AA4643', '华尔街日报':'#89A54E',
'Yahoo! News':'#80699B', 'Reuters':'#3D96AE'}},
logY: false
},
data: [
[1335780000,"新浪网",1,"CN","鸿海第一财季利润未达预期 股价跌停 新浪科技讯
北京时间4月30日下午消息,由于第一财季利润未达市场预期,鸿海今天在台北股票交易所跌停。"],
...
]
};
</pre>
<p>
The "heads" should contain at least three columns for the x-axis, y-axis (value) and a facet for comparison. The name of these fields are arbitary, as long as you assigned the corresponding name in "x", "y" and "facets".</br>
The "text" specifies the piece of text of that record. It can be used for the word cloud part.</br>
The "granularity" can be set to year, month, day, hour, minute or second. The frequencies of records from a same period (during a same year / month / ...) will be combined and shown as one x-point in the graph.</br>
The "data" is a list of records, where each of the records is also in a list, where the columns are of the same order as "heads".
</p>
We support the following options:
<ul>
<li>selectClass: The css class for the <select> controlling object.</li>
<li>facetColors: Dicts of palettes for different colors of the values within a facet.</li>
<li>logY: A boolean for drawing the y-axis in logarithmic scale. Not recommend since the stacked graph will be misleading for the upper series.</li>
</ul>
</td>
<td>
Can be a string, a hashtable or a list of series.
<ul>
<li>String: We'll do a word segmentation with the string.</li>
<pre>
var text = "A piece of text with Chinese characters, 就像这样。";
</pre>
<li>Hashtable: A javascript dictionary of words and their frequencies.</li>
<pre>
var dict = {'word1':5, 'word2':3, 'word3':2};
</pre>
<li>List of series: A javascript list [] where each of the elements is an object: {"color": c, "weight": w, "text": t}. c is the color of the whole series, w is the weight applied to the whole series (applied multiplicative to the word frequencies), t is a string or a hashtable (as above).</li>
<pre>
var list = [{ "color":"red", "weight":1,
"text":"Hello, world!" },
{ "color":"#0000ff", "weight":2,
"text":"A quick fox jumps over the lazy dog." };
</pre>
</ul>
</td>
</tr>
<tr><td colspan=2 align='center'>Draw</td></tr>
<tr>
<td>
<pre>
var difftrends = new DiffTrends(mydata,
'trendcontrols', 'trendcontainer',
'difftrends', concattxtforwordle);
</pre>
The second-to-the-last argument is the variable name. We need to add events to the controller, so you need to specify the variable name and we'll render it to the onchange event. The last argument is a function executed when drawing the trends is finished. In the first demo we extract the words from the trends' texts and invoke the wordle chart. The trends' texts are of the format like this:
<pre>
[ { "name":"Reuters",
"data":[[1334246400000,1], [1334332800000,1], ...],
"color":"#3D96AE",
"text":[[1334246400000,"the text in this time point"],
[1334332800000,"another text in this point"], ...]
},
...
]
</pre>
</td>
<td>
<pre>
var diffwordle = new DiffWordle('cloudcontainer',
{ 'width':350, 'height':200,
'type':0, 'scale':'log' });
diffwordle.draw(texts);
</pre>
<p>The two arguments for the initialization are the id of the container and options. The argument for drawing is the text object (String, hashtable, or list of series).</p>
<p>We support the following options:</p>
<ul>
<li>type: 0 or 1, using different libraries. Default 0.</li>
<li>width: The width of the chart, numerical value, default 350.</li>
<li>height: The height of the chart, numerical value, default 200.</li>
<li>scale: Optional. String or a function. If non-exist, use the given weight. If a string of "log" of "sqrt", use the logarithmic or square root of the original weight. If function:</li>
<pre>
'scale': function (w) { return Math.log(w * 10 + 1); }
</pre>
</ul>
</td>
</tr>
</table>
<a name='wordseg'></a><h2>Word Segmentation Module</h2>
Due to the cross-domain restriction of Javascript, we run a script on the server (seg.php) to send a POST request to a word segmentation Web service <a href="http://www.caq9.info/mmseg/" target="_blank">http://www.caq9.info/mmseg/</a>.
<hr/>
<h5><address>Co-work by <a href="http://www.thuir.org/" target="_blank">THUIR</a> and <a href="http://wing.comp.nus.edu.sg/" target="_blank">WING</a> under the Tsinghua-NUS <a href="http://next.comp.nus.edu.sg/" target="_blank">NExT</a> Search Centre, 2012</address></h5>
</div>
</body>
</html>