R:使用背景图像按顺序绘制多个绘图的有效方法

时间:2017-01-31 19:05:40

标签: r shiny r-raster rgooglemaps

我希望在R中绘制一系列情节的定格动画。这些将显示在轨迹上移动的点。我想在背景中显示地图,以便移动点的位置对应于地图坐标。我这样做的方式是通过RgoogleMaps创建一个地图对象,然后将其存储为png文件,然后使用rasterImage函数将其设置为绘图的背景。最终我试图让这个是一个闪亮的应用程序(下面的代码)。 问题是我闪亮的动画速度太快了(我可以慢下来但看起来不太好),所以情节变得不透明,因为它不能足够快地处理它。

基本上我想用相同的背景显示每次迭代的一组点。有没有更有效的方法来做到这一点?有没有办法,比如说,永久设置背景图像,而不必每次都绘制它。我通过使用recordPlot()然后重放它节省了一些时间,但它仍然没有完全解决问题。我也试过看看我是否能让光栅的分辨率降低,但as.raster中的maxpixels和col参数似乎对我没有任何作用。

如果有一个类似的替代方案效率更高且达到大致相同的目的,那么我不会因为必须使用GoogleMaps而100%售出。

BC_googlemaps_point

library(shiny)
library(colorspace)
library(raster)
library(grDevices)
library(png)

#a png from Google Maps of the area above
bc_longlat_map_img <- png::readPNG("BC_googlemaps_point.png")
bc_longlat_map_img_ras <- grDevices::as.raster(bc_longlat_map_img, maxpixels=100)

bbox <- matrix(c(33.68208, -118.0554, 33.70493, -118.0279), byrow=TRUE, ncol=2)
rownames(bbox) <- c("lon","lat")
colnames(bbox) <- c("min","max")

#make some fake data

pt_data <- matrix(NA,nrow=1000, ncol=2)
colnames(pt_data) <- c("lon","lat")
#length of each side
plot_dims <- apply(bbox,1,diff)
pt_data[1:250,"lon"] <- bbox["lon","min"] + 0.2*plot_dims["lon"]
pt_data[1:250,"lat"] <- seq(bbox["lat","min"]+0.2*plot_dims["lat"],         bbox["lat","max"]-0.2*plot_dims["lat"], length.out=250)

pt_data[251:500,"lon"] <- seq(bbox["lon","min"]+0.2*plot_dims["lon"],     bbox["lon","max"]-0.2*plot_dims["lon"], length.out=250)
pt_data[251:500,"lat"] <- bbox["lat","max"] - 0.2*plot_dims["lat"]

pt_data[501:750,"lon"] <- bbox["lon","max"] - 0.2*plot_dims["lon"]
pt_data[501:750,"lat"] <- seq(bbox["lat","max"]-0.2*plot_dims["lat"], bbox["lat","min"]+0.2*plot_dims["lat"], length.out=250)

pt_data[751:1000,"lon"] <- seq(bbox["lon","max"]-0.2*plot_dims["lon"], bbox["lon","min"]+0.2*plot_dims["lon"], length.out=250)
pt_data[751:1000,"lat"] <- bbox["lat","min"] + 0.2*plot_dims["lat"]

#this is the slowest, have to replot the whole thing each time
 for (ii in 1:1000) {
  plot(bbox["lon",1]-1000, bbox["lat",1]-1000, xlim=bbox["lon",],     ylim=bbox["lat",], xlab="Longitude", ylab="Latitude", las=1) 
   #read in current plots limits to fit Raster Image to
   lims <- par()$usr
   rasterImage(bc_longlat_map_img_ras, xleft=lims[1], ybottom=lims[3],     xright=lims[2], ytop=lims[4])
   points(x=pt_data[ii,"lon"], y=pt_data[ii,"lat"], pch=19, cex=3)
   }

#plot first, then record, and only replay each time
#seems to be a bit faster
 plot(bbox["lon",1]-1000, bbox["lat",1]-1000, xlim=bbox["lon",],     ylim=bbox["lat",], xlab="Longitude", ylab="Latitude", las=1) 
   #read in current plots limits to fit Raster Image to
   lims <- par()$usr
   rasterImage(bc_longlat_map_img_ras, xleft=lims[1], ybottom=lims[3], xright=lims[2], ytop=lims[4])
 plot_back <- recordPlot()

for (ii in 1:1000) {
   replayPlot(plot_back)
   points(x=pt_data[ii,"lon"], y=pt_data[ii,"lat"], pch=19, cex=3)

   }

 #example without the map background.  very fast.
   for (ii in 1:1000) {
    plot(bbox["lon",1]-1000, bbox["lat",1]-1000, xlim=bbox["lon",], ylim=bbox["lat",], xlab="Longitude", ylab="Latitude", las=1) 

    points(x=pt_data[ii,"lon"], y=pt_data[ii,"lat"], pch=19, cex=3)
   }

我试图实现的闪亮应用程序看起来像这样(代码重复):

shark_vis <- shinyApp(
    ui=  shinyUI(
     fluidPage(
      sidebarLayout(
        sidebarPanel("Inputs",
           sliderInput("iter","Progress of simulation",value=1, min=1, max=1000, round=TRUE, step=1,
                             animate=animationOptions(interval=100, loop=FALSE))),
    mainPanel(plotOutput("plot"))
        )
    )
),
server=shinyServer(
   function(input, output) {
   #current image dimensions
bbox <- matrix(c(33.68208, -118.0554, 33.70493, -118.0279), byrow=TRUE,     ncol=2)
rownames(bbox) <- c("lon","lat")
colnames(bbox) <- c("min","max")

#make some fake data

pt_data <- matrix(NA,nrow=1000, ncol=2)
colnames(pt_data) <- c("lon","lat")
#length of each side
plot_dims <- apply(bbox,1,diff)
pt_data[1:250,"lon"] <- bbox["lon","min"] + 0.2*plot_dims["lon"]
pt_data[1:250,"lat"] <- seq(bbox["lat","min"]+0.2*plot_dims["lat"],     bbox["lat","max"]-0.2*plot_dims["lat"], length.out=250)

pt_data[251:500,"lon"] <- seq(bbox["lon","min"]+0.2*plot_dims["lon"],     bbox["lon","max"]-0.2*plot_dims["lon"], length.out=250)
pt_data[251:500,"lat"] <- bbox["lat","max"] - 0.2*plot_dims["lat"]

pt_data[501:750,"lon"] <- bbox["lon","max"] - 0.2*plot_dims["lon"]
pt_data[501:750,"lat"] <- seq(bbox["lat","max"]-0.2*plot_dims["lat"], bbox["lat","min"]+0.2*plot_dims["lat"], length.out=250)

pt_data[751:1000,"lon"] <- seq(bbox["lon","max"]-0.2*plot_dims["lon"], bbox["lon","min"]+0.2*plot_dims["lon"], length.out=250)
pt_data[751:1000,"lat"] <- bbox["lat","min"] + 0.2*plot_dims["lat"]

#plot and store 
plot(bbox["lon",1]-1000, bbox["lat",1]-1000, xlim=bbox["lon",],     ylim=bbox["lat",], xlab="Longitude", ylab="Latitude", las=1) 
   #read in current plots limits to fit Raster Image to
   lims <- par()$usr
   rasterImage(bc_longlat_map_img_ras, xleft=lims[1], ybottom=lims[3],     xright=lims[2], ytop=lims[4])
 plot_back <- recordPlot()


 output$plot <- renderPlot({
    replayPlot(plot_back)
    points(x=pt_data[input$iter,"lon"], y=pt_data[input$iter,"lat"],     pch=19, cex=3, col=1:2)
    })
    }
)
)   

runApp(shark_vis)

1 个答案:

答案 0 :(得分:1)

您可以使用我的googleway包将动画“模拟”到实际的Google地图上。

我已经简化了你的例子,所以我可以让它工作,但这个想法也应该转化为你的例子。

在这里,我正在为墨尔本和悉尼之间的路线制作动画

要制作动画,您需要在地图上加载一系列圆圈,然后根据您想要显示的不透明度将不透明度设置为0或1。

在这种情况下,您想要显示的那些取决于输入滑块的值。

每次避免重新绘制地图和形状的技巧是在开始时加载所有圆圈,然后使用update_circles()功能更改圆圈的属性(即不透明度)。

注意:

  • 您需要有效的Google Maps Javascript API key
  • 输入数据必须是data.frame,而不是矩阵
  • 我还没有找到“休息”点 - 也就是说,有太多圈子无法快速更新
library(shiny)
library(googleway)

ui <- fluidPage(
    sliderInput(inputId = "mySlider", label = "slider", min = 0, max = 222, value = 0, step = 1, 
        animate = animationOptions(interval=100, loop=FALSE)),
    google_mapOutput("myMap", height = 800)
)

server <- function(input, output){

    polyline <- "rqxeF_cxsZgr@xmCekBhMunGnWc_Ank@vBpyCqjAfbAqmBjXydAe{AoF{oEgTqjGur@ch@qfAhUuiCww@}kEtOepAtdD{dDf~BsgIuj@}tHi{C{bGg{@{rGsmG_bDbW{wCuTyiBajBytF_oAyaI}K}bEkqA{jDg^epJmbB{gC}v@i~D`@gkGmJ_kEojD_O{`FqvCetE}bGgbDm_BqpD}pEqdGiaBo{FglEg_Su~CegHw`Cm`Hv[mxFwaAisAklCuUgzAqmCalJajLqfDedHgyC_yHibCizK~Xo_DuqAojDshAeaEpg@g`Dy|DgtNswBcgDiaAgEqgBozB{jEejQ}p@ckIc~HmvFkgAsfGmjCcaJwwD}~AycCrx@skCwUqwN{yKygH}nF_qAgyOep@slIehDcmDieDkoEiuCg|LrKo~Eb}Bw{Ef^klG_AgdFqvAaxBgoDeqBwoDypEeiFkjBa|Ks}@gr@c}IkE_qEqo@syCgG{iEazAmeBmeCqvA}rCq_AixEemHszB_SisB}mEgeEenCqeDab@iwAmZg^guB}cCk_F_iAmkGsu@abDsoBylBk`Bm_CsfD{jFgrAerB{gDkw@{|EacB_jDmmAsjC{yBsyFaqFqfEi_Ei~C{yAmwFt{B{fBwKql@onBmtCq`IomFmdGueD_kDssAwsCyqDkx@e\\kwEyUstC}uAe|Ac|BakGpGkfGuc@qnDguBatBot@}kD_pBmmCkdAgkB}jBaIyoC}xAexHka@cz@ahCcfCayBqvBgtBsuDxb@yiDe{Ikt@c{DwhBydEynDojCapAq}AuAksBxPk{EgPgkJ{gA}tGsJezKbcAcdK__@uuBn_AcuGsjDwvC_|AwbE}~@wnErZ{nGr_@stEjbDakFf_@clDmKkwBbpAi_DlgA{lArLukCBukJol@w~DfCcpBwnAghCweA}{EmyAgaEbNybGeV}kCtjAq{EveBwuHlb@gyIg\\gmEhBw{G{dAmpHp_@a|MsnCcuGy~@agIe@e`KkoA}lBspBs^}sAmgIdpAumE{Y_|Oe|CioKouFwuIqnCmlDoHamBiuAgnDqp@yqIkmEqaIozAohAykDymA{uEgiE}fFehBgnCgrGmwCkiLurBkhL{jHcrGs}GkhFwpDezGgjEe_EsoBmm@g}KimLizEgbA{~DwfCwvFmhBuvBy~DsqCicBatC{z@mlCkkDoaDw_BagA}|Bii@kgCpj@}{E}b@cuJxQwkK}j@exF`UanFzM{fFumB}fCirHoTml@CoAh`A"

    df <- decode_pl(polyline)
    df$opacity <- 1
    df$id <- 1:nrow(df)

    rv <- reactiveValues()
    rv$df <- df

    map_key <- "your_api_key"

    output$myMap <- renderGoogle_map({

        google_map(key = map_key, data = df) %>%
            add_circles(radius = 1000, id = "id", lat = "lat", lon = "lon", 
                        fill_opacity = "opacity", stroke_opacity = "opacity")
    })

    observeEvent({
        input$mySlider
        },{

        r <- input$mySlider
        rv$df[r, "opacity"] <- 1
        rv$df[-r, "opacity"] <- 0

        google_map_update(map_id = "myMap") %>%
            update_circles(data = rv$df, radius = 1000, id = "id", 
                            fill_opacity = "opacity", stroke_opacity = "opacity")

    })

}

shinyApp(ui, server)

截图

开始状态:显示所有内容

enter image description here

滑块上的第34步

enter image description here

滑块上的步骤44

enter image description here

滑块上的步骤82

enter image description here