在tmap中使用动物剪影图标:解决PNG背景透明与报错问题
在tmap中添加透明背景动物剪影图标的解决方案
问题背景
想在tmap里用动物剪影当图标,但把SVG转成tmap要求的PNG时,要么带白色背景,要么触发a raster array must have exactly 3 or 4 planes报错。测试发现非0透明度背景设置有效,但alpha=0时完全失效。
原始问题代码
可运行但带白色背景的代码
library(tmap) library(sf) library(magick) library(tidyverse) nc <- st_read(system.file("shape/nc.shp", package="sf")) %>% mutate(ICON="SQUIRREL") SQUIRREL <- image_read_svg("https://images.phylopic.org/images/2916f8fe-290a-423b-b6f7-fb975c30d518/vector.svg") image_write(SQUIRREL,"SQUIRREL.png", flatten = T, density = 90 ) SQUIRREL_ICON <- tmap_icons("SQUIRREL.png") tm_shape(nc)+ tm_polygons()+ tm_symbols(shapes = SQUIRREL_ICON, shape="ICON")
尝试透明背景的失败代码
# 尝试设置透明背景(触发报错) SQUIRREL_OUTLINE1 <- SQUIRREL %>% image_background(color=rgb(0, 0, 0, 0), flatten = T) image_write(SQUIRREL_OUTLINE1,"SQUIRREL_OUTLINE1.png", flatten = T, density = 90) SQUIRREL_ICON_OUTLINE1 <- tmap_icons("SQUIRREL_OUTLINE1.png") tm_shape(nc)+ tm_polygons()+ tm_symbols(shapes = SQUIRREL_ICON_OUTLINE1, shape="ICON") # 尝试裁剪空白区域(背景仍存在) SQUIRREL_OUTLINE2 <- SQUIRREL %>% image_trim() image_write(SQUIRREL_OUTLINE2,"SQUIRREL_OUTLINE2.png", flatten = T, density = 90) SQUIRREL_ICON_OUTLINE2 <- tmap_icons("SQUIRREL_OUTLINE2.png") tm_shape(nc)+ tm_polygons()+ tm_symbols(shapes = SQUIRREL_ICON_OUTLINE2, shape="ICON")
透明度测试代码
# 红色不透明背景(有效) SQUIRREL_OUTLINE_RED <- SQUIRREL %>% image_background(color="red", flatten = T) image_write(SQUIRREL_OUTLINE_RED,"SQUIRREL_OUTLINE_RED.png", flatten = T, density = 90) SQUIRREL_ICON_OUTLINE_RED <- tmap_icons("SQUIRREL_OUTLINE_RED.png") tm_shape(nc)+ tm_polygons()+ tm_symbols(shapes = SQUIRREL_ICON_OUTLINE_RED, shape="ICON") # 红色半透明背景(有效) SQUIRREL_OUTLINE_RED_RGB05 <- SQUIRREL %>% image_background(color=rgb(1, 0, 0, 0.5), flatten = T) image_write(SQUIRREL_OUTLINE_RED_RGB05,"SQUIRREL_OUTLINE_RED_RGB05.png", flatten = T, density = 90) SQUIRREL_ICON_OUTLINE_RED_RGB05 <- tmap_icons("SQUIRREL_OUTLINE_RED_RGB05.png") tm_shape(nc)+ tm_polygons()+ tm_symbols(shapes = SQUIRREL_ICON_OUTLINE_RED_RGB05, shape="ICON") # 红色完全透明背景(失效) SQUIRREL_OUTLINE_RED_RGB00 <- SQUIRREL %>% image_background(color=rgb(1, 0, 0, 0), flatten = T) image_write(SQUIRREL_OUTLINE_RED_RGB00,"SQUIRREL_OUTLINE_RED_RGB00.png", flatten = T, density = 90) SQUIRREL_ICON_OUTLINE_RED_RGB00 <- tmap_icons("SQUIRREL_OUTLINE_RED_RGB00.png") tm_shape(nc)+ tm_polygons()+ tm_symbols(shapes = SQUIRREL_ICON_OUTLINE_RED_RGB00, shape="ICON")
解决方法
问题核心是flatten = T参数会移除PNG的alpha通道,导致tmap无法识别透明背景。修改步骤如下:
- 读取SVG时不要提前flatten,保留图层和alpha通道信息
- 导出PNG时去掉
flatten = T,确保导出的是4通道(RGBA)的PNG - 若SVG本身带纯色背景,用
image_transparent将背景色转为透明
修改后的完整代码
library(tmap) library(sf) library(magick) library(tidyverse) nc <- st_read(system.file("shape/nc.shp", package="sf")) %>% mutate(ICON="SQUIRREL") # 读取SVG,不进行flatten操作 SQUIRREL <- image_read_svg("https://images.phylopic.org/images/2916f8fe-290a-423b-b6f7-fb975c30d518/vector.svg") # 若SVG有白色背景,将白色转为透明(可根据实际背景色调整) SQUIRREL_TRANSPARENT <- SQUIRREL %>% image_transparent(color = "white") # 导出PNG,去掉flatten=T,保留alpha通道 image_write(SQUIRREL_TRANSPARENT, "SQUIRREL_TRANSPARENT.png", density = 90) # 读取为tmap图标 SQUIRREL_ICON <- tmap_icons("SQUIRREL_TRANSPARENT.png") # 绘制地图 tm_shape(nc)+ tm_polygons()+ tm_symbols(shapes = SQUIRREL_ICON, shape="ICON")
简化版(SVG本身无背景时)
如果使用的SVG本身没有背景(比如示例中的phylopic剪影),可以直接导出:
SQUIRREL <- image_read_svg("https://images.phylopic.org/images/2916f8fe-290a-423b-b6f7-fb975c30d518/vector.svg") image_write(SQUIRREL, "SQUIRREL_TRANSPARENT.png", density = 90) # 去掉flatten=T
关键说明
flatten=T会合并所有图层并丢弃alpha通道,当背景完全透明时,图像会变成3通道RGB格式,触发tmap的数组维度报错image_transparent用于将指定纯色转为透明,适合处理自带背景的SVG- PNG格式默认支持alpha通道,导出时不加
flatten=T就能让tmap正确识别透明背景
内容的提问来源于stack exchange,提问作者BEVAN
相关产品推荐
相关产品推荐

