-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAusOpenDataVisualization.html
368 lines (315 loc) · 15.8 KB
/
AusOpenDataVisualization.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
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body{
width:1060px;
}
}
path { stroke: #fff; }
path:hover { opacity:0.9; }
rect:hover { fill:blue; }
.axis { font: 10px sans-serif; }
.legend tr{ border-bottom:1px solid grey; }
.legend tr:first-child{ border-top:1px solid grey; }
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.x.axis path { display: none; }
.legend{
margin-bottom:76px;
display:inline-block;
border-collapse: collapse;
border-spacing: 0px;
}
.legend td{
padding:4px 5px;
vertical-align:bottom;
}
.legendFreq, .legendPerc{
align:right;
width:50px;
}
</style>
<body>
<div id='summary'>
<h1 style="color:#42b0f4">Australian Open - 10 years Data Analysis</h1>
<p><strong>Rationales of my visualization design and story : </strong>For this assignment I had 10years data from Australian
Open. While exploring this data I found there are 381 players who participated in Australian Open in last years but around
70% of them won only 5 or less matches.
So I divided players into following categories based on total number of matches that they heave won :
<ul>
<li>>50 : Players who won more than 50 matches</li>
<li>31 to 50 : Players who won 31 to 50 matches</li>
<li>16 to 30 : Players who won 16 to 30 matches</li>
<li>6 to 15 : Players who won 6 to 15 matches</li>
<li>1 to 5 : Players who won 1 to 5 matches</li>
<li>0 : Players who did not win any match</li>
</ul>
These categories are depicted by pie chart given below. I used pie chart as it is tha best way visualisation to
show which category dominates the data.<br />
After this I explored the participating countries and how many players have represented them in last 10 years. I found that
60 distinct countries have participated and most of them have only one or two players representing them while few countires
have large numbers of players who represented them in the tournament. For representing this information I used histogram as
it best way to give exact numbers and compare it with other countries. Hieght of the bars in the histogram represents number
of players that have represented that country in last 10 years.
</p>
<p><strong>Data Analysis : </strong>For the analysis part I tried to see the co-relation between both of these factors.
Motivation behind this idea is that I wanted to see if there are some fixed set of coutries which produce high performing
players? There are countries who have large numbers of players representing them but does that also menas those players
have won more number of matches or they are just representing them and not winning many matches. On this ground I started
to explore co-relation between the no. of matches won by each player and from which coutry does he come from.I have done
this analysis vice-versa also, that is I analysed how many players represented given country and how these players are
distributed into categories represented by pie chart.
</p>
<p>
<strong>Interactivity</strong> : Below is the pie chart that depicts the ditribution of players among them categories based on number of matches
won by them and histogram depicts distributuon of players over counterirs. When we hover over slices of pie chart, histogram
will change and now start depicting from which counteries this category's players come from. For example, we can see which
coutry's palyers have won no matches.
Similary we can interact with histogram to see distribution of players on country level. He can hover over histogram's bar of a particular
country and see what is the distribution of its players over winning categories. This visulatisation enables to view and
compare data on both levels.
I have also made a hierarchial view of all the matches played and who was the winner. It can be seen <a href="Tree_structure/Tree_Structure.html" target="_blank">here</a>. You can drag,
drop, zoom in and out to focus on particular year.
</p>
<p>
<strong>My Story : </strong> Following are the interesting outcomes of my data analysis:
<ul>
<li>>70% of players participated in the tournamnet have won no matches or less than 5 matches</li>
<li>Four countries - ESP, USA, FRA, AUS - are represented by more than 30 players in last 10 years.</li>
<li>Most of the coutries who are represented by one or two players contribute to the section where they have not won or won less than 5
matches </li>
<li>SUI is represented by only 4 players in 10 years but have a player (Roger Federer) who won maximum matches (63)</li>
</ul>
Higher number of participating players does not ensure more match wins but if participation is very low (1 or 2) it is
highly probable that there will be either less wins or no wins at all. Hence a country has to make a balance on its
players representation. They should increase number of players and also keep it limited so that they can focus on training of
these players.
</p>
</div>
<div id='dashboard'>
</div>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
function dashboard(id, fData){
var barColor = 'steelblue';
function segColor(c){ return {"0":"#e03976", ">50":"#fcf52a", "31 to 50":"#e08214", "16 to 30":"#41ab5d" ,"6 to 15":"#7a42f4", "1 to 5":"#3acfe0"}[c]; }
// compute total for each state.
fData.forEach(function(d){d.total=d.category[">50"]+d.category["31 to 50"]+d.category["16 to 30"]+d.category["6 to 15"]+d.category["1 to 5"]+d.category["0"];});
0
// function to handle histogram.
function histoGram(fD){
var hG={}, hGDim = {t: 60, r: 0, b: 30, l: 0};
hGDim.w = 1400 - hGDim.l - hGDim.r,
hGDim.h = 300 - hGDim.t - hGDim.b;
//create svg for histogram.
var hGsvg = d3.select(id).append("svg")
.attr("width", hGDim.w + hGDim.l + hGDim.r)
.attr("height", hGDim.h + hGDim.t + hGDim.b).append("g")
.attr("transform", "translate(" + hGDim.l + "," + hGDim.t + ")");
// create function for x-axis mapping.
var x = d3.scale.ordinal().rangeRoundBands([0, hGDim.w], 0.1)
.domain(fD.map(function(d) { return d[0]; }));
// Add x-axis to the histogram svg.
hGsvg.append("g").attr("class", "x axis")
.attr("transform", "translate(0," + hGDim.h + ")")
.call(d3.svg.axis().scale(x).orient("bottom"));
// Create function for y-axis map.
var y = d3.scale.linear().range([hGDim.h, 0])
.domain([0, d3.max(fD, function(d) { return d[1]; })]);
// Create bars for histogram to contain rectangles and freq labels.
var bars = hGsvg.selectAll(".bar").data(fD).enter()
.append("g").attr("class", "bar");
//create the rectangles.
bars.append("rect")
.attr("x", function(d) { return x(d[0]); })
.attr("y", function(d) { return y(d[1]); })
.attr("width", x.rangeBand())
.attr("height", function(d) { return hGDim.h - y(d[1]); })
.attr('fill',barColor)
.on("mouseover",mouseover)// mouseover is defined below.
.on("mouseout",mouseout);// mouseout is defined below.
//Create the frequency labels above the rectangles.
bars.append("text").text(function(d){ return d3.format(",")(d[1])})
.attr("x", function(d) { return x(d[0])+x.rangeBand()/2; })
.attr("y", function(d) { return y(d[1])-5; })
.attr("text-anchor", "middle");
function mouseover(d){ // utility function to be called on mouseover.
// filter for selected state.
var st = fData.filter(function(s){ return s.country == d[0];})[0],
nD = d3.keys(st.category).map(function(s){ return {type:s, category:st.category[s]};});
console.log(st)
console.log(nD)
// call update functions of pie-chart and legend.
pC.update(nD);
leg.update(nD);
}
function mouseout(d){ // utility function to be called on mouseout.
// reset the pie-chart and legend.
pC.update(tF);
leg.update(tF);
}
// create function to update the bars. This will be used by pie-chart.
hG.update = function(nD, color){
// update the domain of the y-axis map to reflect change in frequencies.
y.domain([0, d3.max(nD, function(d) { return d[1]; })]);
// Attach the new data to the bars.
var bars = hGsvg.selectAll(".bar").data(nD);
// transition the height and color of rectangles.
bars.select("rect").transition().duration(500)
.attr("y", function(d) {return y(d[1]); })
.attr("height", function(d) { return hGDim.h - y(d[1]); })
.attr("fill", color);
// transition the frequency labels location and change value.
bars.select("text").transition().duration(500)
.text(function(d){ return d3.format(",")(d[1])})
.attr("y", function(d) {return y(d[1])-5; });
}
return hG;
}
// function to handle pieChart.
function pieChart(pD){
var pC ={}, pieDim ={w:400, h: 250};
pieDim.r = Math.min(pieDim.w, pieDim.h) / 2;
// create svg for pie chart.
var piesvg = d3.select(id).append("svg")
.attr("width", pieDim.w).attr("height", pieDim.h).append("g")
.attr("transform", "translate("+pieDim.w/2+","+pieDim.h/2+")");
// create function to draw the arcs of the pie slices.
var arc = d3.svg.arc().outerRadius(pieDim.r - 10).innerRadius(0);
// create a function to compute the pie slice angles.
var pie = d3.layout.pie().sort(null).value(function(d) { return d.category; });
// Draw the pie slices.
piesvg.selectAll("path").data(pie(pD)).enter().append("path").attr("d", arc)
.each(function(d) { this._current = d; })
.style("fill", function(d) { return segColor(d.data.type); })
.on("mouseover",mouseover).on("mouseout",mouseout);
// create function to update pie-chart. This will be used by histogram.
pC.update = function(nD){
piesvg.selectAll("path").data(pie(nD)).transition().duration(500)
.attrTween("d", arcTween);
}
// Utility function to be called on mouseover a pie slice.
function mouseover(d){
// call the update function of histogram with new data.
hG.update(fData.map(function(v){
return [v.country,v.category[d.data.type]];}),segColor(d.data.type));
}
//Utility function to be called on mouseout a pie slice.
function mouseout(d){
// call the update function of histogram with all data.
hG.update(fData.map(function(v){
return [v.country,v.total];}), barColor);
}
// Animating the pie-slice requiring a custom function which specifies
// how the intermediate paths should be drawn.
function arcTween(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
return function(t) { return arc(i(t)); };
}
return pC;
}
// function to handle legend.
function legend(lD){
var leg = {};
// create table for legend.
var legend = d3.select(id).append("table").attr('class','legend');
// create one row per segment.
var tr = legend.append("tbody").selectAll("tr").data(lD).enter().append("tr");
// create the first column for each segment.
tr.append("td").append("svg").attr("width", '16').attr("height", '16').append("rect")
.attr("width", '16').attr("height", '16')
.attr("fill",function(d){ return segColor(d.type); });
// create the second column for each segment.
tr.append("td").text(function(d){ return d.type;});
// create the third column for each segment.
tr.append("td").attr("class",'legendFreq')
.text(function(d){ return d3.format(",")(d.category);});
// create the fourth column for each segment.
tr.append("td").attr("class",'legendPerc')
.text(function(d){ return getLegend(d,lD);});
// Utility function to be used to update the legend.
leg.update = function(nD){
// update the data attached to the row elements.
var l = legend.select("tbody").selectAll("tr").data(nD);
// update the frequencies.
l.select(".legendFreq").text(function(d){ return d3.format(",")(d.category);});
// update the percentage column.
l.select(".legendPerc").text(function(d){ return getLegend(d,nD);});
}
function getLegend(d,aD){ // Utility function to compute percentage.
return d3.format(".1%")(d.category/d3.sum(aD.map(function(v){ return v.category; })));
}
return leg;
}
// calculate total frequency by segment for all state.
var tF = [ "0", ">50", "31 to 50","16 to 30","6 to 15", "1 to 5"].map(function(d){
return {type:d, category: d3.sum(fData.map(function(t){ return t.category[d];}))};
});
// calculate total frequency by state for all segment.
var sF = fData.map(function(d){return [d.country,d.total];});
console.log(sF)
var pC = pieChart(tF), // create the pie-chart.,
leg= legend(tF), // create the legend.
hG = histoGram(sF); // create the histogram.
}
function TransformData(piedata) {
var result = [];
var hasMatch;
var ctg;
for (var i in piedata) {
hasMatch = false;
for (var index = 0; index < result.length; ++index) {
var datarow= result[index];
if (datarow.country == piedata[i].country) {
ctg = piedata[i].category;
result[index].category[ctg] = result[index].category[ctg] +1;
hasMatch = true;
break;
}
}
if (hasMatch == false) {
ditem = {};
ditem.country = piedata[i].country;
ditem.category = {"0":0 ,">50":0, "31 to 50":0, "16 to 30":0,"6 to 15":0, "1 to 5":0}
ditem.category[piedata[i].category] = ditem.category[piedata[i].category] + 1
result.push(ditem);
}
}
return result;
}
</script>
<script>
var res;
var tennisdata = d3.csv("10yearAUSOpenMatches_Transformed.csv", function(data) {
data.forEach(function(d){
d.player = d.player,
d.country = d.country,
d.matchesPlayed = +d.matchesPlayed,
d.MatchesWon = +d.MatchesWon,
d.MatchesLost = +d.MatchesLost,
d.category = d.category,
d.playersIncategory = +d.playersIncategory
});
res = TransformData(data);
console.log(res);
dashboard('#dashboard',res);
});
//freqData=[
//{State:'AL',freq:{low:4786, mid:1319, high:249}}
//,{State:'AZ',freq:{low:1101, mid:412, high:674}}
//,{State:'CT',freq:{low:932, mid:2149, high:418}}
//,{State:'DE',freq:{low:832, mid:1152, high:1862}}
//,{State:'FL',freq:{low:4481, mid:3304, high:948}}
//,{State:'GA',freq:{low:1619, mid:167, high:1063}}
//,{State:'IA',freq:{low:1819, mid:247, high:1203}}
//,{State:'IL',freq:{low:4498, mid:3852, high:942}}
//,{State:'IN',freq:{low:797, mid:1849, high:1534}}
//,{State:'KS',freq:{low:162, mid:379, high:471}}
//];
//dashboard('#dashboard',freqData);
</script>