rCharts + dimple | Slopegraph

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.

First Try | Out of the Box

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)

With Some Javascript Adjustments

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
  afterScript = "
  //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
  //remove gridlines
  //remove axis title

  var slopelabels = d3.select('#'+opts.id).select('svg').select('g').append('g')

  //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];

    //.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('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})
      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
      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;
        .attr('y', function(d) {
        return d.y;
      if (again) setTimeout(relax,20);


    //add numbers to each point
    var pointtext = d3.select('#'+opts.id).select('svg').select('g').append('g')
        return d3.select(d3.select('.axis').selectAll('.tick')[0].filter(function(dd){
          return d3.select(dd).datum() == d[opts.x]
        return d3.select('.axis').select('.tick text').attr('x')
        return ySlope._scale(d[opts.y])})
      //.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})
        return d[opts.y]