这期涉及空间图表绘制,主要涉及知识点如下:
- ggplot2 sf 中国标准地图绘制
- cowplot 包实现地图子图插入
ggplot2 sf 中国标准地图绘制
本期的绘图我们是按照如下图表进行绘制的(该图来自朋友公号):
其实我很早就想试着用R进行此类图表的绘制了,但由于强大的Arcgis和绘图进度等原因,导致迟迟没有进行,这期就进行此类图表的绘制。注:图中散点的经纬度信息已从朋友那获知,但涉及具体数据则是虚构的。
地图读取和散点标注
这里的中国地图格式为 geojson 格式,还是使用sf包进行灵活读取,具体代码如下:
代码语言:javascript复制china_shp <- "中国省级地图GS(2019)1719号.geojson"
nine <- "九段线GS(2019)1719号.geojson"
china <- sf::read_sf(china_shp)
nine_line <- sf::read_sf(nine)
数据预览如下(部分):
接下来我们进行探索性绘图,主要使用geom_sf() 进行绘制,代码如下:
代码语言:javascript复制library(ggspatial)
ggplot()
geom_sf(data = china,fill="NA",size=1,color="black")
geom_sf(data = nine_line)
coord_sf(crs = " proj=laea lat_0=40 lon_0=104")
annotation_scale(location = "bl")
# spatial-aware automagic north arrow
annotation_north_arrow(location = "tl", which_north = "false",
style = north_arrow_fancy_orienteering)
这里可以看到,我们没有使用常规的WGS84坐标,而是采用 proj=laea lat_0=40 lon_0=104 进行绘制,可视化结果如下:
比例尺和指北针的添加,则是依靠ggspatial包。
散点数据的读取
由于只获得数据经纬度信息,其他数据均为虚构,数据预览如下:
这里注意点,要想使数据绘制在地图上,我们需使用st_as_sf()对其进行转换,处理:
代码语言:javascript复制scatter_df_tro <- st_as_sf(scatter_df,coords = c("lon", "lat"),crs = 4326)
结果如下:
注意红色框中的内容
接下来将数据在地图中显示,具体代码如下:
代码语言:javascript复制ggplot()
geom_sf(data = china,fill="NA",size=.5,color="black")
geom_sf(data = nine_line)
geom_sf(data = scatter_df_tro,aes(fill=class,size=data),shape=21,colour='black',stroke=.25)
coord_sf(crs = " proj=laea lat_0=40 lon_0=104")
scale_fill_manual(values = c("#E21C21","#3A7CB5","#51AE4F"))
scale_size(range = c(1,5))
annotation_scale(location = "bl")
# spatial-aware automagic north arrow
annotation_north_arrow(location = "tl", which_north = "false",
style = north_arrow_fancy_orienteering)
theme_linedraw()
theme(text = element_text(family = 'Times_New_Roman',size = 12,face = "bold"),
panel.background = element_rect(fill = NA),
panel.grid.major = element_line(colour = "grey50"),
#axis.line = element_line(size = 1, colour = "black"),
panel.ontop = FALSE
)
可视化结果如下:
这里还存在如下问题:
(1) 尽量将南海部分放置在右下角(虽然这样也可以)
(2) 图例只是默认的,没有进行定制化操作,影响美观
cowplot包子图添加
cowplot包可是实现对绘图结果的任意组合,很适合绘制地图子图的绘制,这里直接给出绘图代码,如下:
代码语言:javascript复制library(cowplot)
map <- ggplot()
geom_sf(data = china,fill=NA)
geom_sf(data = nine_line,color='gray50',size=.8)
geom_sf(data = scatter_df_tro,aes(fill=class,size=data),shape=21)
coord_sf(ylim = c(-2387082,1654989),crs=" proj=laea lat_0=40 lon_0=104")
scale_fill_manual(values = c("#E21C21","#3A7CB5","#51AE4F"))
scale_size(range = c(1,5))
annotation_scale(location = "bl",text_face = "bold",
text_family = "Times_New_Roman")
# spatial-aware automagic north arrow
annotation_north_arrow(location = "tl", which_north = "false",
style = north_arrow_fancy_orienteering,
)
#定制化图例:这一步可以设计出亮眼的图例哦
guides(fill = guide_legend(override.aes = list(size = 3),
title = "",
label.position = "right",
ncol=3,
),
size = guide_legend(
title = "",
label.position = "right",
ncol=5))
labs(
caption = 'Visualization by DataCharm')
#theme_bw()
theme(
text = element_text(family = 'Times_New_Roman',size = 18,face = "bold"),
panel.background = element_rect(fill = NA),
panel.grid.major = element_line(colour = "grey80",size=.2),
legend.key = element_rect(fill = "white"),
legend.position = "bottom",
)
nine_map <- ggplot()
geom_sf(data = china,fill='NA')
geom_sf(data = nine_line,color='gray70',size=1.)
#geom_sf(data = scatter_df_tro,aes(fill=class,size=data),shape=21,colour='black',stroke=.25)
coord_sf(ylim = c(-4028017,-1877844),xlim = c(117131.4,2115095),crs=" proj=laea lat_0=40 lon_0=104")
theme(
#aspect.ratio = 1.25, #调节长宽比
axis.text = element_blank(),
axis.ticks = element_blank(),
axis.title = element_blank(),
panel.grid = element_blank(),
panel.background = element_blank(),
panel.border = element_rect(fill=NA,color="grey10",linetype=1,size=1.),
plot.margin=unit(c(0,0,0,0),"mm"))
gg_inset_map = ggdraw()
draw_plot(map)
draw_plot(nine_map, x = 0.8, y = 0.15, width = 0.1, height = 0.3)
可视化效果如下:
这里需注意的是xlim和ylim的设置,具体值都是在 proj=laea lat_0=40 lon_0=104 投影坐标系下的值,而常规坐标转不同坐标下的操作也很简单,可使用st_transform进行操作。如下:
代码语言:javascript复制df2 <- tibble(lon = c(105,125),
lat = c(3,25),
)
df2 %>%
st_as_sf(coords = c("lon", "lat"), crs = 4326) -> df2_sf
df2_sf_pre <- sf::st_transform(df2_sf,crs=" proj=laea lat_0=40 lon_0=104")
df2_sf_pre
即可获取对应值,进而进行范围设置。
总结
该期推文也是基于自己对地图的喜欢进行绘制,后面还是会以基础图表的绘制为主,希望大家能够喜欢,多多支持。更多想法可以在留言区进行留言告知。