Skip to content

Instantly share code, notes, and snippets.

@jfreels
Created October 11, 2013 21:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jfreels/6942006 to your computer and use it in GitHub Desktop.
Save jfreels/6942006 to your computer and use it in GitHub Desktop.
d3js: Allocation, return, and attribution example. Sortable, horizontal bar chart with positive and negative values that change on select input.
{
"keys" : [
"variable",
"date",
"allocation",
"return",
"attribution"
],
"values" : [
{
"variable" : "Convertible Arbitrage",
"date" : 14487,
"allocation" : 0.12905,
"return" : 0.0315,
"attribution" : 0.004065
},
{
"variable" : "CTA Global",
"date" : 14487,
"allocation" : 0.12462,
"return" : 0.0054,
"attribution" : 0.00067293
},
{
"variable" : "Distressed Securities",
"date" : 14487,
"allocation" : 0.0070071,
"return" : 0.0244,
"attribution" : 0.00017097
},
{
"variable" : "Emerging Markets",
"date" : 14487,
"allocation" : 0.013153,
"return" : 0.0166,
"attribution" : 0.00021834
},
{
"variable" : "Equity Market Neutral",
"date" : 14487,
"allocation" : 0.013939,
"return" : 0.007,
"attribution" : 9.7575e-05
},
{
"variable" : "Event Driven",
"date" : 14487,
"allocation" : 0.04947,
"return" : 0.0207,
"attribution" : 0.001024
},
{
"variable" : "Fixed Income Arbitrage",
"date" : 14487,
"allocation" : 0.083955,
"return" : 0.0202,
"attribution" : 0.0016959
},
{
"variable" : "Global Macro",
"date" : 14487,
"allocation" : 0.017134,
"return" : 0.005,
"attribution" : 8.5669e-05
},
{
"variable" : "Long Short Equity",
"date" : 14487,
"allocation" : 0.063293,
"return" : 0.0157,
"attribution" : 0.00099371
},
{
"variable" : "Merger Arbitrage",
"date" : 14487,
"allocation" : 0.16361,
"return" : 0.0102,
"attribution" : 0.0016688
},
{
"variable" : "Relative Value",
"date" : 14487,
"allocation" : 0.11604,
"return" : 0.0162,
"attribution" : 0.0018799
},
{
"variable" : "Short Selling",
"date" : 14487,
"allocation" : 0.010975,
"return" : -0.0165,
"attribution" : -0.00018109
},
{
"variable" : "Funds of Funds",
"date" : 14487,
"allocation" : 0.20776,
"return" : 0.0113,
"attribution" : 0.0023476
}
]
}
<!DOCTYPE html>
<meta charset='utf-8'>
<html>
<head>
<script src="http://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<link rel='stylesheet' href='style.css'>
</head>
<body>
<script type='text/javascript' src='script.js'></script>
</body>
</html>
//http://bl.ocks.org/mbostock/5977197
//http://bl.ocks.org/mbostock/3885705
var selectDiv = d3.select('body').append('div').attr('class','selectDiv')
var margin = {top: 20, right: 20, bottom: 30, left: 150},
width = 900 - margin.left - margin.right,
height = 600 - margin.top - margin.bottom;
var formatPercent = d3.format(".0%");
var formatPercent2 = d3.format(".2%");
var svg = d3.select("body").append("svg")
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var dataset = [] // able to look at dataset in console
d3.json('data.json',function (error,data) {
data.values.forEach(function (d) {
d.variable = d.variable.toString()
d.allocation = +d.allocation
d.return = +d.return
d.attribution = +d.attribution
})
data.keys.shift() // remove keys.date
data.keys.shift() // remove keys.variable
dataset = data // able to look at dataset in console
d3.select('.selectDiv')
.append('select')
.attr('id','selectVariable')
.on('change',change)
.selectAll('option')
.data(data.keys).enter()
.append('option')
.attr('value',function (d) { return d; })
.text(function (d) { return d;})
var selectVariableValue = d3.select('#selectVariable').property('value')
d3.select('.selectDiv')
.append('label')
.text('Sort?')
.append('input')
.attr('id','sortCheckbox')
.attr('type','checkbox')
.attr('value','sort')
.attr('name','sort')
.on('change',sortBars)
var yValue = function(d) { return d['variable']; }, // data -> value
yScale = d3.scale.ordinal().rangeRoundBands([0, height], 0.1), // value -> display
yMap = function(d) { return yScale(yValue(d)); }, // data -> display
yAxis = d3.svg.axis().scale(yScale).orient("left");
var xValue = function(d) { return d[selectVariableValue]; }, // data -> value
xScale = d3.scale.linear().range([0,width]), // value -> display
xMap = function(d) { return xScale(xValue(d)); }, // data -> display
xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickFormat(formatPercent);
var xScaleMax = d3.max([
d3.max([d3.max(data.values,xValue),0]), // max positive value
Math.abs(d3.min([d3.min(data.values,xValue),0])) // min negative value
])
yScale.domain(data.values.map(yValue));
xScale.domain([0,d3.max(data.values,xValue)]).nice()
// Create axes
svg.append("g")
.attr("class", "axis")
.attr('id','xAxis')
.attr("transform", "translate(0," + height + ")")
.call(xAxis)
svg.append("g")
.attr("class", "axis")
.attr('id','yAxis')
.call(yAxis)
// Create bars
var bars = svg.selectAll(".bar")
.data(data.values)
bars.enter()
.append("rect")
.attr("class", function (d) { return ( d[selectVariableValue] > 0 )
? 'barPos'
: 'barNeg'})
.attr('x', function (d) { return xScale(Math.min(0,d[selectVariableValue]));})
.attr("y", yMap)
.attr("width", function (d) { return Math.abs(xScale(d[selectVariableValue]) - xScale(0));})
.attr("height", yScale.rangeBand())
bars.append('title')
.text(function (d) { return d['variable'] + '\n' + selectVariableValue + ": " + formatPercent2(d[selectVariableValue]); })
function change() {
var value = this.value // get new dataset value
d3.select('#sortCheckbox').property('checked',false)
if(value==='attribution') {
var formatPercent = d3.format(".2%")
} else {
var formatPercent = d3.format(".0%")
}
var xValue = function(d) { return d[value]; }, // data -> value
xScale = d3.scale.linear().range([0,width]), // value -> display
xMap = function(d) { return xScale(xValue(d)); }, // data -> display
xAxis = d3.svg.axis().scale(xScale).orient("bottom").tickFormat(formatPercent);
var xScaleMax = d3.max([
d3.max([d3.max(data.values,xValue),0]), // max positive value
Math.abs(d3.min([d3.min(data.values,xValue),0])) // min negative value
])
value==='allocation'
? xScale.domain([0,d3.max(data.values,xValue)]).nice()
: xScale.domain([-xScaleMax,xScaleMax]).nice()
bars.selectAll('title')
.text(function (d) { return d['variable'] + '\n' + value + ": " + formatPercent2(d[value]); })
bars.transition().duration(1000) // redraw the bars
.attr("class", function (d) { return d[value] > 0 ? 'barPos':'barNeg'})
.attr('x', function (d) { return xScale(Math.min(0,d[value]));})
.attr("y", yMap)
.attr("width", function (d) { return Math.abs(xScale(d[value]) - xScale(0));})
.attr("height", yScale.rangeBand())
d3.select('#xAxis') // redraw the x axis
.transition().duration(1000)
.call(xAxis)
}
function sortBars() {
var value = d3.select('select').property('value')
var y0 = yScale.domain(data.values.sort(this.checked
? function (a,b) { return b[value] - a[value]; }
: function (a,b) { return d3.ascending(a['variable'],b['variable']); })
.map(function (d) { return d['variable']; }))
.copy()
var transition = svg.transition().duration(1000),
delay = function (d,i) { return i*50 }
transition.selectAll('rect')
.delay(delay)
.attr('y', function (d) { return y0(d.variable)})
transition.select('#yAxis')
.call(yAxis)
.selectAll('g')
.delay(delay)
}
})
body {
font: 10px sans-serif;
}
label {
font: 14px sans-serif;
}
.axis path,
.axis line {
fill: none;
stroke: #000;
shape-rendering: crispEdges;
}
.barPos {
fill: steelblue;
}
.barNeg {
fill: brown;
}
.barPos:hover,
.barNeg:hover {
fill: orange;
}
.values {
fill: black;
}
.variableLabels {
fill: black;
text-anchor: start;
font-size: 14px;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment