如何修复ggplot绘图时出现的‘Error in strwidth’图例显示错误
嗨,你遇到的问题其实是因为ggplot和base R绘图系统完全不兼容导致的,我来帮你拆解解决:
问题根源
你用ggplot()生成图表后,又调用了base R的legend()函数——这俩属于完全独立的绘图框架:ggplot基于grid系统,而legend()是base R绘图的工具,它需要先触发plot.new()(base的绘图初始化)才能工作,但ggplot根本不会触发这个步骤,所以才会报错plot.new has not been called yet。
解决的核心思路是:用ggplot原生的语法来生成图例,绝对不要混用两个系统的函数。
推荐解决方案:ggplot原生图例生成
你之前的代码里,geom_point(colour = meltdf2$colour)是直接把颜色当成固定值传给点,没有让ggplot把颜色识别为一个需要生成图例的美学映射。我们需要调整成映射模式:
步骤1:(可选但推荐)给颜色对应标签
先给你的colour列匹配对应的等级标签(High/Mid/Low),生成一个因子列来控制图例顺序:
# 用dplyr的case_when更清晰,也可以用ifelse嵌套 library(dplyr) meltdf2 <- meltdf2 %>% mutate(score_level = factor( case_when( colour == "red2" ~ "High", colour == "gold" ~ "Mid", colour == "limegreen" ~ "Low" ), levels = c("High", "Mid", "Low") # 指定图例显示顺序 ))
步骤2:修改ggplot代码,映射颜色并指定图例
把颜色映射到刚才的score_level列,然后用scale_colour_manual指定对应颜色,ggplot会自动生成图例:
ggplot(data = meltdf2, aes(x = Month, y = variable, group = variable)) + geom_line(linetype = "dashed", colour = "grey") + geom_point(aes(colour = score_level), size = 3) + # 这里把colour作为美学映射,而非固定值 scale_x_date(date_breaks = "1 month", date_labels = "%b-%y") + scale_colour_manual( values = c("High" = "red2", "Mid" = "gold", "Low" = "limegreen"), # 匹配颜色和标签 name = "Score Level" # 可以自定义图例标题,不需要就设为NULL ) + theme( axis.title.y = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.line.x = element_line(colour = "darkgrey"), panel.background = element_rect(fill = "white"), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), legend.position = "topleft" # 指定图例位置,和你原来的需求一致 )
简化方案:无需新建列
如果不想额外生成score_level列,可以直接用scale_colour_identity把颜色值本身映射成图例,同时指定标签:
ggplot(data = meltdf2, aes(x = Month, y = variable, group = variable)) + geom_line(linetype = "dashed", colour = "grey") + geom_point(aes(colour = colour), size = 3) + scale_x_date(date_breaks = "1 month", date_labels = "%b-%y") + scale_colour_identity( guide = "legend", # 强制生成图例(默认identity scale不生成图例) labels = c("red2" = "High", "gold" = "Mid", "limegreen" = "Low"), breaks = c("red2", "gold", "limegreen"), # 控制图例顺序 name = "Score Level" ) + theme( # 保留你原来的theme设置 axis.title.y = element_blank(), axis.text.y = element_blank(), axis.ticks.y = element_blank(), axis.line.x = element_line(colour = "darkgrey"), panel.background = element_rect(fill = "white"), panel.grid.major = element_blank(), panel.grid.minor = element_blank(), legend.position = "topleft" )
关键提醒
永远不要把ggplot和base R的绘图函数(比如legend()、title()、axis()等)混用,它们的底层逻辑完全不同,必然会导致冲突。所有图表元素都应该用ggplot的语法来调整。
内容的提问来源于stack exchange,提问作者Ant
相关产品推荐
相关产品推荐

