Setting time limits on axis removes all values - r

I have this simple data:
structure(list(ID = 1:2, timing = structure(c(1654641111.14,
1654640774.523), tzone = "CET", class = c("POSIXct", "POSIXt"))), class = "data.frame", row.names = c(NA,
-2L))
ID timing
1 1 2022-06-08 00:31:51.140
2 2 2022-06-08 00:26:14.523
When I plot using ggplot2, I get this:
ggplot(df_test,
aes(x = ID,
y = timing)) +
geom_point()
But when I set limits, the graph is empty:
lims <- as.POSIXct(strptime(c("35:00", "25:00"),
format = "%M:%OS",
tz = "CET"))
ggplot(df_test,
aes(x = ID,
y = timing)) +
geom_point() +
scale_y_datetime(limits = lims)
Warning message:
Removed 2 rows containing missing values (geom_point).
I tried to find any solution, but I can't figure out why the limits remove all my values. Does anyone have a solution?

This is simply due to your limits being round the wrong way (they should be earliest, latest whereas you have latest, earliest).
So you can do:
ggplot(df_test,
aes(x = ID,
y = timing)) +
geom_point() +
scale_y_datetime(limits = rev(lims))

Related

Reverse datetime (POSIXct data) axis in ggplot previous solution broken

A previous post detailed a solution to reversing the time on a ggplot post with this data:
MyData <-
structure(list(Date = structure(c(1492979809.99827, 1492602845.68722,
1493093428.90318, 1492605578.0691, 1492961342.65056, 1492771976.83545,
1493020588.88485, 1493057018.85104, 1492852011.23873, 1492855996.55059
), class = c("POSIXct", "POSIXt")), Value = c(4.52885504579172,
6.0024610790424, 8.96430060034618, 7.06435370026156, 5.08460514713079,
3.47828012891114, 6.29844291834161, 0.898315710946918, 1.44857675535604,
5.74641009094194)), .Names = c("Date", "Value"), row.names = c(NA,
-10L), class = "data.frame")
and this solution:
c_trans <- function(a, b, breaks = b$breaks, format = b$format) {
a <- as.trans(a)
b <- as.trans(b)
name <- paste(a$name, b$name, sep = "-")
trans <- function(x) a$trans(b$trans(x))
inv <- function(x) b$inverse(a$inverse(x))
trans_new(name, trans, inverse = inv, breaks = breaks, format=format)
}
rev_date <- c_trans("reverse", "time")
ggplot(MyData, aes(x=Value, y=Date)) +
geom_point() +
scale_y_continuous(trans = rev_date)
However, when I try and run this code now I get the following error:
Error: Invalid input: time_trans works with objects of class POSIXct only
I am running this code on R version 4.2.2 and cannot find a solution to fix this.
I tried forcing my data into POSIXct format, but the graphing still breaks in the same way.
You could slightly modify the function coord_x_datetime from the tidyquant package to reverse the datetime for your y-axis. Here is the function called coord_y_datetime:
coord_y_datetime <- function(xlim = NULL, ylim = NULL, expand = TRUE) {
if (!is.null(ylim)) {
ylim <- lubridate::as_datetime(ylim)
}
ggplot2::coord_cartesian(xlim = xlim, ylim = ylim, expand = expand)
}
Here is a reproducible example:
library(ggplot2)
ggplot(MyData, aes(x = Value, y = Date)) +
geom_point() +
coord_y_datetime(ylim = c(max(MyData$Date), min(MyData$Date)))
Created on 2022-11-14 with reprex v2.0.2

For Loop for ggplot2 in R

I have this data frame where I want to create multiple plots at the same time in a loop, but when I run the code it gives me an error. Can anyone please tell me what I am doing wrong!
Data:
structure(list(Date = structure(c(289094400, 297043200, 304992000,
312854400, 320716800, 328665600), tzone = "UTC", class = c("POSIXct",
"POSIXt")), NORTH = c(4.06976744186047, 5.51675977653633, 7.2799470549305,
4.75015422578655, 4.59363957597172, 3.15315315315317), YORKSANDTHEHUMBER = c(4.0121120363361,
5.45851528384282, 9.52380952380951, 6.04914933837431, 3.03030303030299,
5.42099192618225), NORTHWEST = c(6.57894736842105, 6.95256660168939,
6.50060753341436, 5.5904164289789, 4.59211237169096, 4.70041322314051
), EASTMIDS = c(4.98489425981872, 8.20143884892085, 6.91489361702127,
5.22388059701494, 5.61465721040189, 4.64465584778958), WESTMIDS = c(4.65838509316771,
4.74777448071216, 8.66855524079319, 6.56934306569344, 3.22896281800389,
3.17535545023698), EASTANGLIA = c(6.74525212835624, 8.58895705521476,
8.47457627118643, 10.7291666666667, 4.8447789275635, 4.84522207267835
), OUTERSEAST = c(6.7110371602884, 7.53638253638255, 9.47317544707589,
8.56512141280351, 3.82269215128102, 2.11515863689776), OUTERMET = c(4.54545454545458,
6.58505698607005, 7.36633663366336, 7.08225746956843, 4.3747847054771,
1.68316831683168), LONDON = c(8.11719500480309, 10.3065304309196,
6.32299637535239, 7.65151515151515, 1.30190007037299, 2.1535255296978
), SOUTHWEST = c(6.17577197149644, 7.71812080536912, 7.63239875389407,
9.45489628557649, 2.46804759806079, 2.19354838709679), WALES = c(6.09418282548476,
8.35509138381203, 7.40963855421687, 7.01065619742007, 1.15303983228513,
3.47150259067357), SCOTLAND = c(5.15222482435597, 4.12026726057908,
5.40106951871658, 8.67579908675796, -0.280112044817908, 2.94943820224719
), NIRELAND = c(4.54545454545454, 4.94752623688156, 4.42857142857145,
2.96397628818967, 6.06731620903454, 0.0835073068893502), UK = c(5.76890543055322,
7.20302836425676, 7.39543442582184, 7.22885986848197, 3.23472252213347,
2.95766398929048)), row.names = c(NA, -6L), class = c("tbl_df",
"tbl", "data.frame"))
Code:
for (i in 2:ncol(data2)) { # Printing ggplot within for-loop
print(ggplot(data2, aes(x = Date, y = data2[, i])) + # Basic ggplot2 plot of x & y's
geom_line() +
labs(title = "Uk States",
y = "",
x = "") +
theme_bw() +
geom_hline(yintercept = 0))
Sys.sleep(1)
}
Error:
Don't know how to automatically pick scale for object of type tbl_df/tbl/data.frame. Defaulting to continuous.
Error in is.finite(x) : default method not implemented for type 'list'
I would suggest to loop over the column names instead of value. You may then use .data to use as y-index.
library(tidyverse)
for(i in names(data2)[-1]) { # Printing ggplot within for-loop
# Basic ggplot2 plot of x & y's
print(ggplot(data2, aes(x = Date, y = .data[[i]])) +
geom_line()+ labs(title = "Uk States",
y = "",
x = "")+
theme_bw()+
geom_hline(yintercept = 0))
Sys.sleep(1)
}
You may also try facet_wrap to combine multiple plots together.
data2 %>%
pivot_longer(cols = -Date) %>%
ggplot(aes(Date, value)) +
geom_line() + facet_wrap(~name) +
labs(title = "Uk States", x = "", y = "") +
theme_bw() +
geom_hline(yintercept = 0)
Another way of generating ggplot in a loop is to use lapply, where we loop for colnames and use aes_string as the aesthetic mapping.
Here the results are saved to the list ggplot_list, where you can extract individual plot by indexing (e.g. plot for NORTH is stored in ggplot_list[[1]])
Note that I've changed labs(title = i) so that the plot title would be your column names.
library(ggplot2)
ggplot_list <- lapply(colnames(data2[-1]), \(i) {
ggplot(data2, aes_string("Date", x)) +
geom_line() +
labs(title = i, y = "", x = "") +
theme_bw() +
geom_hline(yintercept = 0)
})

ggplotly() does not display geom_vline / geom_hline when data is POSIXct

I am trying to make a graph with "time markers". These time markers are vertical lines for certain dates. Time data are POSIXct format. I would like to use the awesome interactive interface of Plotly and use my ggplot objects in it.
The problem is that these "time markers" doesn't show in after using ggplotly(). I ave already tried with plotly::add_segments() but it does not work.
Here are two reproductible examples :
1. With non-POSIXct data it works fine
# dummy dataset
df2 = data.frame(id = 1:10, measure = runif(10, 0, 20))
events2 = data.frame(number = c(2,3,8))
# ggplot graph
p2 = ggplot() + geom_line(data = df2, aes(x = id, y = measure)) +
geom_vline(data = events2, aes(xintercept = events2$number), color = "red")
p2
# plotly graph that displays the geom_vline properly
ggplotly(p2)
2. With POSIXct data is doesn't display the correct result
# dummy dataset
df = data.frame(date = seq(as.POSIXct("2017-07-01", tz = "UTC", format = "%Y-%m-%d"),
as.POSIXct("2018-04-15", tz = "UTC", format = "%Y-%m-%d"),
"1 month"),
measure = runif(10, 0, 20))
events = data.frame(date_envents = as.POSIXct(c("2017-10-12", "2017-11-12", "2018-03-15"), tz = "UTC", format = "%Y-%m-%d"))
# ggplot graph
p = ggplot() + geom_line(data = df, aes(x = date, y = measure)) +
geom_vline(data = events, aes(xintercept = events$date), color = "red")
p
# plotly graph that does not display the geom_vline properly
ggplotly(p)
I have seen some workaround (like this one : Add vertical line to ggplotly plot) but it is "complicated". Is there a more simple way to solve this problem ?
I am using Windows 10 with R version 3.5.0, RStudio and the following packages :
library(tidyverse) and library(plotly)
A simple workaround is to set the xintecept of the geom_vline to numeric.
sample data
df = data.frame(date = seq(as.POSIXct("2017-07-01", tz = "UTC", format = "%Y-%m-%d"),
as.POSIXct("2018-04-15", tz = "UTC", format = "%Y-%m-%d"),
"1 month"),
measure = runif(10, 0, 20))
events = data.frame(date_envents = as.POSIXct(c("2017-10-12", "2017-11-12", "2018-03-15"), tz = "UTC", format = "%Y-%m-%d"))
code
p = ggplot() + geom_line(data = df, aes(x = date, y = measure)) +
geom_vline(data = events, aes(xintercept = as.numeric(events$date)), color = "red")
result
ggplotly(p)

Map custom color gradient to POSIXct values

Data:
df1 <- structure(list(Index = 1:11, Duration = structure(c(1487577655,
1487577670, 1487577675, 1487577680, 1487577685, 1487577680, 1487577700,
1487577705, 1487577695, 1487577700, 1487577680), class = c("POSIXct",
"POSIXt"), tzone = "")), .Names = c("Index", "Duration"), class = "data.frame", row.names = 3:13)
Now I construct the graph as follows:
g1 <- ggplot(df1, aes(x = Index, y = Duration, color = Duration))+
geom_point()+
geom_line()+
scale_y_datetime(labels = date_format("%M:%S"))
As it is now, the color scale is set to the default "Black" to "Blue" gradient.
The problem is, I get an error trying to assign a custom gradient to the data.
For a non-POSIXct object:
scale_color_gradient("Duration", low = "#D80427", high = "#07a0ff", space = "Lab")
works, but I get the following error with the POSIXct object df1$Duration as the explanatory variable:
Error in Ops.POSIXt((x - from[1]), diff(from)) : '/' not defined
for "POSIXt" objects
Is there a different gradient function I need to use when graphing a POSIXct object?
You may use trans = time_trans():
library(ggplot2)
library(scales)
g1 +
scale_color_gradient("Duration", low = "#D80427", high = "#07a0ff",
trans = time_trans())
If you wish another format of the labels in the legend, add e.g. labels = format(pretty(df1$Duration), "%M:%S").
We can convert date to number for colour:
library(ggplot2)
library(scales)
ggplot(df1, aes(x = Index, y = Duration, color = as.numeric(Duration))) +
geom_point() +
geom_line() +
scale_y_datetime(labels = date_format("%M:%S")) +
scale_color_gradient("Duration", low = "#D80427", high = "#07A0FF",
labels = c("00", "10", "20", "30", "40"))
As suggested by #Henrik, to avoid hardcoding the labels use below:
# avoid hardcoding labels using pretty()
ggplot(df1, aes(x = Index, y = Duration, color = as.numeric(Duration))) +
geom_point() +
geom_line() +
scale_y_datetime(labels = date_format("%M:%S")) +
scale_color_gradient("Duration", low = "#D80427", high = "#07A0FF",
breaks = pretty(as.numeric(df1$Duration)),
labels = format(pretty(df1$Duration), "%M:%S"))

R ggplot2: colouring step plot depending on value

How do I configure a ggplot2 step plot so that when the value being plotted is over a certain level it is one colour and when it is below that certain level it is another colour? (Ultimately I would like to specify the colours used.)
My first thought was that this would be a simple issue that only required me to add a column to my existing data frame and map this column to the aes() for geom_step(). That works to a point: I get two colours, but they overlap as shown in this image:
I have searched SO for the past several hours and found many similar but not identical questions. However, despite trying a wide variety of combinations in different layers I have not been able to resolve the problem. Code follows. Any help much appreciated.
require(ggplot2)
tmp <- structure(list(date = structure(c(1325635200, 1325635800, 1325636400,
1325637000, 1325637600, 1325638200, 1325638800, 1325639400, 1325640000,
1325640600, 1325641200, 1325641800, 1325642400, 1325643000, 1325643600,
1325644200, 1325647800, 1325648400, 1325649000, 1325649600, 1325650200,
1325650800, 1325651400, 1325652000, 1325652600, 1325653200, 1325653800,
1325654400, 1325655000, 1325655600, 1325656200, 1325656800), tzone = "", tclass = c("POSIXct",
"POSIXt"), class = c("POSIXct", "POSIXt")), Close = c(739.07,
739.86, 740.41, 741.21, 740.99, 741.69, 742.64, 741.34, 741.28,
741.69, 741.6, 741.32, 741.95, 741.86, 741.02, 741.08, 742.08,
742.88, 743.19, 743.18, 743.78, 743.65, 743.66, 742.78, 743.34,
742.81, 743.31, 743.81, 742.91, 743.09, 742.47, 742.99)), .Names = c("date",
"Close"), row.names = c(NA, -32L), class = "data.frame")
prevclose <- 743
tmp$status <- as.factor(ifelse (tmp$Close> prevclose, "Above", "Below"))
ggplot() +
geom_step(data = tmp,aes(date, Close, colour = status))
You need group = 1 in aes:
# top panel
ggplot(tmp, aes(date, Close, colour = status, group = 1)) +
geom_step() + scale_colour_manual(values = c("pink", "green"))
Maybe you want to do something like this:
# make sure that data is sorted by date
tmp2 <- arrange(tmp, date)
# add intermittent column between below/above
tmp3 <- tmp2[1, ]
for (i in seq(nrow(tmp2))[-1]) {
if (tmp2[i-1, ]$status != tmp2[i, ]$status) {
tmp3 <- rbind(tmp3,
transform(tmp2[i, ], Close = prevclose, status = tmp2[i-1, ]$status),
transform(tmp2[i, ], Close = prevclose))
}
tmp3 <- rbind(tmp3, tmp2[i, ])
}
# bottom panel
ggplot(tmp3, aes(date, Close, colour = status, group = 1)) + geom_step() +
scale_colour_manual(values = c("pink", "green"))

Resources