查看: 618|回复: 0

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区

[复制链接]
发表于 2024-4-18 11:17:27 | 显示全部楼层 |阅读模式


专注系列化、高质量的R语言教程

推文索引 | 联系小编 | 咨询服务


本系列介绍osmextract工具包,该工具包可以用来下载和导入OpenStreetMap数据。与osmdata工具包相比,它可以下载大尺寸的数据。

本篇目录如下:

    1 oe_providers函数

    2 提供商数据库

    3 分区

      3.1 第一层次分区

      3.2 第二层次分区

      3.3 第三层次分区

      3.4 第四层次分区

      3.5 geofabrik_zones

      3.6 bbbike_zones


本篇会涉及到矢量数据的处理,因此除了加载osmextract工具包外,还需加载sf工具包:
library(osmextract)
library(sf)
1 oe_providers函数

osmextract工具包并不是直接从OpenStreetMap(OSM)下载数据的,而是从其他网站(称为provider,提供商)那里下载OSM的数据摘录(data extract)。

使用oe_providers()函数可以查看当前可用的数据提供商:
oe_providers()
##   available_providers          database_name number_of_zones number_of_fields
## 1           geofabrik        geofabrik_zones             475                8
## 2              bbbike           bbbike_zones             236                5
## 3    openstreetmap_fr openstreetmap_fr_zones            1135                6

可以看到,默认情况下有三个数据提供商可用。它们的名称和地址分别如下:
    geofabrik:https://download.geofabrik.de/bbbike:https://download.bbbike.org/osm/openstreetmap_fr:http://download.openstreetmap.fr/
2 提供商数据库

以上输出内容还列举了各个提供商的其他信息。第二列database_name是对应数据库的名称,第三列number_of_zones(分区数目)是数据库的行数,第四列number_of_fields(字段数据)是数据库属性数据的列数。

使用data()函数可以加载这些数据库:
data("geofabrik_zones")
data("bbbike_zones")
data("openstreetmap_fr_zones")

    运行后全局环境中会出现以上数据库。

以openstreetmap_fr_zones为例,先来查看它的数据类型和各字段名称:
class(openstreetmap_fr_zones)
## [1] "sf"         "data.frame"

names(openstreetmap_fr_zones)
## [1] "id"            "name"          "parent"        "level"      
## [5] "pbf"           "pbf_file_size" "geometry"

可以看到,它实际是一个sf格式的矢量文件。它的每一行对应一个分区(zone),各字段含义如下:
    id:分区ID;name:分区名称;parent:包含该分区的上一层区域名称;level:分区层次;pbf:该分区数据摘录的下载网址;pbf_file_size:数据摘录的大小,单位为字节(byte);geometry:sf数据的几何信息。
3 分区

分区(zone)是数据提供商对全球区域的划分,仍以openstreetmap_fr_zones为例,先来查看它的level列:
unique(openstreetmap_fr_zones$level)
## [1] 1 2 3 4

可以看到,它的分区共有4个层次,下面依次进行展示。
3.1 第一层次分区

使用取子集函数subset()筛选出数据框的level字段为1的行:
zone1 <- subset(openstreetmap_fr_zones, level == "1")

使用ggplot2工具包进行绘图:
library(ggplot2)
ggplot(zone1) +
  geom_sf(aes(fill = id)) +
  theme_minimal()

从上图可以看到,该提供商在第一层次共划分了6个分区。通过右侧图例可以大致看出各分区所指代的区域,并且这6个分区并未覆盖全球所有区域。

为了方便观察,在上图基础上再叠加全球陆地边界:
## 全球陆地范围
world <- spData::world
world <- st_transform(world, st_crs(openstreetmap_fr_zones))
world <- st_union(world)

ggplot(zone1) +
  geom_sf(aes(fill = id)) +
  ## alpha = 0可只显示陆地边界
  geom_sf(data = world, alpha = 0.1) +
  theme_minimal()

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-2728
3.2 第二层次分区

使用类似的方法筛选出第二层次的分区并绘图:
zone2 <- subset(openstreetmap_fr_zones, level == "2")

ggplot(zone2) +
  geom_sf(aes(fill = id)) +
  geom_sf(data = world, alpha = 0) +
  theme_minimal() +
  theme(legend.position = "none") +
  lims(x = c(-180, 60))

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-2502

    第二层次的分区数较多,因此省略了图例;第二层次的名为“China”的分区并未包含我国全部领土,因此将x范围(即经度范围)限定在(-180, 60)之间,不显示涉及我国的区域。

如果说第一层次分区是以大洲、大陆为基准,那么第二层次分区则是以全球次级区域、面积较大国家为基准。

需要注意的是,分区范围既包含陆地区域,也包含海洋区域,因此即使一些以国家为基准的分区,边界也不一定与国界线相同,例如:
uk <- subset(openstreetmap_fr_zones, name == "United Kingdom")

ggplot(uk) +
  geom_sf(aes(fill = id)) +
  geom_sf(data = world, alpha = 0) +
  theme_minimal() +
  lims(x = c(-10,3), y = c(48, 62))

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-9631

从覆盖范围上看,第二层次分区比第一层次分区更广,但仍未覆盖全球区域。从集合关系上看,第二层次分区并不是对第一层次分区的内部进行细分,“层次”高低主要是指区域尺度的大小。
3.3 第三层次分区

筛选并绘制第三层次的分区:
zone3 <- subset(openstreetmap_fr_zones, level == "3")

ggplot(zone3) +
  geom_sf(aes(fill = id)) +
  geom_sf(data = world, alpha = 0) +
  theme_minimal() +
  theme(legend.position = "none") +
  lims(x = c(-180, 60))

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-8868

第三层次分区主要以国家和地区的次级区域为基准。对于一些内陆区域,分区边界即是区域边界,例如安徽省:
anhui = subset(openstreetmap_fr_zones, name == "Anhui")

ggplot(anhui) +
  geom_sf(aes(fill = id)) +
  geom_sf(data = world, alpha = 0) +
  theme_minimal() +
  lims(x = c(70, 140), y = c(3, 55))

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-9542

第三层次分区的parent都不为空,通过该字段可以筛选出某个国家在该层次所有的分区:
brazil = subset(openstreetmap_fr_zones, parent == "brazil")

ggplot(brazil) +
  geom_sf(aes(fill = id)) +
  geom_sf(data = world, alpha = 0) +
  theme_minimal() +
  theme(legend.position = "none") +
  lims(x = c(-80, -20), y = c(-45, 10))

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-5543
3.4 第四层次分区

筛选并绘制第四层次的分区:
zone4 <- subset(openstreetmap_fr_zones, level == "4")

ggplot(zone4) +
  geom_sf(aes(fill = id)) +
  geom_sf(data = world, alpha = 0) +
  theme_minimal() +
  theme(legend.position = "none") +
  lims(x = c(-180, 60))

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-1045

    第四层次分区只覆盖全球很少一部分区域,相较于第三层次分区,区域尺度更小。
3.5 geofabrik_zones

再来看看geofabrik_zones的第一层次分区:
zone12 <- subset(geofabrik_zones, level == "1")

ggplot(zone12) +
  geom_sf(aes(fill = id)) +
  geom_sf(data = world, alpha = 0) +
  theme_minimal()

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-5453

    相比于openstreetmap_fr_zones,geofabrik_zones第一层次分区覆盖的范围更广,没有覆盖的区域基本上是海洋。

读者可自行探索geofabrik_zones的其他层次分区。
3.6 bbbike_zones

与其他两个数据提供商不同,bbbike_zones的分区只有一个层次:
unique(bbbike_zones$level)
## [1] 3

绘制地图:
ggplot(bbbike_zones) +
  geom_sf(size = 1.2, col = "red") +
  geom_sf(data = world, alpha = 0) +
  theme_bw()

osmextract | 下载和导入OpenStreetMap数据(一):数据提供商、分区-7973

可以看到,bbbike_zones的分区是很多“点”。通过查看name字段可以知道,这些“点”是指城市。

不过当我们将地图放大到局部区域,就可以发现这些分区并不是“点”,而是矩形区域,大小与城市规模有关:
ggplot(bbbike_zones) +
  geom_sf(aes(fill = id)) +
  geom_sf(data = world, alpha = 0) +
  theme_minimal() +
  theme(legend.position = "none") +
  lims(x = c(-10, 30), y = c(35, 60))

您需要登录后才可以回帖 登录 | 加入联盟

本版积分规则

快速回复 返回顶部 返回列表