在之前「使用 ggplot2 绘制地图——以中国地图为例」课程的基础上,我们今天再来学习下如何使用 Python 的 matplotlib 把邻国的区域也添加到中国地图上:
| 小地图版本 | 长版 |
|---|---|
使用 reticulate 创建与管理 Python 虚拟环境
在 R 中通过 reticulate 包来调用 Python,最好的实践是为项目创建一个专属的 Python 虚拟环境,将所需依赖隔离到独立空间,避免与系统 Python(如 Anaconda)发生版本冲突。
重要说明(避免”已初始化”报错):reticulate 在 R 会话中只能绑定一次 Python——一旦某个
{python}代码块运行,Python 解释器就被锁定,之后再调用use_virtualenv()会报错:ERROR: The requested version of Python cannot be used, as another version has already been initialized.
因此,虚拟环境的激活必须在所有
{python}代码块之前完成。本文档的解决方案是在setupchunk 中通过Sys.setenv(RETICULATE_PYTHON = ...)提前锁定 Python 路径,这是 reticulate 选取 Python 的最高优先级入口。
安装 reticulate(仅首次)
options(repos = c(CRAN = "https://mirrors.tuna.tsinghua.edu.cn/CRAN/")) |
虚拟环境初始化原理(已在 setup chunk 中完成)
本文档的 setup chunk(隐藏运行)包含如下逻辑:
library(reticulate) |
这样做的关键在于:knitr 在处理第一个 {python} chunk 时,reticulate 已经通过 RETICULATE_PYTHON 环境变量知道要使用 .venv,不会再去碰 Anaconda。
在虚拟环境中安装 Python 包(仅首次)
py_pkgs <- c( |
验证激活状态
py_config() |
查看已安装的包
pkgs <- py_list_packages(".venv") |
虚拟环境管理常用命令
virtualenv_list() |
小地图版本
1. 在地图上添加散点
首先加载所需 Python 包,设置字体和坐标系:
import geopandas as gpd |
然后读取地图数据和散点数据:
# 绘图区域(预设好的 bbox) |
在之前课程的基础上,我们还需要读取一份邻国地图数据:
# 邻国地图 |
读取企业散点数据,并将经纬度坐标转换为投影坐标:
# 读取瞪羚、独角兽、创新型企业经纬度数据 |
接下来处理小地图框格内的散点——先提取小地图范围内的点,然后将其缩放并平移到小地图框格的位置:
# 小地图范围 |
设置省份颜色表(对应 R 中 ggsci::default_igv)和线条样式:
# 省份颜色表(32 色,对应 ggsci::default_igv) |
然后就可以绘制散点地图了:
# 定义比例尺和指北针辅助函数 |
此处代码需下载讲义材料查看~
![]()
2. 填充地图
下面我们再演示下填充地图的绘制。
首先统计每个城市的公司数量,并与地图数据合并:
citydf = pointdf.groupby(["市", "市代码"]).size().reset_index(name="n") |
然后绘制连续填充地图:
n = n + 1 是为了对数化之后 0 变成 -Inf,在图上会反映为缺失值。
此处代码需下载讲义材料查看~
![]()
也可以使用分段填色:
# 计算分位数断点 |
![]()
长版地图
长版地图的绘制更简单一些,这里演示省级分段填充地图的绘制。
首先读取长版省级地图、线条和邻国数据:
# 长版绘图区域 |
读取散点数据并汇总统计每个省份的企业数量:
# 读取散点数据 |
按分位数分组:
cutlist_raw = np.quantile(provdf2["n"].values, np.arange(1, 9) / 8) |
然后绘制长版省级填充地图:
# 长版线条样式 |
![]()
关键函数对照表
| R(ggplot2 + sf) | Python(matplotlib + geopandas) | 说明 |
|---|---|---|
st_bbox() %>% st_as_sfc() |
shapely.geometry.box() |
创建矩形区域 |
read_sf() |
gpd.read_file() |
读取 Shapefile |
st_as_sf(coords, crs) |
gpd.points_from_xy() + GeoDataFrame(crs) |
创建点要素 |
st_transform(crs) |
gdf.to_crs(crs) |
坐标系转换 |
st_intersection() |
gdf.geometry.within() |
空间裁剪(点在面内) |
bind_rows() |
pd.concat() |
合并数据框 |
geom_sf() |
gdf.plot() |
绘制地图图层 |
annotation_scale() |
手绘黑白矩形比例尺 | 比例尺 |
annotation_north_arrow() |
ax.annotate(arrowprops) |
指北针 |
scale_fill_scico() |
plt.cm.get_cmap() + mcolors.LogNorm() |
连续色阶 |
scale_fill_scico_d() |
pd.cut() + 逐组绘制 |
分段色阶 |
ggsave() |
plt.savefig() |
保存图片 |
点击这里跳转到 RStata 短书平台获取附件:使用 Python 绘制带邻国地区的中国地图
评论