0

Hi i have a problem that occurs in R.

I can't handle the y - axis, which is hour : minute format.

here is the code sample.

library("data.table")
library("ggplot2") #load library

time <- c("00:05", "06:57","19:00","23:10","00:32","15:00","01:30","03:20") #time data

class <- c("Math", "Eng", "History","Math", "Eng", "History","Math", "Eng") #Course data

day <- c("1/21","1/21","1/21","1/21","1/22","1/22","1/23","1/23") #day data

df <- data.frame(time, class, day) #dataframe

df$time = as.POSIXct(df$time, format = "%H:%M") #make char to time format

pic <- ggplot(df, aes(x = class, y=df$time)) + 
  scale_y_datetime(date_breaks = "1 hour") + 
  facet_grid(. ~ day) #draw picture, break time in 1 hour

pic

if i draw this graph, then Y axis have the year, month and day. i tried to erase the format of year, month and day through as.POSIXct, but didnt work.

also, the limit of time is not from 00:00 to 24:00, its from 1/20 23:00 to 1/22 00:00

i don't know how to figure out the solution of it.

rainbear
  • 5
  • 2
  • 3
    Is `scale_y_datetime(date_labels = "%H:%M")` what you're looking for? – Ian Campbell Jan 21 '22 at 01:36
  • (1) You define `Time` as a variable *outside* of the `df` frame, and use it within the `ggplot`. While it works, it can easily be problem if `df` is filtered or reordered and you do not do the same with `Time`. I recommend you add it as a variable in the frame by replacing `Time <- ...` with `df$Time <- ...` (or some other variable). Your `ggplot(.)` command does not change from this. – r2evans Jan 21 '22 at 01:59
  • (2) I find it odd that you have `day` (date) `and `time` in the frame, but when you make your timestamps, you ignore day, so all of your `TIme` timestamps are "today" at the applicable time, counter to what is suggested by the `dat` values (`"%m/%d"`?). Is this intentional? – r2evans Jan 21 '22 at 02:00
  • 1
    @r2evans (1) oh i see. i change the "Time" to "df$time" – rainbear Jan 21 '22 at 02:31
  • @r2evans (2) i just want to divide 3 graphs each based on "day". if this i remove the day row, and merge with time, "1/22 00:05" like this, then can i make 3 each graphs based on day? – rainbear Jan 21 '22 at 02:35
  • @IanCampbell oh it wokrs thanks. can i ask one more question about this? – rainbear Jan 21 '22 at 02:37
  • I *think* what you're trying to do is have time-of-day on the y axis, displayed as `HH:MM` from midnight to midnight (or some subset therein), and not have "day or month or year" reflected, either in the labels or in the *range* of the y axis. Is that right? That is, even though your data spans touches 3 days, you want the y-axis to only cover no more than 24 hours. Right? – r2evans Jan 21 '22 at 02:39
  • @r2evans oh my god yes. – rainbear Jan 21 '22 at 02:55
  • Okay, then I think IanCampbell's comment is the best way to go. You had another question, what is it? – r2evans Jan 21 '22 at 02:56
  • @r2evans sorry for late comment. is there other way to show the 00:00 to 24:00? – rainbear Jan 21 '22 at 04:09
  • In fact, there is ... https://stackoverflow.com/a/69468780/3358272. That should be used somehow in `scale_y_datetime`, I think it accepts a formatting *function*. – r2evans Jan 21 '22 at 04:16
  • @r2evans omg thank you so much – rainbear Jan 21 '22 at 04:19
  • BTW, you need to fix your code: don't use `df$time` within `ggplot` commands, just `time`. (This might seem to contradict my previous comment, but ... your method of constructing a `data.frame` may lead to the assumption that `ggplot(df, aes(x = class, y=df$time))` is referencing the vector named `class` in the environment, when in fact it first looks for the *column* named `class` in the data provided, `df`.) – r2evans Jan 21 '22 at 04:20
  • @IanCampbell, see https://gist.github.com/r2evans/ed0d132166bfbd9473d99b4fac7d65db. Then highlight the URL in the browser, copy it, run `SE()` (args as desired) in the local R instance, and then it copies the file name into the clipboard. Go to your preferred editor, "open new file", paste the file name (or "save as" then paste, whatever works), and have at it. There is other functionality to it, feel free to play. (Oh yes, it has `~/StackOverflow/` hard-coded as the base directory.) – r2evans Jan 21 '22 at 04:37
  • @IanCampbell, if you're using macos, then see https://stackoverflow.com/a/9036325/3358272 and [`?connections`](https://stat.ethz.ch/R-manual/R-devel/library/base/html/connections.html), and replace `readLines("clipboard")` with `readLines(pipe("pbpaste"))`, I think (cannot test); similarly, `writeLines("clipboard")` with `writeLines(pipe("pbcopy", "w"))` or such. – r2evans Jan 21 '22 at 04:52
  • Regardless, though, it's not hard to replace the clipboard-reliance of that function to be completely (non-`invisible`) functional. – r2evans Jan 21 '22 at 04:53
  • 1
    Pull in code blocks? Huh ... please provide a PR if you get it to work :-) (And let me know how you get new-askers to always use code blocks, reliably. That may be the bigger hurdle.) – r2evans Jan 21 '22 at 05:06

1 Answers1

1

Combining IanCampbell's mention of date_labels= and changing it to labels= using a function I wrote that ensures you see 24:00 instead of 00:00, we can get (I think) what you want.

format.myPOSIX <- function(x, tz = "", usetz = FALSE, ...) {
  midnight <- format.POSIXct(x, format = "%H") %in% "00"
  dayminus1 <- x - 86400
  x[midnight] <- dayminus1[midnight]
  gsub(" 00:", " 24:", format.POSIXct(x, tz = tz, usetz = usetz, ...))
}
print.myPOSIX <- function(x, tz = "", usetz = TRUE, ...) {
  print(format.myPOSIX(x, tz = tz, usetz = usetz))
}

(Some of that is not strictly necessary, but ...)

ggplot(df, aes(x = class, y=time)) + 
  scale_y_datetime(
    date_breaks = "1 hour",
    labels = function(x) format.myPOSIX(x, format = " %H:%M")
  ) + 
  facet_grid(. ~ day)

enter image description here

Notice the space in the formatting string: " %H:%M". This is because of one hard-coded presumption in format.myPOSIX: that the hour is present and has a space before it and a colon after it. I could possibly fix the function to be more robust, but ... perhaps this is sufficient for now.

r2evans
  • 141,215
  • 6
  • 77
  • 149