Use of as.POSIXct and understanding timezone in time series- R - r

I am looking to set x-axis limits on a rather simple time series plot in R.
My plot produces limits that are 6 hours ahead of my time zone (plot would start and end at 14:00:00 in the example below).
I am currently in "America/Denver".
My data was previously plotted so that everything was shifted 6 hours back but I was able to align that properly on the x-axis, but now the bounds/limits of the x-axis are still a problem.
date_format <- function(format = "%b %d - %H:%M") {function(x) format(x, format)}
lims <- as.POSIXct(strptime(c("2021-05-04 08:00:00","2021-05-08 08:00:00"), format = "%Y-%m-%d %H:%M"))
combo_ch1short <- ggplot(data = data_combo_ch1short, aes(x = DateTime, y = Z.kOhm, color = probe.pair.name)) +
scale_x_datetime(labels = date_format(), limits = lims, date_breaks = "12 hours") + ...
Sorry, pretty new to this. Any help is GREATLY appreciated!
Edit:
data_combo_ch1short:
Time probe.pair.name DateTime Z.kOhm
1617890878 ch_1_ch_2 2021-04-12 17:52:32 5228.69
1617890878 ch_1_ch_3 2021-04-12 17:52:32 5031.88
1618251752 ch_1_ch_2 2021-04-12 18:22:32 4089.37
1618251752 ch_1_ch_3 2021-04-12 18:22:32 4231.90
...

You can create lims in any timezone by specifying the timezone in tz argument.
lims <- as.POSIXct(c("2021-05-04 08:00:00","2021-05-08 08:00:00"), tz = 'US/Mountain')

Related

How to format the times and get a time delta in R using chron

I have two time points, I would like to obtain a time delta (notice that my times have milliseconds). I have tried to use the Chron package :
library(chron)
t1<- '2022/06/28 - 10:45:40:124'
t2<-'2022/06/28 - 10:54:50:193'
chron(t1, format='%Y/%m/%d - %H:%M:%S:%f')
But I got the following error:
Error in parse.format(format): unrecognized format %Y/%m/%d - %H:%M:%S:%f
Traceback:
1. chron("2022/06/28 - 10:45:40:124", format = "%Y/%m/%d - %H:%M:%S:%f")
2. convert.dates(dates., format = fmt, origin. = origin.)
3. parse.format(format)
4. stop(paste("unrecognized format", format))
What is wrong with my implementation?
Thank you for your answers.
Use as.chron and fix the format.
fmt <- '%Y/%m/%d - %H:%M:%S:%OS'
t1c <- as.chron(t1, format = fmt)
t2c <- as.chron(t2, format = fmt)
# use any of these depending on what you want
t2c - t1c
difftime(t2c, t1c, units = "days")
difftime(t2c, t1c, units = "hours")
difftime(t2c, t1c, units = "mins")
difftime(t2c, t1c, units = "secs")
We may use parse_date from parsedate
library(parsedate)
parse_date(t1) - parse_date(t2)
Time difference of -9.166667 mins
Or using chron
library(chron)
t1new <- sub(":(\\d+)$", ".\\1", trimws(t1, whitespace = ".*-\\s*"))
t2new <- sub(":(\\d+)$", ".\\1", trimws(t2, whitespace = ".*-\\s*"))
chron(times = t2new, format = c(times = "h:m:s")) -
chron(times = t1new, format = c(times = "h:m:s"))
[1] 00:09:10

ggplot2 axis as time with 1 hour error [duplicate]

This question already has answers here:
Time series plot gets offset by 2 hours if scale_x_datetime is used
(2 answers)
Closed 6 years ago.
I have a question on formatting the x axis as time.
This is a sample of my data:
dput(x)
structure(list(Sample = c("BK01", "BK02", "BK03", "BK04", "BK05",
"BK06", "BK07", "BK08", "BK09", "BK10", "BK11", "BK12", "BK13",
"BK14", "BK15", "BK16", "BK17", "BK18", "BK19", "BK20", "BK21",
"BK22", "BK23", "BK24", "BK25", "BK26", "BK27", "BK28", "BK29",
"BK30", "BK31", "BK32", "BK33"), Breath.d13C = c(-25.62, -27.45,
-26.87, -25.21, -26.01, -24.33, -24.45, -23.73, -25.05, -26.11,
-27, -26.28, -24.62, -26.96, -24.55, -24.52, -21.24, -26.18,
-24.82, -26.12, -27.28, -26.5, -24.46, -22.83, -27.28, -25.55,
-27.12, -24.46, -23.07, -28.35, NA, -25.98, -26.64), Chms = structure(c(1470047400,
1470048300, 1470048300, 1470049200, 1470050100, 1470050100, 1470040200,
1470041100, 1470040200, 1470041100, 1470065400, 1470063600, 1470063600,
1470064500, 1470061800, 1470045600, 1470045600, 1470046500, 1470047400,
1470066300, 1470060000, 1470058200, 1470057300, 1470047400, 1470042000,
1470042000, 1470041100, 1470041100, 1470040200, 1470043800, NA,
1470060000, 1470039300), class = c("POSIXct", "POSIXt"), tzone = "")), class = "data.frame", row.names = c(NA,
-33L), .Names = c("Sample", "Breath.d13C", "Chms"))
I want to use ggplot2 to build a graph of Breath.d13C vs Chms (Collection Time).
library(ggplot2)
ggplot(x, aes(x=Chms,y=Breath.d13C)) +
geom_point() +
scale_y_continuous(name=expression(delta^13*C["Breath"]*" "("\u2030")),
limits=c(-30,-10),
breaks=seq(-30,-10,5),
labels=fmt_decimals(1)) +
scale_x_datetime(name="Collection Time",
labels = date_format("%H:00",tz="UTC"),
date_breaks = "1 hour") +
my_theme
This code gives me . However the times are off by an hour.
I can see this by checking the Chms column or by using the normal R plots
with this code:
plot(x$Chms,x$Breath.d13C,cex=0.8)
The two plots use the same data set, so I have no idea what's causing the error on ggplot2. I'd like to keep using it, though. Any ideas on what am I doing wrong?
Thank you in advance
You need to specify the time zone in scale_x_datetime.
The function date_format() is by default set to "UTC". Therefore, your labels are converted to UTC. To use the time zone e.g. I used "Europe/London" (to get your desired output), you can do the following in your ggplot code: labels = date_format("%H:%M", tz = "Europe/London")
But firstly in order to run your code I also had to define what you specified in your code as fmt_decimals So I used this function given by #joran:
fmt_dcimals <- function(decimals=0){
# return a function responpsible for formatting the
# axis labels with a given number of decimals
function(x) as.character(round(x,decimals))
}
So your code looks like this:
ggplot(x, aes(x=Chms,y=Breath.d13C)) +
geom_point() +
scale_y_continuous(name=expression(delta^13*C["Breath"]*" "("\u2030")),
limits=c(-30,-10),
breaks=seq(-30,-10,5),
labels=fmt_dcimals(1)) +
scale_x_datetime(name="Collection Time",
labels = date_format("%H:%M", tz = "Europe/London"),
date_breaks = "1 hour")
And output:
The problem lie in the time zone you select, i.e. UTC. You should choose the current time zone. The corrected code is as below
library(ggplot2)
ggplot(x, aes(x=Chms,y=Breath.d13C)) +
geom_point() +
scale_y_continuous(name=expression(delta^13*C["Breath"]*" "
("\u2030")),
limits=c(-30,-10),
breaks=seq(-30,-10,5)) +
scale_x_datetime(name="Collection Time",
labels = date_format("2016-08-01 %H:00",""),
date_breaks = "1 hour")
See the plot as belpw

Eliminate timestamp timezone offset in lattice xyplot

When using lattice to plot values against hourly timestamps, I've found there is an annoying timezone shift from UTC to local time in the graph's x-axis labels. Though this example uses lubridate, the issue occurs when using POSIXct directly. For example:
library(lattice)
library(lubridate)
foo <- data.frame(t = seq(ymd_hms("2015-01-01 00:00:00"),
ymd_hms("2015-01-02 00:00:00"),
by = "hour"),
y = 1:25)
head(foo)
xyplot(y~t, foo) # time axis is behind by 5 hours (EST = UTC-5)
One solution is to specify the timezone explicitly:
tz(foo$t) <- "" # or tz(foo$t) <- "EST"
head(foo)
xyplot(y~t, foo) # time axis now agrees
Are there other ways to get lattice to plot directly in UTC without modifying the timezone of the data? Perhaps using the scales = list(x = list(format = ...)) argument? I can imagine situations where it would be bad to change the data's timezone, specifically when dealing with daylight saving events.
A brute force approach would be to temporarily overwrite your system's timezone with the timezone from your data, and reset it to its previous value once the plot has been created:
tzn = Sys.getenv("TZ")
Sys.setenv(TZ = tz(foo$t))
xyplot(
y ~ t
, data = foo
)
Sys.setenv(TZ = tzn)
This is a bug; the process of combining per-panel limits into an overall limit (even if there's only one panel) loses attributes, including the tz attribute.
p <- xyplot(y ~ t, foo)
str(attributes(foo$t))
# List of 2
# $ class: chr [1:2] "POSIXct" "POSIXt"
# $ tzone: chr "UTC"
str(attributes(p$x.limits))
# List of 1
# $ class: chr [1:2] "POSIXct" "POSIXt"
Fixed by setting
attributes(p$x.limits)$tzone <- "UTC"
Other workarounds are
xyplot(y ~ t, foo, xlim = extendrange(foo$t))
xyplot(y ~ t, foo, scales = "free")

Supressing Warnings in scale_x_datetime

This is not a duplicate since none of the methods in that putative duplicate apply here. None of them lead to the warning going away.
In fact I got an answer here from Konrad below - use suppressMessages. In the link that is asserted as a possible duplicate, they suggest suppressWarnings, which does not work.
After finally figuring out how to get R to use my timezone on the ggplot date axis correctly (found scale_x_datetime in a post here, before it was using my local timezone even though the data had the timezone set already), but it now complains with a warning:
Scale for 'x' is already present. Adding another scale for 'x', which will replace the existing scale.
This is annoying because I have to do this a lot, and don't want to get in the habit of ignore all warnings. How can I turn this off? I obviously have tried suppressWarnings (with and without print) and options(warn=-1).
R-Version is 3.1.3
ggplot2_1.0.1
scales_0.2.4
library(lubridate,quietly=T,warn.conflicts=T)
library(ggplot2,quietly=T,warn.conflicts=T)
library(scales,quietly=T,warn.conflicts=T)
sclip.time <- ymd_hms("2014-06-16 00:00:00",tz="US/Pacific")
eclip.time <- ymd_hms("2014-06-17 23:59:59",tz="US/Pacific")
sdata.time <- ymd_hms("2014-06-16 00:00:00",tz="US/Pacific")
edata.time <- ymd_hms("2014-06-17 23:59:59",tz="US/Pacific")
xdata <- seq(sdata.time,edata.time,length.out=100)
xfrac <- seq(0,4*3.1416,length.out=100)
ydata <- pmax(0.25,sin(xfrac))
ydata <- sin(xfrac)
ddf <- data.frame(x=xdata,y=ydata)
date_format_tz <- function(format = "%Y-%m-%d", tz = "UTC") {
function(x) format(x, format, tz=tz)
}
options(warn=-1)
suppressWarnings(
ggplot(ddf) +
geom_line(aes(x,y),col="blue") +
geom_vline(xintercept=as.numeric(sclip.time),color="darkred") +
geom_vline(xintercept=as.numeric(eclip.time),color="darkgreen") +
xlim(sclip.time,edata.time) +
scale_x_datetime( breaks = date_breaks("1 day"),
labels = date_format_tz("%Y-%m-%d %H:%M", tz="US/Pacific"))
)
You have to use the combination of suppressMessages and print as in the snippet below:
suppressMessages(print(
ggplot(ddf) +
geom_line(aes(x,y),col="blue") +
geom_vline(xintercept=as.numeric(sclip.time),color="darkred") +
geom_vline(xintercept=as.numeric(eclip.time),color="darkgreen") +
xlim(sclip.time,edata.time) +
scale_x_datetime( breaks = date_breaks("1 day"),
labels = date_format_tz("%Y-%m-%d %H:%M", tz="US/Pacific"))
))
A way you might get what you want is to use the "try" function, with the option silent=T :
try(silent=T, [R-script])
It is generally a bad idea to do it that way, because you become blind to the errors that might occur, but if you are really certain of what you're doing..
Actually, the message does point to a problem with your following code snippet:
... + xlim(sclip.time,edata.time) +
scale_x_datetime( breaks = date_breaks("1 day"),
labels = date_format_tz("%Y-%m-%d %H:%M", tz="US/Pacific"))
Already the first command will add a scale, and the second command will replace that scale. So the message tells you that the first command has no effect.
You should combine the two and add the limits to scale_x_datetime:
... +
scale_x_datetime(breaks = date_breaks("1 day"),
labels = date_format_tz("%Y-%m-%d %H:%M", tz="US/Pacific"),
limits = c(sclip.time,edata.time))

Dealing with uncommon date structures in ggplot2

I have a data set and it contains the following variable for date.
dat$Leads_MONTH
[1] "10-Jan" "10-Feb" "10-Mar" "10-Apr" "10-May" "10-Jun" "10-Jul" "10-Aug" "10-Sep" "10-Oct" "10-Nov" "10-Dec" "11-Jan" "11-Feb" "11-Mar" "11-Apr"
[17] "11-May" "11-Jun" "11-Jul" "11-Aug" "11-Sep" "11-Oct" "11-Nov" "11-Dec" "12-Jan" "12-Feb" "12-Mar" "12-Apr" "12-May" "12-Jun" "12-Jul" "12-Aug"
[33] "12-Sep" "12-Oct" "12-Nov" "12-Dec" "13-Jan" "13-Feb" "13-Mar" "13-Apr" "13-May" "13-Jun" "13-Jul"
I want to plot this data on the x axis using ggplot2 but am having some issues with this task. Is there a way to get ggplot2 to format Leads_MONTH as a date format and then plot it using ggplot2.
ggplot(dat, aes(Leads_MONTH, LEADSforester)) +
geom_bar(stat="identity", fill="#336699") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
The above code produces a plot but the dates on the x axis are not in the write order.
I tried to set the variable as a date but am not having any luck.
> dat$Leads_MONTH <- as.Date(dat$Leads_MONTH)
Error in charToDate(x) :
character string is not in a standard unambiguous format
For the bar plot, you can manually convert Leads_MONTH to factor and specify the levels.
dat <- data.frame(Leads_MONTH = c(
"10-Jan", "10-Feb", "10-Mar", "10-Apr", "10-May", "10-Jun", "10-Jul", "10-Aug", "10-Sep", "10-Oct", "10-Nov", "10-Dec", "11-Jan", "11-Feb", "11-Mar", "11-Apr",
"11-May", "11-Jun", "11-Jul", "11-Aug", "11-Sep", "11-Oct", "11-Nov", "11-Dec", "12-Jan", "12-Feb", "12-Mar", "12-Apr", "12-May", "12-Jun", "12-Jul", "12-Aug",
"12-Sep", "12-Oct", "12-Nov", "12-Dec", "13-Jan", "13-Feb", "13-Mar", "13-Apr", "13-May", "13-Jun", "13-Jul"),
LEADSforester = runif(43))
library(ggplot2)
# Convert Leads_MONTH to factor and specify the levels
dat$Leads_MONTH <- factor(dat$Leads_MONTH, levels = dat$Leads_MONTH)
ggplot(dat, aes(Leads_MONTH, LEADSforester)) +
geom_bar(stat="identity", fill="#336699") +
theme(axis.text.x = element_text(angle = 90, hjust = 1))
If you want to convert into Date class, you need to add day and specify the argument format
as.Date(paste0(dat$Leads_MONTH, '-1'), format = '%y-%b-%d')
Try:
library(zoo)
as.yearmon(dat$Leads_MONTH, format="%y-%b")
To convert them to normal date objects wrap that in as.Date

Resources