I'm trying to present a ggplot graph similar to Base R graphs. The issue I have is dealing with time series data (date and time) to draw the x and y axis properly.
I used the same approach provided by Baptiste to create an x and y axis function: R-style axes with ggplot
However, it doesn't look right (see image below). I am not sure how to fix the y-axis and I also don't know how to fix the x-axis so that the limits are only between 07:00:00AM and 10:00:00AM. Any help would be appreciated!
#y-axis
base_breaks_y <- function(x){
b <- pretty(x)
d <- data.frame(x=as.POSIXct(c("2019-01-30 07:00:00")), xend=as.POSIXct(c("2019-01-30 10:00:00")), y=min(b), yend=max(b))
list(geom_segment(data=d, aes(x=x, y=y, xend=xend, yend=yend), inherit.aes=FALSE),
scale_y_continuous(breaks=b))
}
#x-axis
base_breaks_x <- function(x){
b <- pretty(x)
d <- data.frame(y=-Inf, yend=-Inf, x=min(b), xend=max(b))
list(geom_segment(data=d, aes(x=x, y=y, xend=xend, yend=yend), inherit.aes=FALSE),
scale_x_datetime(breaks=b, labels=date_format("%H:%M")))
}
#plot
ggplot(data=df1, aes(x=date.time, y=value)) +
geom_line() +
#labels
ylab("Value") +
xlab("Time Series") +
#aesthetics
theme_bw() +
theme(panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
text = element_text(size=11)) +
#scale date time range
base_breaks_x(df1$date.time) +
base_breaks_y(df1$value)
Example data:
> dput(df1)
structure(list(date.time = structure(c(1548833480, 1548833555,
1548833630, 1548833705, 1548833781, 1548833856, 1548833931, 1548834006,
1548834083, 1548834158, 1548834233, 1548834308, 1548834384, 1548834459,
1548834534, 1548834609, 1548834685, 1548834760, 1548834835, 1548834910,
1548834987, 1548835062, 1548835137, 1548835212, 1548835288, 1548835363,
1548835438, 1548835513, 1548835590, 1548835665, 1548835740, 1548835815,
1548835891, 1548835966, 1548836041, 1548836116, 1548836192, 1548836267,
1548836342, 1548836417, 1548836494, 1548836569, 1548836644, 1548836719,
1548836795, 1548836870, 1548836945, 1548837020, 1548837096, 1548837171,
1548837246, 1548837321, 1548837398, 1548837473, 1548837548, 1548837623,
1548837699, 1548837774, 1548837849, 1548837924, 1548838000, 1548838075,
1548838150, 1548838225, 1548838302, 1548838377, 1548838452, 1548838527,
1548838603, 1548838678, 1548838753, 1548838828, 1548838905, 1548838980,
1548839055, 1548839130, 1548839206, 1548839281, 1548839356, 1548839431,
1548839507, 1548839582, 1548839657, 1548839732, 1548839809, 1548839884,
1548839959, 1548840034, 1548840110, 1548840185, 1548840260, 1548840335,
1548840411, 1548840486, 1548840561, 1548840636, 1548840713, 1548840788,
1548840863, 1548840938), class = c("POSIXct", "POSIXt"), tzone = "UTC"),
value = c(3139, 2261, 2147, 2184, 2469, 2356, 2231, 1894,
1679, 1710, 1634, 1642, 1611, 1484, 1415, 1404, 1367, 1343,
1261, 1252, 1190, 1135, 1072, 1014, 979, 943, 935, 947, 952,
943, 937, 938, 920, 887, 867, 910, 954, 1036, 1106, 1160,
1216, 1226, 1288, 1368, 1348, 1363, 1474, 1420, 1276, 1310,
1357, 1207, 1051, 951, 923, 963, 1002, 1044, 1118, 1178,
1217, 1246, 1201, 1305, 1352, 1367, 1379, 1375, 1433, 1537,
1625, 1663, 1756, 1831, 1802, 1858, 2003, 1915, 1874, 1847,
1850, 2028, 2220, 2396, 2689, 2063, 2857, 2021, 2140, 2282,
2397, 2613, 2590, 2662, 2615, 2693, 2802, 2805, 2945, 3151
)), row.names = c(NA, 100L), class = "data.frame")
One option to fix your issue would be to use x = xend = -Inf
for the y axis as in the original post but instead of setting it via the aesthetics, which will result in an error
Error: Invalid input: time_trans works with objects of class POSIXct only
set them as arguments:
library(ggplot2)
library(scales)
base_breaks_y <- function(x) {
b <- pretty(x)
d <- data.frame(y = min(b), yend = max(b))
list(
geom_segment(
data = d, aes(y = y, yend = yend),
x = -Inf, xend = -Inf, inherit.aes = FALSE
),
scale_y_continuous(breaks = b)
)
}
ggplot(data = df1, aes(x = date.time, y = value)) +
geom_line() +
labs(y = "Value", x = "Time Series") +
theme_bw() +
theme(
panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
text = element_text(size = 11)
) +
base_breaks_x(df1$date.time) +
base_breaks_y(df1$value)
EDIT Getting the limits for the x axis right requires slightly more work. First we have to set the limits. Second, we have to take account of the limits when computing the breaks and the range for the geom_segment
:
base_breaks_x <- function(x, limits = NULL) {
x <- c(x, limits)
b <- pretty(x)
d <- data.frame(y = -Inf, yend = -Inf, x = min(b), xend = max(b))
list(
geom_segment(data = d, aes(x = x, y = y, xend = xend, yend = yend), inherit.aes = FALSE),
scale_x_datetime(
breaks = b, labels = date_format("%H:%M"),
limits = limits
)
)
}
ggplot(data = df1, aes(x = date.time, y = value)) +
geom_line() +
labs(y = "Value", x = "Time Series") +
theme_bw() +
theme(
panel.border = element_blank(),
panel.grid.major = element_blank(),
panel.grid.minor = element_blank(),
text = element_text(size = 11)
) +
base_breaks_x(
df1$date.time,
limits = as.POSIXct(c("2019-01-30 07:00:00", "2019-01-30 10:00:00"), tz = "GMT")
) +
base_breaks_y(df1$value)