ggplot2中没有数据时如何进行换行

39
我使用R来绘制一些数据。
Date <- c("07/12/2012 05:00:00", "07/12/2012 06:00:00", "07/12/2012 07:00:00",
      "07/12/2012 08:00:00","07/12/2012 10:00:00","07/12/2012 11:00:00")
Date <- strptime(Date, "%d/%m/%Y %H:%M")
Counts <- c("0","3","10","6","5","4")
Counts <- as.numeric(Counts)
df1 <- data.frame(Date,Counts,stringsAsFactors = FALSE)
library(ggplot2)
g = ggplot(df1, aes(x=Date, y=Counts)) + geom_line(aes(group = 1))
g
我该如何让R不在时间间断处绘制连续线图?我的数据通常每小时有一个数据点,但有时会出现间断(在上午8点到10点之间)。在这些点之间,我不希望将线连接起来。在R中是否有此功能? 编辑 非常感谢这里的回复。现在我的数据是每10秒钟一个数据点,并且我希望使用这个数据做同样的分析。
df <- structure(list(Date = c("11/12/2012", "11/12/2012", "11/12/2012", 
                     "11/12/2012", "11/12/2012", "11/12/2012", "11/12/2012", 
                     "11/12/2012", "11/12/2012", "11/12/2012", "11/12/2012"),
                     Time = c("20:16:00", "20:16:10", "20:16:20", "20:16:30", 
                     "20:16:40", "20:16:50", "20:43:30", "20:43:40", 
                     "20:43:50", "20:44:00", "20:44:10"),
                     Axis1 = c(181L, 14L, 65L, 79L, 137L, 104L, 7L, 0L, 0L, 
                     14L, 0L),
                     Steps = c(13L, 1L, 6L, 3L, 8L, 4L, 1L, 0L, 0L, 0L, 0L)),
                .Names = c("Date", "Time", "Axis1", "Steps"),
                row.names = c(57337L, 57338L, 57339L, 57340L, 57341L, 57342L, 
                57502L, 57503L, 57504L, 57505L, 57506L), class = "data.frame")

我认为我理解了代码添加“组”列到原始数据帧时试图做什么,但我的问题是如何让R知道数据现在是以10秒时间间隔呈现的?当我应用第一行代码来确定数字是否连续或是否存在间隔(例如idx < - c(1,diff(df $ Time))),我会得到以下错误:

Error in r[i1] - r[-length(r):-(length(r) - lag + 1L)] : 
  non-numeric argument to binary operator

在我的Time变量后,我是否需要添加as.POSIXct来确保它正确识别时间?

3个回答

27

您需要通过将共同值设置为要连接的那些点来设置group。在这里,您可以将前4个值设置为1,最后2个值设置为2。并将它们保留为因子。

df1$grp <- factor(rep(1:2, c(4,2)))
g <- ggplot(df1, aes(x=Date, y=Counts)) + geom_line(aes(group = grp)) + 
                     geom_point()

编辑:一旦您加载了data.frame,您可以使用以下代码自动生成grp列:

idx <- c(1, diff(df$Date))
i2 <- c(1,which(idx != 1), nrow(df)+1)
df1$grp <- rep(1:length(diff(i2)), diff(i2))

注意: 重要的是要添加geom_point(),因为如果不连续范围恰好是数据框中的最后一个条目,则不会绘制它(因为没有两个点连接线)。在这种情况下,geom_point()将绘制它。

例如,我将生成一个具有更多间隙的数据:

# get a test data
set.seed(1234)
df <- data.frame(Date=seq(as.POSIXct("05:00", format="%H:%M"), 
                as.POSIXct("23:00", format="%H:%M"), by="hours"))
df$Counts <- sample(19)
df <- df[-c(4,7,17,18),]

# generate the groups automatically and plot
idx <- c(1, diff(df$Date))
i2 <- c(1,which(idx != 1), nrow(df)+1)
df$grp <- rep(1:length(diff(i2)), diff(i2))
g <- ggplot(df, aes(x=Date, y=Counts)) + geom_line(aes(group = grp)) + 
            geom_point()
g

ggplot2_groups

编辑:对于您的新数据(假设为df),


需要翻译的内容已经完成了,是否还有其他需要帮助的地方呢?
df$t <- strptime(paste(df$Date, df$Time), format="%d/%m/%Y %H:%M:%S")

idx <- c(10, diff(df$t))
i2 <- c(1,which(idx != 10), nrow(df)+1)
df$grp <- rep(1:length(diff(i2)), diff(i2))

现在使用 aes(x=t, ...) 来绘制图表。


非常感谢。有没有一种自动化地完成这个任务的方法,而不需要逐个查看数据文件(因为我有1000多个文件需要这样运行,而且我可能没法一个一个地查看)?并且@Juba - 是的,我希望得到零值。在我的真实数据中,如果连续20分钟都是零值,这些数据会被删除。 - KT_1
1
@Arun 好的,好的,我投降了 :) 顺便说一句,你的编辑很棒。太遗憾了,我不能给你点赞两次! - juba
:) 谢谢 juba。没有问题。@KT_1,当然,我假设所有连续值之间相隔1小时。任何超过1小时的时间间隔将被分为另一组(直到下一个条目,我发现>1小时的差异)。 - Arun
1
@KT_1,帖子底部的最后一次编辑应该就可以了。这真的很简单。只需将“1”更改为“10”。 - Arun
非常感谢@Arun - 这正是我想要的。R Studio 给出了一些奇怪的值,但当我只使用 R 时,一切都正常工作。我认为在 R Studio 中存在某种关于日期的错误。 - KT_1
显示剩余9条评论

17

我认为R或ggplot2没有办法知道是否存在缺失的数据点,除非你使用NA指定它。例如:

df1 <- rbind(df1, list(strptime("07/12/2012 09:00:00", "%d/%m/%Y %H:%M"), NA))
ggplot(df1, aes(x=Date, y=Counts)) + geom_line(aes(group = 1))

在此输入图片描述


(+1) 然而,在这种情况下,OP更像是期望两组图形,不是吗?我的意思是,设置分组变量而不是将组设置为1更合适... - Arun

7

Juba的答案,包括显式 NA 在你想要的位置中断,是最好的方法。这里有一种替代方法,在正确的位置引入这些 NA (而不必手动计算)。

every.hour <- data.frame(Date=seq(min(Date), max(Date), by="1 hour"))
df2 <- merge(df1, every.hour, all=TRUE)
g %+% df2

图片描述

在将日期和时间更改为正确格式后,您可以对后面的df示例执行类似操作。

df$DateTime <- as.POSIXct(strptime(paste(df$Date, df$Time), 
                                   format="%m/%d/%Y %H:%M:%S"))
every.ten.seconds <- data.frame(DateTime=seq(min(df$DateTime), 
                                             max(df$DateTime), by="10 sec"))
df.10 <- merge(df, every.ten.seconds, all=TRUE)

3
这是一个非常简明的回答。如果您有多个分组,您可以使用complete而不是合并,它将填充每个变量组合的NAs。 - qwr
2
如果我今天写这个答案,我可能会使用类似于complete的东西。但是当我写这个答案时,tidyr还不存在。添加一个新的答案,展示如何使用complete解决问题可能会很有用。请随意这样做 ;) - Brian Diggs
简单而有效的答案!您可以简单地执行 df %>% dplyr :: mutate(var = if_else(condition == TRUE,NA,var) 并将 condition == TRUE 替换为您需要的任何内容。 - Simon Stolz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接