R语言:如何不借助mapply/循环单次调用绘制不同属性多条线条?
函数参数行为差异
polygon()的帮助文档说明:
当绘制多个多边形时,density、angle、col、border和lty参数的值会按常规方式循环使用。
而lines()的帮助文档说明:
当type="h"时,col可以是向量,并会按需循环使用。
由此可知:除非使用type="h"(且仅对col参数有效),否则无法通过单次lines()调用绘制多条具有不同属性的线条。这种限制既不符合polygon()的逻辑,也有违直觉——毕竟lines()是复数形式,polygon()是单数形式,但单次调用polygon()反而能更高效绘制多个多边形。
需求说明
如何在不借助mapply这类函数的情况下,通过单次调用绘制多条具有不同属性的线条?循环绘制大量图形会严重影响性能,且matplot不适用(因为线条的顶点数可能不固定)。曾考虑用col=NA的polygon()仅显示线条,但多边形会自动闭合(这也是R的一个问题:无法绘制开放多边形)。
可以利用segments()函数的参数循环特性实现单次调用绘制多条不同属性的开放线条。segments()支持将x0, y0, x1, y1作为向量传入,同时col, lty, lwd等参数也会按向量循环匹配,完美适配顶点数不同的多条线条场景。
示例代码
假设我们有三条顶点数不同的线条:
# 定义三条线条的坐标数据 line1 <- data.frame(x = c(1, 2, 3), y = c(1, 3, 2)) line2 <- data.frame(x = c(1, 4), y = c(2, 4)) line3 <- data.frame(x = c(2, 3, 4, 5), y = c(1, 2, 3, 1)) # 将每条线条拆分为连续的线段(起点+终点) get_segments <- function(df) { data.frame( x0 = df$x[-nrow(df)], y0 = df$y[-nrow(df)], x1 = df$x[-1], y1 = df$y[-1] ) } seg_list <- lapply(list(line1, line2, line3), get_segments) all_segs <- do.call(rbind, seg_list) # 定义每条线条的样式属性 line_cols <- c("red", "blue", "green") line_ltys <- c(1, 2, 3) line_lwds <- c(1, 2, 3) # 重复属性以匹配对应线条的线段数量 seg_cols <- rep(line_cols, sapply(seg_list, nrow)) seg_ltys <- rep(line_ltys, sapply(seg_list, nrow)) seg_lwds <- rep(line_lwds, sapply(seg_list, nrow)) # 单次调用完成所有线条绘制 plot(NA, xlim = c(1,5), ylim = c(1,4)) segments(x0 = all_segs$x0, y0 = all_segs$y0, x1 = all_segs$x1, y1 = all_segs$y1, col = seg_cols, lty = seg_ltys, lwd = seg_lwds)
原理说明
segments()本身就是为多线段绘制设计的,所有位置参数和样式参数都支持向量输入并按循环规则匹配。只需把每条连续线条拆成多个首尾相连的线段,再将对应线条的样式参数重复对应次数,就能通过单次调用完成所有线条的绘制,既避免了循环带来的性能损耗,也适配了顶点数不同的场景。
内容的提问来源于stack exchange,提问作者jeanlain

