第 2 章 批量处理光合测定数据

对于多数人来讲,一个季节用光合仪测量的数据文件至少是两位数的,处理起来非常不方便,针对这个问题,简单写了一个批量读取 LI-6400 和 LI-6800 原始数据的包(因为现有的容易实现的读取 excel 格式的包还不支持 6800 和 6400 这种形式的公式计算)2,使用非常简单,同时也适合处理未关闭数据文件而导致的无法生成 excel 格式的数据时的问题。

2.1 安装

暂时只有我的 github repo 中的版本:

devtools::install_github("zhujiedong/readphoto")

2.2 LI-6400 数据处理

2.2.1 LI-6400 数据的整合{#6400combine}

基本参数如下:

library(readphoto)
df64  <- read_bat_6400("./data/6400", header_line = 17, data_start = 27)

数据输出如下所示(仅显示前8列数据):

表 2.1: LI-6400 批量整合数据
files Obs HHMMSS FTime EBal. Photo Cond Ci
1 aci 1 10:55:14 483.0 0 6.990 0.0831 251.0
4 aci 2 10:57:35 623.5 0 5.160 0.0853 192.0
7 aci 3 10:59:55 763.5 0 3.140 0.0881 136.0
10 aci 4 11:02:26 914.5 0 0.910 0.0927 81.9
13 aci 5 11:04:46 1055.0 0 -0.167 0.0966 52.7
16 aci 6 11:07:23 1211.5 0 5.240 0.1010 305.0
19 aci 7 11:09:43 1352.0 0 6.610 0.1040 284.0
22 aci 8 11:12:04 1492.5 0 9.280 0.1050 438.0
25 aci 9 11:14:24 1633.0 0 10.200 0.1020 616.0
28 aci 10 11:16:44 1772.5 0 10.500 0.0943 795.0
31 aci 11 11:19:49 1958.0 0 10.700 0.0853 970.0
34 aci 12 11:22:09 2097.5 0 11.100 0.0812 1150.0
41 aq 2 10:12:52 737.5 0 6.450 0.0700 239.0
44 aq 3 10:15:12 878.0 0 6.450 0.0684 235.0
47 aq 4 10:17:32 1017.5 0 5.960 0.0655 241.0

如果想另存为 csv 格式:

write.csv(df64, "./combined.csv")

header_line 表示你数据表头所在行,data_start 表示你数据起始行,Obs = 1 时所在行,不含表头。这个也要确认好了,不同的测量不能放在一起(当然一般不会出现这种情况,同一台仪器,处理数据当然是希望 aci 和 aci 在一起,lrc 和 lrc 在一起,调查测量和调查测量在一起),不同的测量可能起始行不同,这样就会报错,特别需要注意的是,目前路径写法仅支持 “/” 分隔,不能使用 “\“ 作为分隔。例如在数据放在 D 盘的 6400 文件夹下,那么写法应为”d:/6400”, 不能为 “d:\6400”, 尽管后者对 R 是合法的,主要是因为我要区分你不同数据来源的文件是哪个,也即下文提到的 df$files 列。

其中,数据的来源在表格中第一列,叫做 files,是数据来源的文件名(即你起的名字),例如本例中你看到的 aci 是我之前数据里面 aci 响应曲线的数据。

这些数据可以用于后文相关的分析中,尤其是像 fitacis 这样的函数,因为本质上他们都是符合 tidyverse 样式的数据。

2.2.2 LI-6400 数据重计算

参数的重计算函数为 recomp_6400, 其参数除了 read_bat_6400 所包含的参数外,还有叶面积 S, 以及叶片正反面的气孔比例,默认值分别为 6 和 0.5。

library(readphoto)
x1 <- read_bat_6400("./data/6400")
y1 <- recomp_6400("./data/6400", header_line = 17, data_start = 27, S = 6, K = 0.5)

x1$Photo - y1$Photo
##  [1] -0.0008873753  0.0026900500 -0.0012036469  0.0003483414  0.0006122641
##  [6] -0.0113872639 -0.0020986076  0.0004962787  0.0188727482 -0.0294595908
## [11] -0.0436611445 -0.0339083408  0.0046772165  0.0036653298  0.0030397988
## [16] -0.0105901673  0.0040624956  0.0017317049 -0.0073252290  0.0054977377
## [21]  0.0039736503  0.0021704065  0.0046772165  0.0036653298  0.0030397988
## [26] -0.0105901673  0.0040624956  0.0017317049 -0.0073252290  0.0054977377
## [31]  0.0039736503  0.0021704065
x1$Trmmol - y1$Trmmol
##  [1] -2.998596e-04  1.407338e-04  3.189451e-05 -4.586467e-04 -3.836822e-04
##  [6]  5.402725e-04 -2.344852e-04 -7.684772e-05  5.979599e-04 -6.534341e-04
## [11] -6.779145e-04  2.469749e-04  3.812201e-04  2.313957e-04  3.508312e-04
## [16] -2.794358e-04 -5.406530e-04  5.230606e-04 -9.183370e-04  7.638850e-04
## [21] -2.578893e-04  2.203045e-04  3.812201e-04  2.313957e-04  3.508312e-04
## [26] -2.794358e-04 -5.406530e-04  5.230606e-04 -9.183370e-04  7.638850e-04
## [31] -2.578893e-04  2.203045e-04
x1$Cond - y1$Cond
##  [1] -1.974217e-04 -3.594216e-04 -3.779119e-04 -3.806675e-04 -3.201411e-04
##  [6] -1.483324e-04 -7.803345e-04 -2.671018e-04  1.028977e-04 -3.966192e-04
## [11] -3.190769e-04 -2.314266e-04 -2.746300e-04  1.094050e-05 -4.584791e-05
## [16] -1.084094e-04 -1.827768e-04 -1.344969e-04 -1.714096e-04 -8.180257e-05
## [21] -4.687906e-05 -1.000424e-04 -2.746300e-04  1.094050e-05 -4.584791e-05
## [26] -1.084094e-04 -1.827768e-04 -1.344969e-04 -1.714096e-04 -8.180257e-05
## [31] -4.687906e-05 -1.000424e-04
x1$Ci-y1$Ci
##  [1]  0.434643936 -0.297820404 -0.308200950 -0.007847373 -0.035490198
##  [6]  0.433706824 -0.416734067 -0.052089770  0.147655545 -0.315797917
## [11] -0.271335987 -0.228968795  0.356519198  0.311487646  0.052196075
## [16]  0.557128947  0.058563406  0.300198435  0.052607786  0.339000061
## [21] -0.252622980 -0.494554616  0.356519198  0.311487646  0.052196075
## [26]  0.557128947  0.058563406  0.300198435  0.052607786  0.339000061
## [31] -0.252622980 -0.494554616
# half of original the area
y1 <- recomp_6400("./data/6400",  header_line = 17, data_start = 27, S = 3, K = 0.5)
y1$Photo/x1$Photo
##  [1] 2.000254 1.998957 2.000767 1.999234 2.007333 2.004346 2.000635 1.999893
##  [9] 1.996299 2.005611 2.008161 2.006110 1.998550 1.998863 1.998980 2.003671
## [17] 1.998391 1.999240 2.003866 1.995584 1.994199 2.010360 1.998550 1.998863
## [25] 1.998980 2.003671 1.998391 1.999240 2.003866 1.995584 1.994199 2.010360
# test with random area less than six
area <- 6 - runif(32, 1, 3)
y1 <- recomp_6400("./data/6400",  header_line = 17, data_start = 27, S = area, K = 0.5)
y1$Photo/x1$Photo
##  [1] 1.890741 1.442401 1.922837 1.460636 1.263409 1.414596 1.757261 1.521830
##  [9] 1.291741 1.581095 1.452796 1.398753 1.884053 1.437109 1.228692 1.745059
## [17] 1.651811 1.603419 1.203926 1.310704 1.822923 1.804928 1.470240 1.768144
## [25] 1.900306 1.882726 1.906420 1.620766 1.682811 1.289687 1.447063 1.381292

我们看到各个值之差非常小,因为我们使用的是相同的叶面积,理论上这两次读数的差异应为 0, 但在实际计算过程中,有小数点位数的影响,所以某些值不完全为 0,但该差值足够小。我们将所有的数据叶面积减半后,二者比值也约等于 2.

2.3 LI-6800 数据的处理 {#6800data}

LI-6800 的数据我们可以直接处理 Excel 即可,读取我这里有两种方案,一种是 R 读取方案,一种是 python 读取方案,之所以这么复杂,是因为 LI-6800 的 Excel 格式较为复杂,不被常用的软件包所支持。我们分开来看两种方式:

2.3.1 R 下 Excel 格式读取的重计算 {##6800xlconnect}

偶然发现了 XLConnect 软件包的一个功能(以前知道这个软件包,但忽视了),那就是直接读取 LI-6800 Excel 格式的数据并重计算,我将其写成了函数,放在了我的 readphoto 软件包里,软件包的安装:

remotes::install_github("zhujiedong/readphoto")

当然,最近连我自己安装 github 的软件包都经常出问题,如果大家同样遇到问题,可以按照下面的方式安装:

remotes::install_git("https://gitee.com/zhu_jie_dong/readphoto")

其中:

  • path 是 Excel 文件的路径;

  • start_row 是数据开始的行号;

  • S 为修改的叶面积,默认值为 6,如果叶面积无需更改,则使用默认的 NULL。如果使用 aperture 更改了面积,且叶片能够充满叶室,比方说是 2 \(cm^2\),该值必须输入一个长度和测量值数量完全一致的向量,例如有 3 个测量值,我们输入 S 的长度则为 3,例如,一共有三个测量值,只有第一个叶片没充满叶室,面积为 1.5,其他的为 2,则输入方式为 S = c(1.5, 2, 2)。

我们直接使用下面的例子解释,导入的数据是 6 cm2 的默认面积:

library(readphoto)

df6 <- xlconnect_read("./data/aci-xlc.xlsx")
df6$A
##  [1] 24.7381184 18.1379358 10.8055345  3.0239340 -0.9144044 26.9519572
##  [7] 27.5088717 40.9101889 50.1393342 55.3865984 58.0662751 59.3556428
df3 <- xlconnect_read("./data/aci-xlc.xlsx", S = rep(3, 12))
df6$A/df3$A
##  [1] 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5 0.5
df_random <- xlconnect_read("./data/aci-xlc.xlsx", S = rnorm(12, 3, 0.1))
df6$A/df_random$A
##  [1] 0.4703268 0.5052066 0.5075169 0.5063254 0.5166228 0.4393696 0.4790926
##  [8] 0.5081278 0.5143876 0.4945837 0.5079758 0.4884164

光合速率的倍数的变化在预期之内。

2.3.2 使用 Python 来处理

本节内容与题目不符,不过大家也不用担心,我提供了一个图形界面来操作,可以将所有文件批量处理为 csv 格式。

python 方案见链接:github微信

2.3.3 批量处理 csv 文件

如果还是比习惯用 R,我们来处理上面的 csv 文件即可。其实没什么特别的,就是需要批量导入后添加一个分组标签即可。以下为示例:

files_csv <- list.files("./data/csvdata", full.names = TRUE)
files_csv
## [1] "./data/csvdata/racirtest1.csv" "./data/csvdata/rcirtest3.csv"
add_remark <- function(path){
  df <- read.csv(path)
  df$remarks <- gsub(".csv", "", basename(path))
  return(df)
}

list_csv <- lapply(files_csv, add_remark)

df_remark <- do.call(rbind, list_csv)

n <- ncol(df_remark)
head(df_remark[,(n-3):n])
##   H2O_r_sp    SS_s    SS_r    remarks
## 1       20 96.8399 99.4131 racirtest1
## 2       20 96.8405 99.4111 racirtest1
## 3       20 96.8409 99.4112 racirtest1
## 4       20 96.8411 99.4125 racirtest1
## 5       20 96.8413 99.4125 racirtest1
## 6       20 96.8411 99.4118 racirtest1
tail(df_remark[,(n-3):n])
##     H2O_r_sp    SS_s    SS_r   remarks
## 443       20 97.0539 99.6148 rcirtest3
## 444       20 97.0531 99.6159 rcirtest3
## 445       20 97.0533 99.6146 rcirtest3
## 446       20 97.0527 99.6133 rcirtest3
## 447       20 97.0534 99.6146 rcirtest3
## 448       20 97.0527 99.6146 rcirtest3

到此为止已经整理为所谓的 tidy data 了,用 tidyverse 也好,用 base 语法也好,总之是比较容易处理的数据了,例如上面其实是 RACiR 数据了,有两个,那么当然可以使用 plantecophys::fitacis 来一条命令搞定所有数据的拟合了。

这里需要注意的是使用 xlconnect_read 也可以使用类似的操作,但我觉得不如这种方法省事,故而只列出来这一种,有需要的也可以按照类似方法处理即可。