Skip to content

Instantly share code, notes, and snippets.

@delgadom
Last active May 21, 2018 01:32
Show Gist options
  • Save delgadom/7fe6b33276fb4aca80656a5541a05988 to your computer and use it in GitHub Desktop.
Save delgadom/7fe6b33276fb4aca80656a5541a05988 to your computer and use it in GitHub Desktop.
simple econometric walkthrough

This gist walks the user through a scatter plot and set of lines and text based on csv data

<!DOCTYPE html>
<html>
<head>
<!-- Load D3 from site -->
<script src="http://d3js.org/d3.v4.min.js" charset="utf-8"></script>
<link rel="stylesheet" href="scatter.css"></style>
</head>
<!-- CSS (Styling) -->
<!-- End CSS (Styling) -->
<body>
<h4>Next step</h4>
<h3></h3
<!-- Begin D3 Javascript -->
<script type="text/javascript" src="scatter.js"></script>
</body>
</html>
step line point x y w color
1 0 0 20 60 1 black
1 0 1 140 95 1 black
2 0 0 5 72 1 blue
2 0 1 60 100 1 blue
2 1 0 40 170 1 green
2 1 1 90 135 1 green
2 2 0 155 65 1 red
2 2 1 190 90 1 red
3 0 0 35 10 1 blue
3 0 1 55 70 1 blue
3 1 0 70 15 1 green
3 1 1 85 60 1 green
3 2 0 112 65 1 red
3 2 1 120 90 1 red
4 0 0 250 80 1 red
4 0 1 393 47 1 red
4 0 2 467 63 1 red
4 1 0 7 137 1 blue
4 1 1 120 91 1 blue
4 1 2 212 73 1 blue
4 2 0 340 111 1 green
4 2 1 473 92 1 green
4 2 2 589 149 1 green
4 3 0 50 130 3 black
4 3 1 250 70 3 black
4 3 2 500 110 3 black
5 0 0 15 70 1 red
5 0 1 30 50 1 red
5 0 2 62 84 1 red
5 1 0 80 130 1 blue
5 1 1 90 130 1 blue
5 1 2 126 110 1 blue
5 2 0 122 20 1 green
5 2 1 130 50 1 green
5 2 2 157 80 1 green
step x y r color
0 30 50 2 black
0 15 70 2 black
0 62 84 2 black
0 80 130 4 black
0 126 110 4 black
0 90 130 4 black
0 130 50 1 black
0 157 80 1 black
0 122 20 1 black
1 30 50 2 red
1 15 70 2 red
1 62 84 2 red
1 80 130 4 blue
1 126 110 4 blue
1 90 130 4 blue
1 130 50 1 green
1 157 80 1 green
1 122 20 1 green
2 150 80 8 red
2 167 63 8 red
2 193 97 8 red
2 20 61 2 blue
2 1 73 2 blue
2 57 97 2 blue
2 40 171 8 green
2 73 132 8 green
2 89 149 8 green
3 110 71 2 red
3 116 90 2 red
3 119 68 2 red
3 43 9 2 blue
3 48 62 2 blue
3 41 37 2 blue
3 73 25 8 green
3 79 43 8 green
3 77 32 8 green
4 250 80 1 red
4 467 63 1 red
4 393 47 1 red
4 120 91 1 blue
4 212 73 1 blue
4 7 137 1 blue
4 340 111 1 green
4 473 92 1 green
4 589 149 1 green
5 30 50 2 red
5 15 70 2 red
5 62 84 2 red
5 80 130 4 blue
5 126 110 4 blue
5 90 130 4 blue
5 130 50 1 green
5 157 80 1 green
5 122 20 1 green
/* Format X and Y Axis */
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
.regression-line {
fill: none;
}
var current_index = 0;
var sorted_points = [];
var sorted_lines = [];
var sorted_text = [];
var max_steps = 1;
// Setup settings for graphic
var canvas_width = 600;
var canvas_height = 300;
var padding_horiz = 70; // for chart edges
var padding_vert = 30; // for chart edges
// initialize scale functions
var xScale = d3.scaleLinear().domain([0, 1]).range([padding_horiz, canvas_width - padding_horiz * 2]);
var yScale = d3.scaleLinear().domain([0, 1]).range([canvas_height - padding_vert, padding_vert]);
var zScale = d3.scaleLinear().domain([0, 1]).range([1, 8]);
// Define X axis
var xAxis = d3.axisBottom(xScale);
// Define Y axis
var yAxis = d3.axisLeft(yScale);
// Create SVG element
var svg = d3.select("h3") // This is where we put our vis
.append("svg")
.attr("width", canvas_width)
.attr("height", canvas_height)
var line = d3.line()
.x(function(d) { return xScale(Number(d.x)); })
.y(function(d) { return yScale(Number(d.y)); })
.curve(d3.curveMonotoneX);
var initialize_points = function(points_dataset) {
points_dataset.forEach(function(elem) {
elem.step = Number(elem.step);
elem.x = Number(elem.x);
elem.y = Number(elem.y);
elem.r = Number(elem.r);
});
points_dataset.forEach(function(elem) {
while (Number(elem['step']) >= sorted_points.length - 1) {
sorted_points.push(new Array());
}
sorted_points[Number(elem['step'])].push(elem);
});
// update max steps with length of sorted_points
if (sorted_points.length > max_steps) {
max_steps = sorted_points.length;
};
// Setup data
var dataset = sorted_points[0]; // Initialize empty array
// Create scale functions
xScale.domain([0, d3.max(dataset, function(d) {
return d['x']; // input domain
})])
.range([padding_horiz, canvas_width - padding_horiz * 2]); // output range
yScale.domain([0, d3.max(dataset, function(d) {
return d['y']; // input domain
})])
.range([canvas_height - padding_vert, padding_vert]); // remember y starts on top going down so we flip
zScale.domain([0, d3.max(dataset, function(d) {
return d['r']; // input domain
})])
.range([1, 8]); // remember z starts on top going down so we flip
// Define X axis
d3.axisBottom(xScale)
.ticks(5);
// Define Y axis
d3.axisLeft(yScale)
.ticks(5);
// Create Circles
svg.selectAll("circle")
.data(dataset)
.enter()
.append("circle") // Add circle svg
.attr("cx", function(d) {
return xScale(d['x']); // Circle's X
})
.attr("cy", function(d) { // Circle's Y
return yScale(d['y']);
})
.attr("r", function(d) {
return zScale(d['r']);
}) // radius
.attr("fill", function(d) {
return d['color'];
}); // Change color
// Add to X axis
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + (canvas_height - padding_vert) +")")
.call(xAxis);
// Add to Y axis
svg.append("g")
.attr("class", "y axis")
.attr("transform", "translate(" + padding_horiz +",0)")
.call(yAxis);
}
var initialize_lines = function(lines_dataset) {
lines_dataset.forEach(function(elem) {
elem.point = Number(elem.point);
elem.line = Number(elem.line);
elem.step = Number(elem.step);
elem.x = Number(elem.x);
elem.y = Number(elem.y);
elem.w = Number(elem.w);
});
lines_dataset.forEach(function(elem) {
while (Number(elem['step']) >= sorted_lines.length) {
sorted_lines.push(new Array());
}
sorted_lines[Number(elem['step'])].push(elem);
});
// update max steps with length of sorted_lines
if (sorted_lines.length > max_steps) {
max_steps = sorted_lines.length;
};
var lines = [];
if (sorted_lines[current_index] !== undefined) {
sorted_lines[0].forEach(function(elem) {
while (Number(elem['line']) >= lines.length - 1) {
lines.push(new Array());
};
lines[Number(elem['line'])].push(elem);
});
lines.forEach(function(l) {
svg.append("path")
.data(l)
.attr("class", "regression-line")
.attr("stroke", function(d) { return d.color })
.attr("d", line(l)
)});
};
}
var initialize_text = function(text_dataset) {
text_dataset.forEach(function(elem) {
elem.step = Number(elem.step);
elem.x = Number(elem.x);
elem.y = Number(elem.y);
elem.font_size = Number(elem.font_size);
});
text_dataset.forEach(function(elem) {
while (Number(elem['step']) >= sorted_text.length - 1) {
sorted_text.push(new Array());
}
sorted_text[Number(elem['step'])].push(elem);
});
// update max steps with length of sorted_text
if (sorted_text.length > max_steps) {
max_steps = sorted_text.length;
};
updateText();
}
var updateLines = function() {
// Update lines
var lines = [];
if (sorted_lines[current_index] !== undefined) {
sorted_lines[current_index].forEach(function(elem) {
while (Number(elem['line']) >= lines.length - 1) {
lines.push(new Array());
};
lines[Number(elem['line'])].push(elem);
});
lines.forEach(function(l) {
svg.append("path")
.data(l)
.attr("class", "regression-line")
.attr("stroke", function(d) { return d.color })
.attr("d", line(l)
)});
};
}
var updateText = function() {
svg.selectAll('text')
.filter('.text-label')
.remove();
setTimeout(function() {
if (sorted_text[current_index] !== undefined) {
sorted_text[current_index].forEach(function(elem) {
svg.append("text")
.attr("class", "p text-label")
.attr("x", xScale(elem['x']))
.attr("y", yScale(elem['y']))
.text(elem['text'])
.attr('font-size', elem['font-size'])
.attr('text-anchor', elem['text-anchor'])
.attr('fill', elem['color'])
});
}
}, 1000);
}
var step_through_animation = function() {
current_index = (current_index + 1) % sorted_points.length;
var dataset = sorted_points[current_index];
// Update scale domains
xScale.domain([0, d3.max(dataset, function(d) {
return d['x']; })]);
yScale.domain([0, d3.max(dataset, function(d) {
return d['y']; })]);
zScale.domain([0, d3.max(dataset, function(d) {
return d['r']; })]);
svg.selectAll('path')
.transition()
.duration(100)
.remove();
// Update circles
svg.selectAll("circle")
.data(dataset) // Update with new data
.transition() // Transition from old to new
.duration(1000) // Length of animation
.delay(function(d, i) {
return i / dataset.length * 500; // Dynamic delay (i.e. each item delays a little longer)
})
//.ease("linear") // Transition easing - default 'variable' (i.e. has acceleration), also: 'circle', 'elastic', 'bounce', 'linear'
.attr("cx", function(d) {
return xScale(d['x']); // Circle's X
})
.attr("cy", function(d) {
return yScale(d['y']); // Circle's Y
})
.attr("r", function(d) {
return zScale(d['r']); // Circle's size
})
.attr("fill", function(d) {
return d['color'];
}) // Change color;
.on("end", updateLines)
// Update X Axis
svg.select(".x.axis")
.transition()
.duration(1000)
.call(xAxis);
// Update Y Axis
svg.select(".y.axis")
.transition()
.duration(1000)
.call(yAxis);
updateText();
}
d3.csv("points.csv", function(points_dataset) {
initialize_points(points_dataset);
});
d3.csv("lines.csv", function(lines_dataset) {
initialize_lines(lines_dataset);
});
d3.csv("text.csv", function(text_dataset) {
initialize_text(text_dataset);
});
// On click, update with new data
d3.select("h4").on("click", function() {
step_through_animation();
});
step x y font-size color text-anchor text
1 110 100 10 black end simple linear regression on all points
2 100 120 14 black start this is another piece of text
3 35 50 12 blue center i1
3 65 40 12 green center i2
3 103 80 12 red center i3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment