how to make scale_y_reverse work with scale_y_time - r

I'm plotting HH:MM:SS on the y-axis against YYYY:MM on the x-axis, but am having issues trying to use scale_y_reverse with scale_y_time together.
sample data below:
library(hms)
library(ggplot2)
df_stack <- data.frame(yr_mn = rep(c("2020-01", "2020-02", "2020-03", "2020-04"),2),
timept_type = c(rep("A",4),rep("B",4)),
timept = as_hms(c("08:00:00", "09:10:00", "11:05:30", "10:45:00", "09:30:10", "10:00:00", "11:25:00", "08:40:00")))
df_stack %>%
ggplot(., aes(x=yr_mn, y=timept, color=timept, fill=timept)) +
geom_point() +
geom_line(aes(group=1))+
facet_wrap(vars(timept_type), scales="free", ncol=2) +
scale_y_time(limits = c(as.POSIXct(as_hms("07:00:00")), as.POSIXct(as_hms("11:30:00")))) +
scale_y_reverse() # this cause the y-axis labels to no longer be in hh:mm:ss format
If I comment out the last line scale_y_reverse() then the graph looks fine, but if I include it, the scale_y_reverse seems to convert the HH:MM:SS into seconds. I have no idea if it's something I'm doing incorrectly or if there's a built-in method within scale_y_time to resolve this. Thanks!

You can omit the scale_y_time and supply functions to scale_y_reverse to generate the labels and the breaks.
df_stack %>%
ggplot(aes(yr_mn, timept, color = timept, fill = timept)) +
geom_point() +
geom_line(aes(group = 1)) +
facet_wrap(vars(timept_type), scales = "free", ncol = 2) +
scale_y_reverse(labels = function(x) as_hms(x),
breaks = seq(as.numeric(as_hms("07:00:00")),
as.numeric(as_hms("11:30:00")),
1800))
Result:

After digging into the code for scale_x_reverse() and scale_x_time(), I've made a simplified version for my data (where x is time, and y is value).
Add a - in front of the variable to be reversed in the aesthetic, and add a reverse label function to scale_x_time(labels = function(x) -x)
ggplot(df, aes(x = -clock, y = points)) +
geom_point() +
scale_x_time(labels = function(x) -x)
xlab("Clock") + ylab("Points")

Reversing the limits may easier and less error-prone.
ggplot(df, aes(x = clock, y = points)) +
geom_point() +
scale_x_time(limits = c(12*60*60,0)) # in seconds
xlab("Clock") + ylab("Points")

Related

How to plot time in the x-axis? [duplicate]

I have tried to read through stackoverflow, blogs, books etc but have been unable to find the answer on plotting time in the x-axis in the following format(HH:MM:SS.000) in R and another quantity on the y-axis. I have the following dataset:
Time EcNo
12:54:09.000 -14.47
12:54:10.000 -17.96
12:54:11.000 -15.97
12:54:12.000 -14.61
12:54:13.000 -12.68
12:54:14.000 -10.73
12:54:15.000 -10.54
12:54:16.000 -11.62
12:54:17.000 -12.49
12:54:18.000 -11.12
How would I plot EcNo on Yaxis vs Time(x axis) in the format HH:MM:SS.000 as shown above.
I honestly would appreciate some help.
many thanks
You may also try ggplot:
library(ggplot2)
df$time <- as.POSIXct(strptime(df$Time, format="%H:%M:%S"))
# Automatic scale selection
ggplot(data = df, aes(x = time, y = EcNo)) + geom_point()
scale_x_datetime is a ggplot function, but for the nice arguments date_breaks, and date_format you need package scales:
library(scales)
ggplot(data = df, aes(x = time, y = EcNo)) + geom_point() +
scale_x_datetime(breaks = date_breaks("1 sec"), labels = date_format("%S"))
ggplot(data = df, aes(x = time, y = EcNo)) + geom_point() +
scale_x_datetime(breaks = date_breaks("1 sec"), labels = date_format("%OS3"))
ggplot(data = df, aes(x = time, y = EcNo)) + geom_point() +
scale_x_datetime(breaks = date_breaks("4 sec"), labels = date_format("%M:%S"))
plot(strptime(dta$Time, format="%H:%M:%S"), dta$EcNo, xaxt="n")
axis(1, at=as.numeric(strptime(dta$Time, format="%H:%M:%S")),
labels=strftime( strptime(dta$Time, format="%H:%M:%S"),format="%H:%M:%S"))
df <- data.frame(
Time=c('12:54:09.000','12:54:10.000','12:54:11.000','12:54:12.000','12:54:13.000','12:54:14.000','12:54:15.000','12:54:16.000','12:54:17.000','12:54:18.000'),
EcNo=c(-14.47,-17.96,-15.97,-14.61,-12.68,-10.73,-10.54,-11.62,-12.49,-11.12)
)
op <- options(digits.secs=3)
plot(as.POSIXct(df$Time,format="%H:%M:%OS"),df$EcNo,xaxt="n")
axis.POSIXct(1, as.POSIXct(df$Time,format="%H:%M:%OS"), format="%H:%M:%OS")

How to order geom_segment ggplot with colour

I am new to ggplot library. And trying to draw the plot using the following data.frame:
library(tidyverse)
df <-tribble(~event, ~startdate,~enddate,~loc,
"A",as.POSIXct("1984/02/10"),as.POSIXct("1987/06/10"),"1",
"B",as.POSIXct("1984/02/11"),as.POSIXct("1990/02/12"),"2",
"A",as.POSIXct("1992/05/15"),as.POSIXct("1999/06/15"),"3",
"C",as.POSIXct("2003/08/29"),as.POSIXct("2015/08/29"),"4",
"B",as.POSIXct("2002/04/11"),as.POSIXct("2012/04/12"),"5",
"E",as.POSIXct("2000/02/10"),as.POSIXct("2005/02/15"),"6")
max_date = max(df$startdate,df$enddate)
Using the following code snippet:
ggplot(NULL)+
geom_segment(data = df,aes(x=loc, xend =loc,y = startdate, yend = enddate,colour=event),size = 5,alpha=0.6) +
geom_label(aes(label=df$event,x = df$loc,y=max_date), size=2) +
#geom_point(data=final_df,aes(x=newspaper,y=date),color="black") + Point from other data frame
coord_flip() + xlab("LoC") + ylab("Year")
I can able to output the following chart:
How can I order the above chart using the colour i.e. using the event field (in other word how can I perform group by operation on the event field so that first it should display first all events A then events B, C etc.)? I have tried to use scale_x_continuous and reorder from tidyverse package but it didn't work. How can I display more "Year" on the x-axis? I tried to use scale_x_date (mentioned here R: ggplot display all dates on x axis but it needs as.Date and ggplot geom_segment needs as.POSIXct format). Please feel free to correct me!
Any help would be great! Thank you!
Two options. I've also reversed your x and y so you don't have to use coord_flip() and made several other small modifications including the x-axis labels (you were looking for scale_y_datetime since you flipped the axes and the "dates" were actually in POSIXct). Also, one difference with Duck's answer is my scales = "free" in facet_grid. You might decide your labels and your "loc" variable may not make sense given these new graphs anyway.
library(tibble); library(ggplot2)
df <-tribble(~event, ~startdate,~enddate,~loc,
"A",as.POSIXct("1984/02/10"),as.POSIXct("1987/06/10"),"1",
"B",as.POSIXct("1984/02/11"),as.POSIXct("1990/02/12"),"2",
"A",as.POSIXct("1992/05/15"),as.POSIXct("1999/06/15"),"3",
"C",as.POSIXct("2003/08/29"),as.POSIXct("2015/08/29"),"4",
"B",as.POSIXct("2002/04/11"),as.POSIXct("2012/04/12"),"5",
"E",as.POSIXct("2000/02/10"),as.POSIXct("2005/02/15"),"6")
max_date = max(df$startdate,df$enddate)
ggplot(df)+
geom_segment(aes(y=event, yend = event, x = startdate, xend = enddate, colour=event),size = 5,alpha=0.6) +
geom_label(aes(label=event, y = event, x=max_date), size=2) +
xlab("Year") + ylab("LoC") +
scale_x_datetime(date_breaks = "year", date_labels = "%Y") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5))
ggplot(df)+
geom_segment(aes(y=loc, yend = loc, x = startdate, xend = enddate, colour=event),size = 5,alpha=0.6) +
geom_label(aes(label=event, y = loc, x=max_date), size=2) +
xlab("Year") + ylab("LoC") +
scale_x_datetime(date_breaks = "year", date_labels = "%Y") +
theme(axis.text.x = element_text(angle = 90, vjust = 0.5)) +
facet_grid(rows = vars(event), scales = "free")
Created on 2020-10-18 by the reprex package (v0.3.0)
Consider this as an option, as mentioned by #ArthurYip setting reorder could affect the sense of your plot. You could avoid the labels and using facet_grid() in next way:
library(ggplot2)
#Plot
ggplot(df)+
geom_segment(aes(x=loc, xend =loc,y = startdate, yend = enddate,colour=event),size = 5,alpha=0.6) +
coord_flip() + xlab("LoC") + ylab("Year")+
facet_grid(event~.,switch = "x")
Output:

Using geom_segment to connect a line to the y-axis

I want to use geom_segment to make a line intercept the y-axis, the problem I am experiencing becomes readily apparent. Starting off with sample data:
dat <- data.frame(Yaxis = c(100,200,300,400,500,600,700,800), Year = c(2012,2013,2014,2015,2016,2017,2018,2019))
p <- ggplot(data=dat, aes(x=Year)) + geom_line(aes(y=Yaxis))
and adding a geom_segment layer produces:
p + geom_segment(aes(x=0,xend=2012,y=75,yend=100))
my attempts to amend this haven't worked out so far:
p + geom_segment(aes(x=0,xend=2012,y=75,yend=100)) + scale_x_continuous(expand= c(0,0), breaks = c(2012,2013,2014,2015,2016,2017,2018,2019))
For reference, here is a crude drawing of what I intend the graph to look like:
Thanks to #Sathish 's answer, I was able to create the graph I intended using
ggplot(data=dat, aes(x=as.Date(paste(Year,'-01-01', sep=""), "%Y-%m-%d"), y=Yaxis)) +
geom_line() +
geom_segment(aes(
x=as.Date("2011-01-01", "%Y-%m-%d"),
xend=as.Date("2012-01-01", "%Y-%m-%d"),
y=75,
yend=100), color = "red") +
scale_x_date(expand = c(0,0))
Convert Year column to Date class.
library('ggplot2')
ggplot(data=dat, aes(x=as.Date(paste(Year, '-01-01', sep = ""), "%Y-%m-%d"), y=Yaxis)) +
geom_line() +
geom_segment(aes(x=as.Date("2012-01-01", "%Y-%m-%d"),xend=as.Date("2020-01-01", "%Y-%m-%d"),y=75,yend=100), color = "red") +
xlab(label = "Year")

How to show every second R ggplot2 x-axis label value?

I want to show every second of x-axis label list in the presentation.
Simplified code example in the following and its output in Fig. 1 where four Dates shown but #2 and #4 should be skipped.
# https://stackoverflow.com/a/6638722/54964
require(ggplot2)
my.dates = as.Date(c("2011-07-22","2011-07-23",
"2011-07-24","2011-07-28","2011-07-29"))
my.vals = c(5,6,8,7,3)
my.data <- data.frame(date =my.dates, vals = my.vals)
plot(my.dates, my.vals)
p <- ggplot(data = my.data, aes(date,vals))+ geom_line(size = 1.5)
Expected output: skip dates second and fourth.
Actual code
Actual code where due to rev(Vars) logic, I cannot apply as.Date to the values in each category; the variable molten has a column Dates
p <- ggplot(molten, aes(x = rev(Vars), y = value)) +
geom_bar(aes(fill=variable), stat = "identity", position="dodge") +
facet_wrap( ~ variable, scales="free") +
scale_x_discrete("Column name dates", labels = rev(Dates))
Expected output: skip #2,#4, ... values in each category.
I thought here changing scale_x_discrete to scale_x_continuous and having a break sequence breaks = seq(1,length(Dates),2)) in scale_x_continuous but it fails because of the following error.
Error: `breaks` and `labels` must have the same length
Proposal based Juan's comments
Code
ggplot(data = my.data, aes(as.numeric(date), vals)) +
geom_line(size = 1.5) +
scale_x_continuous(breaks = pretty(as.numeric(rev(my.data$date)), n = 5))
Output
Error: Discrete value supplied to continuous scale
Testing EricWatt's proposal application into Actual code
Code proposal
p <- ggplot(molten, aes(x = rev(Vars), y = value)) +
geom_bar(aes(fill=variable), stat = "identity", position="dodge") +
facet_wrap( ~ variable, scales="free") +
scale_x_discrete("My dates", breaks = Dates[seq(1, length(Dates), by = 2)], labels = rev(Dates))
Output
Error: `breaks` and `labels` must have the same length
If you have scale_x_discrete("My dates", breaks = Dates[seq(1, length(Dates), by = 2)]), you get x-axis without any labels so blank.
Fig. 1 Output of the simplified code example,
Fig. 2 Output of EricWatt's first proposal
OS: Debian 9
R: 3.4.0
This works with your simplified example. Without your molten data.frame it's hard to check it against your more complicated plot.
ggplot(data = my.data, aes(date, vals)) +
geom_line(size = 1.5) +
scale_x_date(breaks = my.data$date[seq(1, length(my.data$date), by = 2)])
Basically, use scale_x_date which will likely handle any strange date to numeric conversions for you.
My solution eventually on the actual code motivated by the other linked thread and EricWatt's answer
# Test data of actual data here # https://stackoverflow.com/q/45130082/54964
ggplot(data = molten, aes(x = as.Date(Time.data, format = "%d.%m.%Y"), y = value)) +
geom_bar(aes(fill = variable), stat = "identity", position = "dodge") +
facet_wrap( ~ variable, scales="free") +
theme_bw() + # has to be before axis text manipulations because disables their effect otherwise
theme(axis.text.x = element_text(angle = 90, hjust=1),
text = element_text(size=10)) +
scale_x_date(date_breaks = "2 days", date_labels = "%d.%m.%Y")

cumulative plot using ggplot2

I'm learning to use ggplot2 and am looking for the smallest ggplot2 code that reproduces the base::plot result below. I've tried a few things and they all ended up being horrendously long, so I'm looking for the smallest expression and ideally would like to have the dates on the x-axis (which are not there in the plot below).
df = data.frame(date = c(20121201, 20121220, 20130101, 20130115, 20130201),
val = c(10, 5, 8, 20, 4))
plot(cumsum(rowsum(df$val, df$date)), type = "l")
Try this:
ggplot(df, aes(x=1:5, y=cumsum(val))) + geom_line() + geom_point()
Just remove geom_point() if you don't want it.
Edit: Since you require to plot the data as such with x labels are dates, you can plot with x=1:5 and use scale_x_discrete to set labels a new data.frame. Taking df:
ggplot(data = df, aes(x = 1:5, y = cumsum(val))) + geom_line() +
geom_point() + theme(axis.text.x = element_text(angle=90, hjust = 1)) +
scale_x_discrete(labels = df$date) + xlab("Date")
Since you say you'll have more than 1 val for "date", you can aggregate them first using plyr, for example.
require(plyr)
dd <- ddply(df, .(date), summarise, val = sum(val))
Then you can proceed with the same command by replacing x = 1:5 with x = seq_len(nrow(dd)).
After a couple of years, I've settled on doing:
ggplot(df, aes(as.Date(as.character(date), '%Y%m%d'), cumsum(val))) + geom_line()
Jan Boyer seems to have found a more concise solution to this problem in this question, which I have shortened a bit and combined with the answers of Prradep, so as to provide a (hopefully) up-to-date-answer:
ggplot(data = df,
aes(x=date)) +
geom_col(aes(y=value)) +
geom_line(aes(x = date, y = cumsum((value))/5, group = 1), inherit.aes = FALSE) +
ylab("Value") +
theme(axis.text.x = element_text(angle=90, hjust = 1))
Note that date is not in Date-Format, but character, and that value is already grouped as suggested by Prradep in his answer above.

Resources