建议化学家:自动化/简化他的伏安法数据绘图代码

时间:2017-07-22 03:20:10

标签: r excel plot

我是一名化学家,最近处理了大量的伏安法数据。让我非常清楚并提供一些研究信息。我在固态导电薄膜上从起始电压到结束电压进行扫描。这些扫描在单个文件夹中保存为.txt文件(名称方案:运行#.txt)。我正在研究电导随温度变化的变化。在给定温度下绘制电流v。电压的LINEST线给出了一条斜率=电导的线。一旦我有每次扫描的电导(斜率),我绘制电导与温度,以查看温度相关的电导特性。我一直在Excel中这样做,但已经找到了使用R完成工作的更快捷的方法。我是R(Rstudio)的新手并且认识到我的编码不是最好的。毫无疑问,这个过程可以简化和加速,这将有很大帮助。这就是我目前正在执行的过程:

# Set working directory with folder containing all .txt files for inspection

# Add all .txt files to the global environment

allruns<-list.files(pattern=".txt")

for(i in 1:length(allruns))assign(allruns[i],read.table(allruns[i]))

由于电压列(1x1000矩阵)对于所有运行都是相同的并且在每个.txt文件的列V1中,因此我将x指定为第一个文件夹中的电压列

x<-run1.txt$V1

所有电流(这些电压随电压变化而变化)都可以在所有.txt文件的V2列中找到,因此我为每个电流分配y#。这些是一次输入一个..

y1<-run1.txt$V2
y2<-run2.txt$V2
y3<-run3.txt$V2
# ...
yn<-runn.txt$V2

这样我就可以获得每个LINEST的eqn(每次扫描一个LINEST,然后用abline绘制)。再次输入一个:

run1<-lm(y1~x)
run2<-lm(y2~x)
run3<-lm(y3~x)
# ...
runn<-lm(yn~x)

为了在同一个图上获得一个包含所有LINEST(每次扫描一个)的单个图形,没有显示数据点,我一直在使用这种编码模式首先在单个图中以单独的系列获取所有数据点:

plot(x,y1,col="transparent",main="LSV Solid Film", xlab = "potential(V)",ylab="current(A)", xlim=rev(range(x)),ylim=range(c(y3,yn)))

par(new=TRUE)
plot(x,y2,col="transparent",main="LSV Solid Film", xlab = "potential(V)",ylab="current(A)", xlim=rev(range(x)),ylim=range(c(y3,yn)))

par(new=TRUE)
plot(x,y3,col="transparent",main="LSV Solid Film", xlab = "potential(V)",ylab="current(A)", xlim=rev(range(x)),ylim=range(c(y1,yn)))

# ...

par(new=TRUE)
plot(x,yn,col="transparent",main="LSV Solid Film", xlab = "potential(V)",ylab="current(A)", xlim=rev(range(x)),ylim=range(c(y1,yn)))

#To obtain all LINEST lines (one for each scan, on the single graph):
abline(run1,col=””, lwd=1)
abline(run2,col=””,lwd=1)
abline(run3,col=””,lwd=1)
# ...
abline(runn,col=””,lwd=1)

# Then to get each LINEST equation:
summary(run1)
summary(run2)
summary(run3)
# ...
summary(runn)

每次使用summary()时,我都会复制斜率并将其粘贴到Excel工作表中 - 以及我单​​独记录的相应扫描温度。然后,我将电影的电导率v点绘制为X-Y散射,用平滑线给出温度相关的电导曲线。给我R中的单个LINEST线图和Excel中的电导v temp。

这种技术实际上比在Excel中完成所有操作要快得多,但它可以更快更有效地完成!此外,如果我需要更改某些内容,则需要根据需要进行任何更改来重新执行整个过程。这个过程花了我5个小时的Excel和1.5个小时的R(也许我太慢了)。尽管如此,我们非常感谢任何有助于自动化/简化这一过程的提示。

2 个答案:

答案 0 :(得分:1)

关于list s中的数据操作,有很多问题;存储matrix列表或data.frame列表的速度很快,在一个列表上干净利落地操作的代码可以很容易地应用于剩余的n-1

(注意:我在这里展示它的方法是一种技巧:将所有内容保存在间隔良好的列表中。其他人会建议 - 非常合理 - 将事物合并为一个data.frame并添加group变量(用于识别数据源自哪个文件/实验)将有助于更高级的多实验回归或组合绘图,例如ggplot2。我不会去在这里进入后一种技术,还没有。)

  1. 长期谴责for(...) assign(..., read.csv(...));你完成了重要的工作,所以这很容易:

    allruns <- sapply(list.files(pattern = "*.txt"), read.table, simplify = FALSE)
    

    sapply(..., simplify=FALSE)的使用类似于lapply(...),但它有一个很好的副作用,即命名单个list - ified元素,在这种情况下,每个文件名。这可能不是关键,但在其他地方非常方便。)

  2. 提取不变量和可变数据非常简单:

    allLMs <- lapply(allruns, function(mdl) lm(V2 ~ V1, data = mdl))
    

    我在这里使用每张桌子V1而不是曾经提取过的x ......虽然你可能想知道为什么,我认为保持它有两个原因: (1)只是在V1变量甚至是一行不同的情况下,这将拯救你; (2)构建这样的模型非常容易。

    此时,allLMs中的每个对象都是lm对象,这意味着我们可以这样做:

    summary(allLMs[[1]])
    
  3. 绘图:我想我理解你为什么使用par=NEW,我不得不笑......在我开始使用这种技术之前,我已经深入R了一段时间。我认为你需要的实际上更简单:

    xlim <- rev(range(allruns[[1]]$V1))
    ylim <- range(sapply(allruns, `[`, "V2"))
    # this next plot just sets the box and axes, no points
    plot(NA, type = "na", xlim = xlim, ylim = ylim)
    
    # no need to plot points with "transparent" ...
    ign <- sapply(allLMs, abline, col = "") # and other abline options ...
    
  4. 再次使用列表将所有模型复制到Excel中:

    out <- do.call(rbind, sapply(allLMs, function(m) summary(m)$coefficients[,1]))
    

    现在这将是一个data.frame,所有系数都在两列中。 (可以随意使用类似的技术来提取其他模型摘要属性,包括std errt.valuePr(>|t|)(在$coefficients中);或$r.squared$adj.r.squared等。)

    write.csv(out, file="clipboard", sep="\t")
    

    并粘贴到Excel中。 (或者,更好的是,将其保存为CSV文件并导入,因为您可能希望保留它。)

  5. 使用列表的一个技巧就是坚持不懈:尽可能长时间地将事物保存在列表中,这样您就不会单独处理模型。一个口头禅是如果你做了一次,你不应该再次输入它,只需循环/应用/映射/等等。在必要之前,不要从列表中提取太多。

答案 1 :(得分:0)

注意:r2evans&#39;答案提供了良好的一般建议,并且不需要繁重的包依赖性。但看到其他策略可能并不会有什么坏处。

tidyverse对于这类事情来说非常方便,这里举例说明,

library(tidyverse)

# creating dummy data files
dummy <- function(T) {
  V <- seq(-5, 5, length=20)
  I <- jitter(T*V + T, factor = 1)
  write.table(data.frame(V=V, I = I), 
              file = paste0(T,".txt"), 
              row.names = FALSE)
}
purrr::walk(300:320, dummy)

# reading
lf <- list.files(pattern = "\\.txt")

read_one <- function(f, ...) {cbind(T = as.numeric(gsub("\\.txt", "", f)), read.table(f, ...))}
m <- purrr::map_df(lf, read_one, header = TRUE, .id="id")
head(m)

ggplot(m, aes(V, I, group = T)) + 
   facet_wrap( ~ T) + 
   geom_point() + 
   geom_smooth(se = FALSE)

enter image description here

models <- m %>% 
  split(.$T) %>% 
  map(~lm(I ~ V, data = .))

coefs <- models %>% map_df(broom::tidy, .id = "T")

ggplot(coefs, aes(as.numeric(T), estimate)) + 
  geom_line() + 
  facet_wrap(~term, scales = "free")

enter image description here