Etude des spectres

Deux types de bois ont été étudiés par ATR-FTIR : un bois de tension (bois ayant subis une inclinaison de son tronc pendant sa croissance) et un bois opposé (partie opposée à l’inclinasion). Les spectres étudiés sont des spectres moyens des parois secondaires des cellules du xylème pour le bois opposé et des spectres moyens de la couche G pour le bois de tension. Ils ont été issus à partir des images spectrales réalisées par ATR FTIR. Ces images spectrales représentent une petite partie du xylème secondaire juvénile et lignifié appartenant à des tiges de Peuplier; obtenu d’un génotype cloné et sauvage: Clone INRA 717 1B4 (P. tremula x P. alba).

Importation des spectres sur Rstudio

Lecture des spectres de bois opposé

34 spectres moyens ont été réalisées à partir de deux individus 717 1B4 : « 717_1B4_4I » et « 717_1B4_9I ».

Pour 717_1B4_4I : 2 images spectrales ont été choisies pour extraire 8 et 8 spectres moyens au niveau des parois secondaires des fibres du xylème.
Pour 717_1B4_9I : 2 images spectrales avec 9 et 9 spectres moyens.

Rmq: Pour l’échantillon 717_1B4_4I, la même coupe anatomique a été utilisé pour obtenir une image en BO et une image en BT.

Images spectrales BO

Images spectrales BO

source("D:/PaulMarchand/SPIR/étude ACP/readSP.pe.r")
filenames_BO <- dir("../../étude ACP/Spectres_BO_BT/OW PAROIS//")
files_spir <- readSP.pe(paste0("../../étude ACP/Spectres_BO_BT/OW PAROIS//", filenames_BO[1]))
data_spectres <- data.frame(lambda = files_spir$xData, files_spir$yData)
colnames(data_spectres)[ncol(data_spectres)] <- sapply(strsplit(filenames_BO[1], "\\."),
                                                       function(x){x[1]}
                                                       )
rm(files_spir)
for (i in 2:length(filenames_BO)){
files_spir <- readSP.pe(paste0("../../étude ACP/Spectres_BO_BT/OW PAROIS//", filenames_BO[i]))
data_spectres <- merge(data_spectres,
                       data.frame(lambda = files_spir$xData, files_spir$yData))
colnames(data_spectres)[ncol(data_spectres)] <- sapply(strsplit(filenames_BO[i], "[.]"),
                                                       function(x){x[1]}
                                                       )
rm(files_spir)
}

Lecture des spectres de bois de tension

24 spectres moyens ont été réalisées à partir de deux individus 717 1B4 : « 717_1B4_4I » et « 717_1B4_9I ».

Pour 717_1B4_4I : 2 images spectrales ont été choisies pour extraire 8 et 8 spectres moyens au niveau de la couche G.
Pour 717_1B4_9I : 1 image spectrale avec 8 spectres moyens au niveau de la couche G.

Images spectrales BT_couche G

Images spectrales BT_couche G

filenames_BT <- dir("../../étude ACP/Spectres_BO_BT/TW COUCHE G//")
for (i in 1:length(filenames_BT)){
files_spir <- readSP.pe(paste0("../../étude ACP/Spectres_BO_BT/TW COUCHE G//", filenames_BT[i]))
data_spectres <- merge(data_spectres,
                       data.frame(lambda = files_spir$xData, files_spir$yData))
colnames(data_spectres)[ncol(data_spectres)] <- sapply(strsplit(filenames_BT[i], "[.]"),
                                                       function(x){x[1]}
                                                       )
rm(files_spir)
}
Data_spectres_condens <- data.frame(lambda = data_spectres[, 1],
                       MIR = I(as.matrix(data_spectres[, 2:ncol(data_spectres)])))
rownames(Data_spectres_condens$MIR)<- Data_spectres_condens$lambda

Représentation graphique des spectres bruts

echant_vec <- as.factor(sapply(strsplit(colnames(Data_spectres_condens$MIR), split = "[_]"),
                               function(x){x[1]}))
levels(echant_vec)
## [1] "Couche G Bois de tension 717 1B4" "Parois bois opposé 717 1B4"
matplot(Data_spectres_condens$lambda, Data_spectres_condens$MIR, type = "l", lty = 1, pch = 0, xlab = "Nombre d'onde cm-1", ylab = "Absorbance", 
        xlim = c(4000, 750), col = c("red","black")[as.factor(echant_vec)], 
        main = "Représentation des spectres bruts")
legend("topleft", legend = levels(echant_vec), col = c("red","black"), lty = 1)

Prétraitements des spectres

Sélection des longueurs d’onde d’intérêt

La région spectrale présentant le plus d’informations est la région “fingerprint” caractéristique des principales liaisons chimiques impliquées dans les différentes molécules. Cette région se situe entre 850 et 1800 cm -1.

data_sub <- subset(Data_spectres_condens, lambda >= 850 & lambda <= 1800)
echant_vec <- as.factor(sapply(strsplit(colnames(Data_spectres_condens$MIR), split = "[_]"),
                               function(x){x[1]}))
levels(echant_vec)
## [1] "Couche G Bois de tension 717 1B4" "Parois bois opposé 717 1B4"
matplot(data_sub$lambda, data_sub$MIR, type = "l", lty = 1, pch = 0, 
        xlab = "Nombre d'onde cm-1", ylab = "Absorbance", 
        xlim = c(1800, 850), col = c("red","black")[as.factor(echant_vec)], 
        main = "Spectres restreints entre 1800 et 850 cm-1")
legend("topleft", legend = levels(echant_vec), col = c("red","black"), lty = 1)

Lissage des spectres :

tsf <- (max(data_sub$lambda) - min(data_sub$lambda)) / (length(data_sub$lambda) - 1)
data_smooth <- data.frame(lambda = data_sub$lambda,
                          MIR = I(as.matrix(apply(data_sub$MIR, 2, function(x){
                            sgolayfilt(x, p = 1, n = 9, m = 0, ts = tsf)}))))
matplot(data_smooth$lambda, data_smooth$MIR, type = "l", lty = 1,
        pch = 0, xlab = "Nombre d'onde cm-1", 
        ylab = "Absorbance", xlim = c(1800, 850), 
        col = c("red","black")[as.factor(echant_vec)], 
        main = "Spectres après lissage \n (facteur: n = 9)")
legend("topleft", legend = levels(echant_vec), col = c("red","black"), lty = 1)

Normalisation des spectres

Normalisation de type SNV (Standart Normale Variate) des données spectrales.

normalize <- function(x) ((x - mean(x)) / sd(x))
data_norm <- data_smooth
data_norm$MIR <- I(as.matrix(apply(data_smooth$MIR,2,normalize)))
matplot(data_norm$lambda, data_norm$MIR, type = "l", lty = 1, pch = 0, xlab = "Nombre d'onde cm-1", ylab = "Absorbance", 
        xlim = c(1800, 850), col = c("red","black")[as.factor(echant_vec)], 
        main = "Normalisation SNV des spectres")
legend("topleft", legend = levels(echant_vec), col = c("red","black"), lty = 1)

Detrend des spectres

Cette action implique également une normalisation des spectres. Elle permet d’enlever la tendance d’augmentation d’absorbance lorsque les nombres d’onde diminuent.

data_dt <- data.frame(lambda = data_smooth$lambda,
                      MIR = I(t(detrend(X = t(data_smooth$MIR),
                                         wav = data_smooth$lambda))))
matplot(data_dt$lambda, data_dt$MIR, type = "l", lty = 1, pch = 0, xlab = "Nombre d'onde cm-1", ylab = "Absorbance", 
        xlim = c(1800, 850), col = c("red","black")[as.factor(echant_vec)], 
        main = "Normalisation Detrend des spectres")
legend("topleft", legend = levels(echant_vec), col = c("red","black"), lty = 1)

Analyses des spectres

Etude des spectres par l’Analyse en Composantes Principales (ACP)

Une étude exploratrice est mise en place pour mettre en évidence les potentiels différences entre les différents spectres étudiés. La complexité et variabilité des données spectrales est telles qu’il est parfois difficile d’extraire les informations pertinentes par simple comparaison visuelle des spectres. La méthode de réduction des données comme la méthode ACP permet réduire le nombre de variables et de rendre l’information moins redondante en créant seulement quelques nouvelles variables plus robustes nommées « composantes principales ».

ACP après Normalisation SNV

data_A_norm <- as.data.frame(t(data_norm))
colnames(data_A_norm) <- data_A_norm[1, ]
data_A_norm <- data_A_norm[-1, ]
data_AC_norm <- cbind(echant_vec, data_A_norm)
data_ACP_norm <- PCA(data_AC_norm, quali.sup = 1, graph = F)
barplot(data_ACP_norm$eig[, 1] / sum(data_ACP_norm$eig[, 1]) * 100, main="Eigenvalues", names.arg=1:nrow(data_ACP_norm$eig), ylim = c(0,70), xlab = "Nombres de composantes principales de l'ACP", ylab = "% des Composantes principales")

#plot.PCA(data_ACP_norm, axes = c(1,2), label = "none", choix = "ind", habillage = 1)
plotellipses(data_ACP_norm,label = "none", choix = "ind", habillage = 1, title = "ACP BO-BT \n (BO: parois secondaires, BT: couche G) \n (après normalisation)")

ACP après Detrend

data_A_dt <- as.data.frame(t(data_dt))
colnames(data_A_dt) <- data_A_dt[1, ]
data_A_dt <- data_A_dt[-1, ]
data_AC_dt <- cbind(echant_vec, data_A_dt)
data_ACP_dt <- PCA(data_AC_dt, quali.sup = 1, graph = F)
barplot(data_ACP_dt$eig[, 1] / sum(data_ACP_dt$eig[, 1]) * 100, main="Eigenvalues", names.arg=1:nrow(data_ACP_dt$eig), ylim = c(0,70), xlab = "Nombres de composantes principales de l'ACP", ylab = "% des Composantes principales")

#plot.PCA(data_ACP_dt, axes = c(1,2), label = "none", choix = "ind", habillage = 1)
plotellipses(data_ACP_dt,label = "none", choix = "ind", habillage = 1, title = "ACP BO-BT \n (BO: parois secondaires, BT: couche G) \n (après Detrend)")

Etude des Loadings de l’ACP

Les “loadings” représentent les vecteurs propres de l’ACP expliquant les différences observées et les séparations sur les différents axes de l’ACP.

plot(data_norm$lambda, data_ACP_norm$var$coord[,1], type = "l", lty = 1, pch = 0, xlab = "nombre d'onde cm-1", ylab = c("PC1 (%)", round(data_ACP_norm$eig$`percentage of variance`[1],2)), xlim = c(1800, 850), ylim = c(-1.0, 1.0), main = "Loadings PC 1 BO-BT (norm)")
abline(h = 0.0, lty = 1, col = "grey")

plot(data_dt$lambda, data_ACP_dt$var$coord[,1], type = "l", lty = 1, pch = 0, xlab = "nombre d'onde cm-1", ylab = c("PC1 (%)", round(data_ACP_dt$eig$`percentage of variance`[1],2)), xlim = c(1800, 850), ylim = c(-1.0, 1.0), main = "Loadings PC 1 BO-BT (detrend)")
abline(h = 0.0, lty = 1, col = "grey")