字符值微调解决ggplot2分组绘图(含linewidth)报错问题
ggplot2线型与线条宽度的诡异报错问题
我使用ggplot2 3.5.1版本(R 4.2.1)编写代码,想要绘制多条包含实线、虚线的线条,每组对应一条线,线条宽度取自数据框的列。运行时触发报错:当linetype非solid时,线条上的linewidth不能变化,但实际上我的每条线条的linewidth都是固定值,不存在单条线内宽度变化的情况。
更诡异的是,仅将部分组名从"ss_1"这类双s开头的名称改为"s_1"这类单s开头的名称,就能完全规避这个报错,且所有测试都是在干净环境下进行的。
补充说明:之前为解决linewidth渲染异常问题(放入aes()后线条宽度显示错误且无法随数据变化),我将linewidth移出了aes(),后来通过scale_linewidth()解决了原问题。但我仍好奇,为什么不当使用linetype时,数据框的字符变化会影响报错的出现,希望了解背后原因或确认是否为bug。
可复现代码
触发报错的情况
首先创建数据集df1:
library(ggplot2) df1 = data.frame(year = c(rep(2020:2021, 2), 2020:2022), groupid = c(rep("ss_1", 2), rep("ss_2", 2), rep("sim", 3)), linewidth = c(rep(0.4, 4), rep(1, 3)), value = 1:7, linetype = c(rep("ss", 4), rep("sim", 3)))
执行以下绘图代码会触发报错:
ggplot() + geom_line(data=df1, aes(x=year,y=value,group=groupid,linetype = linetype), linewidth=df1$linewidth)
无报错的修改后情况
修改组名和linetype列的值得到数据集df2:
df2 = data.frame(year = c(rep(2020:2021, 2), 2020:2022), groupid = c(rep("s_1", 2), rep("s_2", 2), rep("sim", 3)), linewidth = c(rep(0.4, 4), rep(1, 3)), value = 1:7, linetype = c(rep("s", 4), rep("sim", 3)))
执行相同的绘图代码,不会报错:
ggplot() + geom_line(data=df2, aes(x=year,y=value,group=groupid,linetype = linetype), linewidth=df2$linewidth)
原因推测
这大概率是ggplot2处理非标准线型名称+全局linewidth参数时的边缘bug:
- 当你使用"ss"这类非内置线型名称时,ggplot2会自动将其映射为离散型线型,但由于
linewidth是作为全局参数传入(而非绑定到aes的分组),内部逻辑可能误判为单条线内的宽度在变化,从而触发报错。 - 修改为"s"后,可能因为字符串特征的变化,让ggplot2的内部分组映射逻辑产生了不同的处理结果,避免了误判。
正确解决方案
按照ggplot2的标准用法,将linewidth放入aes()内,并配合scale_linewidth()设置宽度范围,即可正常渲染且无报错:
ggplot() + geom_line(data=df2, aes(x=year,y=value,group=groupid,linetype = linetype, linewidth=linewidth)) + scale_linewidth(range=c(0.4,1))
内容的提问来源于stack exchange,提问作者zackelaz
相关产品推荐
相关产品推荐

