R 如何使用gganimate创建具有风动画的轮廓?

R 如何使用gganimate创建具有风动画的轮廓?,r,ggplot2,contour,gganimate,R,Ggplot2,Contour,Gganimate,我已经为一天中的每个小时创建了一个风动画()。与显示19个点不同,我希望在整个区域内每小时使用这19个点创建一个等高线图插值/外推,就像使用ArcGIS和样条插值工具生成的等高线图一样 下面的代码显示了我用来创建每小时风动画的ggplot和gganimate。我只创建了一个小数据框作为完整24小时数据的子样本,因为我不熟悉将csv附加到这个论坛中。 是否有一种方法可以包括覆盖该区域的轮廓,而不是geom_点 library(ggplot2) library(ggmap) library(gga

我已经为一天中的每个小时创建了一个风动画()。与显示19个点不同,我希望在整个区域内每小时使用这19个点创建一个等高线图插值/外推,就像使用ArcGIS和样条插值工具生成的等高线图一样

下面的代码显示了我用来创建每小时风动画的ggplot和gganimate。我只创建了一个小数据框作为完整24小时数据的子样本,因为我不熟悉将csv附加到这个论坛中。 是否有一种方法可以包括覆盖该区域的轮廓,而不是
geom_点

library(ggplot2)
library(ggmap)
library(gganimate)

site <- c(1:18, 1:18)    
date <- data.frame(date=c(rep(as.POSIXct("2018-06-07 00:00:00"),18),rep(as.POSIXct("2018-06-07 01:00:00"),18)))    
long <- c(171.2496,171.1985, 171.2076, 171.2236,171.2165,171.2473,171.2448,171.2416,171.2243,171.2282,171.2344,171.2153,171.2532,171.2444,171.2443,171.2330,171.2356,171.2243)   
lati <- c(-44.40450,-44.38520,-44.38530,-44.38750,-44.39195,-44.41436,-44.38798,-44.38934,-44.37958,-44.37836,-44.37336,-44.37909,-44.40801, -44.40472,-44.39558,-44.40971,-44.39577,-44.39780)    
PM <- c(57,33,25,48,34,31,52,48,31,51,44,21,61,53,49,34,60,18,41,26,28,26,26,18,32,28,27,29,22,16,34,42,37,28,33,9)    
ws <- c(0.8, 0.1, 0.4, 0.4, 0.2, 0.1, 0.4, 0.2, 0.3, 0.3, 0.2, 0.7, NaN, 0.4, 0.3, 0.4, 0.3, 0.3, 0.8, 0.2, 0.4, 0.4, 0.1, 0.5, 0.5, 0.2, 0.3, 0.3, 0.3, 0.4, NaN, 0.5, 0.5, 0.4, 0.3, 0.2)    
wd <- c(243, 274, 227, 253, 199, 327, 257, 270, 209, 225, 230, 329, NaN, 219, 189, 272, 239, 237, 237, 273, 249, 261, 233, 306, 259, 273, 218, 242, 237, 348, NaN, 221, 198, 249, 236,252  )    
PMwind <- cbind(site,date,long,lati,PM, ws, wd)

tmlat <- c(-44.425, -44.365)                
tmlon <- c(171.175, 171.285)  

tim <- get_map(location = c(lon = mean(tmlon), lat = mean(tmlat)),
               zoom = 14,
               maptype = "terrain")

ggmap(tim) + 
    geom_point(aes(x=long, y = lati, colour=PM), data=PMwind,
               size=3,alpha = .8, position="dodge", na.rm = TRUE) +     
    geom_spoke(aes(x=long, y = lati, angle = ((270 -  wd) %% 360) * pi / 180), data=PMwind, 
               radius = -PMwind$ws * .01, colour="yellow", 
               arrow = arrow(ends = "first", length = unit(0.2, "cm"))) +
    transition_states(date, transition_length = 20, state_length = 60) +
    labs(title = "{closest_state}") +
    ease_aes('linear', interval = 0.1) +
    scale_color_gradient(low = "green", high = "red")+
    theme_minimal()+
    theme(axis.text.x=element_blank(), axis.title.x=element_blank()) +
    theme(axis.text.y=element_blank(), axis.title.y=element_blank()) +
    shadow_wake(wake_length = 0.01)
库(ggplot2)
图书馆(ggmap)
库(gganimate)

site这是可以做到的,但我要说的是,使用当前的工具还远远不够简单。要从问题中的数据集转到动画轮廓,我们需要解决以下障碍:

  • 我们只有几个数据点,不规则地分布在给定的区域。轮廓生成通常需要一个规则的点网格

  • ggplot2中的
    geom_等高线
    /
    stat_等高线
    无法很好地处理边缘处的开放等高线。有关尝试使用填充多边形的等高线时发生的情况的讨论,请参见

  • 与轮廓相关联的多边形不一定会随时间而保留:它们会出现、消失、分裂成多个较小的多边形、合并成较大的多边形等。这使得gganimate中的事情变得困难,它需要知道第t帧中的哪些元素对应于第t+1帧中的哪些元素,为了正确地插值它们

  • 前两个障碍可以通过现有的变通办法加以解决。第三种需要一些非正统的黑客

    第1部分:插值不规则点 为每个日期值获取PMwind的经度/纬度/PM值,并使用akima软件包中的
    interp
    将其插值到常规网格中。外推设置为
    TRUE
    的双三次样条插值将为您提供一个40 x 40的规则网格(默认情况下,如果您希望网格更粗/更细,请更改
    nx
    /
    ny
    参数值)点和插值PM值

    library(dplyr)
    
    PMwind2 <- PMwind %>%
      select(date, long, lati, PM) %>%
      tidyr::nest(-date) %>%
      mutate(data = purrr::map(data,
                               ~ akima::interp(x = .$long, y = .$lati, z = .$PM,
                                               linear = FALSE, # use spline interpolation
                                               extrap = TRUE) %>%
                                 akima::interp2xyz(data.frame = TRUE))) %>%
      tidyr::unnest()
    
    > str(PMwind2) # there are 2 x 40 x 40 observations, corresponding to 2 dates
    'data.frame':   3200 obs. of  4 variables:
     $ date: POSIXct, format: "2018-06-07" "2018-06-07" "2018-06-07" ...
     $ x   : num  171 171 171 171 171 ...
     $ y   : num  -44.4 -44.4 -44.4 -44.4 -44.4 ...
     $ z   : num  31.8 31.4 31 30.6 30.3 ...
    

    第3部分:不设置等高线/多边形的动画,而是设置点值的动画 生成动画绘图的每一帧后(但在打印/绘制到图形设备之前),获取其数据,创建新绘图(我们实际需要的绘图),并将其发送到图形设备。我们可以通过将一些代码插入到ggproto对象
    gganimate:::Scene
    中的函数
    plot\u frame
    ,在该函数中进行打印

    Scene2 <- ggproto(
      "Scene2", gganimate:::Scene,
      plot_frame = function(self, plot, i, newpage = is.null(vp), vp = NULL, 
                            widths = NULL, heights = NULL, ...) {    
        plot <- self$get_frame(plot, i)
    
        # for each frame, use the plot data interpolated by gganimate to create a new plot
        new.plot <- ggplot(data = plot[["data"]][[1]],
                           aes(x = x, y = y, z = z)) + 
          geom_contour_fill(breaks = scale.breaks) +
          ggtitle(plot[["plot"]][["labels"]][["title"]]) +
          map.annotation +
          scale_fill_gradient(low = "green", high = "red",
                              limits = range(scale.breaks)) +
          theme_minimal()
        plot <- ggplotGrob(new.plot)
    
        # no change below
        if (!is.null(widths)) plot$widths <- widths
        if (!is.null(heights)) plot$heights <- heights
        if (newpage) grid::grid.newpage()
        grDevices::recordGraphics(
          requireNamespace("gganimate", quietly = TRUE),
          list(),
          getNamespace("gganimate")
        )
        if (is.null(vp)) {
          grid::grid.draw(plot)
        } else {
          if (is.character(vp)) seekViewport(vp)
          else pushViewport(vp)
          grid::grid.draw(plot)
          upViewport()
        }
        invisible(NULL)
      })
    
    最后,结果如下:

    library(gganimate)
    
    animate2(p.base + 
               geom_point(aes(color = z)) + # this layer will be replaced by geom_contour_fill in 
                                            # the final plot; it's here as the placeholder in 
                                            # order for gganimate to interpolate the relevant data
               transition_time(date) +
               ggtitle("{frame_time}"),
             nframes = 30, fps = 10)        # you can increase nframes for smoother transition
                                            # (which would also be much bigger in file size)
    

    哇,这太棒了。谢谢,我今天重新运行代码准备最终报告时收到错误消息。创建map.annotation时失败,原因是“UseMethod(“isSymmetric”)中存在错误:没有适用于“c”类对象的“isSymmetric”方法(“ggmap”、“光栅”)“。最近是否更新了某个库,使其与上述代码崩溃?谷歌几个月前决定更新ggmap时,就发生了这种情况。请帮忙?提前谢谢@Z.LinNevermind。现在修好了。必须是ggplot或ggpmap中的更新。今天一切都好:)
    library(magrittr)
    
    create_scene2 <- function(transition, view, shadow, ease, transmuters, nframes) {
      if (is.null(nframes)) nframes <- 100
      ggproto(NULL, Scene2, transition = transition, 
              view = view, shadow = shadow, ease = ease, 
              transmuters = transmuters, nframes = nframes)
    }
    
    ggplot_build2 <- gganimate:::ggplot_build.gganim
    body(ggplot_build2) <- body(ggplot_build2) %>%
      as.list() %>%
      inset2(4,
             quote(scene <- create_scene2(plot$transition, plot$view, plot$shadow, 
                                          plot$ease, plot$transmuters, plot$nframes))) %>%
      as.call()
    
    prerender2 <- gganimate:::prerender
    body(prerender2) <- body(prerender2) %>%
      as.list() %>%
      inset2(3,
             quote(ggplot_build2(plot))) %>%
      as.call()
    
    animate2 <- gganimate:::animate.gganim
    body(animate2) <- body(animate2) %>%
      as.list() %>%
      inset2(7,
             quote(plot <- prerender2(plot, nframes_total))) %>%
      as.call()
    
    library(gganimate)
    
    animate2(p.base + 
               geom_point(aes(color = z)) + # this layer will be replaced by geom_contour_fill in 
                                            # the final plot; it's here as the placeholder in 
                                            # order for gganimate to interpolate the relevant data
               transition_time(date) +
               ggtitle("{frame_time}"),
             nframes = 30, fps = 10)        # you can increase nframes for smoother transition
                                            # (which would also be much bigger in file size)