R: Cách xây dựng bản đồ nhiệt với gói tờ rơi


10

Tôi đọc một bài viết về bản đồ tương tác với R bằng cách sử dụng leafletgói.

Trong bài viết này, tác giả tạo ra một bản đồ nhiệt như thế này:

X=cbind(lng,lat)
kde2d <- bkde2D(X, bandwidth=c(bw.ucv(X[,1]),bw.ucv(X[,2])))

x=kde2d$x1
y=kde2d$x2
z=kde2d$fhat
CL=contourLines(x , y , z)

m = leaflet() %>% addTiles() 
m %>% addPolygons(CL[[5]]$x,CL[[5]]$y,fillColor = "red", stroke = FALSE)

Tôi không quen với bkde2Dchức năng này, vì vậy tôi tự hỏi liệu mã này có thể được khái quát hóa cho bất kỳ shapefile nào không?

Điều gì xảy ra nếu mỗi nút có trọng lượng riêng, mà chúng tôi muốn thể hiện trên bản đồ nhiệt?

Có cách nào khác để tạo bản đồ nhiệt với leafletbản đồ trong R không?


bke2d cho phép bạn thực hiện 2d binning (ước tính mật độ hạt nhân) cho một tập hợp các điểm (vì vậy các cặp lng / lat hoạt động tốt). gói ks hỗ trợ làm mịn kernel cho dữ liệu từ 1 đến 6 chiều. gói akima có thể thực hiện phép nội suy (hữu ích khi bạn cần một lưới thông thường). có thể đáng để đọc trên chế độ xem nhiệm vụ không gian cho việc này trước khi cố gắng tạo ra thứ gì đó có thể không thể hiện đúng dữ liệu.
hrbrmstr

ok, cảm ơn vì đường link, tôi chắc chắn sẽ xem cái này Trên thực tế, hàm bke2d không hoạt động tốt với dữ liệu của tôi vì nó hoạt động trong ví dụ và tôi không thể hiểu tại sao.
Felipe

Câu trả lời:


10

Đây là cách tiếp cận của tôi để tạo bản đồ nhiệt tổng quát hơn trong Leaflet bằng R. Cách tiếp cận này sử dụng contourLines, giống như bài đăng trên blog đã đề cập trước đây, nhưng tôi sử dụng lapplyđể lặp lại tất cả các kết quả và chuyển đổi chúng thành đa giác chung. Trong ví dụ trước, người dùng có thể vẽ riêng từng đa giác, vì vậy tôi sẽ gọi đây là "tổng quát hơn" (ít nhất đây là khái quát mà tôi muốn khi đọc bài đăng trên blog!).

## INITIALIZE
library("leaflet")
library("data.table")
library("sp")
library("rgdal")
# library("maptools")
library("KernSmooth")

inurl <- "https://data.cityofchicago.org/api/views/22s8-eq8h/rows.csv?accessType=DOWNLOAD"
infile <- "mvthefts.csv"

## LOAD DATA
## Also, clean up variable names, and convert dates
if(!file.exists(infile)){
    download.file(url = inurl, destfile = infile)
}
dat <- data.table::fread(infile)
setnames(dat, tolower(colnames(dat)))
setnames(dat, gsub(" ", "_", colnames(dat)))
dat <- dat[!is.na(longitude)]
dat[ , date := as.IDate(date, "%m/%d/%Y")]

## MAKE CONTOUR LINES
## Note, bandwidth choice is based on MASS::bandwidth.nrd()
kde <- bkde2D(dat[ , list(longitude, latitude)],
              bandwidth=c(.0045, .0068), gridsize = c(100,100))
CL <- contourLines(kde$x1 , kde$x2 , kde$fhat)

## EXTRACT CONTOUR LINE LEVELS
LEVS <- as.factor(sapply(CL, `[[`, "level"))
NLEV <- length(levels(LEVS))

## CONVERT CONTOUR LINES TO POLYGONS
pgons <- lapply(1:length(CL), function(i)
    Polygons(list(Polygon(cbind(CL[[i]]$x, CL[[i]]$y))), ID=i))
spgons = SpatialPolygons(pgons)

## Leaflet map with polygons
leaflet(spgons) %>% addTiles() %>% 
    addPolygons(color = heat.colors(NLEV, NULL)[LEVS])

Đây là những gì bạn sẽ có tại thời điểm này: nhập mô tả hình ảnh ở đây

## Leaflet map with points and polygons
## Note, this shows some problems with the KDE, in my opinion...
## For example there seems to be a hot spot at the intersection of Mayfield and
## Fillmore, but it's not getting picked up.  Maybe a smaller bw is a good idea?

leaflet(spgons) %>% addTiles() %>%
    addPolygons(color = heat.colors(NLEV, NULL)[LEVS]) %>%
    addCircles(lng = dat$longitude, lat = dat$latitude,
               radius = .5, opacity = .2, col = "blue")

Và đây là bản đồ nhiệt với các điểm sẽ như thế nào:

nhập mô tả hình ảnh ở đây

Đây là một khu vực gợi ý cho tôi rằng tôi cần điều chỉnh một số tham số hoặc có thể sử dụng một kernel khác:

nhập mô tả hình ảnh ở đây

## Leaflet map with polygons, using Spatial Data Frame
## Initially I thought that the data frame structure was necessary
## This seems to give the same results, but maybe there are some 
## advantages to using the data.frame, e.g. for adding more columns
spgonsdf = SpatialPolygonsDataFrame(Sr = spgons,
                                    data = data.frame(level = LEVS),
                                    match.ID = TRUE)
leaflet() %>% addTiles() %>%
    addPolygons(data = spgonsdf,
                color = heat.colors(NLEV, NULL)[spgonsdf@data$level])

Quét sạch các interwebs cố gắng tìm ra điều này và đây là ví dụ tốt nhất tôi tìm thấy. Đã cắm nó vào mã của tôi và nó "chỉ hoạt động." Tuyệt vời. Cảm ơn bạn!
Jeff Allen

Cảm ơn! Tôi thực sự đã tạo một repo với một số ví dụ bản đồ khác có thể hữu ích cho những người khác github.com/geneorama/wnv_map_demo
genorama

Cảm ơn vì hướng dẫn nhỏ này. Làm thế nào bạn chọn bandwidthtrong bkde2d()?
the_darkside

2
@the_darkside câu hỏi tuyệt vời. Trong thực tế, tôi thích nó cho đến khi tôi nhận được thứ gì đó tôi thích, ban đầu tôi đã phát triển bản đồ này đặc biệt để kiểm tra các giả định về băng thông. Trong trường hợp này tôi thực sự sử dụng MASS::bandwidth.nrd(dat$latitude)MASS::bandwidth.nrd(dat$longitude)là điểm khởi đầu. Xem ?MASS::kde2dtài liệu liên kết đến bandwith.nrd. Cũng xem ?KernSmooth::dpiknếu bạn quan tâm cho một phương pháp khác.
genorama

Nếu gridsize = c(100,100)điều đó có nghĩa là có tổng cộng 10.000 tế bào?
the_darkside

4

Dựa trên câu trả lời của genorama ở trên, bạn cũng có thể chuyển đổi đầu ra của bkde2D thành raster chứ không phải đường viền, sử dụng các giá trị fhat làm giá trị ô raster

library("leaflet")
library("data.table")
library("sp")
library("rgdal")
# library("maptools")
library("KernSmooth")
library("raster")

inurl <- "https://data.cityofchicago.org/api/views/22s8-eq8h/rows.csv?accessType=DOWNLOAD"
infile <- "mvthefts.csv"

## LOAD DATA
## Also, clean up variable names, and convert dates
if(!file.exists(infile)){
  download.file(url = inurl, destfile = infile)
}
dat <- data.table::fread(infile)
setnames(dat, tolower(colnames(dat)))
setnames(dat, gsub(" ", "_", colnames(dat)))
dat <- dat[!is.na(longitude)]
dat[ , date := as.IDate(date, "%m/%d/%Y")]

## Create kernel density output
kde <- bkde2D(dat[ , list(longitude, latitude)],
              bandwidth=c(.0045, .0068), gridsize = c(100,100))
# Create Raster from Kernel Density output
KernelDensityRaster <- raster(list(x=kde$x1 ,y=kde$x2 ,z = kde$fhat))

#create pal function for coloring the raster
palRaster <- colorNumeric("Spectral", domain = KernelDensityRaster@data@values)

## Leaflet map with raster
leaflet() %>% addTiles() %>% 
  addRasterImage(KernelDensityRaster, 
                 colors = palRaster, 
                 opacity = .8) %>%
  addLegend(pal = palRaster, 
            values = KernelDensityRaster@data@values, 
            title = "Kernel Density of Points")

Đây là đầu ra của bạn. Lưu ý rằng các giá trị mật độ thấp vẫn hiển thị như được tô màu trong raster.

Đầu ra raster

Chúng ta có thể loại bỏ các ô mật độ thấp này bằng cách sau:

#set low density cells as NA so we can make them transparent with the colorNumeric function
 KernelDensityRaster@data@values[which(KernelDensityRaster@data@values < 1)] <- NA

#create pal function for coloring the raster
palRaster <- colorNumeric("Spectral", domain = KernelDensityRaster@data@values, na.color = "transparent")

## Redraw the map
leaflet() %>% addTiles() %>% 
  addRasterImage(KernelDensityRaster, 
                 colors = palRaster, 
                 opacity = .8) %>%
  addLegend(pal = palRaster, 
            values = KernelDensityRaster@data@values, 
            title = "Kernel Density of Points")

Bây giờ bất kỳ ô raster nào có giá trị nhỏ hơn 1 đều trong suốt.

Bản đồ cuối cùng

Nếu bạn muốn một raster binned, hãy sử dụng hàm colorBin thay vì hàm colorNumeric:

palRaster <- colorBin("Spectral", bins = 7, domain = KernelDensityRaster@data@values, na.color = "transparent")

## Leaflet map with raster
leaflet() %>% addTiles() %>% 
  addRasterImage(KernelDensityRaster, 
                 colors = palRaster, 
                 opacity = .8) %>%
  addLegend(pal = palRaster, 
            values = KernelDensityRaster@data@values, 
            title = "Kernel Density of Points")

Mật độ hạt nhân Rinned Raster

Để làm cho nó mượt mà hơn, chỉ cần tăng lưới trong hàm bkde2D. Điều này làm tăng độ phân giải của raster được tạo. (Tôi đã đổi nó thành

gridsize = c(1000,1000)

Đầu ra:

Raster làm mịn


Làm thế nào bạn có thể chuyển đổi mô tả truyền thuyết Mật độ hạt nhân mật độ điểm thành một cái gì đó trực quan hơn, như vụ trộm trên mỗi km vuông? Tôi đoán có một phương trình liên kết băng thông, lưới và phép chiếu, hoặc thậm chí kdf $ fhat mô tả các đơn vị.
thứ

3

Một cách dễ dàng để tạo bản đồ nhiệt Leaflet trong R là sử dụng plugin Leaflet.heat . Một hướng dẫn tuyệt vời về cách sử dụng nó có thể được tìm thấy ở đây . Hi vọng bạn tìm được thứ hữu dụng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.