Search code examples
rr-highcharter

How to order monthly dates on x_axis?


Update: Graphs using @Kat's answer

enter image description here

enter image description here

Originally wrote:

I have two datasets: data and data2, both with four columns.

Datasets:

data <- structure(list(year = c(2022, 2022, 2022, 2022, 2022, 2022, 2022, 
                                2022, 2022, 2022, 2022, 2022), 
                       month = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 
                       AUM = c(32679911L, 32346742L, 34420603L, 34420603L, 37224840L, 36470615L, 36470615L, 36368089L, 33122740L, 35996741L, 36653126L, 36047829L),
                       DATA = structure(c(19023, 19051, 19082, 19111, 19143, 19173, 19202, 19235, 19265, 19296, 19326, 19356), 
                                        class = "Date")), 
                  row.names = c(NA, -12L), 
                  class = c("data.table", "data.frame"))

data2 <- structure(list(year = c(2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022, 2022),
                    month = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 
                    CUM_SUM = c(-297163L, -552969L, -1186800L, -1323710L, -778329L, -334843L, 96513L, 75763L, 874981L, 1100124L, 1009281L, 961152L),
                    DATA = structure(c(19023, 19051, 19082, 19111, 19143, 19173, 19202, 19235, 19265, 19296, 19326, 19356), class = "Date")), 
               row.names = c(NA, -12L), class = c("data.table", "data.frame"))

data looks like this:

enter image description here

This is the code of my graph:

# Line Plot:
highchart() %>%
  hc_add_series(name = "AUM", yAxis = 0, id = "aum_line", data = data, type = 'line', hcaes(x = DATA, y = AUM), events = list(
    legendItemClick = htmlwidgets::JS(
      "function(e) {
                      var shown = this.visible ? false : true;
                      this.update({visible: shown});
                      return false;
                    }"
    ))) %>%
  hc_add_series(name = "AUM",id = 'aum_line_percent', data = data, type = "line", hcaes(x = DATA, y = AUM),
                compare = 'percent', linkedTo = 'aum_line', visible = F) %>% # <-- linked & invisible!)  
  hc_add_series(name = 'Cumulative NP', yAxis = 1, id = 'pl_cum_line', data = data2, type = 'line', hcaes(x = DATA, y = CUM_SUM), events = list(
    legendItemClick = htmlwidgets::JS(
      "function(e) {
                      var shown = this.visible ? false : true;
                      this.update({visible: shown});
                      return false;
                    }"
    ))) %>%
  hc_add_series(name = "Cumulative NP",id = 'pl_cum_line_percent', data = data2, type = "line", hcaes(x = DATA, y = CUM_SUM),
                compare = 'percent', linkedTo = 'pl_cum_line', visible = F) %>% # <-- linked & invisible!) 
  hc_yAxis_multiples(list(title = list(text = "AUM", style = list(fontSize = "1.5em", color = '#607B8B' )), opposite = FALSE),
                     list(showLastLabel = FALSE, opposite = TRUE, title = list(text = "Cumulative NP", style = list(fontSize = "1.5em", color = '#CD8162')))) %>%
  hc_xAxis(type = "datetime") %>% 
  hc_plotOptions(column = list(dataLabels = list(enabled = F),enableMouseTracking = T)) %>%
  hc_chart(zoomType = 'xy') %>%
  hc_colors(c('#607B8B','#607B8B','#CD8162','#CD8162')) %>%
  hc_tooltip(split = T, crosshairs = T,
             formatter = htmlwidgets::JS(
               "function(tooltip) {
                        function pref(pts) {                     /* create y-axis tooltips with this function */
                        col = pts.color; y = pts.y; nm = pts.series.name;        /* collect color, y, name */
                        compVal = pts.series.linkedSeries[0].dataModify.compareValue;  /* 1st val in view */
                        delta = (y - compVal)/compVal * 100;   /* compute the comparison value as HC does */
                        adder = `(${delta.toFixed(2)}%)</span>`;   /* create remaining string for tooltip */
                        y = Highcharts.numberFormat(y, 0, '.', ' ');                 /* format y after calc */
                        return `<b><span style='color:${col};'>● ${nm}:</span></b> ${y} ` + adder;
                        }
                        xform = Highcharts.dateFormat('%B %e, %Y', this.x);        /* x-axis tooltip formatted */
                        ttd1 = pref(this.points[0]);                /* call function to create y-axis tooltips */
                        ttd2 = pref(this.points[1]);
                        return [xform, ttd1, ttd2];                                 /* send tooltip formatting */
                        }")
  ) %>%
  hc_exporting(enabled = TRUE)

That looks like this:

enter image description here

What I would like to do is to move the x_axis labels to the right. For example, the last points on the graph are values from December 22 and it looks like they are from Jan 23. Therefore, instead of Apr 22, Jul 22, Oct 22 and Jan 23, it should be March 22, Jun 22, Sept 22 and Dec 22.


Solution

  • In the R code, you'll notice that I've added dateTimeLabelFormats for hour. That's because when I parse the dates for the last day of the month, JS automatically detects your time zone. When I revert the format to a number, JS adjusts for your timezone. This ends up being a few hours different. Since the date is no longer at 0000 (midnight), Highcharts assumes you want the time on the x-axis. I've set the date format to abbreviated month name & year.

    There are methods to start and finish in Greenwich time. The simplest is to adjust the epoch by your timezone. Since my timezone is likely different than yours, which is likely different from whoever looks at your final chart, I've kept it simple. If you are near where the date changes (I think near Hawaii? Between Hawaii and Japan?) It might be worth ensuring the dates start and end in UTC. (Being that far from Greenwich could cause your dates to be an entire day off.)

    I've commented out the original call for hc_xAxis and added a new call. This utilizes the argument tickPositioner. Whatever Highcharts has deemed belongs as a label on the x-axis is collected. This function takes those dates and determines the last day of the preceding month. Finally, it sends new labels for the x-axis back to the chart.

    Like other answers I've provided, I've added comments in the JS to identify what's happening. However, if you have any questions or if there is anything wrong/untested, please let me know.

    highchart() %>%
      hc_add_series(name = "AUM", yAxis = 0, id = "aum_line", data = data, type = 'line', hcaes(x = DATA, y = AUM), events = list(
        legendItemClick = htmlwidgets::JS(
          "function(e) {
                          var shown = this.visible ? false : true;
                          this.update({visible: shown});
                          return false;
                        }"
        ))) %>%
      hc_add_series(name = "AUM",id = 'aum_line_percent', data = data, type = "line", hcaes(x = DATA, y = AUM),
                    compare = 'percent', linkedTo = 'aum_line', visible = F) %>% # <-- linked & invisible!)  
      hc_add_series(name = 'Cumulative NP', yAxis = 1, id = 'pl_cum_line', data = data2, type = 'line', hcaes(x = DATA, y = CUM_SUM), events = list(
        legendItemClick = htmlwidgets::JS(
          "function(e) {
                          var shown = this.visible ? false : true;
                          this.update({visible: shown});
                          return false;
                        }"
        ))) %>%
      hc_add_series(name = "Cumulative NP",id = 'pl_cum_line_percent', data = data2, type = "line", hcaes(x = DATA, y = CUM_SUM),
                    compare = 'percent', linkedTo = 'pl_cum_line', visible = F) %>% # <-- linked & invisible!) 
      hc_yAxis_multiples(list(title = list(text = "AUM", style = list(fontSize = "1.5em", color = '#607B8B' )), opposite = FALSE),
                         list(showLastLabel = FALSE, opposite = TRUE, title = list(text = "Cumulative NP", style = list(fontSize = "1.5em", color = '#CD8162')))) %>%
      # hc_xAxis(type = "datetime", showLastLabel = F) %>% 
      hc_xAxis(tickPositioner = htmlwidgets::JS(
        "function() {
            oticks = this.tickPositions;                  /* get the current tick labels */
            giveMe = [];
            for(i = 0; i < oticks.length; i++) {          /* get last day of the month for each data point */
                tht = new Date(oticks[i]);
                tellMe = new Date(tht.getFullYear(), tht.getMonth(), 0);
                giveMe.push(tellMe.getTime());            /* revert date format to proper format for HC */
            }
            return giveMe;                                /* send updated tick labels to chart */
        }"),
        type = "datetime", dateTimeLabelFormats = list(month = '%b %Y', hour = '%b %Y')) %>% 
      hc_plotOptions(column = list(dataLabels = list(enabled = F),enableMouseTracking = T)) %>%
      hc_chart(zoomType = 'xy') %>%
      hc_colors(c('#607B8B','#607B8B','#CD8162','#CD8162')) %>%
      hc_tooltip(split = T, crosshairs = T,
                 formatter = htmlwidgets::JS(
                   "function(tooltip) {
                        function pref(pts) {                     /* create y-axis tooltips with this function */
                            col = pts.color; y = pts.y; nm = pts.series.name;       /* collect color, y, name */
                            compVal = pts.series.linkedSeries[0].dataModify.compareValue;  /* 1st val in view */
                            delta = (y - compVal)/compVal * 100;   /* compute the comparison value as HC does */
                            adder = `(${delta.toFixed(2)}%)</span>`;   /* create remaining string for tooltip */
                            y = Highcharts.numberFormat(y, 0, '.', ' ');               /* format y after calc */
                            return `<b><span style='color:${col};'>● ${nm}:</span></b> ${y} ` + adder;
                        }
                        xform = Highcharts.dateFormat('%B %e, %Y', this.x);       /* x-axis tooltip formatted */
                        ttd1 = pref(this.points[0]);               /* call function to create y-axis tooltips */
                        ttd2 = pref(this.points[1]);
                        return [xform, ttd1, ttd2];                                /* send tooltip formatting */
                    }")) %>%
      hc_exporting(enabled = TRUE)
    

    enter image description here

    enter image description here

    enter image description here

    enter image description here