Plotting pre-computed statistics on POSIX dates with ggplot's geom_boxplot

181 views Asked by At

I'm trying to create a series of boxplots showing a distribution of date values. I compute the quantiles using data.table, then I feed them to ggplot to be plotted. When I try to plot them, however, I get an error that says "Error: '/' not defined for "POSIXt" objects".

Here's a reproducible example using data from lubridate:

library(data.table)
library(ggplot2)
library(lubridate)

# Load data from the lubridate library
data(lakers)

# create POSIX date variable
lakers <- within(lakers, posix.date <- ymd(date))
lakers <- data.table(lakers, key = "player")

# Calculate quantiles of dates by player
# follows post at http://stackoverflow.com/questions/14758566/how-can-i-use-functions-returning-vectors-like-fivenum-with-ddply-or-aggregate
Tukeys.five <- c("Min","Q1","Med","Q3","Max") 
plot.stats <- lakers[
    ,
    {quant <- as.list(quantile(posix.date, prob = seq(0,1, by = 0.25),
                               names = F))
    setattr(quant, 'names', Tukeys.five)
    quant},
    by = player
    ]

# Now attempt to plot this with ggplot
ggplot(plot.stats, aes(x = player, ymin = Min, lower = Q1, middle = Med, 
                       upper = Q3, max = Max, group = player)) +
  geom_boxplot(stat = "identity") + coord_flip() 
# Error: '/' not defined for "POSIXt" objects
# In addition: Warning message:
# In loop_apply(n, do.ply) :
#   position_dodge requires constant width: output may be incorrect

Any ideas why I would be getting this error, or how to fix it? I tried converting the dates to numeric values, and that plots correctly, but then the axis only shows the numeric values instead of the dates.

1

There are 1 answers

1
MrFlick On BEST ANSWER

It looks like the code for geom_boxplot does division to try to calculate box widths. As far as I can tell that branch seem unavoidable. A hack-y workaround would be to actually define division for date time values.

`/.POSIXt`<-function(e1,e2) as.numeric(e1)/as.numeric(e2)

Running this before your code seems to produce the requested plot. Testing with

`/.POSIXt`<-function(e1,e2) as.numeric(e1)/as.numeric(e2)
ggplot(plot.stats[1:10,], aes(x = player, ymin = Min, lower = Q1, middle = Med, 
                       upper = Q3, max = Max, group = player)) +
  geom_boxplot(stat = "identity") + coord_flip() 

enter image description here