James Keirstead implemented slopegraphs in R based on the the very thorough post from Charlie Park. I couldn't resist trying to do something similar with rCharts and dimplejs.
A slopegraph most closely resembles a line graph. Let's plot the data in a simple line graph using type = 'line'
with dimple.
d1 <- dPlot2( #dPlot2 for minor internal change to iframesrc
value ~ year,
groups = "group",
data = data,
type = "line",
height = 800,
width = 550,
bounds = list(x=200,y=30,height=700,width=300)
)
d1$show("iframesrc")
Let's transform this simple line with some javascript. I'll incorporate this nice labelling example to help us avoid overlapping labels on our y axis.
#with improvements from afterScript template
d1$setTemplate(
afterScript = "
<script>
//axes adjustments for slopegraph
//based on template myChart.axes[2] should be y
//but just to make sure do map
var ySlope = myChart.axes.filter(function(axis){return axis.position==='y'})[0];
var xSlope = myChart.axes.filter(function(axis){return axis.position==='x'})[0]
//remove axis labels if desired
ySlope.shapes.remove();
//remove gridlines
ySlope.gridlineShapes.remove();
//remove axis title
ySlope.titleShape.remove();
var slopelabels = d3.select('#'+opts.id).select('svg').select('g').append('g')
.attr('class','slopelabels')
//get unique values for groups in data
//note will only work with one group level
var firstPoints = data.filter(function(d){
return d[opts.x] == myChart.axes[0]._draw.scale().domain()[0];
});
slopelabels.selectAll('text')
.data(firstPoints)
.enter()
.append('text')
.attr('class','labels')
//.attr('x', function(d){
// return xSlope._scale(d[opts.x])
//})
.attr('x',d3.select('.axis').select('.tick text').attr('x') - 20)
.attr('y', function(d){
return ySlope._scale(d[opts.y])
})
.attr('dy','0.2em')
.attr('transform',d3.select('.axis').select('.tick').attr('transform'))
.attr('fill',function(d) {
return myChart._assignedColors[d[opts.groups]].fill
})
//.attr('stroke',function(d){return myChart._assignedColors[d[opts.groups]].stroke})
.attr('opacity',function(d){return myChart._assignedColors[d[opts.groups]].opacity})
.style('text-anchor','end')
.text(function(d){
return d[opts.groups]
});
// constraint relaxation on labels
// from http://bl.ocks.org/syntagmatic/4053096
//add y for each of these to use code as is
firstPoints.forEach(function(d){
d.y = ySlope._scale(d[opts.y]);
})
var alpha = 0.5;
var spacing = 12;
function relax() {
var again = false;
firstPoints.forEach(function(a,i) {
firstPoints.slice(i+1).forEach(function(b) {
var dy = a.y - b.y;
if (Math.abs(dy) < spacing) {
again = true;
var sign = dy > 0 ? 1 : -1;
a.y += sign*alpha;
b.y -= sign*alpha;
}
});
});
d3.selectAll('.labels')
.attr('y', function(d) {
return d.y;
});
if (again) setTimeout(relax,20);
};
relax();
//add numbers to each point
var pointtext = d3.select('#'+opts.id).select('svg').select('g').append('g')
.attr('class','pointtext')
pointtext.selectAll('text')
.data(data)
.enter()
.append('g')
.attr('transform',function(d){
return d3.select(d3.select('.axis').selectAll('.tick')[0].filter(function(dd){
return d3.select(dd).datum() == d[opts.x]
})[0]).attr('transform')
})
.append('text')
.attr('x',function(d){
return d3.select('.axis').select('.tick text').attr('x')
})
.attr('y',function(d){
return ySlope._scale(d[opts.y])})
.attr('dy','0.2em')
//.attr('fill',function(d){return myChart._assignedColors[d[opts.groups]].fill})
//.attr('stroke',function(d){return myChart._assignedColors[d[opts.groups]].stroke})
//.attr('opacity',function(d){return myChart._assignedColors[d[opts.groups]].opacity})
.attr('text-anchor','middle')
.style('font-size','12')
.style('pointer-events','none')
.text(function(d){
return d[opts.y]
})
</script>"
)
d1$show("iframesrc")