【问题标题】:raster::rasterToContour; contour lines are not continuousraster::rasterToContour;等高线不连续
【发布时间】:2021-08-07 07:32:26
【问题描述】:

我正在尝试使用 R 中的 raster 包从光栅对象中提取等高线。

rasterToContour 似乎运行良好并且绘图很好,但在调查时似乎轮廓线被分解成不规则的部分。来自?rasterToContour的示例数据

library(raster)

f <- system.file("external/test.grd", package="raster")
r <- raster(f)
x <- rasterToContour(r)
class(x)
plot(r)
plot(x, add=TRUE)

我正在尝试提取栅格中示例站点的等高线。因此,我们选择一个随机站点,提取其高程,然后再次运行rasterToContour(),指定等高线的高程level

# our sample site - a random cell chosen on the raster
xyFromCell(r, 5000) %>%
  SpatialPoints(proj4string = crs(r)) %>%
  {. ->> site_sp} %>%
  st_as_sf %>%
  {. ->> site_sf}

# find elevation of sample site, and extract contour lines
extract(r, site_sf) %>%
  {. ->> site_elevation}

# extract contour lines
r %>%
  rasterToContour(levels = site_elevation) %>%
  {. ->> contours_sp} %>%
  st_as_sf %>%
  {. ->> contours_sf}

# plot the site and new contour lines (approx elevation 326)
plot(r)
plot(contours_sf, add = TRUE)
plot(site_sf, add = TRUE)

# plot the contour lines and sample site - using sf and ggplot
ggplot()+
  geom_sf(data = contours_sf)+
  geom_sf(data = site_sf, color = 'red')

然后我们使用st_intersects 来查找与站点相交的线(缓冲区宽度为 100 以确保它与线接触)。但是,这会返回所有的等高线。

contours_sf %>%
  filter(
    st_intersects(., site_sf %>% st_buffer(100), sparse = FALSE)[1,]
  ) %>%
  ggplot()+
  geom_sf()

我假设所有行都被返回,因为它们似乎是单个 MULTILINESTRING sf 对象。

contours_sf

# Simple feature collection with 1 feature and 1 field
# geometry type:  MULTILINESTRING
# dimension:      XY
# bbox:           xmin: 178923.1 ymin: 329720 xmax: 181460 ymax: 333412.3
# CRS:            +proj=sterea +lat_0=52.1561605555556 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +datum=WGS84 +units=m +no_defs
# level                       geometry
# C_1 326.849822998047 MULTILINESTRING ((179619.3 ...

所以,我使用ngeo::st_segments()contours_sf MULTILINESTRING 拆分为单独的行(我找不到任何sf 方法来执行此操作,但我愿意使用其他方法,尤其是如果这是问题)。

出乎意料的是,这会返回 394 个特征;从这个数字来看,我预计大约有 15 条单独的线。

contours_sf %>%
  nngeo::st_segments()

# Simple feature collection with 394 features and 1 field
# geometry type:  LINESTRING
# dimension:      XY
# bbox:           xmin: 178923.1 ymin: 329720 xmax: 181460 ymax: 333412.3
# CRS:            +proj=sterea +lat_0=52.1561605555556 +lon_0=5.38763888888889 +k=0.9999079 +x_0=155000 +y_0=463000 +datum=WGS84 +units=m +no_defs
# First 10 features:
#   level                         result
# 1  326.849822998047 LINESTRING (179619.3 329739...
# 2  326.849822998047 LINESTRING (179580 329720.4...
# 3  326.849822998047 LINESTRING (179540 329720, ...
# 4  326.849822998047 LINESTRING (179500 329735.8...
# 5  326.849822998047 LINESTRING (179495.3 329740...
# 6  326.849822998047 LINESTRING (179460 329764, ...
# 7  326.849822998047 LINESTRING (179442.6 329780...
# 8  326.849822998047 LINESTRING (179420 329810, ...
# 9  326.849822998047 LINESTRING (179410.2 329820...
# 10 326.849822998047 LINESTRING (179380 329847.3...

然后,当我们过滤以仅保留与站点相交的线(缓冲区宽度为 100)时,仅返回预期轮廓线的一小部分(线的红色部分,我假设反射 100 缓冲区宽度)。

contours_sf %>%
  nngeo::st_segments() %>%
  filter(
    # this syntax used as recommended by this answer https://stackoverflow.com/a/57025700/13478749
    st_intersects(., site_sf %>% st_buffer(100), sparse = FALSE)
  ) %>%

  ggplot()+
  geom_sf(colour = 'red', size = 3)+
  geom_sf(data = contours_sf)+
  geom_sf(data = site_sf, colour = 'cyan')+
  geom_sf(data = site_sf %>% st_buffer(100), colour = 'cyan', fill = NA)

任何人都对以下几点有想法:

  1. 解释为什么等高线“断”
  2. 提供一种将碎片“连接”在一起的有效方法
  3. nngeo::st_segments() 的替代品,如果这实际上是 394 行而不是 ~15 行的来源

【问题讨论】:

    标签: r raster sf r-raster


    【解决方案1】:

    将 MULTILINESTRING 转换为 LINESTRING 似乎可以满足您的需要:

    contours_sf %>% st_cast("LINESTRING") %>% 
      filter(st_intersects(., st_buffer(site_sf, 100), sparse=FALSE)[,1]) %>%
    
    ggplot()+
      geom_sf(data = contours_sf)+
      geom_sf(data = site_sf, color = 'red') +
      geom_sf(color = 'pink') 
    

    【讨论】:

      【解决方案2】:

      如果你从分解线条开始,也许效果会更好

      library(raster)
      f <- system.file("external/test.grd", package="raster")
      r <- raster(f)
      x <- rasterToContour(r)
      x <- disaggregate(x)
      

      terra

      library(terra)
      r <- rast(f)
      x <- as.contour(r)
      
      x
      # class       : SpatVector 
      # geometry    : lines 
      # dimensions  : 8, 1  (geometries, attributes)
      
      x <- disaggregate(x)
      x
      # class       : SpatVector 
      # geometry    : lines 
      # dimensions  : 56, 1  (geometries, attributes)
      

      你可以这样继续

      y <- st_as_sf(x)
      

      或者像这样

      r <- rast(system.file("ex/meuse.tif", package="terra"))
      site <- vect(xyFromCell(r, 5000), crs=crs(r))
      elevation <- extract(r, site)
      v <- disaggregate(as.contour(r, levels=elevation))
      i <- which.min(distance(site, v))
      vv <- v[i]
      
      plot(r)
      lines(v)
      lines(vv, col="red", lwd=2)
      points(site, col="blue", cex=2)
      

      【讨论】:

      • 谢谢@Robert,这两个选项都很好用
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-05-21
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 2012-01-03
      • 1970-01-01
      相关资源
      最近更新 更多