R zoo plot multiple years of data overlapping
Question
I have the following df:
> head(giftByDay)
giftDate gift yr mon day
1 2009-07-01 100.00 2009 7 1
2 2009-07-03 300.00 2009 7 3
3 2009-07-06 470.00 2009 7 6
4 2009-07-07 7436.66 2009 7 7
5 2009-07-09 50.00 2009 7 9
6 2009-07-11 25.00 2009 7 11
It has 3 years of data (fiscal year ends June 30) and I'm trying to put it all 3 in one plot as 3 separate lines to compare year over year performance. Also I'm trying to put dollars on the y-axis and MM-DD on the x-axis.
I break it into 3 chunks based on year:
> yr2009 <- subset(giftByDay, giftByDay$giftDate >= "2009-07-01" & giftByDay$giftDate < "2010-07-01")
> yr2010 <- subset(giftByDay, giftByDay$giftDate >= "2010-07-01" & giftByDay$giftDate < "2011-07-01")
> yr2011 <- subset(giftByDay, giftByDay$giftDate >= "2011-07-01" & giftByDay$giftDate < "2012-07-01")
Next I create zoo objects for plotting:
> yr2009$d2 <- format(as.Date(yr2009$giftDate), "%m-%d")
> x1 <- zoo(yr2009$gift, yr2009$d2)
> yr2010$d2 <- format(as.Date(yr2010$giftDate), "%m-%d")
> x2 <- zoo(yr2010$gift, x2.Date)
> yr2011$d2 <- format(as.Date(yr2011$giftDate), "%m-%d")
> x3 <- zoo(yr2011$gift, x3.Date)
The problems start when I try to actually plot it:
> plot(x1, type="l", col=1)
Error in plot.window(...) : need finite 'xlim' values
In addition: Warning messages:
1: In xy.coords(x, y, xlabel, ylabel, log) : NAs introduced by coercion
2: In min(x) : no non-missing arguments to min; returning Inf
3: In max(x) : no non-missing arguments to max; returning -Inf
> points(x2, type="l", col=2)
Warning message:
In xy.coords(x, y) : NAs introduced by coercion
> points(x3, type="l", col=3)
Warning message:
In xy.coords(x, y) : NAs introduced by coercion
There's actually stuff in the objects:
> head(x1)
01-01 01-04 01-05 01-08 01-11 01-13
15.0 125.0 1000.0 6350.0 200.0 291281.1
But I can't figure out why it won't plot. Any suggestions?
EDIT:
> giftByDayList <- split(as.xts(giftByDay), "years")
Error in as.POSIXlt.character(x, tz, ...) :
character string is not in a standard unambiguous format
> class(giftByDay$giftDate)
[1] "character"
I'm not sure what's causing this error.
EDIT 2:
> gbd <- zoo(giftByDay)
> gbd <- as.xts(gbd)
Error in xts(coredata(x), order.by = order.by, frequency = frequency, :
order.by requires an appropriate time-based object
> giftByDayList <- split(as.xts(gbd), "years")
Error in xts(coredata(x), order.by = order.by, frequency = frequency, :
order.by requires an appropriate time-based object
EDIT 3:
> giftByDayList <- split(xts(giftByDay[,-1],as.Date(giftByDay$giftDate)), "years")
> giftByDayList <- lapply(giftByDayList, toyear, 2011)
Error in `index<-.xts`(`*tmp*`, value = list(sec = c(0, 0, 0, 0, 0, 0, :
unsupported ‘index’ index type of class ‘POSIXt’unsupported ‘index’ index type of class ‘POSIXlt’
> str(giftByDayList )
List of 3
$ :An ‘xts’ object from 2009-07-01 to 2009-12-31 containing:
Data: num [1:89, 1:4] 100 300 470 7437 50 ...
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:4] "gift" "yr" "mon" "day"
Indexed by objects of class: [Date] TZ:
xts Attributes:
NULL
$ :An ‘xts’ object from 2010-01-01 to 2010-12-31 containing:
Data: num [1:213, 1:4] 15 125 1000 6350 200 ...
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:4] "gift" "yr" "mon" "day"
Indexed by objects of class: [Date] TZ:
xts Attributes:
NULL
$ :An ‘xts’ object from 2011-01-02 to 2011-10-26 containing:
Data: num [1:189, 1:4] 1500 235 1000 18154 10 ...
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:4] "gift" "yr" "mon" "day"
Indexed by objects of class: [Date] TZ:
xts Attributes:
NULL
>
Solution
1) data.frame solution. Try this. We set up some test data and then calculate the fiscal year and rebase each date in the transform statement. Finally we plot the gift vs. rebased date by fiscalyear. Note that its really just two statements, one for the transform and one for the plot.
## set up test data
giftDate <- seq(as.Date("2009-07-01"), length = 36, by = "month")
giftByDay <- data.frame(giftDate, gift = 1:36,
yr = as.numeric(format(giftDate, "%Y")),
mon = as.numeric(format(giftDate, "%m")),
day = as.numeric(format(giftDate, "%d")))
## now that we have test data, calculate fiscalyear, rebase each date to 1999-2000
## and plot
giftByDay <- transform(giftByDay, fiscalyear = yr + (mon > 6),
Date = as.Date(paste(2000 - (mon > 6), mon, day, sep = "-")))
library(lattice)
xyplot(gift ~ Date, giftByDay, group = fiscalyear, type = "o", auto.key = TRUE)
EDIT:
Added zoo solution below.
2) zoo solution. In this case the solution is not simpler than just using a data frame although it might have an advantage if the particular form of z
can be used for other calculations:
library(zoo)
library(lattice)
giftByDay <- transform(giftByDay, fiscalyear = yr + (mon > 6))
z <- read.zoo(giftByDay[2:6], index = 2:4, split = 5, FUN = function(y, m, d)
as.Date(paste(2000 - (m > 6), m, d, sep = "-")))
xyplot(z, screen = 1, col = 1:3, type = "o", auto.key = TRUE, ylab = "Gift")
Here is what the zoo object z
looks like:
> z
2010 2011 2012
1999-07-01 1 13 25
1999-08-01 2 14 26
1999-09-01 3 15 27
1999-10-01 4 16 28
1999-11-01 5 17 29
1999-12-01 6 18 30
2000-01-01 7 19 31
2000-02-01 8 20 32
2000-03-01 9 21 33
2000-04-01 10 22 34
2000-05-01 11 23 35
2000-06-01 12 24 36
OTHER TIPS
This answer is a modified version of my answer to Related to xts/time-series and plot questions... on R-help.
You can do this by converting each index value to have the same year. The toyear
function below does this.
toyear <- function(x, year) {
# get year of last obs
xyear <- .indexyear(last(x))+1900
# get index and convert to POSIXlt
ind <- as.POSIXlt(index(x))
# set index year to desired value
ind$year <- year-1900
index(x) <- ind
# label column with year of last obs
colnames(x) <- paste(colnames(x),xyear,sep=".")
x
}
# split data into a list of xts objects by year
giftByDayList <- split(xts(giftByDay[,-1],as.Date(giftByDay$giftDate)), "years")
# convert each list element to be "2011"
giftByDayList <- lapply(giftByDayList, toyear, 2011)
# merge all list elements into one object
giftByDayByYear <- as.zoo(do.call(merge, giftByDayList))
# plot on one "screen"
plot(giftByDayByYear, screens=1, col=rainbow(ncol(giftByDayByYear)))