forked from RodrigoRoaRodriguez/d3tutorial
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexercise6.html
More file actions
132 lines (113 loc) · 4.75 KB
/
Copy pathexercise6.html
File metadata and controls
132 lines (113 loc) · 4.75 KB
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
<!DOCTYPE html>
<meta charset="utf-8">
<style>
body{background-color: #fcc;}
svg{display:block}
svg#the-right-svg{background-color: #dfd;}
svg#the-wrong-svg{background-color: #faa;}
tspan {font-family:monospace; fill:#dfd;}
</style>
<h1 style="font: bold 2em monospace">EXERCISE 6</h1>
<svg id="the-wrong-svg" width="400" height="200"></svg>
<svg id="the-right-svg" width="80vw" height="40vw" viewbox="0 0 400 200">
</svg>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
/**
* EXERCISE DESCRIPTION:
* In this case you will load the data from an external file. So that this will
* be as similar as possible to what a relational database would return we will
* use a csv (coma separated value) file.This is more general than it might
* appear at first glance, since even if you used a database instead of using
* dependency injection (what we are doing here) it would be an asynchronous
* operation and you could end up using d3's convenience functions.
*
* SUBJECTS COVERED
* - Asynchronous operations (loading data).
*/
// PART I: get the data in the application
// The code in this file is processed top to bottom. With the exeption of
// fuctions declared specifically with the keyword `function`, you will not able
// to acess anything below your current line of code.
let time = {}
console.log(time.future) // This wil print `undefined`.
time.future = 'The present'
// ITERRUPTION: Chrome and other web-browsers will not allow cross-origins
// requests for safety reasons so from this point onward you need to start
// your own local server for development. You will be able to acess your
// files at the url: `localhost:[port]/[path from where you start the server]`
//
// If you have python2 you can do:
// python -m SimpleHTTPServer [port]
// If you have python3 you can do:
// python3 -m http.server [port]
//
// If you have Node then you can:
// npm install http-server -g
// and then
// http-server [path] [options]
// However, there is no guarantee that any line of code above will have
// executed either unless it is a blocking operation in the same thread
let nonBlockingFetch = d3.text('./exercise6.html') // d3.text is an ansynchornous operation that loads a file as text
console.log(nonBlockingFetch); // This will print an empty object. Since gets run before the GET request to the server has ocurred.
// The function, however, has a way to handle this, if you provide it a CALLBACK
// (a function for it to call back) it will execute that function appropiately.
// d3.text('./exercise6.html', fileContents => console.log(fileContents))
// So in order to load the data this is what you do:\
let printRows = rows => rows.forEach(row => console.log(row))
// d3.csv('./doodle-data.csv', printRows) // to see how rows are formatted by D3
//It `rows` the same that we had in exercise 3? No. Becuse count is a string,
//not a number. So just do anything of what was suggested after exercise 1.
let countToNumber = row =>{
row.count = +row.count
return row
}
let mySvg = d3.select('svg#the-right-svg')
// So this is what we will do once we have our visualization data.
let visualizeAsTreemap = csvRows =>{
let myData = csvRows.map(countToNumber)
let treemap = new RodrigoTreemap(myData)
treemap.drawOnSVG(mySvg)
}
// And here we get the data and tell it to do just that.
d3.csv('./doodle-data.csv', visualizeAsTreemap)
// Copy-pasted from exercise 3
function RodrigoTreemap(data){
// The lines below make structured that data into a hierachical datatype
let makeNested = d3.nest().key(d=>d.date)
let NestedData = makeNested.entries(data)
let root = {
key: 'Doodle votes',
values: NestedData,
}
let hierarchicalData = d3.hierarchy(root, d=>d.values).sum(d=>d.count).sort( (a,b)=>b.count-a.count)
// The layout adds the info necessary to draw the treemap
let makeTreemap = d3.treemap().size([400,200]).padding([2])
this.treemapData = makeTreemap(hierarchicalData, d=>d.count)
this.drawOnSVG = (svg) =>{
let colorScale = d3.scaleOrdinal(d3.schemeCategory10)
let perTime = svg.selectAll('g')
.data(this.treemapData.leaves())
.enter().append('g')
.attr('transform', d => 'translate(' + d.x0 + ',' + d.y0 + ')')
perTime.append('rect')
.attr('id', d => d.data.key)
.attr('width', d => d.x1 - d.x0)
.attr('height', d => d.y1 - d.y0)
.attr('fill', d=>colorScale(d.parent.data.key))
let labels = perTime.append('text')
labels.append('tspan')
.attr('dy', '1em')
.attr('x', 8)
.style('font-weight', 'bold')
.text(d=>d.parent.data.key)
labels.selectAll('tspan.time').data(d=>d.data.time.split('–')).enter()
.append('tspan')
.attr('class', 'time')
.attr('dy', '1em')
.attr('x', 12)
.style('font-size', 11)
.text(d=>d)
}
}
</script>