从 shapefile 和 CSV 生成传单地图的闪亮应用程序太慢了;大型形状文件会崩溃

问题描述 投票:0回答:1

我一直在尝试构建一个应用程序,让我可以探索起点-目的地流数据。它接受一个 csv,其中包含起始区域编号、目标区域编号和一堆信息字段,以及区域的多边形形状文件,让我可以描绘流入或流出特定区域的流量。我实际上有一个可以运行的 Shiny 应用程序,但它要么效率太低,要么这不是适合这项工作的工具。我将粘贴下面的代码。

我的问题是它似乎太占用内存了。对于少数区域,它可以工作,但速度非常慢(最初加载需要很长时间,并且每次输入之一更改时都需要更新)。更大的问题是我通常使用大型区域系统,有数百甚至数千个区域,总共有数百万个顶点。当我尝试将其应用于其中一个大型区域系统时,它最初会加载,但在两到三个移动(缩放或平移)或仅一次输入更改后,RStudio 就会崩溃。

所以我想知道是否有任何方法可以提高效率,或者 RStudio/Shiny 是否根本不适合用于此类用途。请记住,我对优化几乎一无所知,所以如果您稍微简化一下解释,我将不胜感激。

这是有效的应用程序:

library(shiny)
library(rgdal)
library(sp)
library(leaflet)
library(RColorBrewer)

shape <- readOGR(dsn=".", layer="zones")
shape <- spTransform(shape, CRS("+init=EPSG:4326"))

读取 shapefile,然后读取数据。 “i”和“j”是出发地和目的地区域编号。我还需要要映射的可能字段列表,并且它必须由完全数字的字段组成。我还没有弄清楚如何在没有循环的情况下对其进行子集化。任何有关这方面的帮助将不胜感激。

values <- read.csv("values.csv")
zonelist <- sort(unique(c(values$i, values$j)))
zones <- length(zonelist)
fieldlist <- as.vector(character())
fields <- 0
for (valname in colnames(values)){
  if (valname != "i" &
      valname != "j" &
      is.numeric(values[[valname]])
      ) {
        fields <- fields + 1
        fieldlist[fields] <- valname
        }
}

我将它们放入矩阵 mm 中。再次强调,任何更有效的方法都将受到欢迎。

mm <- array(numeric(), dim=c(fields,zones,zones))
mm[,,] <- 0
valarray <- array(numeric(), dim=fields*zones*zones)
valarray[] <- 0
for (k in 1:length(values)){
  if (colnames(values)[k] %in% fieldlist) {
    valarray[(values$j - 1) * zones * fields
             + (values$i - 1) * fields
             + which(colnames(values)[k] == fieldlist)
             ] <- values[[k]]
  } 
}
mm[,,] <- valarray

界面很简单:选择从/到参考区域,选择参考区域,选择要映射的数值字段。显示流程的传单地图。

ui <- fluidPage(
   titlePanel("Interzonal values mapping"),
   sidebarLayout(
      sidebarPanel(
         selectInput(inputId = "ft", label = "From/to zone", choices = c("from", "to")),
         selectInput(inputId = "zn", label = "Reference zone", choices = zonelist),
         selectInput(inputId = "fl", label = "Field to map", choices = fieldlist),
         width = 2
      ),
   mainPanel(leafletOutput("mapped_zonelist", height = 800),
             width = 10)
   )
)

服务器根据输入从矩阵 mm 中选取要映射为向量 (vs) 的流量,并根据流量值格式化区域图。

server <- function(input, output) {
   m <- reactive({
     if (input$ft == "from"){
        vs <- mm[which(input$fl == fieldlist), as.numeric(input$zn), ]
       } else {
        vs <- mm[which(input$fl == fieldlist), , as.numeric(input$zn)]
       }
     
     c_weight <- numeric()
     c_weight[1:zones] <- 1
     c_weight[as.numeric(input$zn)] <- 2
     c_color <- character()
     c_color[1:zones] <- "blue"
     c_color[as.numeric(input$zn)] <- "black"

     leaflet() %>%
       addTiles() %>%
       addPolygons(data=shape,
                   fillOpacity = 0.7,
                   opacity = 0.8,
                   weight = c_weight[shape@data$n],
                   color = c_color[shape@data$n],
                   fillColor = colorNumeric(palette = brewer.pal(10, "RdBu"), domain = vs)(vs[shape@data$n]),
                   popup = paste0("Zone ", input$zn, " to zone ", as.character(shape@data$n),
                                  "<br>",
                                  input$fl, " = ", vs)
                  )
   })
   output$mapped_zonelist <- renderLeaflet(m())
}

shinyApp(ui = ui, server = server)
r shiny r-leaflet
1个回答
1
投票

根据您的形状文件的大小/复杂性,我要做的第一件事就是简化它。正常加载你的 shapefile,然后:

install.packages("rmapshaper")
shape_simp <- rmapshaper::ms_simplify(shape, keep = 0.05)

keep =
论证进行实验。数字越大,生成的 shapefile 的复杂性就越高。这可能无法完全解决您的问题,但这是一个开始。

© www.soinside.com 2019 - 2024. All rights reserved.