R Leaflet addAwesomeMarkers如何按字符型列值条件设置标记颜色
问题背景
使用leaflet包的addAwesomeMarkers功能时,需要根据数据集指定列的取值动态调整地图标记的显示颜色:
- 基于内置
quakes数据集测试,若通过mutate生成的判断列为数值型,可正常实现颜色区分,测试代码如下:
data(quakes) quakes <- quakes %>% mutate( type = ifelse(stations > 60, 1,2) ) getColor <- function(quakes) { sapply(quakes$type, function(type) { if(type == 1) { "green" } else { "red" } }) } icons <- awesomeIcons( icon = 'ios-close', iconColor = 'black', library = 'ion', markerColor = getColor(quakes[1:20, ]) ) leaflet(quakes[1:20, ]) %>% addTiles() %>% addAwesomeMarkers(~long, ~lat, icon=icons, label=~as.character(mag))
上述代码运行后可正常实现符合条件的绿、红标记颜色区分。
- 当
mutate生成的type列为字符型取值(stations>60时赋值"foo",否则赋值"bar")时,所有标记都被统一设置为else分支的红色,无法正常区分颜色,测试代码如下:
quakes <- quakes %>% mutate( type = ifelse(stations > 60, "foo","bar") ) getColor <- function(quakes) { sapply(quakes$type, function(type) { if(type == "foo") { "green" } else { "red" } }) } icons <- awesomeIcons( icon = 'ios-close', iconColor = 'black', library = 'ion', markerColor = getColor(quakes[1:20, ]) )
运行时控制台同时输出警告:
Input to asJSON(keep_vec_names=TRUE) is a named vector. In a future version of jsonlite, this option will not be supported, and named vectors will be translated into arrays instead of objects. If you want JSON object output, please use a named list instead. See ?toJSON.
故障原因
问题出在sapply的返回值上:对字符型列做sapply遍历判断时,返回的结果是带原列值作为names属性的字符向量,awesomeIcons在接收markerColor参数时,带名向量会被jsonlite序列化为对象而非数组,导致颜色映射规则解析失败,所有标记回退到默认分支的红色。
数值型场景下未触发问题属于偶然情况,本质是数值型names的序列化结果没有完全打断参数解析,并非写法本身没有隐患。
解决方法
两种方案均可实现基于字符型列值的动态颜色设置,第二种更符合leaflet的设计逻辑,出错概率更低:
- 保留原有写法,仅需在
getColor返回结果时去掉向量的names属性即可
getColor <- function(quakes) { res <- sapply(quakes$type, function(type) { if(type == "foo") { "green" } else { "red" } }) unname(res) # 核心:移除向量的names属性,保证序列化结果为颜色值数组 }
- (推荐)不提前生成静态icons对象,直接在
addAwesomeMarkers中用公式接口动态映射颜色,自动适配数据行数,也不会出现带名向量的序列化问题
library(leaflet) library(dplyr) data(quakes) quakes <- quakes %>% mutate(type = ifelse(stations > 60, "foo", "bar")) leaflet(quakes[1:20, ]) %>% addTiles() %>% addAwesomeMarkers( ~long, ~lat, icon = ~awesomeIcons( icon = 'ios-close', iconColor = 'black', library = 'ion', markerColor = ifelse(type == "foo", "green", "red") ), label = ~as.character(mag) )
内容的提问来源于stack exchange,提问作者r0bt
相关产品推荐
相关产品推荐

