Skip to content

Instantly share code, notes, and snippets.

@johnwalley
Last active January 13, 2020 03:45
Show Gist options
  • Save johnwalley/764d192d8b9971dc26ffd0556de887cd to your computer and use it in GitHub Desktop.
Save johnwalley/764d192d8b9971dc26ffd0556de887cd to your computer and use it in GitHub Desktop.
Bar Scatter Transition
license: mit
height: 668

Example of transitioning between a scatter chart and bar chart.

id risk return equity interest
Strategy 1 0.3 0.026 0.6 0.4
Strategy 2 0.16 0.031 0.8 0.2
Strategy 3 0.42 0.034 0.5 0.5
Strategy 4 0.08 0.06 0.5 0.5
Strategy 5 0.1 0.021 0.3 0.7
<!DOCTYPE html>
<html lang="en">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<div class="container">
<h1>Investment Strategies</h1>
<p>Different asset allocations offer a range of potential risk and return characteristics.
</p>
<div class="btn-group" role="group">
<button type="button" id="scatter" class="btn btn-default" value="scatter">Efficient frontier</button>
<button type="button" id="bar" class="btn btn-default" value="bar">Sources of investment risk</button>
</div>
<div>
<svg width="1024" height="480"></svg>
</div>
<p id="summary"></p>
</div>
<style>
.axis text,
.yAxis text {
font-family: sans-serif;
font-size: 14px;
fill: darkslategray;
}
</style>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script>
var DURATION = 500;
var margin = { top: 20, right: 20, bottom: 40, left: 160 };
var svg = d3.select("svg");
var width = +svg.attr("width") - margin.left - margin.right;
var height = +svg.attr("height") - margin.top - margin.bottom;
var g = svg.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var xScaleScatter = d3.scaleLinear()
.range([0, width]);
var xScaleBar = d3.scaleLinear()
.range([0, width]);
var yScaleScatter = d3.scaleLinear()
.range([height, 0]);
var yScaleBar = d3.scaleBand()
.range([height, 0])
.padding(0.2);
var z = d3.scaleOrdinal()
.range([
'#ccf7f6',
'#70e4e0',
'#00d8d2',
'#00acaf',
'#007f8c',
'#005e66',
'#003c3f',
'#002d2f',
'#0d2223'
]);
var idScale = d3.scaleOrdinal()
.range([
'#6aedc7', //green
'#39c2c9', //blue
'#ffce00', //yellow
'#ffa71a', //orange
'#f866b9', //pink
'#998ce3' //purple
]);
d3.csv('data.csv', function (d) {
d.risk = +d.risk;
d.return = +d.return;
d.equity = +d.equity;
d.interest = +d.interest;
return d;
}
, function (data) {
data = data.sort(function (a, b) { return a.return - b.return; })
xScaleScatter.domain([0, d3.max(data, function (d) { return d.risk; })]).nice();
xScaleBar.domain([0, 1]);
yScaleScatter.domain([0, d3.max(data, function (d) { return d.return; })]).nice();
yScaleBar.domain(data.map(function (d) { return d.id; }));
z.domain(["equity", "interest"]);
var xAxis = g.append("g")
.attr("class", "axis axis--x")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScaleScatter).ticks(10, "%"));
xAxis.select(".domain").remove();
xAxis.selectAll(".tick")
.attr("y", 20)
.attr("x", 0);
var yAxisScatter = g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(yScaleScatter).ticks(10, "%"));
yAxisScatter.select(".domain").remove();
yAxisScatter.selectAll(".tick")
.attr("y", 0)
.attr("x", -20);
var yAxisBar = g.append("g")
.attr("class", "axis axis--y")
.call(d3.axisLeft(yScaleBar));
yAxisBar.select(".domain").remove();
var bars = g.selectAll('.bar')
.data(data)
.enter()
.append("rect")
.attr("class", "bar")
.attr("cursor", "pointer")
.attr("fill", function (d) { return idScale(d.id); })
.attr("rx", 20)
.attr("ry", 20)
.attr("width", 20)
.attr("y", function (d) { return yScaleScatter(d.return) - 10; })
.attr("height", 20)
.attr("x", function (d) { return xScaleScatter(d.risk) - 10; });
var stack = d3.stack()
.keys(["equity", "interest"])
.order(d3.stackOrderNone);
var stacks = g.selectAll(".stack")
.data(stack(data))
.enter()
.append("g")
.attr("class", "stack")
.attr("fill", function (d) { return z(d.key); })
.selectAll("rect")
.data(function (d) { return d; })
.enter()
.append("rect")
.attr("y", function (d) { return yScaleBar(d.data.id); })
.attr("x", function (d) { return xScaleBar(d[0]); })
.attr("height", yScaleBar.bandwidth())
.attr("width", function (d) { return (xScaleBar(d[1]) - xScaleBar(d[0])); })
.attr("opacity", 0);
var previousChartType = "scatter";
drawScatter();
d3.select("#scatter").on("click", function () {
drawScatter();
});
d3.select("#bar").on("click", function () {
drawBar();
});
function drawScatter() {
d3.select("#summary").text("Risk and return position of the five investment strategies. The vertical axis shows the potential return. The horizontal axis shows the Value at Risk (VaR).");
xAxis.transition()
.duration(DURATION)
.call(d3.axisBottom(xScaleScatter).ticks(10, "%"));
xAxis.select(".domain").remove();
yAxisScatter.transition()
.duration(DURATION)
.delay(3 * DURATION)
.attr('opacity', 1);
yAxisBar.transition()
.duration(DURATION)
.delay(previousChartType === "bar" ? 3 * DURATION : 0)
.attr('opacity', 0);
bars.transition()
.duration(previousChartType === "bar" ? DURATION : 0)
.delay(DURATION)
.style("opacity", 1)
.transition()
.duration(previousChartType === "bar" ? DURATION : 0)
.attr("rx", 20)
.attr("ry", 20)
.attr("width", 20)
.attr("x", function (d) { return xScaleScatter(d.risk) - 10; })
.attr("height", 20)
.attr("y", function (d) { return yScaleBar(d.id) + yScaleBar.bandwidth() / 2 - 10; })
.transition()
.duration(previousChartType === "bar" ? DURATION : 0)
.attr("y", function (d) {
return yScaleScatter(d.return) - 10;
});
stacks.transition()
.transition()
.duration(DURATION)
.attr("y", function (d) { return yScaleBar(d.data.id); })
.attr("x", function (d) { return xScaleScatter(d[0]) * d.data.risk; })
.attr("width", function (d) { return (xScaleScatter(d[1]) - xScaleScatter(d[0])) * d.data.risk; })
.transition()
.duration(previousChartType === "bar" ? DURATION : 0)
.style("opacity", 0);
previousChartType = "scatter";
}
function drawBar() {
d3.select("#summary").text("Sources of the investment risk underlying the five investment strategies");
xAxis.transition()
.duration(DURATION)
.delay(3 * DURATION)
.call(d3.axisBottom(xScaleBar).ticks(10, "%"));
xAxis.select(".domain").remove();
yAxisScatter.transition()
.duration(DURATION)
.attr('opacity', 0);
yAxisBar.transition()
.duration(DURATION)
.attr('opacity', 1);
bars.transition()
.duration(previousChartType === "scatter" ? DURATION : 0)
.attr("y", function (d) { return yScaleBar(d.id) + yScaleBar.bandwidth() / 2 - 10; })
.transition()
.duration(previousChartType === "scatter" ? DURATION : 0)
.attr("y", function (d) { return yScaleBar(d.id); })
.attr("height", yScaleBar.bandwidth())
.attr("rx", 0)
.attr("ry", 0)
.attr("x", function (d) { return xScaleScatter(0); })
.attr("width", function (d) { return xScaleScatter(d.risk); })
.transition()
.duration(previousChartType === "scatter" ? DURATION : 0)
.style("opacity", 1);
stacks.transition()
.duration(previousChartType === "scatter" ? DURATION : 0)
.delay(2 * DURATION)
.style("opacity", 1)
.transition()
.duration(DURATION)
.attr("y", function (d) { return yScaleBar(d.data.id); })
.attr("x", function (d) { return xScaleBar(d[0]); })
.attr("width", function (d) { return xScaleBar(d[1]) - xScaleBar(d[0]); });
previousChartType = "bar";
}
function drawBar2() {
xAxisScatter.transition()
.duration(DURATION)
.attr('opacity', 0);
xAxisBar.transition()
.duration(DURATION)
.attr('opacity', 1);
yAxis.transition()
.duration(DURATION)
.delay(DURATION)
.call(d3.axisLeft(yScaleBar).ticks(10, "%"))
bars.transition()
.duration(previousChartType === "scatter" ? DURATION : 0)
.attr("x", function (d) { return xScaleScatterBar(d.id) + xScaleScatterBar.bandwidth() / 2; })
.transition()
.duration(previousChartType === "scatter" ? DURATION : 0)
.attr("x", function (d) { return xScaleScatterBar(d.id); })
.attr("width", xScaleScatterBar.bandwidth())
.attr("rx", 0)
.attr("ry", 0)
.attr("y", function (d) { return yScaleBar(d.risk); })
.attr("height", function (d) { return height - yScaleBar(d.risk); })
.transition()
.duration(previousChartType === "scatter" ? DURATION : 0)
.style("opacity", 0);
stacks.transition()
.duration(previousChartType === "scatter" ? DURATION : 0)
.delay(2 * DURATION)
.style("opacity", 1);
previousChartType = "bar";
}
});
</script>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment