-
Notifications
You must be signed in to change notification settings - Fork 0
/
bubblechart.html
252 lines (209 loc) · 7.16 KB
/
bubblechart.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
<!DOCTYPE html>
<meta charset="utf-8">
<!-- Load d3.js -->
<script src="https://d3js.org/d3.v4.js"></script>
<!-- Load color scale -->
<script src="https://d3js.org/d3-scale-chromatic.v1.min.js"></script>
<!-- A bit of CSS: change stroke color of circle on hover (white -> black) -->
<style>
body {
font: 12px sans-serif;
}
.bubbles {
stroke-width: 2px;
stroke: white;
}
.bubbles:hover {
stroke: black;
}
</style>
<!-- Create a div where the graph will take place -->
<div id="bubblechart"></div>
<script>
// set the dimensions and margins of the graph
var margin = {top: 20, right: 20, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 500 - margin.top - margin.bottom;
// append the svg object to the body of the page (for some reason google chrome complains when I use bubblechart)
var svg = d3.select("body")
.append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + 10*margin.bottom)
.append("g")
.attr("transform",
"translate(" + margin.left + "," + margin.top + ")");
//Read the data
d3.csv("data/bubblechart.csv", function(data) {
// Add X axis
var x = d3.scaleLinear()
.domain([1970, 2013])
.range([ 0, width ]);
var xAxis = svg.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(x).tickFormat(d3.format(" ")));
// Add Y axis
var y = d3.scaleLinear()
.domain([0, 3300000000])
.range([ height, 0]);
svg.append("g")
.call(d3.axisLeft(y).tickFormat(d3.format("$" + ".2s")));
// Add a scale for bubble size
var z = d3.scaleLinear()
.domain([0, 3300000000])
.range([ 4, 40]);
// Add a scale for bubble color
var myColor = d3.scaleOrdinal()
.domain('pass','fail')
.range(["#fbb4ae", "#b3cde3"]);
// Add a clipPath: everything out of this area won't be drawn.
var clip = svg.append("defs").append("svg:clipPath")
.attr("id", "clip")
.append("svg:rect")
.attr("width", width )
.attr("height", height )
.attr("x", 0)
.attr("y", 0);
// Add brushing
var brush = d3.brushX() // Add the brush feature using the d3.brush function
.extent([ [0,0], [width,height] ]) // initialise the brush area: start at 0,0 and finishes at width,height: it means I select the whole graph area
.on("end", updateChart) // Each time the brush selection changes, trigger the 'updateChart' function
// Create a tooltip div that is hidden by default:
var tooltip =
d3.select("body")
.append("g")
.attr("class", "tooltip")
.style("background-color", "white")
.style("border", "solid")
.style("border-width", "1px")
.style("left", "70px")
.style("top", "40px")
.style("position", "absolute")
.style("width", "100px")
.style("border-radius", "5px")
.style("padding", "10px")
.style("opacity", 0)
var f = d3.format(".4s");
// Create functions to show / update (when mouse move but stay on same circle) / hide the tooltip
var showTooltip = function(d) {
tooltip
.transition()
.duration(200)
tooltip
.style("opacity", 1)
.html("<b>Title:</b> " + d.title + "<br>" + "<b> Year: </b>" + d.year + "<br>" + "<b>Gross Profit:</b> $" + f(d.intgross_2013) + "<br>" + "<b>Test Result:</b> " + d.clean_test)
.style("left", (d3.mouse(this)[0]+30) + "px")
.style("top", (d3.mouse(this)[1]+30) + "px")
}
var moveTooltip = function(d) {
tooltip
.style("left", (d3.mouse(this)[0]+30) + "px")
.style("top", (d3.mouse(this)[1]+30) + "px")
}
var hideTooltip = function(d) {
tooltip
.transition()
.duration(200)
.style("opacity", 0)
}
svg.append('g')
.attr("clip-path", "url(#clip)")
// Add the brushing
svg.append("g")
.attr("class", "brush")
.call(brush);
// A function that set idleTimeOut to null
var idleTimeout
function idled() { idleTimeout = null; }
// Not sure exactly what all of this does, but somehow I got it to work
var bubblechart = svg.append('g')
.selectAll("dot")
.data(data)
.enter()
.append("circle")
.attr("clip-path", "url(#clip)")
// Add transition
bubblechart
.attr("class", "bubbles")
.attr("cy", 500)
.attr("cx", function (d) { return x(d.year); } )
.transition().duration(1000)
.attr("cx", function (d) { return x(d.year); } )
.attr("cy", function (d) { return y(d.intgross_2013); } )
.attr("r", function (d) { return z(d.intgross_2013); } )
.style("fill", function (d) { return myColor(d.binary); } )
// -3- Trigger the functions
bubblechart
.on("mouseover", showTooltip )
.on("mousemove", moveTooltip )
.on("mouseleave", hideTooltip )
function updateTop(low_year, upper_year){
text = svg
.append("text")
.attr("x", 0)
.attr("y", height + 2*margin.bottom)
.attr("text-anchor", "left")
.append("tspan")
.text("Looking at the film budgets, it becomes obvious that high-budget films are more likely to fail the Bechdel test. While this trend seems to be leveling out over")
.append("tspan")
.attr("dy", "1em")
.attr("x", 0)
.text("time, this inequality is stil present, and most likely due to the lack of women in producer, director and writer roles in Hollywood.")
.append("tspan")
.attr("dy", "2em")
.attr("x", 0)
.text("Use the brushing tool to zoom in on certain years. Use the reset button to zoom back out.")
text
.append("tspan")
.style("font-size", "12px")
.attr("dy", "2em")
.attr("x", 0)
.style("text-decoration", "underline")
.text("Top 10 Movies")
var topData = data.filter(function(d){return (d.year >= low_year & d.year <= upper_year)})
.sort(function(a,b) {
return d3.descending(+a.intgross_2013, +b.intgross_2013);
}).slice(0, 10);
text_with_data = text
.selectAll("chart")
.data(topData)
.enter()
var f = d3.format("$" + ".2s");
text_with_data
.append("tspan")
.attr("dy", "1em")
.attr("x", 0)
.style("fill", function(d) {return myColor(d.binary)})
.text(function(d){return f(d.intgross_2013) + " " + d.title})
}
// A function that updates the chart for given boundaries
function updateChart() {
extent = d3.event.selection
// If no selection, back to initial coordinate. Otherwise, update X axis domain
if(!extent){
if (!idleTimeout) return idleTimeout = setTimeout(idled, 350); // This allows to wait a little bit
x.domain([ 4,8])
}else{
x.domain([ x.invert(extent[0]), x.invert(extent[1]) ])
svg.select(".brush").call(brush.move, null) // This remove the grey brush area as soon as the selection has been done
}
// Update axis and circle position
xAxis.transition().duration(1000).call(d3.axisBottom(x))
svg
.selectAll("circle")
.transition().duration(1000)
.attr("cx", function (d) { return x(d.year); } )
.attr("cy", function (d) { return y(d.intgross_2013); } )
}
updateTop(1970, 2010)
})
var button = d3.button()
.on('press', function(d, i) {updateTop(lyear, uyear)})
// Add buttons
var buttons = svg.selectAll('.button')
.data(data)
.enter()
.append('g')
.attr('class', 'button')
.call(button);
</script>
<button style="float:left" onClick="window.location.reload();">Reset</button>