FAMetA is a R package aimed to the estimation of FA import (I), de novo synthesis (S), fractional contribution of the 13C-tracers (D0, D1, D2), elongation (E) and desaturation (Des) based on mass isotopologue data.
Example files can be found at https://drive.google.com/drive/folders/1-mhqBd6W8VJkIYwVuIOr2Gn4Z9vBUN9-?usp=sharing.
# Install FAMetA
install.packages("FAMetA", dependencies = c("Depends", "Imports"))
# load library
library(FAMetA)
To start the MS analysis, raw data files need to be converted into mzXML format and a csv file with all the required information must be prepared with the following columns: sample (file names), acquisitionmode (MS in this particular case), sampletype (groups) and any other additional information such as protein levels for example, which can be used later to normalize your data.
Once all mzXML files have been obtained, peak picking have to be performed using the batchdataProcessing()
function from LipidMS package. Alternatively, any other package or external software may be employed and data can be loaded from a csv file using readfadatafile()
function.
library(FAMetA)
library(tools)
# Example files can be found at
# <https://drive.google.com/drive/folders/1-mhqBd6W8VJkIYwVuIOr2Gn4Z9vBUN9-?usp=sharing>.
# This dataset contains 12 samples of linfocites grown in culture media
# supplemented with 13Cglc, 13Cglc+iFASN, 13Cglc+iSCD and 13Cglc+iFADS2
# (3 replicates of each condition), 2 blank samples and 3 injections of a
# standards mix.
#==============================================================================#
# Data pre-processing using LipidMS package
#==============================================================================#
#=================#
# Read metadata
<- read.csv("samples.csv", header = T, sep=",")
metadata
# check file names (they must include .mzXML)
if (!all(file_ext(metadata$sample) == "mzXML")){
$sample[file_ext(metadata$sample) != "mzXML"] <-
metadatapaste(metadata$sample[file_ext(metadata$sample) != "mzXML"], ".mzXML", sep="")
}
#=================#
# Set processing parameters
# Peak-picking
<- "negative"
polarity <- 15 # dmz and drt to generate bins/partitions for peak-picking
dmzagglom <- 200 # max rt window for bins
drtagglom <- 100 # drt window for clustering (redefines previous bins)
drtclust <- 8 # min number of points to define a peak (MS1, MS2)
minpeak <- 100000 # at least minpeak points must have minint intensity
minint <- 5 # max rt gap to fill missing points in a peak
drtgap <- 8 # min width of a peak when there are more than 1 peak in a EIC
drtminpeak <- 30 # max rt window for a EIC
drtmaxpeak <- 10 # max number of peaks in a EIC
recurs <- 5 # signal-to-baseline ratio (MS1, MS2)
sb <- 5 # signal-to-noise ratio
sn <- 2 # weight to assign new peaks
weight <- 5 # dmz for isotopes search
dmzIso <- 5 # drt for isotopes search
drtIso
<- TRUE # parallel processing
parallel <- 4 # number of cores
ncores
#=================#
# Peak-picking
<- batchdataProcessing(metadata = metadata,
msbatch polarity = polarity,
dmzagglom = dmzagglom,
drtagglom = drtagglom,
drtclust = drtclust,
minpeak = minpeak,
drtgap = drtgap,
drtminpeak = drtminpeak,
drtmaxpeak = drtmaxpeak,
recurs = recurs,
sb = sb,
sn = sn,
minint = minint,
weight = weight,
dmzIso = dmzIso,
drtIso = drtIso,
parallel = parallel,
ncores = ncores)
Once we have obtained the msbatch, we need to align samples and group all features to build the final feature matrix with alignmsbatch()
and groupmsbatch()
functions.
#=================#
# Batch processing
<- 10 # max dmz and rt to group peaks for alignment
dmzalign <- 60 # max rt window for clustering in alignment
drtalign <- 0.2 # span for alignment
span <- 0.50 # min fraction of samples represented in a peak group to be used for alignment
minsamplesfracalign <- 10 # max dmz and rt to group peaks for grouping
dmzgroup <- 50 # max rt window for clustering in grouping
drtagglomgroup <- 10 # max rt difference within a peak group
drtgroup <- 0.20 # min fraction of samples represented in a peak group to be kept
minsamplesfracgroup
#=================#
# Alignment
<- alignmsbatch(msbatch, dmz = dmzalign, drt = drtalign, span = span,
msbatch minsamplesfrac = minsamplesfracalign,
parallel = parallel, ncores = ncores)
#=================#
# Grouping
<- groupmsbatch(msbatch, dmz = dmzgroup, drtagglom = drtagglomgroup,
msbatch drt = drtgroup, minsamplesfrac = minsamplesfracgroup,
parallel = parallel, ncores = ncores)
#=================#
# Save msbatch
save(msbatch, "msbatch.rda.gz", compress = TRUE)
# If any other external software is used for processing, data can be loaded from
# a csv file using the following function:
# fadata <- readfadatafile("externafadata.csv", sep=",", dec=".")
# In this case, go directly to data correction step.
Now we can annotate all fatty acids present in our samples.
Next step consists in FA annotation. First, automatic FA annotation can be performed with annotateFA()
function and identified FA can be checked using plotFA()
.
#==============================================================================#
# FA annotation
#==============================================================================#
#=================#
# Annotate FA
<- annotateFA(msbatch, dmz = 5)
msbatch
#=================#
# plot peaks from identified FAs to check them
<- plotFA(msbatch, dmz = 10)
plots
pdf("FAs.pdf")
for (p in 1:length(plots)){
print(plots[[p]])
}dev.off()
#=================#
# export annotations for curation
write.csv(msbatch$fas, file="faid.csv", row.names=FALSE)
Then, FA annotations can be modified at the csv file by removing rows of unwanted FA, modifying initial and end retention times or adding new rows with missing compounds. Here, unique compound names with the nomenclature “FA(16:1)n7”, where n7 (omega-7) indicates the last double bound position, are required to differentiate between FA isomers. In case of unknown positions, x, y and z letters are allowed (i.e. FA(16:1)nx). In addition, internal standards for later normalization can also be added at this point in a new row indicating IS in the compound name column. Check faid.csv and faid_curated.csv files to see an example. Changes can also be performed directly on the msbatch using addFA, removeFA, changeFArt and searchIS functions. See documentation for details.
#==============================================================================#
# FA curation
#==============================================================================#
#=================#
# read csv file with modified annotations
<- read.csv("faid_curated.csv", sep=",", dec=".")
faid
#=================#
# change FA annotations
<- curateFAannotations(msbatch, faid)
msbatch
#=================#
# plot FA peaks again to check identities
<- plotFA(msbatch, dmz = 10)
plots
pdf("FAs_curated.pdf")
for (p in 1:length(plots)){
print(plots[[p]])
}dev.off()
Once all FA have been correctly identified and defined at the msbatch, isotopes have to be searched based on peak limits (iniRT and endRT), mass tolerance (in ppm) and peak correlation.
#==============================================================================#
# Search FA isotopes and get the fadata object
#==============================================================================#
<- searchFAisotopes(msbatch, dmz = 10, coelCutoff = 0.6)
fadata
# if you want to save fadata in a csv to subset it for example:
<- cbind(rbind(fadata$fattyacids, data.frame(Compound="IS", Label="")),
df rbind(fadata$intensities, fadata$IS))
<- rbind(c("", "sampletype", fadata$metadata$sampletype),
df c("Compound", "Label", colnames(fadata$intensities)), df)
write.table(df, file="fadata.csv", sep=",", col.names = FALSE, row.names = FALSE)
# and then, you could read it again using:
<- readfadatafile("fadata.csv", sep=",", dec=".") fadata
searchFAisotopes()
function will return a simplified fadata list which will be used for the metabolic analysis. In case external software have been used to process data, readfadatafile()
function can import a csv file and return a similar fadata list. An example data file can be found at https://drive.google.com/drive/folders/1-mhqBd6W8VJkIYwVuIOr2Gn4Z9vBUN9-?usp=sharing.
#==============================================================================#
# Import FA data
#==============================================================================#
<- "externalfadata.csv"
inputfile <- readfadatafile(inputfile, sep=",", dec=".") fadata
Previous to metabolic analysis, data must be corrected and normalized using dataCorrection()
function, which will execute four steps: data correction for natural abundance of 13C using the accucor algorithm (Su et al., 2017), data normalization with internal standards (optional), blank substraction (optional) and external normalization (applied if additional columns are added to the metadata file).
In case blank substraction have to be applied, blankgroup argument must contain the group name used in metadata to define blank samples. Similarly, for esternal normalization, externalnormalization argument must contain the column name at the metadata file that contains the values to be used.
#==============================================================================#
# Data correction
#==============================================================================#
<- dataCorrection(fadata, blankgroup = "Blank")
fadata
# Alternatively, to add external normalization:
# fadata <- dataCorrection(fadata, blankgroup = "blank",
# externalnormalization = "protein")
Finally, metabolic analysis can be performed. To this end, 3 different functions have to be run sequentially: synthesisAnalysis()
, elongationAnalysis()
and desaturationAnalysis()
. Then results will be summarize and represented using summarizeResults()
.
Synthesis analysis will model FA data for FA up to 16 carbons to estimate 13C-tracer contribution to the acetyl-CoA pool for FA synthesis (D) and the FA fraction that has been synthesized de novo. D0, D1 and D2 represent the contribution of M+0, M+1 and M+2 acetate, respectively, and P (phi) is the overdispersion parameter of the quasi-multinomial distribution.
#==============================================================================#
# Metabolic analysis
#==============================================================================#
#=================#
# Synthesis analysis
<- synthesisAnalysis(fadata=fadata, R2Thr = 0.95, maxiter = 1e3,
fadata maxconvergence = 100, startpoints = 5)
# If inhibitors have been used, make sure D2 has not been underestimated. If so,
# D2 could be set as the one calculated for 13-Glc Control samples to improve
# the results:
# D2 <- fadata$synthesis$results$D2[fadata$synthesis$results$FA == "FA(16:0)"]
# fadata$synthesis$results$Group[fadata$synthesis$results$FA == "FA(16:0)"]
# D2[4:12] <- rep(mean(D2[1:3]))
# relaunch synthesis analysis fixing D2
# fadata <- synthesisAnalysis(fadata=fadata, R2Thr = 0.95, maxiter = 1e3,
# maxconvergence = 100, startpoints = 5, D2 = D2)
# Explore results
View(fadata$synthesis$results)
View(fadata$synthesis$predictedValues)
pdf("plotsSynthesis.pdf")
for (f in 1:length(fadata$synthesis$plots)){
for (s in 1:length(fadata$synthesis$plots[[f]])){
print(fadata$synthesis$plots[[f]][[s]])
}
}dev.off()
# to use multinomial distribution without over dispersion, set P parameter to 0
<- synthesisAnalysis(fadata=fadata, R2Thr = 0.95, maxiter = 1e3,
fadata maxconvergence = 100, startpoints = 5, P = 0)
D0, D1, D2 can also be fixed if they are known. This is particularly useful in case inhibitors have been used as they could reduce S below the confidence interval and thus, S and D parameters could be misestimated.
Main route of de novo synthesis plus elongation starts at 16 carbons and then adds blocks of 2 carbons. Therefore, isotopologue distributions for FA longer than 16 carbons will be modeled taking into account de novo synthesis until FA(16:0), followed by single and independent elongation steps (E1, E2 …, En). Parameters D0, D1 and D2 are imported from FA(16:0)/FA(14:0) and thus the only relevant parameters to be estimated in the elongation analysis are Ei and I.
For n6 and n3 series, elongation is expected from FA(18:2)n6 and FA(18:3)n3 so that synthesis (S16:0) and first elongation step (E1) are set to 0.
#=================#
# Elongation analysis
<- elongationAnalysis(fadata, R2Thr = 0.95, maxiter = 1e4,
fadata maxconvergence=100, startpoints = 5, DThr = 0.1)
# Explore results
View(fadata$elongation$results)
View(fadata$elongation$predictedValues)
pdf("plotsElongation.pdf")
for (f in 1:length(fadata$elongation$plots)){
for (s in 1:length(fadata$elongation$plots[[f]])){
print(fadata$elongation$plots[[f]][[s]])
}
}dev.off()
Finally, after synthesis and elongation analysis have been run, desaturation analysis can be performed.
#=================#
# Desaturation analysis
<- desaturationAnalysis(fadata)
fadata
# Explore results
View(fadata$desaturations$results)
To ease data interpretation, summarizeResults()
function has been been designed to generate different results tables and heatmaps.
#=================#
# Summarize results
<- summarizeResults(fadata, controlgroup = "Control13Cglc")
fadata
#=================#
# Save fadata
save(fadata, file="fadata.rda")
#=================#
# Export results
write.csv(fadata$results$results, file = "results.csv", row.names=FALSE)
write.csv(fadata$results$summary, file = "summary.csv")
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$mid),
$mid),
fadatafile = "mid.csv", sep=",", col.names = FALSE)
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$synthesis$predictedValues),
$synthesis$predictedValues),
fadatafile = "predictedmid.csv", sep=",", col.names = FALSE)
pdf("relativepoolsizeRaw.pdf")
print(fadata$results$heatmaps$relativepoolsize$raw$plot)
dev.off()
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$heatmaps$relativepoolsize$raw$values),
$results$heatmaps$relativepoolsize$raw$values),
fadatafile = "relativepoolsizeRaw.csv", sep=",", col.names = FALSE)
pdf("relativepoolsizeZscore.pdf")
print(fadata$results$heatmaps$relativepoolsize$zscore$plot)
dev.off()
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$heatmaps$relativepoolsize$raw$values),
$results$heatmaps$relativepoolsize$zscore$values),
fadatafile = "relativepoolsizeZscore.csv", sep=",", col.names = FALSE)
if ("log2FC" %in% names(fadata$results$heatmaps$relativepoolsize)){
pdf("relativepoolsizeLog2FC.pdf")
print(fadata$results$heatmaps$relativepoolsize$log2FC$plot)
dev.off()
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$heatmaps$relativepoolsize$log2FC$values),
$results$heatmaps$relativepoolsize$log2FC$values),
fadatafile = "relativepoolsizeLog2FC.csv", sep=",", col.names = FALSE)
}
pdf("resultsRaw_endogenouslySynthesized.pdf")
print(fadata$results$heatmaps$synthesized$raw$plot)
dev.off()
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$heatmaps$synthesized$raw$values),
$results$heatmaps$synthesized$raw$values),
fadatafile = "resultsRaw_endogenouslySynthesized.csv", sep=",",
col.names = FALSE)
if ("log2FC" %in% names(fadata$results$heatmaps$synthesized)){
pdf("resultsLog2FC_endogenouslySynthesized.pdf")
print(fadata$results$heatmaps$synthesized$log2FC$plot)
dev.off()
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$heatmaps$synthesized$log2FC$values),
$results$heatmaps$synthesized$log2FC$values),
fadatafile = "resultsLog2FC_endogenouslySynthesized.csv", sep=",",
col.names = FALSE)
}
#=================#
# Isotopologue distributions: observed vs predicted
pdf("isotopologueDistributions.pdf")
for (f in 1:length(fadata$synthesis$plots)){
for (s in 1:length(fadata$synthesis$plots[[f]])){
print(fadata$synthesis$plots[[f]][[s]])
}
}for (f in 1:length(fadata$elongation$plots)){
for (s in 1:length(fadata$elongation$plots[[f]])){
print(fadata$elongation$plots[[f]][[s]])
}
}dev.off()
#=================#
# Reorganized tables for synthesis and elongation parameters (S16, E1, E2, E3,
# E4 and E5)
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$allparameters$S16),
$results$allparameters$S16),
fadatafile = "S16.csv", sep=",", col.names = FALSE)
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$allparameters$E1),
$results$allparameters$E1),
fadatafile = "E1.csv", sep=",", col.names = FALSE)
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$allparameters$E2),
$results$allparameters$E2),
fadatafile = "E2.csv", sep=",", col.names = FALSE)
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$allparameters$E3),
$results$allparameters$E3),
fadatafile = "E3.csv", sep=",", col.names = FALSE)
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$allparameters$E4),
$results$allparameters$E4),
fadatafile = "E4.csv", sep=",", col.names = FALSE)
write.table(rbind(fadata$metadata$sampletype,
colnames(fadata$results$allparameters$E5),
$results$allparameters$E5),
fadatafile = "E5.csv", sep=",", col.names = FALSE)
In case any additional fatty acid needs to be added (i.e. extra unknown fatty acids such as FA(18:2)nv) or some parameters changed (i.e. add E1 step for FA(18:3)n3 or n6), it is possible to change the parameters database from FAMetA.
#=================#
# Customize parameters database
<- FAMetA::parameters
parameters
# Add a new unknown FA(18:1)
<- data.frame(FattyAcid = "FA(18:1)nv",
newrow M = 18,
S16 = 1,
E1 = 1,
E2 = 0,
E3 = 0,
E4 = 0,
E5 = 0)
<- data.frame(rbind(parameters, newrow))
parameters <- parameters[order(parameters$FattyAcid),]
parameters View(parameters)
# Change fatty acid settings: add E1 step for FA(18:3)n6
$E1[parameters$FattyAcid == "FA(18:3)n6"] <- 1
parameters
# Then add the parameters argument to elongationAnalysis and summarizeResults
# functions
<- elongationAnalysis(fadata, R2Thr = 0.95, maxiter = 1e4,
fadata maxconvergence=100, startpoints = 5, D2Thr = 0.1,
parameters = parameters)
<- FAMetA:::summarizeResults(fadata, controlgroup = "H460_13Cglc",
fadata parameters = parameters)
This same strategy can be used to modify the desaturations database (desaturationdb).
If you have any further questions, please do not hesitate to contact us at maribel_alcoriza@iislafe.es.