geom_path()拒绝越过coord_polar()中的0/360行

And*_*rew 10 r data-visualization ggplot2

我正在尝试绘制对象随时间变化的角度(比如说是风向标)。我想将其绘制在极坐标系上,并用一条路径连接时间点,以显示角度如何随时间变化。我只是有一个数据框,其中一列是角度(以度为单位)(数字),然后是记录角度的时间步长(整数)。

但是当我运行以下代码时:

ggplot(df, aes(x = angle.from.ref, y = time.step)) +
  coord_polar() + 
  geom_path() + 
  geom_point() +
  scale_x_continuous(limits = c(0, 360), breaks = seq(0, 360, 45))
Run Code Online (Sandbox Code Playgroud)

我得到的东西看起来像这样:

像这样

所创建的路径geom_path()拒绝越过0/360度线。如果359值后跟1值,则该路径将不会创建穿过x = 0/360点的短链接。取而代之的是,路径沿圆弧一直向后弯曲,从另一侧到达x = 1。

我曾希望使用coord_polar()该方法可以解决此问题,但显然不是。有什么办法可以ggplot使值0和360相邻/连续?

Z.L*_*Lin 6

绕过交叉问题可能更直接:在360/0点进行插值,并将每转绘制为自己的截面。运作方式如下:

library(dplyr)
library(ggplot2)

# sample data
n <- 100
df <- data.frame(
  angle.from.ref = seq(0, 800, length.out = n),
  time.step = seq(Sys.time(), by = "min", length.out = n)
)

df %>%
  interpolate.revolutions() %>%
  ggplot(aes(x = angle.from.ref, y = time.step, 
             group = revolution)) +
  geom_line(aes(color = factor(revolution)), size = 1) + # color added for illustration
  scale_x_continuous(limits = c(0, 360),
                     breaks = seq(0, 360, 45)) +
  coord_polar()
Run Code Online (Sandbox Code Playgroud)

情节

interpolate.revolutions功能代码:

interpolate.revolutions <- function(df, threshold = 360){
  # where df is a data frame with angle in the first column & radius in the second

  res <- df

  # add a label variable such that each span of 360 degrees belongs to
  # a different revolution
  res$revolution <- res[[1]] %/% threshold

  # keep only the angle values within [0, 360 degrees]
  res[[1]] <- res[[1]] %% threshold

  # if there are multiple revolutions (i.e. the path needs to cross the 360/0 threshold), 
  # calculate interpolated values & add them to the data frame
  if(n_distinct(res$revolution) > 1){        
    split.res <- split(res, res$revolution)
    res <- split.res[[1]]
    for(i in seq_along(split.res)[-1]){
      interp.res <- rbind(res[res[[2]] == max(res[[2]]), ],
                          split.res[[i]][split.res[[i]][[2]] == min(split.res[[i]][[2]]), ])
      interp.res[[2]] <- interp.res[[2]][[1]] + 
        (threshold - interp.res[[1]][1]) / 
        (threshold - interp.res[[1]][1] + interp.res[[1]][2]) *
        diff(interp.res[[2]])
      interp.res[[1]] <- c(threshold, 0)          
      res <- rbind(res, interp.res, split.res[[i]])
    }
  }
  return(res)
}
Run Code Online (Sandbox Code Playgroud)

该方法也可以应用于绘图中的多条线。只需将功能分别应用于每一行:

# sample data for two lines, for different angle values taken at different time points
df2 <- data.frame(
  angle.from.ref = c(seq(0, 800, length.out = 0.75 * n),
                     seq(0, 1500, length.out = 0.25 * n)),
  time.step = c(seq(Sys.time(), by = "min", length.out = 0.75 * n),
                seq(Sys.time(), by = "min", length.out = 0.25 * n)),
  line = c(rep(1, 0.75*n), rep(2, 0.25*n))
)


df2 %>%
  tidyr::nest(-line) %>%
  mutate(data = purrr::map(data, interpolate.revolutions)) %>%
  tidyr::unnest() %>%

  ggplot(aes(x = angle.from.ref, y = time.step, 
             group = interaction(line, revolution),
             color = factor(line))) +
  geom_line(size = 1) +
  scale_x_continuous(limits = c(0, 360),
                     breaks = seq(0, 360, 45)) +
  coord_polar()
Run Code Online (Sandbox Code Playgroud)

情节