ramnathv / rCharts

Interactive JS Charts from R
http://rcharts.io
Other
1.19k stars 654 forks source link

Format dimple axis with a function? #421

Closed walkerke closed 9 years ago

walkerke commented 10 years ago

I'm currently working on a project to develop interactive population pyramids using rCharts. These charts require some of the population values to be negative numbers; however, I want all of the values on the population axis to show absolute values, not the negative values in the data.

I have figured out how to do this correctly with Highcharts and NVD3 by passing a JS function to the axis's properties. However, I can't figure out how to do this with Dimple (which is the library I am most interested in due to its Storyboard property).

For clarification, I've included a reproducible example here: http://dl.dropboxusercontent.com/s/waqm14a72s32mog/pyramid_example.html.

I'm going to keep working to figure this out myself, but I thought I'd ask here as well in case someone with more JS experience than myself has a quick fix.

Thanks for all your work on this package, it is really incredible!

timelyportfolio commented 10 years ago

Thanks so much for an easily reproducible issue. dimple.js uses the ... from d3.format(...) and as far as I know does not allow formatting through function(d){return ...}, but I could be mistaken here. Here is one solution, but it is admitttedly a little hacky. However, the ease of access from the dimple design, allows us to do some pretty fancy things. The newest rCharts lets us accomplish these hacks through the afterScript parameter.

#rCharts issue #421

dat <- data.frame(Age = rep(c("0-4", "5-9", "10-14", "15-19", "20-24", "25-29", "30-34", "35-39", "40-44", "45-49",
                              "50-54", "55-59", "60-64", "65-69", "70-74", "75-79", "80-84", "85-89", "90-94",
                              "95-99", "100+"), 2),
                  Gender = rep(c("Male", "Female"), each = 21), 
                  Population = c(-10597149, -10463160, -10520040, -10731809,
                                 -11704248, -11162189, -10805435, -9918820,
                                 -10191657, -10316211, -11058480, -10435062, 
                                 -8873957, -7237434, -5092364, -3501387, -2375076,
                                 -1408466, -562765, -114047, -13105, 10134157,
                                 10014685, 10072264, 10216850, 11105011,
                                 10763303, 10680178, 9938587, 10328779, 10498065,
                                 11462719, 11048682, 9671602, 8059112, 5962386, 4402017,
                                 3376338, 2420464, 1243054, 350761, 60228), 
                  ord = 1:42)

library(rCharts)

dat <- dat[order(rev(dat$ord)), ]

dat$Population <- dat$Population / 1000000

d1 <- dPlot(
  x = "Population", 
  y = "Age", 
  groups = "Gender", 
  data = dat, 
  type = 'bar')

d1$yAxis(type = "addCategoryAxis", orderRule = "ord")
d1$xAxis(
  type = "addMeasureAxis", 
  outputFormat = "#!
function(d) {
    return d3.format(',.1f')(Math.abs(d)) + 'M'
}
!#"
)
d1$legend(
  x = 60
  , y = 10
  , width = 700
  , height = 20
  , horizontalAlign = "left"
)
#will not work with multiple inline charts on the same page
#however should work fine if using iframes
d1$setTemplate( afterScript = 
"
<script>
  myChart.axes[0].shapes.selectAll('text').text(function(d){
    return Math.abs(d);
  })
</script>
")

d1
ramnathv commented 10 years ago

@timelyportfolio is right in that dimplejs only allows us to pass a string to d3.format. So it is not possible to achieve what you seek directly within dimplejs. I am copying @johnkiernander, the author of dimplejs, to see if there is a cleaner solution, or if he may consider this use case a valid feature request.

johnkiernander commented 10 years ago

It's not part of the public API but dimple.axis._getFormat could be overridden to achieve what you want. It returns a function which is used to format the axis (and tooltip) values - exactly what you are trying to set here.

Here it is overridden using just dimple. Hopefully @ramnathv or @timelyportfolio will be able to translate this into the rcharts environment for you:

ramnathv commented 10 years ago

Thanks @johnkiernander. This is easy to incorporate in rCharts, but you would need to have the dev branch installed.

d1 <- dPlot(
  x = "Population", 
  y = "Age", 
  groups = "Gender", 
  data = dat, 
  type = 'bar'
)

d1$yAxis(type = "addCategoryAxis", orderRule = "ord")
d1$xAxis(type = "addMeasureAxis")
d1$setTemplate(afterScript = '
  <script>               
  x._getFormat = function () {
    return function(d) {
      return d3.format(",.1f")(Math.abs(d) / 1000000) + "M";
    };
  };
  myChart.draw()
  </script>
')
walkerke commented 10 years ago

Thanks so much to @timelyportfolio, @ramnathv, and @johnkiernander for your prompt and very helpful responses! I've tested Ramnath's code and it works perfectly.

I'll share what I've been working on with all of you when I get the chance to write it up in the next few weeks.

walkerke commented 10 years ago

I've written up what I've been working on here: http://walkerke.github.io/2014/06/rcharts-pyramids/ -- feel free to have a look. Thanks again for everything!

walkerke commented 10 years ago

Quick question - I've re-installed rCharts to get the newest Dimple updates, and my afterScript content is no longer working. I'm reading through the refactored JS to try to figure this out - but I thought I'd ask if you had any ideas, or if anyone else has experienced this problem. Thanks!

timelyportfolio commented 10 years ago

Without seeing it I am guessing that the template is one where the chart rendering is in an anonymous function so myChart is outside of scope when afterScript gets called. I have this as something I need to figure out, but for the time being you can do install_github('timelyportfolio/rCharts@dimple_v2.0.0') . Sorry this is in flux. Still trying to determine the best way to avoid conflicts when multiple charts exist on a page. Let me know if this fixes it temporarily. If you need multiple, iframes will provide correct isolation.

walkerke commented 9 years ago

Closing this - anyone reading this should move to the rcdimple package and see this RPubs: http://rpubs.com/walkerke/india_pyramid

ramnathv commented 9 years ago

Thanks for updating the issue @walkerke. rcdimple is the way to go.