玩转数据可视化之R语言ggplot2:(八)ggplot2绘制空间地理数据图

玩转数据可视化之R语言ggplot2


  • 🌸个人主页:JoJo的数据分析历险记
  • 📝个人介绍:小编大四统计在读,目前保研到统计学top3高校继续攻读统计研究生
  • 💌如果文章对你有帮助,欢迎关注、点赞、收藏、订阅专栏

本系列主要介绍R语言ggplot2的使用
参考资料:
ggplot2: Elegant Graphics for Data Analysis

🌲8.ggplot2绘制空间地理数据图

绘制地理数据图在我们研究一些空间统计问题时很有效。例如绘制一张全国疫情情况热力图。现在用的比较多的是Arcgis软件绘制地理数据图,也可以使用python,python数据可视化未来我也会写相应的专栏。如果有精力的话,考虑再出一个Arcgis的专栏绘制空间地理数据图。言归正传,在ggplot2中,绘制空间地理数据图主要分为两个步骤:

  • 第一个是使用相应地理数据先绘制地图
  • 第二个是使用其他相关的数据在地图上添加信息
    接下来我们来看看具体是如何实现这两个步骤的
# 导入基本库
library(ggplot2)
library(tidyverse)# 数据操作处理库,具体可以看我的R语言数据分析专栏

🌳8.1 使用多边形geom_polygon()绘制地图

在R中,绘制地图最简单的方法就是通过geom_polygon()绘制不同区域的边界。我们使用ggplot2中map_data()里的数据
我们在这里以美国密歇根州数据为例进行地图绘制,首先我们来看一下这个数据

mi_county <- map_data('county','michigan')#筛选出密西根州的地理数据
head(mi_county)
A data.frame: 6 × 6
longlatgrouporderregionsubregion
<dbl><dbl><dbl><int><chr><chr>
1-83.8867544.8568611michiganalcona
2-83.3653644.8683212michiganalcona
3-83.3653644.8683213michiganalcona
4-83.3309844.8396814michiganalcona
5-83.3080644.8053015michiganalcona
6-83.3023344.7766516michiganalcona

可以看出上述数据包含六列,long和lat分别表示经纬度,group表示子区域的分组,subregion表示所在的子区域名称

# 将subregion修改名为id
colnames(mi_county)[6] <- 'id'#修改列名

下面我们使用geom_point和geom_polygon()来更仔细的观察一下这个数据集

ggplot(mi_county, aes(long, lat)) + 
  geom_point(size = .25, show.legend = FALSE) +
  coord_quickmap()

ggplot(mi_county, aes(long, lat, group = group)) +
  geom_polygon(fill='white',col='grey50')+
  coord_quickmap()

png

png

geom_point()和geom_polygon()在我们之前的内容中都介绍过,但是这里要注意的是,
在我们画多边形图的时候,要注意定义分组变量,否则多边形的连接会出现交叉混乱,这个很好理解。
还有我们在两个图中都使用了coord_quickmap()这是确保他们的经纬度一致。
虽然我们可以使用上述方法绘制地图,但是这个方法有一些局限性就是我们现实世界中,很少有这样的数据,比较多的往往是矢量数据。下面我们介绍如何使用矢量数据进行绘图

🌴8.2 sf包绘制地图

为了处理矢量地理数据,我们之前使用sp包进行分析,但是sp包的兼容性较差,因此我们现在使用sf包来绘制地图,
主要有geom_sf()和coord_sf()函数来配合sf包一起使用。
接下来我们使用ozmap包里面的矢量数据来介绍sf是如何工作的。

# 导入库
library(ozmaps)
library(sf)
oz_states <- ozmap_states
oz_states
Warning message:
"package 'ozmaps' was built under R version 4.1.3"
Warning message:
"package 'sf' was built under R version 4.0.5"
Linking to GEOS 3.9.1, GDAL 3.2.1, PROJ 7.2.1

Registered S3 method overwritten by 'geojsonsf':
  method        from   
  print.geojson geojson

A sf: 9 × 2
NAMEgeometry
<chr><MULTIPOLYGON [arc_degree]>
1New South Wales MULTIPOLYGON (((150.7016 -3...
2Victoria MULTIPOLYGON (((146.6196 -3...
3Queensland MULTIPOLYGON (((148.8473 -2...
4South Australia MULTIPOLYGON (((137.3481 -3...
5Western Australia MULTIPOLYGON (((126.3868 -1...
6Tasmania MULTIPOLYGON (((147.8397 -4...
7Northern Territory MULTIPOLYGON (((136.3669 -1...
8Australian Capital TerritoryMULTIPOLYGON (((149.2317 -3...
9Other Territories MULTIPOLYGON (((167.9333 -2...

ozmaps包包含了澳大利亚各州边界、地方政府区域、选举边界等数据。
上述得到了澳大利亚领土边界

这个输出显示了与数据相关的,并告诉我们数据本质上是一个包含9行2列的TIBLE。
sf数据的一个优势是显而易见的,我们可以很容易地看到数据的整体结构:澳大利亚由六个州和一些地区组成。有9个不同的地理单元,所以这个TIBLE中有9行。

最重要的列是geometry,表示每个州或地区的空间几何对象。其中每一个元素都是一个多元的多边形。从字面意思来看,这个元素包含了多边形多个顶点,对于这种数据,我们可以使用geom_sf()和coord_sf()直接绘制,甚至我们都不需要指定特定的美学特征aes(),具体如下:

ggplot(oz_states) + 
geom_sf()+
coord_sf()

png

为了理解为什么这样是work的,我们来解释一下geom_sf()

  • 1.对于上面这个数据集,我们不指定任何的aes,因为geom_sf()会自动去匹配geometry
  • 2.如果数据是一个sf对象,geom_sf()会自动判断一个geometry列,即使列名不是geometry
  • 3.我们也可以自己设置aes(geomtry = my_column),当数据有很多geometry对象时

🖊️8.2.1 对地图分层

在某些情况下,我们可能希望将一张地图覆盖在另一张地图上。
ggplot2软件包支持允许将多个geom_sf()层添加到图形。
我将使用oz_state数据以不同的颜色绘制澳大利亚各个州,并将此图与澳大利亚选举区域的边界重叠。
为了节省绘图时间,这里使用rmapshaper::ms_simply包来简化原始数据。下面来看一下具体如何实现

# 选举边界
oz_votes <- rmapshaper::ms_simplify(abs_ced)
ggplot() + 
  #绘制州边界
  geom_sf(data = oz_states, aes(fill = NAME), show.legend = FALSE) +
  #绘制选举区域边界
  geom_sf(data = oz_votes, fill = NA) + 
  coord_sf()
Registered S3 method overwritten by 'geojsonlint':
  method         from 
  print.location dplyr

png

我们使用fill来填充颜色,本例数据我们使用的是name的分类型变量,它并没有传递任何其他的信息,但是这种方法可以为我们提高一个信息就是我们可以使用fill来区分不同区域某一变量的情况,例如假设oz_state有人口这一数据,我们可以以人口来fill

🖌️8.2.2 对地图添加标签

上一章我们介绍了如何给图形添加注释,这一章我们来看一下如何给地图添加标签。我们可以使用geom_sf_label()
和geom_sf_text(),例如我们想要对悉尼地区个选举地域增加标签。我们可以使用geom_sf_label()显示各个选民区域的名字

# 筛选出悉尼大都会的选民区域
sydney_map <- ozmaps::abs_ced %>% filter(NAME %in% c(
  "Sydney", "Wentworth", "Warringah", "Kingsford Smith", "Grayndler", "Lowe", 
  "North Sydney", "Barton", "Bradfield", "Banks", "Blaxland", "Reid", 
  "Watson", "Fowler", "Werriwa", "Prospect", "Parramatta", "Bennelong", 
  "Mackellar", "Greenway", "Mitchell", "Chifley", "McMahon"
))

# 绘制悉尼大都会选民区域图,并增加标签
ggplot(sydney_map) + 
  geom_sf(aes(fill = NAME), show.legend = FALSE) + 
  coord_sf(xlim = c(150.97, 151.3), ylim = c(-33.98, -33.79)) + 
  geom_sf_label(aes(label = NAME), label.padding = unit(1, "mm"))

Warning message in st_point_on_surface.sfc(sf::st_zm(x)):
"st_point_on_surface may not give correct results for longitude/latitude data"

png

🖍️8.2.3 在地图上绘制其他图形

虽然geom_sf()是一种特殊的绘图,但是和其他几何图形一样,允许通过层级的方法添加其他元素。
相当于geom_sf()后依然是一个geoms标准对象,我们可以做所有之前的处理。例如我们想要在某些地方标记点

oz_capitals <- tibble::tribble( 
  ~city,           ~lat,     ~lon,
  "Sydney",    -33.8688, 151.2093,  
  "Melbourne", -37.8136, 144.9631, 
  "Brisbane",  -27.4698, 153.0251, 
  "Adelaide",  -34.9285, 138.6007, 
  "Perth",     -31.9505, 115.8605, 
  "Hobart",    -42.8821, 147.3272, 
  "Canberra",  -35.2809, 149.1300, 
  "Darwin",    -12.4634, 130.8456, 
)

ggplot() + 
  geom_sf(data = oz_votes) + 
  geom_sf(data = oz_states, fill = NA) + 
  geom_point(data = oz_capitals, aes(x = lon, y = lat), colour = "red") + 
  coord_sf()

png

🌵8.3 地图投影

在上面的地图绘制中,我们默认的选择了笛卡尔平面,粗略来看,这是可以的,但如果我们关心准确性,这还不够好。这种方法有两个基本问题。

  • 地球的形状

关于地球形状的一系列假设被称为大地基准面,虽然这对某些数据可视化可能并不重要,但对其他数据可视化来说则至关重要。
例如如果我们要研究北美区域,使用(NAD83),如果要研究全球区域,使用(WGS84)可能较好

  • 地图的形状

地球是近似椭球的,但在大多数情况下,我们的空间地理数据需要绘制在二维平面上。要将椭球体的表面映射到一个平面,我们需要进行一些变形,这就是地图投影的工作。

总的来说,大地基准面(如WGS84)、地图投影类型和投影参数(如原点位置)指定了一个坐标参考系(CRS),这是一套完整的假设,用于将纬度和经度信息转换为二维地图。sf对象通常包括一个默认的CRS,我们可以使用st_crs()来访问

st_crs(oz_votes)
Coordinate Reference System:
  User input: EPSG:4283 
  wkt:
GEOGCRS["GDA94",
    DATUM["Geocentric Datum of Australia 1994",
        ELLIPSOID["GRS 1980",6378137,298.257222101,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["geodetic latitude (Lat)",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["geodetic longitude (Lon)",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
        SCOPE["Horizontal component of 3D system."],
        AREA["Australia including Lord Howe Island, Macquarie Islands, Ashmore and Cartier Islands, Christmas Island, Cocos (Keeling) Islands, Norfolk Island. All onshore and offshore."],
        BBOX[-60.56,93.41,-8.47,173.35]],
    ID["EPSG",4283]]

上面返回了一个WKT字符串,可以看出oz_states默认的crs是4283,我们直接通过看EPSG代码来却数据的crs

st_crs(oz_votes) == st_crs(4283)

TRUE

在ggplot2中,CRS由coord_sf()控制,以确保绘图中的每一层使用相同的投影。默认情况下,coord_sf()使用与数据的geometry列关联的CRS。因为sf数据会自动提供一个合理的CRS选择,这个过程通常是不可见的,不需要用户干预。但是,如果需要自己设置CRS,可以通过将有效的用户输入传递给st_CRS()来指定CRS参数。下面的示例说明了如何从默认的CRS切换到EPSG代码3112

ggplot(oz_votes) + geom_sf()
ggplot(oz_votes) + geom_sf() + coord_sf(crs = st_crs(3112))

png

png

🌾8.4 导入shp文件分析

一般我们在实际分析时,要根据实际问题得到相应的shp矢量文件,在sf中,可以使用read_sf()读取文件。这里我以海南省十八个市县的地理边界数据为例导入

hainan <- read_sf("C:\\Users\\DELL\\Desktop\\数据\\十八个市县.shp")
hainan
A sf: 18 × 7
省代码市代码市类型省类型geometry
<chr><dbl><chr><dbl><chr><chr><MULTIPOLYGON [arc_degree]>
海南省460000白沙县 469025省直辖县MULTIPOLYGON (((109.2941 18...
海南省460000保亭县 469029省直辖县MULTIPOLYGON (((109.5084 18...
海南省460000昌江县 469026省直辖县MULTIPOLYGON (((109.0407 19...
海南省460000澄迈县 469023省直辖县MULTIPOLYGON (((110.1328 19...
海南省460000儋州市 460400地级市 MULTIPOLYGON (((109.4279 19...
海南省460000定安县 469021省直辖县MULTIPOLYGON (((110.2206 19...
海南省460000东方市 469007省直辖县MULTIPOLYGON (((109.121 18....
海南省460000海口市 460100地级市 MULTIPOLYGON (((110.5089 20...
海南省460000乐东县 469027省直辖县MULTIPOLYGON (((109.4009 18...
海南省460000临高县 469024省直辖县MULTIPOLYGON (((109.851 19....
海南省460000陵水县 469028省直辖县MULTIPOLYGON (((110.0107 18...
海南省460000琼海市 469002省直辖县MULTIPOLYGON (((110.6064 19...
海南省460000琼中县 469030省直辖县MULTIPOLYGON (((109.8724 19...
海南省460000三亚市 460200地级市 MULTIPOLYGON (((109.4009 18...
海南省460000屯昌县 469022省直辖县MULTIPOLYGON (((110.1109 19...
海南省460000万宁市 469006省直辖县MULTIPOLYGON (((110.1542 19...
海南省460000文昌市 469005省直辖县MULTIPOLYGON (((111.2004 19...
海南省460000五指山市469001省直辖县MULTIPOLYGON (((109.7113 18...

我们可以在这个数据基础进行相应的操作,后续考虑出一些使用矢量数据实战分析的文章,下面我们先简单看一下该地理数据的地图

ggplot(hainan)+
geom_sf(aes(fill=市),show.legend = FALSE)+
coord_sf()

png

💟文章推荐

如果想了解更多ggplot2数据可视化技巧,欢迎访问下列文章
🌝玩转数据可视化之R语言ggplot2:(三)ggplot2实现将多张图放在一起,包括并排和插图绘制(快速入门)
🌜玩转数据可视化之R语言ggplot2::(四)单一基础几何图形绘制
🌟玩转数据可视化之R语言ggplot2:(五)分组画图
☀️玩转数据可视化之R语言ggplot2:(六)统计变换绘图:包括加权绘图、数据分布图、曲面图、图形重叠处理等
玩转数据可视化之R语言ggplot2:(七)对图形添加注释和标签(包含标题、坐标轴、参考线和高亮等注释方法)

posted @ 2022-08-27 11:08  JOJO数据科学  阅读(1746)  评论(0编辑  收藏  举报