下面使用光谱数据(强度与波长)的常见显示来比较多个光谱中数据中峰的位置。假设它们都在 0 处共享一条基线,则可以方便地将多条线垂直偏移一个恒定的间距,以避免重叠线的干扰。
从而变成
我正在寻找一种更好的策略来自动执行这种垂直移动,从长格式的数据开始。这是一个最小的例子。
# fake data (5 similar-looking spectra)
spec <- function(){
x <- runif(100, 0, 100)
data.frame(x=x, y=jitter(dnorm(x, mean=jitter(50), sd=jitter(5)), amount=0.01))
}
require(plyr)
all <- ldply(1:5, function(ii) data.frame(spec(), id=ii))
我目前的策略如下:
将光谱从长格式转换为宽格式。这涉及插值,因为光谱不一定具有相同的 x 轴值。
找到光谱之间的最小偏移以避免邻居之间的重叠
将光谱移动该距离的倍数
融化回长格式
我使用 plyr 实现了这个,
# function that evenly spaces the spectra to avoid overlap
# d is in long format, s is a scaling factor for the vertical shift
require(plyr); require(ggplot2)
spread_plot <- function(d, s=1){
ranges <- ddply(d, "id", with, each(min,max,length)(x))
common_x <- seq(max(ranges$min), min(ranges$max), length=max(ranges$length))
new_y <- dlply(d, "id", function(x) approx(x$x, x$y, common_x)$y)
mat <- do.call(cbind, new_y)
test <- apply(mat, 1, diff)
shift <- max(-test[test < 0])
origins <- s*seq(0, by=shift, length=ncol(mat))
for(ii in seq_along(origins)){
current <- unique(d[["id"]])[ii]
d[d[["id"]] == current, "y"] <-
d[d[["id"]] == current, "y"] + origins[ii]
}
d
}
test <- spread_plot(all)
ggplot(test, aes(x, y, colour=id, group=id))+
geom_line() + guides(colour=guide_legend())
这种策略有几个缺点:
它很慢
偏移量不是一个漂亮的数字;我不知道如何自动将其很好地舍入,以便光谱偏移例如 0.02 或 50 等,具体取决于强度范围。
pretty(origins)
是有问题的,因为它可以返回不同数量的值。
我觉得我缺少一个更简单的解决方案,可能直接使用长格式的原始数据。