R语言循环内绘制多边形出现异常行为是什么原因?
R语言循环叠加绘制多边形失效问题解决
问题场景
- 目标:在单张多边形底图上,通过循环批量叠加绘制多个多边形图层
- 网传经验称循环内必须用
print()包裹绘图语句才能实现图层叠加,但实际运行效果和该说法存在偏差:- 简单测试场景下:用
print()包裹plot语句时,控制台会输出大量NULL提示,但可以完成绘图;去掉print()也能正常出图 - 复杂业务场景下:逐行运行循环内的代码可以正常绘制所有图形,但将代码放入循环结构后始终无法出图,该异常在搭载macOS Monterey系统的Mac设备上可复现
- 简单测试场景下:用
- 问题复现参考代码:
require(maptools) data(wrld_simpl) plot(wrld_simpl) for (i in 1:12){ region=wrld_simpl[wrld_simpl$NAME==wrld_simpl$NAME[i],] print(plot(region,border="red",add=T)) }
核心原因
- 「循环内必须加print才能绘图」的经验,仅适用于
ggplot2等基于grid图形系统的绘图包:这类包的绘图函数不会直接渲染图形,只会返回一个图形对象,在循环、自定义函数这类非顶层运行环境中,不会自动触发渲染,必须显式调用print()输出图形对象才能完成绘制。 - 示例中
maptools配套的plot方法属于R基础绘图体系,调用时会直接向当前激活的绘图设备输出内容,不需要额外调用print()。套print()时输出的大量NULL,就是基础plot函数的返回值(基础plot不返回图形对象,执行完仅返回空值),属于完全多余的操作。 - 复杂场景下循环绘图失效,通常是三类原因导致:
- 循环内的plot语句漏加
add = TRUE参数,每次调用plot都会新建空白画布覆盖之前的内容,看起来和没绘图一样 - 循环内的其他代码存在副作用,误触发了绘图设备重置、关闭,比如误运行
dev.off()、其他扩展包的函数自动清空了画布 - macOS系统默认Quartz绘图设备存在缓冲机制,部分旧版本R环境下循环内的绘图内容会暂存在缓冲区,不会实时刷新到画布上
- 循环内的plot语句漏加
修正方案
基础绘图体系下循环叠加多边形不需要加print(),确保参数正确即可,遇到macOS设备不刷新的情况手动强制刷新设备:
require(maptools) data(wrld_simpl) # 先绘制基础底图 plot(wrld_simpl) for (i in 1:12){ region <- wrld_simpl[wrld_simpl$NAME == wrld_simpl$NAME[i],] # 叠加图层必须加add=TRUE,不需要套print plot(region, border = "red", add = TRUE) } # macOS遇到绘图不显示时运行,强制刷新绘图缓冲区 dev.flush()
额外注意事项
- 如果后续改用
ggplot2、tmap等返回图形对象的包做循环绘图,才需要用print()包裹绘图对象 - 目前
maptools包已经从CRAN退役,长期使用建议迁移到sf生态处理空间数据,绘图兼容性和稳定性更好 - 循环绘图前确认当前激活的是目标绘图设备,不要在循环内执行新建、关闭绘图设备的操作
内容的提问来源于stack exchange,提问作者Agus camacho
相关产品推荐
相关产品推荐

