Last year, I wrote about how to create interactive population pyramids in R with rCharts: http://walkerke.github.io/2014/06/rcharts-pyramids/. I am now updating this with htmlwidgets and some of the other new R packages that have been released in the past year. A preview is below; thanks are due as always to Kenton Russell for his awesome contributions to the R community.

library(dplyr)
library(tidyr)
library(rvest)
library(rcdimple)

# Get the table from the Census database with rvest

url <- "http://www.census.gov/population/international/data/idb/region.php?N=%20Results%20&T=10&A=separate&RT=0&Y=2015,2020,2025,2030,2035,2040,2045,2050&R=-1&C=IN"

df <- url %>%
  html() %>%
  html_nodes("table") %>%
  html_table() %>%
  data.frame()

names(df) <- c("Year", "Age", "total", "Male", "Female", "percent", "pctMale", "pctFemale", "sexratio") 

cols <- c(1, 3:9)

df[,cols] <- apply(df[,cols], 2, function(x) as.numeric(as.character(gsub(",", "", x))))

# Format the table with dplyr and tidyr

df1 <- df %>%
  mutate(Order = 1:nrow(df), 
         Male = -1 * Male) %>%
  filter(Age != "Total") %>%
  select(Year, Age, Male, Female, Order) %>%
  gather(Gender, Population, -Age, -Order, -Year)

max_x <- plyr::round_any(max(df1$Population), 10000, f = ceiling)
min_x <- plyr::round_any(min(df1$Population), 10000, f = floor)

# Build the chart with rcdimple

df1 %>%
  dimple(x = "Population", y = "Age", group = "Gender", type = 'bar', storyboard = "Year") %>%
  yAxis(type = "addCategoryAxis", orderRule = "Order") %>%
  xAxis(type = "addMeasureAxis", overrideMax = max_x, overrideMin = min_x) %>%
  default_colors(c("green", "orange")) %>%
  add_legend() %>%
  add_title(html = "<h3 style='font-family:Helvetica; text-align: center;'>India's population, 2015-2050</h3>") %>%
  
  # Here, I'll pass in some JS code to make all the values on the X-axis and in the tooltip absolute values
  tack(., options = list(
    chart = htmlwidgets::JS("
                            function(){
                            var self = this;
                            // x axis should be first or [0] but filter to make sure
                            self.axes.filter(function(ax){
                            return ax.position == 'x'
                            })[0] // now we have our x axis set _getFormat as before
                            ._getFormat = function () {
                            return function(d) {
                            return d3.format(',.0f')(Math.abs(d) / 1000000) + 'm';
                            };
                            };
                            // return self to return our chart
                            return self;
                            }
                            "))
    )