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.

  1. d1 <- dPlot2( #dPlot2 for minor internal change to iframesrc
  2. value ~ year,
  3. groups = "group",
  4. data = data,
  5. type = "line",
  6. height = 800,
  7. width = 550,
  8. bounds = list(x=200,y=30,height=700,width=300)
  9. )
  10. d1$show("iframesrc")

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.

  1. #with improvements from afterScript template
  2. d1$setTemplate(
  3. afterScript = "
  4. <script>
  5. //axes adjustments for slopegraph
  6. //based on template myChart.axes[2] should be y
  7. //but just to make sure do map
  8. var ySlope = myChart.axes.filter(function(axis){return axis.position==='y'})[0];
  9. var xSlope = myChart.axes.filter(function(axis){return axis.position==='x'})[0]
  10. //remove axis labels if desired
  11. ySlope.shapes.remove();
  12. //remove gridlines
  13. ySlope.gridlineShapes.remove();
  14. //remove axis title
  15. ySlope.titleShape.remove();
  16. var slopelabels = d3.select('#'+opts.id).select('svg').select('g').append('g')
  17. .attr('class','slopelabels')
  18. //get unique values for groups in data
  19. //note will only work with one group level
  20. var firstPoints = data.filter(function(d){
  21. return d[opts.x] == myChart.axes[0]._draw.scale().domain()[0];
  22. });
  23. slopelabels.selectAll('text')
  24. .data(firstPoints)
  25. .enter()
  26. .append('text')
  27. .attr('class','labels')
  28. //.attr('x', function(d){
  29. // return xSlope._scale(d[opts.x])
  30. //})
  31. .attr('x',d3.select('.axis').select('.tick text').attr('x') - 20)
  32. .attr('y', function(d){
  33. return ySlope._scale(d[opts.y])
  34. })
  35. .attr('dy','0.2em')
  36. .attr('transform',d3.select('.axis').select('.tick').attr('transform'))
  37. .attr('fill',function(d) {
  38. return myChart._assignedColors[d[opts.groups]].fill
  39. })
  40. //.attr('stroke',function(d){return myChart._assignedColors[d[opts.groups]].stroke})
  41. .attr('opacity',function(d){return myChart._assignedColors[d[opts.groups]].opacity})
  42. .style('text-anchor','end')
  43. .text(function(d){
  44. return d[opts.groups]
  45. });
  46. // constraint relaxation on labels
  47. // from http://bl.ocks.org/syntagmatic/4053096
  48. //add y for each of these to use code as is
  49. firstPoints.forEach(function(d){
  50. d.y = ySlope._scale(d[opts.y]);
  51. })
  52. var alpha = 0.5;
  53. var spacing = 12;
  54. function relax() {
  55. var again = false;
  56. firstPoints.forEach(function(a,i) {
  57. firstPoints.slice(i+1).forEach(function(b) {
  58. var dy = a.y - b.y;
  59. if (Math.abs(dy) < spacing) {
  60. again = true;
  61. var sign = dy > 0 ? 1 : -1;
  62. a.y += sign*alpha;
  63. b.y -= sign*alpha;
  64. }
  65. });
  66. });
  67. d3.selectAll('.labels')
  68. .attr('y', function(d) {
  69. return d.y;
  70. });
  71. if (again) setTimeout(relax,20);
  72. };
  73. relax();
  74. //add numbers to each point
  75. var pointtext = d3.select('#'+opts.id).select('svg').select('g').append('g')
  76. .attr('class','pointtext')
  77. pointtext.selectAll('text')
  78. .data(data)
  79. .enter()
  80. .append('g')
  81. .attr('transform',function(d){
  82. return d3.select(d3.select('.axis').selectAll('.tick')[0].filter(function(dd){
  83. return d3.select(dd).datum() == d[opts.x]
  84. })[0]).attr('transform')
  85. })
  86. .append('text')
  87. .attr('x',function(d){
  88. return d3.select('.axis').select('.tick text').attr('x')
  89. })
  90. .attr('y',function(d){
  91. return ySlope._scale(d[opts.y])})
  92. .attr('dy','0.2em')
  93. //.attr('fill',function(d){return myChart._assignedColors[d[opts.groups]].fill})
  94. //.attr('stroke',function(d){return myChart._assignedColors[d[opts.groups]].stroke})
  95. //.attr('opacity',function(d){return myChart._assignedColors[d[opts.groups]].opacity})
  96. .attr('text-anchor','middle')
  97. .style('font-size','12')
  98. .style('pointer-events','none')
  99. .text(function(d){
  100. return d[opts.y]
  101. })
  102. </script>"
  103. )
  104. d1$show("iframesrc")