Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Have Dygraph.WEEKLY labeling use Mondays as ticks in R

I'm graphing weekly data using the dygraphs package. dygraphs automatically selects a weekly default axis. However, I'm hoping there is a way to have the default axis (Sundays) line up with my data (Mondays).

# Required packages
library("magrittr")
library("dygraphs")
library("xts")

# Data
daily <- structure(c(4000, 5000, 3000, 7000, 2000, 5000, 7000, 
                   2000, 3000, 6000, 5000, 9000, 2000, 2000, 2000, 
                   7000, 9000, 2000, 1000, 13000), .Dim = c(10L, 2L), .Dimnames = list(
                     NULL, c("col1", "col2")), index = structure(c(1476032400, 
                                                                   1476637200, 1477242000, 1477846800, 1478451600, 1479056400, 1479661200, 
                                                                   1480266000, 1480870800, 1481475600), tzone = "Asia/Saigon", tclass = c("POSIXct", 
                                                                                                                                          "POSIXt")), class = c("xts", "zoo"), .indexCLASS = c("POSIXct", 
                                                                                                                                                                                               "POSIXt"), tclass = c("POSIXct", "POSIXt"), .indexTZ = "Asia/Saigon", tzone = "Asia/Saigon")

# Graph
dygraph(daily, main = "Stackoverflow") %>%
  dyRangeSelector() %>%
  dyOptions(useDataTimezone = TRUE) 

dygraph render

like image 364
Frank P. Avatar asked Jan 03 '17 17:01

Frank P.


2 Answers

You can try using a custom ticker function that starts on the first day of your data and places a tick every seven days.

Here's an example inspired from the dygraph-tickers.js Dygraph.getDateAxis function:

dygraph(daily, main = "Stackoverflow") %>%
  dyRangeSelector() %>%
  dyAxis("x",ticker='function(start_time, end_time, pixels, opts, dygraph, vals) {
         var formatter = opts("axisLabelFormatter");
         var ticks = [];
         var t;
         //spacing is a week in milliseconds
         var spacing = 1000 * 604800;

         for (t = start_time; t <= end_time; t += spacing) {
          ticks.push({ v:t,
         label: formatter(new Date(t), Dygraph.WEEKLY, opts, dygraph)
         });
         }
         return ticks;
   }') %>%
  dyOptions(useDataTimezone = TRUE)
like image 88
NicE Avatar answered Nov 12 '22 10:11

NicE


A workaround for this would be reformatting dyAxis label values via JavaScript functions (of course, considering that the only thing you need is changing the default first day of the week).

Take a look:

# libs and daily object ...

# the x values are passed as milliseconds, turn them into a date and extract day and month
getMonthDay <- 'function(d) {
  var monthNames = ["Jan", "Feb", "Mar", "Apr", "May", "Jun","Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
  var date;
  if (typeof d == "number") { // value
    date = new Date(d);
  } else { // label
    date = new Date(d.toString().substring(0, 15));
  }
  date.setDate(date.getDate() + 1);
  return date.getUTCDate() + " " + monthNames[date.getMonth()];
}'

# Graph
dygraph(daily, main = "Stackoverflow") %>%
  dyRangeSelector() %>%
  dyAxis(
    "x",
    valueFormatter = JS(getMonthDay),
    axisLabelFormatter = JS(getMonthDay),
    rangePad = 40 # the rangePad would adapt by itself
  )  %>%
  dyOptions(useDataTimezone = TRUE)

Note that we have a condition to check the type of the d object. That's because the

  • valueFormatter - returns the valueOf the date object;
  • axisLabelFormatter - returns the actual date itself

So, in case d parameter is:

  • a number (valueFormatter), we simply create a new Date object;
  • an object (axisLabelFormatter) - yes, it sends the param as an Object; so, we need to convert it to a proper Date.

The substring() approach is needed because dygraphs sends the object like this:

Sun Oct 09 2016 00:00:00 GMT+0700

... and, because of the 00's time, once you try to convert to a date, JavaScript will return

Sat Oct 08 2016 14:00:00 GMT-0300 (Local Standard Time)

This way, we'll always consider only the day, month and year for that. Also, you'd have the rangePad being applied properly:

enter image description here

like image 33
diogo Avatar answered Nov 12 '22 10:11

diogo