comparison quality_report.xml @ 2:d4803c1e5e19 draft

planemo upload for repository https://github.com/galaxyproteomics/tools-galaxyp/tree/master/tools/cardinal commit f127be2141cf22e269c85282d226eb16fe14a9c1
author galaxyp
date Fri, 15 Feb 2019 10:21:09 -0500
parents ae9ffc7ba261
children 16556ca0196b
comparison
equal deleted inserted replaced
1:ae9ffc7ba261 2:d4803c1e5e19
1 <tool id="cardinal_quality_report" name="MSI Qualitycontrol" version="@VERSION@.1"> 1 <tool id="cardinal_quality_report" name="MSI Qualitycontrol" version="@VERSION@.2">
2 <description> 2 <description>
3 mass spectrometry imaging QC 3 mass spectrometry imaging QC
4 </description> 4 </description>
5 <macros> 5 <macros>
6 <import>macros.xml</import> 6 <import>macros.xml</import>
32 library(KernSmooth) 32 library(KernSmooth)
33 library(scales) 33 library(scales)
34 library(pheatmap) 34 library(pheatmap)
35 35
36 36
37 @READING_MSIDATA@ 37 @READING_MSIDATA_INRAM@
38
39 ## create full matrix to make processed imzML files compatible with segmentation and other steps
40 iData(msidata) <- iData(msidata)[]
38 41
39 ## remove duplicated coordinates 42 ## remove duplicated coordinates
40 print(paste0(sum(duplicated(coord(msidata))), " duplicated coordinates were removed")) 43 print(paste0(sum(duplicated(coord(msidata))), " duplicated coordinates were removed"))
41 msidata <- msidata[,!duplicated(coord(msidata))] 44 msidata <- msidata[,!duplicated(coord(msidata))]
42
43 ## create full matrix to make processed imzML files compatible with segmentation and other steps
44 iData(msidata) <- iData(msidata)[]
45 45
46 ## optional annotation from tabular file to obtain pixel groups (otherwise all pixels are considered to be one sample) 46 ## optional annotation from tabular file to obtain pixel groups (otherwise all pixels are considered to be one sample)
47 47
48 #if str($tabular_annotation.load_annotation) == 'yes_annotation': 48 #if str($tabular_annotation.load_annotation) == 'yes_annotation':
49 49
62 msidata\$annotation = as.factor(merged_annotation[,4]) 62 msidata\$annotation = as.factor(merged_annotation[,4])
63 63
64 #end if 64 #end if
65 65
66 ###################### calculation of data properties ################################ 66 ###################### calculation of data properties ################################
67 @DATA_PROPERTIES@ 67 @DATA_PROPERTIES_INRAM@
68 68
69 ## Median intensities 69 ## Median intensities
70 medint = round(median(spectra(msidata)[], na.rm=TRUE), digits=2) 70 medint = round(median(spectra(msidata)[], na.rm=TRUE), digits=2)
71 ## Spectra multiplied with m/z (potential number of peaks) 71 ## Spectra multiplied with m/z (potential number of peaks)
72 numpeaks = ncol(spectra(msidata)[])*nrow(spectra(msidata)[]) 72 numpeaks = ncol(msidata)*nrow(msidata)
73 ## Percentage of intensities > 0 73 ## Percentage of intensities > 0
74 percpeaks = round(npeaks/numpeaks*100, digits=2) 74 percpeaks = round(npeaks/numpeaks*100, digits=2)
75 ## Number of empty TICs 75 ## Number of empty TICs
76 TICs = colSums(spectra(msidata)[], na.rm=TRUE) 76 TICs = colSums(spectra(msidata)[], na.rm=TRUE)
77 NumemptyTIC = sum(TICs == 0) 77 NumemptyTIC = sum(TICs == 0)
79 medTIC = round(median(TICs), digits=1) 79 medTIC = round(median(TICs), digits=1)
80 sdTIC = round(sd(TICs), digits=0) 80 sdTIC = round(sd(TICs), digits=0)
81 ## Median and sd # peaks per spectrum 81 ## Median and sd # peaks per spectrum
82 medpeaks = round(median(colSums(spectra(msidata)[]>0, na.rm=TRUE), na.rm=TRUE), digits=0) 82 medpeaks = round(median(colSums(spectra(msidata)[]>0, na.rm=TRUE), na.rm=TRUE), digits=0)
83 sdpeaks = round(sd(colSums(spectra(msidata)[]>0, na.rm=TRUE), na.rm=TRUE), digits=0) 83 sdpeaks = round(sd(colSums(spectra(msidata)[]>0, na.rm=TRUE), na.rm=TRUE), digits=0)
84 print(cor(TICs,colSums(spectra(msidata)[]>0), method="pearson"))
85 ## Processing informations 84 ## Processing informations
86 centroidedinfo = centroided(msidata) 85 centroidedinfo = centroided(msidata)
87 86
88 ############## Read and filter tabular file with m/z ########################### 87 ############## Read and filter tabular file with m/z ###########################
89 88
90 ### reading calibrant file: 89 ### reading m/z input (calibrant) file:
91 90
92 #if $calibrant_file: 91 #if $calibrant_file:
93 92
94 calibrant_list = read.delim("$calibrant_file", header = $calibrant_header, na.strings=c("","NA"), stringsAsFactors = FALSE) 93 calibrant_list = read.delim("$calibrant_file", header = $calibrant_header, na.strings=c(" ","","NA"), stringsAsFactors = FALSE)
95 calibrant_list = calibrant_list[,c($mz_column, $name_column)] 94 calibrant_list = calibrant_list[,c($mz_column, $name_column)]
96 95
97 ### calculate how many input calibrant m/z are valid: 96 ### calculate how many input calibrant m/z are valid:
98 97
99 inputcalibrants = calibrant_list[calibrant_list[,1]>minmz & calibrant_list[,1]<maxmz,] 98 inputcalibrants = calibrant_list[calibrant_list[,1]>minmz & calibrant_list[,1]<maxmz,]
136 "Intensities > 0", 135 "Intensities > 0",
137 "Number of empty spectra", 136 "Number of empty spectra",
138 "Median TIC ± sd", 137 "Median TIC ± sd",
139 "Median # peaks per spectrum ± sd", 138 "Median # peaks per spectrum ± sd",
140 "Centroided", 139 "Centroided",
141 paste0("calibrants (#valid/#input) in \n", "$calibrant_file.display_name")) 140 paste0("input m/z (#valid/#input) in \n", "$calibrant_file.display_name"))
142 141
143 values2 = c(paste0(medint), 142 values2 = c(paste0(medint),
144 paste0(percpeaks, " %"), 143 paste0(percpeaks, " %"),
145 paste0(NumemptyTIC), 144 paste0(NumemptyTIC),
146 paste0(medTIC, " ± ", sdTIC), 145 paste0(medTIC, " ± ", sdTIC),
159 ####################### II) x-y images ####################################### 158 ####################### II) x-y images #######################################
160 ############################################################################## 159 ##############################################################################
161 print("x-y images") 160 print("x-y images")
162 161
163 ## only do plots for file with intensity peaks 162 ## only do plots for file with intensity peaks
163
164 if (npeaks > 0){ 164 if (npeaks > 0){
165
165 ## function for density plots 166 ## function for density plots
166 plot_colorByDensity = function(x1,x2, 167 plot_colorByDensity = function(x1,x2,
167 ylim=c(min(x2),max(x2)), 168 ylim=c(min(x2),max(x2)),
168 xlim=c(min(x1),max(x1)), 169 xlim=c(min(x1),max(x1)),
169 xlab="",ylab="",main=""){ 170 xlab="",ylab="",main=""){
202 ## for each annotation group find last pixel, there dashed lines will be drawn in plots over spectra index 203 ## for each annotation group find last pixel, there dashed lines will be drawn in plots over spectra index
203 pixel_name_df = data.frame(pixels(msidata), msidata\$annotation) 204 pixel_name_df = data.frame(pixels(msidata), msidata\$annotation)
204 colnames(pixel_name_df) = c("pixel_number", "pixel_name") 205 colnames(pixel_name_df) = c("pixel_number", "pixel_name")
205 last_pixel = aggregate(pixel_number~pixel_name, data = pixel_name_df, max) 206 last_pixel = aggregate(pixel_number~pixel_name, data = pixel_name_df, max)
206 pixel_vector = last_pixel[,2] 207 pixel_vector = last_pixel[,2]
207 abline_vector = pixel_vector[1:number_combined-1] 208 abline_vector = pixel_vector
208 print(abline_vector) 209
210 ## remove position_df to clean up RAM space
211 rm(position_df)
212 gc()
209 } 213 }
210 214
211 ################### 1) Pixel order image ################################### 215 ################### 1) Pixel order image ###################################
212 216
213 pixelnumber = 1:pixelcount 217 pixelnumber = 1:pixelcount
218 geom_tile() + coord_fixed()+ 222 geom_tile() + coord_fixed()+
219 ggtitle(gg_title) + theme_bw()+ 223 ggtitle(gg_title) + theme_bw()+
220 theme(plot.title = element_text(hjust = 0.5))+ 224 theme(plot.title = element_text(hjust = 0.5))+
221 theme(text=element_text(family="ArialMT", face="bold", size=12))+ 225 theme(text=element_text(family="ArialMT", face="bold", size=12))+
222 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange"), 226 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange"),
223 space = "Lab", na.value = "black", name = "Pixel\nnumber")) 227 space = "Lab", na.value = "black", name = "Pixel\nnumber"))
228
229 ## remove pixelxyarray to clean up RAM space
230 rm(pixelxyarray)
231 gc()
224 232
225 ################ 2) Number of calibrants per spectrum ###################### 233 ################ 2) Number of calibrants per spectrum ######################
226 234
227 ## matrix with calibrants in columns and in rows if there is peak intensity in range or not 235 ## matrix with calibrants in columns and in rows if there is peak intensity in range or not
228 pixelmatrix = matrix(ncol=ncol(msidata), nrow = 0) 236 pixelmatrix = matrix(ncol=ncol(msidata), nrow = 0)
258 } 266 }
259 267
260 ## for each pixel count TRUE (each calibrant m/z range with intensity > 0 is TRUE) 268 ## for each pixel count TRUE (each calibrant m/z range with intensity > 0 is TRUE)
261 countvector= as.factor(colSums(pixelmatrix, na.rm=TRUE)) 269 countvector= as.factor(colSums(pixelmatrix, na.rm=TRUE))
262 countdf= cbind(coord(msidata)[,1:2], countvector) ## add pixel coordinates to counts 270 countdf= cbind(coord(msidata)[,1:2], countvector) ## add pixel coordinates to counts
263 mycolours = c("black","grey", "darkblue", "blue", "green" , "red", "yellow", "magenta", "olivedrab1", "lightseagreen") 271 mycolours = brewer.pal(9, "Set1")
264 272
265 print(ggplot(countdf, aes(x=x, y=y, fill=countvector))+ 273 print(ggplot(countdf, aes(x=x, y=y, fill=countvector))+
266 geom_tile() + coord_fixed() + 274 geom_tile() + coord_fixed() +
267 ggtitle(paste0("Number of calibrants per pixel (±",$plusminus_ppm, " ppm)")) + 275 ggtitle(paste0("Number of calibrants per pixel (±",$plusminus_ppm, " ppm)")) +
268 theme_bw() + 276 theme_bw() +
269 theme(plot.title = element_text(hjust = 0.5))+ 277 theme(plot.title = element_text(hjust = 0.5))+
270 theme(text=element_text(family="ArialMT", face="bold", size=12))+ 278 theme(text=element_text(family="ArialMT", face="bold", size=12))+
271 scale_fill_manual(values = mycolours[1:length(countvector)], 279 scale_fill_manual(values = mycolours[1:length(countvector)],
272 na.value = "black", name = "# calibrants")) 280 na.value = "black", name = "# calibrants"))
273 281
282 ## remove countdf to clean up RAM space
283 rm(countdf)
284 gc()
285
274 }else{print("2) The inputcalibrant m/z were not provided or outside the m/z range")} 286 }else{print("2) The inputcalibrant m/z were not provided or outside the m/z range")}
275 287
276 ########################## 3) fold change image ########################### 288 ########################## 3) fold change image ###########################
277 289
278 #if $calibrantratio: 290 #if $calibrantratio:
279 #for $foldchanges in $calibrantratio: 291 #for $foldchanges in $calibrantratio:
280 mass1 = $foldchanges.mass1 292 mass1 = $foldchanges.mass1
281 mass2 = $foldchanges.mass2 293 mass2 = $foldchanges.mass2
282 distance = $foldchanges.distance 294 distance1 = $foldchanges.distance/1000000 * mass1
295 distance2 = $foldchanges.distance/1000000 * mass2
283 296
284 ### if user did not write a label use input m/z as label 297 ### if user did not write a label use input m/z as label
285 #if not str($foldchanges.filenameratioplot).strip(): 298 #if not str($foldchanges.filenameratioplot).strip():
286 #set $label = "Fold change %s Da / %s Da" % ($foldchanges.mass1, $foldchanges.mass2) 299 #set $label = "log2 fold change %s Da / %s Da" % ($foldchanges.mass1, $foldchanges.mass2)
287 #else: 300 #else:
288 #set $label = $foldchanges.filenameratioplot 301 #set $label = $foldchanges.filenameratioplot
289 #end if 302 #end if
290 303
291 ### filter msidata for given m/z range (for both input m/z) 304 ### filter msidata for given m/z range (for both input m/z)
292 filtered_data1 = msidata[mz(msidata) >= mass1-distance & mz(msidata) <= mass1+distance,] 305 filtered_data1 = msidata[mz(msidata) >= mass1-distance1 & mz(msidata) <= mass1+distance1,]
293 filtered_data2 = msidata[mz(msidata) >= mass2-distance & mz(msidata) <= mass2+distance,] 306 filtered_data2 = msidata[mz(msidata) >= mass2-distance2 & mz(msidata) <= mass2+distance2,]
294
295 ### find m/z in the two given ranges with the highest mean intensity
296 ### this two m/z will be used to calculate the fold change (red line in plot)
297 maxmassrow1 = rowMeans(spectra(filtered_data1), na.rm=TRUE)
298 maxmass1 = mz(filtered_data1)[which.max(maxmassrow1)]
299 maxmassrow2 = rowMeans(spectra(filtered_data2), na.rm=TRUE)
300 maxmass2 = mz(filtered_data2)[which.max(maxmassrow2)]
301
302 ### plot legend: chosen value in blue, distance in blue, max m/z in red
303 ### m/z range for each plot (fixed range of 5 Da) 307 ### m/z range for each plot (fixed range of 5 Da)
304 ### xlim does not work because it does not adjust for the max. intensities within the range 308 ### xlim does not work because it does not adjust for the max. intensities within the range
305 mzdown1 = features(msidata, mz = mass1-2) 309 mzdown1 = features(msidata, mz = mass1-2)
306 mzup1 = features(msidata, mz = mass1+3) 310 mzup1 = features(msidata, mz = mass1+3)
307 mzdown2 = features(msidata, mz = mass2-2) 311 mzdown2 = features(msidata, mz = mass2-2)
308 mzup2 = features(msidata, mz = mass2+3) 312 mzup2 = features(msidata, mz = mass2+3)
309 313
310 ### plot for first m/z 314 ### plot for first m/z
311 par(mfrow=c(2,1), oma=c(0,0,2,0)) 315 par(mfrow=c(2,1), oma=c(0,0,2,0))
312 plot(msidata[mzdown1:mzup1,], pixel = 1:pixelcount, main=paste0("Average spectrum ", mass1, " Da")) 316 plot(msidata[mzdown1:mzup1,], pixel = 1:pixelcount, main=paste0("Average spectrum ", mass1, " Da"))
313 abline(v=c(mass1-distance, mass1, mass1+distance), col="blue",lty=c(3,6,3)) 317 abline(v=c(mass1-distance1, mass1, mass1+distance1), col="blue",lty=c(3,6,3))
314 abline(v=maxmass1, col="red", lty=5)
315 318
316 ### plot for second m/z 319 ### plot for second m/z
317 plot(msidata[mzdown2:mzup2,], pixel = 1:pixelcount, main= paste0("Average spectrum ", mass2, " Da")) 320 plot(msidata[mzdown2:mzup2,], pixel = 1:pixelcount, main= paste0("Average spectrum ", mass2, " Da"))
318 abline(v=c(mass2-distance, mass2, mass2+distance), col="blue", lty=c(3,6,3)) 321 abline(v=c(mass2-distance2, mass2, mass2+distance2), col="blue", lty=c(3,6,3))
319 abline(v=maxmass2, col="red", lty=5)
320 title("Control of fold change plot", outer=TRUE) 322 title("Control of fold change plot", outer=TRUE)
321 323
322 ### filter spectra for max m/z to have two vectors, which can be divided 324 ### filter spectra for max m/z to have two vectors, which can be divided
323 ### plot spatial distribution of fold change 325 ### plot spatial distribution of fold change
324 ### only possible when there are intensities > 0 in both given m/z ranges 326
325 327 ## calculate mean intensity for each m/z over the ppm range; then calculate log2 foldchange
326 if (length(maxmass1)>0&length(maxmass2)>0){ 328 mass1vector = colMeans(spectra(filtered_data1), na.rm =TRUE)
327 mass1vector = spectra(msidata)[features(msidata, mz = maxmass1),] 329 mass2vector = colMeans(spectra(filtered_data2), na.rm = TRUE)
328 mass2vector = spectra(msidata)[features(msidata, mz = maxmass2),] 330 foldchange= log2(mass1vector/mass2vector)
329 foldchange= log2(mass1vector/mass2vector) 331 fcmatrix = cbind(foldchange, coord(msidata)[,1:2])
330 fcmatrix = cbind(foldchange, coord(msidata)[,1:2]) 332
331 333 print(ggplot(fcmatrix, aes(x=x, y=y, fill=foldchange))+
332 print(ggplot(fcmatrix, aes(x=x, y=y, fill=foldchange), colour=colo)+ 334 geom_tile() + coord_fixed()+
333 geom_tile() + coord_fixed()+ 335 ggtitle("$label")+
334 ggtitle("$label")+ 336 theme_bw()+
335 theme_bw()+ 337 theme(plot.title = element_text(hjust = 0.5))+
336 theme(plot.title = element_text(hjust = 0.5))+ 338 theme(text=element_text(family="ArialMT", face="bold", size=12))+
337 theme(text=element_text(family="ArialMT", face="bold", size=12))+ 339 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange")
338 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange") 340 ,space = "Lab", na.value = "black", name ="FC"))
339 ,space = "Lab", na.value = "black", name ="FC")) 341
340 }else{ 342 ## remove FC files to clean up RAM space
341 plot(0,type='n',axes=FALSE,ann=FALSE) 343 rm(fcmatrix)
342 title(main=paste("At least one m/z range did not contain any intensity > 0,\n therefore no foldchange plot could be drawn"))} 344 rm(filtered_data1)
345 rm(filtered_data2)
346 gc()
343 347
344 #end for 348 #end for
345 #end if 349 #end if
346 350
347 #################### 4) m/z heatmaps ####################################### 351 #################### 4) m/z heatmaps #######################################
351 for (mass in 1:length(inputcalibrants[,1])){ 355 for (mass in 1:length(inputcalibrants[,1])){
352 356
353 357
354 image(msidata, mz=inputcalibrants[,1][mass], plusminus=plusminusvalues[mass], 358 image(msidata, mz=inputcalibrants[,1][mass], plusminus=plusminusvalues[mass],
355 main= paste0(inputcalibrants[,2][mass], ": ", round(inputcalibrants[,1][mass], digits = 2)," (±",$plusminus_ppm, " ppm)"), 359 main= paste0(inputcalibrants[,2][mass], ": ", round(inputcalibrants[,1][mass], digits = 2)," (±",$plusminus_ppm, " ppm)"),
356 contrast.enhance = "histogram", ylim= c(maximumy+0.2*maximumy,minimumy-0.2*minimumy)) 360 contrast.enhance = "histogram", ylim= c(maximumy+0.2*maximumy,minimumy-1))
357 } 361 }
358 } else {print("4) The input peptide and calibrant m/z were not provided or outside the m/z range")} 362 } else {print("4) The input peptide and calibrant m/z were not provided or outside the m/z range")}
359 363
360 #################### 5) Number of peaks per pixel - image ################## 364 #################### 5) Number of peaks per pixel - image ##################
361 365
370 theme(plot.title = element_text(hjust = 0.5))+ 374 theme(plot.title = element_text(hjust = 0.5))+
371 theme(text=element_text(family="ArialMT", face="bold", size=12))+ 375 theme(text=element_text(family="ArialMT", face="bold", size=12))+
372 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange") 376 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange")
373 ,space = "Lab", na.value = "black", name = "# peaks")) 377 ,space = "Lab", na.value = "black", name = "# peaks"))
374 378
379 ## remove peakscoordarray to clean up RAM space
380 rm(peakscoordarray)
381 gc()
382
375 383
376 ############################### 6) TIC image ############################### 384 ############################### 6) TIC image ###############################
377 385
378 TICcoordarray=cbind(coord(msidata)[,1:2], TICs) 386 TICcoordarray=cbind(coord(msidata)[,1:2], TICs)
379 387
384 theme(plot.title = element_text(hjust = 0.5))+ 392 theme(plot.title = element_text(hjust = 0.5))+
385 theme(text=element_text(family="ArialMT", face="bold", size=12))+ 393 theme(text=element_text(family="ArialMT", face="bold", size=12))+
386 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange") 394 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange")
387 ,space = "Lab", na.value = "black", name = "TIC")) 395 ,space = "Lab", na.value = "black", name = "TIC"))
388 396
397 ## remove TICcoordarray to clean up RAM space
398 rm(TICcoordarray)
399 gc()
400
389 ############################### 6b) median int image ############################### 401 ############################### 6b) median int image ###############################
390 402
391 median_int = apply(spectra(msidata)[],2,median) 403 median_int = apply(spectra(msidata)[],2,median)
392 median_coordarray=cbind(coord(msidata)[,1:2], median_int) 404 median_coordarray=cbind(coord(msidata)[,1:2], median_int)
405
393 print(ggplot(median_coordarray, aes(x=x, y=y, fill=median_int))+ 406 print(ggplot(median_coordarray, aes(x=x, y=y, fill=median_int))+
394 geom_tile() + coord_fixed() + 407 geom_tile() + coord_fixed() +
395 ggtitle("Median intensity per pixel")+ 408 ggtitle("Median intensity per spectrum")+
396 theme_bw() + 409 theme_bw() +
397 theme(plot.title = element_text(hjust = 0.5))+ 410 theme(plot.title = element_text(hjust = 0.5))+
398 theme(text=element_text(family="ArialMT", face="bold", size=12))+ 411 theme(text=element_text(family="ArialMT", face="bold", size=12))+
399 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange") 412 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange")
400 ,space = "Lab", na.value = "black", name = "median\nintensity")) 413 ,space = "Lab", na.value = "black", name = "median\nintensity"))
401 414
402 415 ## remove median_coordarray to clean up RAM space
416 rm(median_coordarray)
417 gc()
418
419 ############################### 6c) max int image ###############################
420
421 max_int = apply(spectra(msidata)[],2,max)
422 max_coordarray=cbind(coord(msidata)[,1:2], max_int)
423
424 print(ggplot(max_coordarray, aes(x=x, y=y, fill=max_int))+
425 geom_tile() + coord_fixed() +
426 ggtitle("Maximum intensity per spectrum")+
427 theme_bw() +
428 theme(plot.title = element_text(hjust = 0.5))+
429 theme(text=element_text(family="ArialMT", face="bold", size=12))+
430 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange")
431 ,space = "Lab", na.value = "black", name = "max\nintensity"))
432
433 ## remove median_coordarray to clean up RAM space
434 rm(max_coordarray)
435 gc()
403 436
404 ############################### 7) Most abundant m/z image ################# 437 ############################### 7) Most abundant m/z image #################
405 438
406 highestmz = apply(spectra(msidata)[],2,which.max) 439 ## for each spectrum find the row (m/z) with the highest intensity
440 highestmz = apply(spectra(msidata)[],2,which.max)
441 ## in case for some spectra max returns integer(0), highestmz is a list and integer(0) have to be replaced with NA and unlisted
442 if (class(highestmz) == "list"){
443 ##find zero-length values
444 zero_entry <- !(sapply(highestmz, length))
445 ### replace these values with NA
446 highestmz[zero_entry] <- NA
447 ### unlist list to get a vector
448 highestmz = unlist(highestmz)}
449
407 highestmz_matrix = cbind(coord(msidata)[,1:2],mz(msidata)[highestmz]) 450 highestmz_matrix = cbind(coord(msidata)[,1:2],mz(msidata)[highestmz])
408 colnames(highestmz_matrix)[3] = "highestmzinDa" 451 colnames(highestmz_matrix)[3] = "highestmzinDa"
409 452
410 print(ggplot(highestmz_matrix, aes(x=x, y=y, fill=highestmzinDa))+ 453 print(ggplot(highestmz_matrix, aes(x=x, y=y, fill=highestmzinDa))+
411 geom_tile() + coord_fixed() + 454 geom_tile() + coord_fixed() +
414 theme(plot.title = element_text(hjust = 0.5))+ 457 theme(plot.title = element_text(hjust = 0.5))+
415 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange"), space = "Lab", na.value = "black", name = "m/z", 458 scale_fill_gradientn(colours = c("blue", "purple" , "red","orange"), space = "Lab", na.value = "black", name = "m/z",
416 limits=c(min(highestmz_matrix\$highestmzinDa), max(highestmz_matrix\$highestmzinDa)))+ 459 limits=c(min(highestmz_matrix\$highestmzinDa), max(highestmz_matrix\$highestmzinDa)))+
417 theme(text=element_text(family="ArialMT", face="bold", size=12))) 460 theme(text=element_text(family="ArialMT", face="bold", size=12)))
418 461
462 ## remove highestmz_matrix to clean up RAM space
463 rm(highestmz_matrix)
464 gc()
465
419 466
420 ########################## 8) optional pca image for two components ################# 467 ########################## 8) optional pca image for two components #################
421 468
422 #if $do_pca: 469 #if $do_pca:
423 470
424 set.seed(1) 471 set.seed(1)
425 pca = PCA(msidata, ncomp=2) 472 pca = PCA(msidata, ncomp=2)
473
474 ## plot overview image and plot and PC1 and 2 images
426 par(mfrow = c(2,1)) 475 par(mfrow = c(2,1))
427 plot(pca, col=c("black", "darkgrey"), main="PCA for two components") 476 plot(pca, col=c("black", "darkgrey"), main="PCA for two components")
428 image(pca, col=c("black", "white"), strip=FALSE, ylim= c(maximumy+0.2*maximumy,minimumy-0.2*minimumy)) 477 image(pca, col=c("black", "white"), strip=FALSE, ylim= c(maximumy+0.2*maximumy,minimumy-1))
478
479 for (PCs in 1:2){
480 print(image(pca, column = c(paste0("PC",PCs)) , superpose = FALSE, col.regions = risk.colors(100), ylim=c(maximumy+2, minimumy-2)))}
481
482 ## remove pca to clean up RAM space
483 rm(pca)
484 gc()
429 485
430 #end if 486 #end if
431 487
432 ################## III) properties over spectra index ###################### 488 ################## III) properties over spectra index ######################
433 ############################################################################ 489 ############################################################################
471 527
472 ########################## 10) TIC per spectrum ########################### 528 ########################## 10) TIC per spectrum ###########################
473 529
474 ## 10a)density scatterplot 530 ## 10a)density scatterplot
475 par(mfrow = c(2,1), mar=c(5,6,4,2)) 531 par(mfrow = c(2,1), mar=c(5,6,4,2))
476 532
477 plot_colorByDensity(pixels(msidata), TICs, ylab = "", xlab = "", main="TIC per spectrum") 533 ## colorDensityplot does not work after TIC normalization, therefore make normal plot
534 if (min(TICs) == max(TICs)){
535 plot(pixels(msidata), TICs, ylab = "", xlab = "", pch=20, main="TIC per spectrum", col="#FF3100")
536 }else{
537 plot_colorByDensity(pixels(msidata), TICs, ylab = "", xlab = "", main="TIC per spectrum")
538 }
539
478 title(xlab="Spectra index", line=3) 540 title(xlab="Spectra index", line=3)
479 title(ylab = "Total ion chromatogram intensity", line=4) 541 title(ylab = "Total ion chromatogram intensity", line=4)
480 if (!is.null(levels(msidata\$annotation))){ 542 if (!is.null(levels(msidata\$annotation))){
481 abline(v=abline_vector, lty = 3)} 543 abline(v=abline_vector, lty = 3)}
482 544
483 ## 10b) histogram 545 ## 10b) histogram
484 hist(log(TICs), main="", las=1, xlab = "log(TIC per spectrum)", ylab="") 546 hist((TICs), main="", las=1, xlab = "TIC per spectrum", ylab="")
485 title(main= "TIC per spectrum", line=2) 547 title(main= "TIC per spectrum", line=2)
486 title(ylab="Frequency = # spectra", line=4) 548 title(ylab="Frequency = # spectra", line=4)
487 abline(v=median(log(TICs[TICs>0])), col="blue") 549 abline(v=median(TICs[TICs>0]), col="blue")
488 550
489 ## 10c) additional histogram to show annotation contributions 551 ## 10c) additional histogram to show annotation contributions
490 if (!is.null(levels(msidata\$annotation))){ 552 if (!is.null(levels(msidata\$annotation))){
491 df_10 = data.frame(log(TICs), msidata\$annotation) 553 df_10 = data.frame((TICs), msidata\$annotation)
492 colnames(df_10) = c("TICs", "annotation") 554 colnames(df_10) = c("TICs", "annotation")
493 555
494 hist_10 = ggplot(df_10, aes(x=TICs, fill=annotation)) + 556 hist_10 = ggplot(df_10, aes(x=TICs, fill=annotation)) +
495 geom_histogram()+ theme_bw()+ 557 geom_histogram()+ theme_bw()+
496 theme(text=element_text(family="ArialMT", face="bold", size=12))+ 558 theme(text=element_text(family="ArialMT", face="bold", size=12))+
497 theme(plot.title = element_text(hjust = 0.5))+ 559 theme(plot.title = element_text(hjust = 0.5))+
498 theme(legend.position="bottom",legend.direction="vertical")+ 560 theme(legend.position="bottom",legend.direction="vertical")+
499 theme(legend.key.size = unit(0.2, "line"), legend.text = element_text(size = 8))+ 561 theme(legend.key.size = unit(0.2, "line"), legend.text = element_text(size = 8))+
500 labs(title="TIC per spectrum and annotation group", x="log(TIC per spectrum)", y = "Frequency = # spectra") + 562 labs(title="TIC per spectrum and annotation group", x="TIC per spectrum", y = "Frequency = # spectra") +
501 guides(fill=guide_legend(ncol=5,byrow=TRUE))+ 563 guides(fill=guide_legend(ncol=5,byrow=TRUE))+
502 geom_vline(xintercept = median(log(TICs[TICs>0])), size = 1, colour = "black",linetype = "dashed") 564 geom_vline(xintercept = median(TICs[TICs>0]), size = 1, colour = "black",linetype = "dashed")
503 print(hist_10)} 565 print(hist_10)}
504 566
505 ################################## IV) properties over m/z #################### 567 ################################## IV) properties over m/z ####################
506 ############################################################################ 568 ############################################################################
507 print("properties over m/z") 569 print("properties over m/z")
539 plot_colorByDensity(mz(msidata),mzTIC, main= "Sum of intensities per m/z", ylab ="") 601 plot_colorByDensity(mz(msidata),mzTIC, main= "Sum of intensities per m/z", ylab ="")
540 title(xlab="m/z", line=2.5) 602 title(xlab="m/z", line=2.5)
541 title(ylab="Intensity sum", line=4) 603 title(ylab="Intensity sum", line=4)
542 604
543 ## 13b) histogram 605 ## 13b) histogram
544 hist(log(mzTIC), main="", xlab = "", las=1, ylab="") 606 hist(mzTIC, main="", xlab = "", las=1, ylab="")
545 title(main="Sum of intensities per m/z", line=2, ylab="") 607 title(main="Sum of intensities per m/z", line=2, ylab="")
546 title(xlab = "log (sum of intensities per m/z)") 608 title(xlab = "sum of intensities per m/z")
547 title(ylab = "Frequency", line=4) 609 title(ylab = "Frequency", line=4)
548 abline(v=median(log(mzTIC[mzTIC>0])), col="blue") 610 abline(v=median(mzTIC[mzTIC>0]), col="blue")
549 611
550 ################################## V) intensity plots ######################## 612 ################################## V) intensity plots ########################
551 ############################################################################ 613 ############################################################################
552 print("intensity plots") 614 print("intensity plots")
553 ########################## 14) Intensity distribution ###################### 615 ########################## 14) Intensity distribution ######################
561 title(ylab="Median spectrum intensity", line=4) 623 title(ylab="Median spectrum intensity", line=4)
562 if (!is.null(levels(msidata\$annotation))){ 624 if (!is.null(levels(msidata\$annotation))){
563 abline(v=abline_vector, lty = 3)} 625 abline(v=abline_vector, lty = 3)}
564 626
565 ## 14b) histogram: 627 ## 14b) histogram:
566 hist(log2(spectra(msidata)[]), main="", xlab = "", ylab="", las=1) 628 hist(spectra(msidata)[], main="", xlab = "", ylab="", las=1)
567 title(main="Log2-transformed intensities", line=2) 629 title(main="Intensity histogram", line=2)
568 title(xlab="log2 intensities") 630 title(xlab="intensities")
569 title(ylab="Frequency", line=4) 631 title(ylab="Frequency", line=4)
570 abline(v=median(log2(spectra(msidata)[(spectra(msidata)>0)]), na.rm=TRUE), col="blue") 632 abline(v=median(spectra(msidata)[(spectra(msidata)>0)], na.rm=TRUE), col="blue")
571 633
572 634
573 ## 14c) histogram to show contribution of annotation groups 635 ## 14c) histogram to show contribution of annotation groups
574 636
575 if (!is.null(levels(msidata\$annotation))){ 637 if (!is.null(levels(msidata\$annotation))){
576 638
577 df_13 = data.frame(matrix(,ncol=2, nrow=0)) 639 df_13 = data.frame(matrix(,ncol=2, nrow=0))
578 for (subsample in levels(msidata\$annotation)){ 640 for (subsample in levels(msidata\$annotation)){
579 log2_int_subsample = log2(spectra(msidata)[,msidata\$annotation==subsample]) 641 log2_int_subsample = spectra(msidata)[,msidata\$annotation==subsample]
580 df_subsample = data.frame(as.numeric(log2_int_subsample)) 642 df_subsample = data.frame(as.numeric(log2_int_subsample))
581 df_subsample\$annotation = subsample 643 df_subsample\$annotation = subsample
582 df_13 = rbind(df_13, df_subsample)} 644 df_13 = rbind(df_13, df_subsample)}
583 df_13\$annotation = as.factor(df_13\$annotation) 645 df_13\$annotation = as.factor(df_13\$annotation)
584 colnames(df_13) = c("logint", "annotation") 646 colnames(df_13) = c("int", "annotation")
585 647
586 hist_13 = ggplot(df_13, aes(x=logint, fill=annotation)) + 648 hist_13 = ggplot(df_13, aes(x=int, fill=annotation)) +
587 geom_histogram()+ theme_bw()+ 649 geom_histogram()+ theme_bw()+
588 theme(text=element_text(family="ArialMT", face="bold", size=12))+ 650 theme(text=element_text(family="ArialMT", face="bold", size=12))+
589 labs(title="Log2-transformed intensities per sample", x="log2 intensities", y = "Frequency") + 651 labs(title="Intensities per sample", x="intensities", y = "Frequency") +
590 theme(plot.title = element_text(hjust = 0.5))+ 652 theme(plot.title = element_text(hjust = 0.5))+
591 theme(legend.position="bottom",legend.direction="vertical")+ 653 theme(legend.position="bottom",legend.direction="vertical")+
592 theme(legend.key.size = unit(0.2, "line"), legend.text = element_text(size = 8))+ 654 theme(legend.key.size = unit(0.2, "line"), legend.text = element_text(size = 8))+
593 guides(fill=guide_legend(ncol=5,byrow=TRUE))+ 655 guides(fill=guide_legend(ncol=5,byrow=TRUE))+
594 geom_vline(xintercept = median(log2(spectra(msidata)[(spectra(msidata)>0)])), size = 1, colour = "black",linetype = "dashed") 656 geom_vline(xintercept = median(spectra(msidata)[(spectra(msidata)>0)]), size = 1, colour = "black",linetype = "dashed")
595 print(hist_13) 657 print(hist_13)
596 658
597 ## 14d) boxplots to visualize in a different way the intensity distributions 659 ## 14d) boxplots to visualize in a different way the intensity distributions
598 par(mfrow = c(1,1), cex.axis=1.3, cex.lab=1.3, mar=c(13.1,4.1,5.1,2.1)) 660 par(mfrow = c(1,1), cex.axis=1.3, cex.lab=1.3, mar=c(13.1,4.1,5.1,2.1))
599 661
600 mean_matrix = matrix(,ncol=0, nrow = nrow(msidata)) 662 mean_matrix = matrix(,ncol=0, nrow = nrow(msidata))
601 for (subsample in levels(msidata\$annotation)){ 663 for (subsample in levels(msidata\$annotation)){
602 mean_mz_sample = rowMeans(spectra(msidata)[,msidata\$annotation==subsample],na.rm=TRUE) 664 mean_mz_sample = rowMeans(spectra(msidata)[,msidata\$annotation==subsample],na.rm=TRUE)
603 mean_matrix = cbind(mean_matrix, mean_mz_sample)} 665 mean_matrix = cbind(mean_matrix, mean_mz_sample)}
604 666
605 boxplot(log2(mean_matrix), ylab = "log2 mean intensity per m/z", main="Mean m/z intensities per annotation group", xaxt = "n") 667 boxplot(mean_matrix, ylab = "Mean intensity per m/z", main="Mean m/z intensities per annotation group", xaxt = "n")
606 (axis(1, at = c(1:number_combined), labels=levels(msidata\$annotation), las=2)) 668 (axis(1, at = c(1:number_combined), labels=levels(msidata\$annotation), las=2))
607 669
608 ## 14e) Heatmap of pearson correlation on mean intensities between annotation groups 670 ## 14e) Heatmap of pearson correlation on mean intensities between annotation groups
609 671
610 corr_matrix = mean_matrix 672 corr_matrix = mean_matrix
611 corr_matrix[corr_matrix == 0] <- NA 673 corr_matrix[corr_matrix == 0] <- NA
612 colnames(corr_matrix) = levels(msidata\$annotation) 674 colnames(corr_matrix) = levels(msidata\$annotation)
613 corr_matrix = cor(log2(corr_matrix), method= "pearson",use="complete.obs") 675 ## pearson correlation is only possible if there are at least 2 groups
614 676 if (length(colnames)>1)
615 heatmap.parameters <- list(corr_matrix, 677 {
616 show_rownames = T, show_colnames = T, 678 corr_matrix = cor(corr_matrix, method= "pearson",use="complete.obs")
617 main = "Pearson correlation on mean intensities") 679
618 do.call("pheatmap", heatmap.parameters) 680 heatmap.parameters <- list(corr_matrix,
681 show_rownames = T, show_colnames = T,
682 main = "Pearson correlation on mean intensities")
683 do.call("pheatmap", heatmap.parameters)
684 }
619 } 685 }
620 686
621 ################################## VI) Mass spectra and m/z accuracy ######################## 687 ################################## VI) Mass spectra and m/z accuracy ########################
622 ############################################################################ 688 ############################################################################
623 print("Mass spectra and m/z accuracy") 689 print("Mass spectra and m/z accuracy")
624 690
625 ############################ 15) Mass spectra ############################## 691 ############################ 15) Mass spectra ##############################
626 692
627 ## find three random pixel to plot their spectra in the following plots: 693 ## replace any NA with 0, otherwise plot function will not work at all
694 msidata_no_NA = msidata
695 spectra(msidata_no_NA)[is.na(spectra(msidata_no_NA)[])] = 0
696
697 ## find three equal m/z ranges for the average mass spectra plots:
698 third_mz_range = nrow(msidata_no_NA)/3
699
700 par(mfrow = c(2, 2), cex.axis=1, cex.lab=1, mar=c(5.1,4.1,4.1,2.1))
701 plot(msidata_no_NA, pixel = 1:ncol(msidata_no_NA), main= "Average spectrum")
702 plot(msidata_no_NA[1:third_mz_range,], pixel = 1:ncol(msidata_no_NA), main= "Zoomed average spectrum")
703 plot(msidata_no_NA[third_mz_range:(2*third_mz_range),], pixel = 1:ncol(msidata_no_NA), main= "Zoomed average spectrum")
704 plot(msidata_no_NA[(2*third_mz_range):nrow(msidata_no_NA),], pixel = 1:ncol(msidata_no_NA), main= "Zoomed average spectrum")
705
706 ## plot 4 random mass spectra
707 ## find four random pixel to plot their spectra in the following plots:
628 pixel1 = sample(pixelnumber,1) 708 pixel1 = sample(pixelnumber,1)
629 pixel2 = sample(pixelnumber,1) 709 pixel2 = sample(pixelnumber,1)
630 pixel3 = sample(pixelnumber,1) 710 pixel3 = sample(pixelnumber,1)
631 711 pixel4 = sample(pixelnumber,1)
632 ## replace any NA with 0, otherwise plot function will not work at all
633 msidata_no_NA = msidata
634 spectra(msidata_no_NA)[is.na(spectra(msidata_no_NA)[])] = 0
635 712
636 par(mfrow = c(2, 2), cex.axis=1, cex.lab=1, mar=c(5.1,4.1,4.1,2.1)) 713 par(mfrow = c(2, 2), cex.axis=1, cex.lab=1, mar=c(5.1,4.1,4.1,2.1))
637 plot(msidata_no_NA, pixel = 1:ncol(msidata_no_NA), main= "Average spectrum")
638 plot(msidata_no_NA, pixel = pixel1, main=paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel1,1:2]))) 714 plot(msidata_no_NA, pixel = pixel1, main=paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel1,1:2])))
639 plot(msidata_no_NA, pixel = pixel2, main= paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel2,1:2]))) 715 plot(msidata_no_NA, pixel = pixel2, main=paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel2,1:2])))
640 plot(msidata_no_NA, pixel = pixel3, main= paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel3,1:2]))) 716 plot(msidata_no_NA, pixel = pixel3, main= paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel3,1:2])))
717 plot(msidata_no_NA, pixel = pixel4, main= paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel4,1:2])))
641 718
642 ################### 16) Zoomed in mass spectra for calibrants ############## 719 ################### 16) Zoomed in mass spectra for calibrants ##############
643 720
644 count = 1 721 count = 1
645 differencevector = numeric() 722 differencevector = numeric()
651 plusminusvalues = rep($plusminus_ppm/1000000, length(inputcalibrantmasses)) * inputcalibrantmasses 728 plusminusvalues = rep($plusminus_ppm/1000000, length(inputcalibrantmasses)) * inputcalibrantmasses
652 729
653 for (mass in 1:length(inputcalibrantmasses)){ 730 for (mass in 1:length(inputcalibrantmasses)){
654 731
655 ### define the plot window with xmin und xmax 732 ### define the plot window with xmin und xmax
656 minmasspixel = features(msidata_no_NA, mz=inputcalibrantmasses[mass]-0.5) 733 minmasspixel1 = features(msidata_no_NA, mz=inputcalibrantmasses[mass]-0.5)
657 maxmasspixel = features(msidata_no_NA, mz=inputcalibrantmasses[mass]+1.5) 734 maxmasspixel1 = features(msidata_no_NA, mz=inputcalibrantmasses[mass]+1.5)
735 minmasspixel2 = features(msidata_no_NA, mz=inputcalibrantmasses[mass]-0.25)
736 maxmasspixel2 = features(msidata_no_NA, mz=inputcalibrantmasses[mass]+0.5)
737 minmasspixel3 = features(msidata_no_NA, mz=inputcalibrantmasses[mass]-3)
738 maxmasspixel3 = features(msidata_no_NA, mz=inputcalibrantmasses[mass]+3)
658 739
659 ### find m/z with the highest mean intensity in m/z range (red line in plot 16) and calculate ppm difference for plot 17 740 ### find m/z with the highest mean intensity in m/z range (red line in plot 16) and calculate ppm difference for plot 17
660 filtered_data = msidata_no_NA[mz(msidata_no_NA) >= inputcalibrantmasses[mass]-plusminusvalues[mass] & mz(msidata_no_NA) <= inputcalibrantmasses[mass]+plusminusvalues[mass],] 741 filtered_data = msidata_no_NA[mz(msidata_no_NA) >= inputcalibrantmasses[mass]-plusminusvalues[mass] & mz(msidata_no_NA) <= inputcalibrantmasses[mass]+plusminusvalues[mass],]
661 742
662 if (nrow(filtered_data) > 0 & sum(spectra(filtered_data)) > 0){ 743 if (nrow(filtered_data) > 0 & sum(spectra(filtered_data)) > 0){
677 differencevector2[mass] = round(ppmdifference2, digits=2) 758 differencevector2[mass] = round(ppmdifference2, digits=2)
678 759
679 ## plotting of 4 spectra in one page 760 ## plotting of 4 spectra in one page
680 par(mfrow = c(2, 2), oma=c(0,0,2,0)) 761 par(mfrow = c(2, 2), oma=c(0,0,2,0))
681 ## average plot 762 ## average plot
682 plot(msidata_no_NA[minmasspixel:maxmasspixel,], pixel = 1:length(pixelnumber), main= "Average spectrum") 763 plot(msidata_no_NA[minmasspixel1:maxmasspixel1,], pixel = 1:length(pixelnumber), main= "Average spectrum")
683 abline(v=c(inputcalibrantmasses[mass] -plusminusvalues[count], inputcalibrantmasses[mass] ,inputcalibrantmasses[mass] +plusminusvalues[count]), col="blue", lty=c(3,5,3)) 764 abline(v=c(inputcalibrantmasses[mass] -plusminusvalues[count], inputcalibrantmasses[mass] ,inputcalibrantmasses[mass] +plusminusvalues[count]), col="blue", lty=c(3,5,3))
684 abline(v=c(maxvalue), col="red", lty=2) 765 abline(v=c(maxvalue), col="red", lty=2)
685 abline(v=c(mzvalue), col="green2", lty=4) 766 abline(v=c(mzvalue), col="green2", lty=4)
686 ## average plot including points per data point 767 ## average plot including points per data point
687 plot(msidata_no_NA[minmasspixel:maxmasspixel,], pixel = 1:length(pixelnumber), main="Average spectrum with data points") 768 plot(msidata_no_NA[minmasspixel1:maxmasspixel1,], pixel = 1:length(pixelnumber), main="Average spectrum with data points")
688 points(mz(msidata_no_NA[minmasspixel:maxmasspixel,]), rowMeans(spectra(msidata_no_NA)[minmasspixel:maxmasspixel,]), col="blue", pch=20) 769 points(mz(msidata_no_NA[minmasspixel1:maxmasspixel1,]), rowMeans(spectra(msidata_no_NA)[minmasspixel1:maxmasspixel1,]), col="blue", pch=20)
689 ## plot of a random pixel (1) 770 ## plot of third average plot
690 plot(msidata_no_NA[minmasspixel:maxmasspixel,], pixel = pixel2, main= paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel2,1:2]))) 771 plot(msidata_no_NA[minmasspixel2:maxmasspixel2,], pixel = 1:length(pixelnumber), main= "Average spectrum")
691 abline(v=c(inputcalibrantmasses[mass] -plusminusvalues[count], inputcalibrantmasses[mass] ,inputcalibrantmasses[mass] +plusminusvalues[count]), col="blue", lty=c(3,5,3)) 772 abline(v=c(inputcalibrantmasses[mass] -plusminusvalues[count], inputcalibrantmasses[mass] ,inputcalibrantmasses[mass] +plusminusvalues[count]), col="blue", lty=c(3,5,3))
692 abline(v=c(maxvalue), col="red", lty=2) 773 abline(v=c(maxvalue), col="red", lty=2)
693 abline(v=c(mzvalue), col="green2", lty=4) 774 abline(v=c(mzvalue), col="green2", lty=4)
694 ## plot of a random pixel (2) 775 ## plot of fourth average plot
695 plot(msidata_no_NA[minmasspixel:maxmasspixel,], pixel = pixel3, main= paste0("Spectrum at ", rownames(coord(msidata_no_NA)[pixel3,1:2]))) 776 plot(msidata_no_NA[minmasspixel3:maxmasspixel3,], pixel = 1:length(pixelnumber), main= "Average spectrum")
696 abline(v=c(inputcalibrantmasses[mass] -plusminusvalues[count], inputcalibrantmasses[mass] ,inputcalibrantmasses[mass] +plusminusvalues[count]), col="blue", lty=c(3,5,3)) 777 abline(v=c(inputcalibrantmasses[mass] -plusminusvalues[count], inputcalibrantmasses[mass] ,inputcalibrantmasses[mass] +plusminusvalues[count]), col="blue", lty=c(3,5,3))
697 abline(v=c(maxvalue), col="red", lty=2) 778 abline(v=c(maxvalue), col="red", lty=2)
698 abline(v=c(mzvalue), col="green2", lty=4) 779 abline(v=c(mzvalue), col="green2", lty=4)
699 title(paste0("theor. m/z: ", round(inputcalibrants[count,1], digits=4)), col.main="blue", outer=TRUE, line=0, adj=0.074) 780 title(paste0("theor. m/z: ", round(inputcalibrants[count,1], digits=4)), col.main="blue", outer=TRUE, line=0, adj=0.074)
700 title(paste0("most abundant m/z: ", round(maxvalue, digits=4)), col.main="red", outer=TRUE, line=0, adj=0.49) 781 title(paste0("most abundant m/z: ", round(maxvalue, digits=4)), col.main="red", outer=TRUE, line=0, adj=0.49)
705 if (!is.null(levels(msidata\$annotation))){ 786 if (!is.null(levels(msidata\$annotation))){
706 if (number_combined < 10){ 787 if (number_combined < 10){
707 key_zoomed = TRUE 788 key_zoomed = TRUE
708 }else{key_zoomed = FALSE} 789 }else{key_zoomed = FALSE}
709 par(mfrow = c(1, 1)) 790 par(mfrow = c(1, 1))
710 plot(msidata_no_NA[minmasspixel:maxmasspixel,], pixel=1:ncol(msidata_no_NA),main="Average spectrum per annotation group", 791 plot(msidata_no_NA[minmasspixel1:maxmasspixel1,], pixel=1:ncol(msidata_no_NA),main="Average spectrum per annotation group",
711 pixel.groups=msidata\$annotation, key=key_zoomed, col=hue_pal()(number_combined),superpose=TRUE) 792 pixel.groups=msidata\$annotation, key=key_zoomed, col=hue_pal()(number_combined),superpose=TRUE)
712 abline(v=c(inputcalibrantmasses[mass] -plusminusvalues[count], inputcalibrantmasses[mass] ,inputcalibrantmasses[mass] +plusminusvalues[count]), col="black", lty=c(3,1,3)) 793 abline(v=c(inputcalibrantmasses[mass] -plusminusvalues[count], inputcalibrantmasses[mass] ,inputcalibrantmasses[mass] +plusminusvalues[count]), col="black", lty=c(3,1,3))
713 } 794 }
714 count=count+1 795 count=count+1
715 } 796 }
716 797
798 ## remove msidata_no_NA to clean up RAM space
799 rm(msidata_no_NA)
800 gc()
801
717 ######### 17) ppm difference input calibrant m/z and m/z with max intensity in given m/z range######### 802 ######### 17) ppm difference input calibrant m/z and m/z with max intensity in given m/z range#########
718 803
719 par(mfrow = c(1,1)) 804 par(mfrow = c(1,1))
720 ### plot the ppm difference calculated above: theor. m/z value to highest m/z value: 805 ### plot the ppm difference calculated above: theor. m/z value to highest m/z value:
721 806
753 print(diff_plot2) 838 print(diff_plot2)
754 839
755 #################### 19) ppm difference over pixels ##################### 840 #################### 19) ppm difference over pixels #####################
756 841
757 par(mfrow = c(1,1)) 842 par(mfrow = c(1,1))
758 mycolours = c("darkgrey", "darkblue", "blue", "green" , "red", "orange", "yellow", "magenta", "olivedrab1", "lightseagreen")
759 count = 1 843 count = 1
760 ppm_df = as.data.frame(matrix(,ncol=0, nrow = ncol(msidata))) 844 ppm_df = as.data.frame(matrix(,ncol=0, nrow = ncol(msidata)))
761 for (calibrant in inputcalibrantmasses){ 845 for (calibrant in inputcalibrantmasses){
762 ### find m/z with the highest mean intensity in m/z range, if no m/z in the range, ppm differences for this calibrant will be NA 846 ### find m/z with the highest mean intensity in m/z range, if no m/z in the range, ppm differences for this calibrant will be NA
763 filtered_data = msidata[mz(msidata) >= calibrant-plusminusvalues[count] & mz(msidata) <= calibrant+plusminusvalues[count],] 847 filtered_data = msidata[mz(msidata) >= calibrant-plusminusvalues[count] & mz(msidata) <= calibrant+plusminusvalues[count],]
764 848
765 if (nrow(filtered_data) > 0){ 849 if (nrow(filtered_data) > 0){
766 ### filtered for m/z range, find max peak in each spectrum (pixel)( 850 ### filtered for m/z range, find max peak in each spectrum
767 ppm_vector = numeric() 851 ppm_vector = numeric()
768 for (pixel_count in 1:ncol(filtered_data)){ 852 for (pixel_count in 1:ncol(filtered_data)){
853 ## for each spectrum (pixel_count) find the m/z that has the highest intensity
769 mz_max = mz(filtered_data)[which.max(spectra(filtered_data)[,pixel_count])] 854 mz_max = mz(filtered_data)[which.max(spectra(filtered_data)[,pixel_count])]
770
771 mzdiff = mz_max - calibrant 855 mzdiff = mz_max - calibrant
772 ppmdiff = mzdiff/calibrant*1000000 856 ppmdiff = mzdiff/calibrant*1000000
773 857
774 ### if maximum intensity in m/z range was 0 set ppm diff to NA (not shown in plot) 858 ### if maximum intensity in m/z range was 0 set ppm diff to NA (not shown in plot)
775 if (max(spectra(filtered_data)[,pixel_count]) == 0){ 859 if (max(spectra(filtered_data)[,pixel_count]) == 0 || is.na(max(spectra(filtered_data)[,pixel_count]))){
776 ppmdiff = NA} 860 ppmdiff = NA}
777 ppm_vector[pixel_count] = ppmdiff} 861 ppm_vector[pixel_count] = ppmdiff}
778 862
779 }else{ 863 }else{
780 ppm_vector = rep(NA, ncol(msidata)) 864 ppm_vector = rep(NA, ncol(msidata))
796 for (each_cal in 1:ncol(ppm_df)){ 880 for (each_cal in 1:ncol(ppm_df)){
797 lines(ppm_df[,each_cal], col=mycolours[each_cal], type="p")} 881 lines(ppm_df[,each_cal], col=mycolours[each_cal], type="p")}
798 legend("topright", inset=c(-0.2,0), xpd = TRUE, bty="n", cex=0.8,legend=inputcalibrantmasses, col=mycolours[1:ncol(ppm_df)],lty=1) 882 legend("topright", inset=c(-0.2,0), xpd = TRUE, bty="n", cex=0.8,legend=inputcalibrantmasses, col=mycolours[1:ncol(ppm_df)],lty=1)
799 if (!is.null(levels(msidata\$annotation))){ 883 if (!is.null(levels(msidata\$annotation))){
800 abline(v=abline_vector, lty = 3)}} 884 abline(v=abline_vector, lty = 3)}}
885
886 ### make x-y-images for mz accuracy
887
888 ppm_dataframe = cbind(coord(msidata)[,1:2], ppm_df)
889
890 for (each_cal in 1:ncol(ppm_df)){
891 tmp_ppm = ppm_dataframe[,c(1,2,each_cal+2)]
892 tmp_ppm[,3] = as.numeric(tmp_ppm[,3])
893 colnames(tmp_ppm) = c("x","y", "ppm_each_cal")
894
895 print(ggplot(tmp_ppm, aes(x=x, y=y, fill=ppm_each_cal))+
896 geom_tile() + coord_fixed() +
897 ggtitle(paste0("m/z accuracy for ",inputcalibrants[,2][each_cal]))+
898 theme_bw() +
899 theme(plot.title = element_text(hjust = 0.5))+
900 theme(text=element_text(family="ArialMT", face="bold", size=12))+
901 scale_fill_gradient2(low = "navy", mid = "white", high = "red", midpoint = 0 ,space = "Lab", na.value = "black", name = "ppm\nerror"))}
902
801 903
802 }else{print("plot 16+17+18+19) The inputcalibrant m/z were not provided or outside the m/z range")} 904 }else{print("plot 16+17+18+19) The inputcalibrant m/z were not provided or outside the m/z range")}
803 }else{ 905 }else{
804 print("inputfile has no intensities > 0") 906 print("inputfile has no intensities > 0")
805 } 907 }
825 <param name="plusminus_ppm" value="200" type="float" label="ppm range" help="Will be added in both directions to input calibrant m/z"/> 927 <param name="plusminus_ppm" value="200" type="float" label="ppm range" help="Will be added in both directions to input calibrant m/z"/>
826 <param name="do_pca" type="boolean" label="PCA with 2 components"/> 928 <param name="do_pca" type="boolean" label="PCA with 2 components"/>
827 <repeat name="calibrantratio" title="Plot fold change of two m/z" min="0" max="10"> 929 <repeat name="calibrantratio" title="Plot fold change of two m/z" min="0" max="10">
828 <param name="mass1" value="1111" type="float" label="M/z 1" help="First m/z"/> 930 <param name="mass1" value="1111" type="float" label="M/z 1" help="First m/z"/>
829 <param name="mass2" value="2222" type="float" label="M/z 2" help="Second m/z"/> 931 <param name="mass2" value="2222" type="float" label="M/z 2" help="Second m/z"/>
830 <param name="distance" value="0.25" type="float" label="M/z range" help="Plusminus m/z window added to input m/z. In both m/z ranges the maximum intensity is used to calculate the fold change"/> 932 <param name="distance" value="200" type="float" label="ppm range" help="Will be added in both directions to input calibrant m/z and intensities will be averaged in this range."/>
831 <param name="filenameratioplot" type="text" optional="true" label="Title" help="Optional title for fold change plot."> 933 <param name="filenameratioplot" type="text" optional="true" label="Title" help="Optional title for fold change plot.">
832 <sanitizer invalid_char=""> 934 <sanitizer invalid_char="">
833 <valid initial="string.ascii_letters,string.digits"> 935 <valid initial="string.ascii_letters,string.digits">
834 <add value="_" /> 936 <add value="_" />
835 </valid> 937 </valid>
836 </sanitizer> 938 </sanitizer>
837 </param> 939 </param>
838 </repeat> 940 </repeat>
839 <param name="pixel_output" type="boolean" label="Tabular output with spectra information"/>
840 </inputs> 941 </inputs>
841 <outputs> 942 <outputs>
842 <data format="pdf" name="QC_report" from_work_dir="qualitycontrol.pdf" label = "${tool.name} on ${on_string}"/> 943 <data format="pdf" name="QC_report" from_work_dir="qualitycontrol.pdf" label = "${tool.name} on ${on_string}: results"/>
843 </outputs> 944 </outputs>
844 <tests> 945 <tests>
845 <test> 946 <test>
846 <expand macro="infile_imzml"/> 947 <param name="infile" value="" ftype="imzml">
948 <composite_data value="Example_Processed.imzML"/>
949 <composite_data value="Example_Processed.ibd"/>
950 </param>
847 <conditional name="processed_cond"> 951 <conditional name="processed_cond">
848 <param name="processed_file" value="processed"/> 952 <param name="processed_file" value="processed"/>
849 <param name="accuracy" value="200"/> 953 <param name="accuracy" value="200"/>
850 <param name="units" value="ppm"/> 954 <param name="units" value="ppm"/>
851 </conditional> 955 </conditional>
859 <param name="filename" value="Testfile_imzml"/> 963 <param name="filename" value="Testfile_imzml"/>
860 <param name="do_pca" value="True"/> 964 <param name="do_pca" value="True"/>
861 <repeat name="calibrantratio"> 965 <repeat name="calibrantratio">
862 <param name="mass1" value="328.9"/> 966 <param name="mass1" value="328.9"/>
863 <param name="mass2" value="398.8"/> 967 <param name="mass2" value="398.8"/>
864 <param name="distance" value="0.25"/> 968 <param name="distance" value="500"/>
865 <param name="filenameratioplot" value = "Ratio of mass1 (328.9) / mass2 (398.8)"/> 969 <param name="filenameratioplot" value = "Ratio of mass1 (328.9) / mass2 (398.8)"/>
866 </repeat> 970 </repeat>
867 <output name="QC_report" file="QC_imzml.pdf" compare="sim_size"/> 971 <output name="QC_report" file="QC_imzml.pdf" compare="sim_size"/>
868 </test> 972 </test>
869 973
917 This tool uses Cardinal to read files and create a quality control report with descriptive plots for mass spectrometry imaging data. 1021 This tool uses Cardinal to read files and create a quality control report with descriptive plots for mass spectrometry imaging data.
918 1022
919 @MSIDATA_INPUT_DESCRIPTION@ 1023 @MSIDATA_INPUT_DESCRIPTION@
920 - Coordinates stored as decimals rather than integers will be rounded to obtain a regular pixel grid. This might lead to duplicated coordinates which will be automatically removed before the tools analysis starts. 1024 - Coordinates stored as decimals rather than integers will be rounded to obtain a regular pixel grid. This might lead to duplicated coordinates which will be automatically removed before the tools analysis starts.
921 @SPECTRA_TABULAR_INPUT_DESCRIPTION@ 1025 @SPECTRA_TABULAR_INPUT_DESCRIPTION@
922 1026 - at least two different annotations should be in the annotation column
1027
923 @MZ_2COLS_TABULAR_INPUT_DESCRIPTION@ 1028 @MZ_2COLS_TABULAR_INPUT_DESCRIPTION@
1029 - maximum of 9 m/z values per run are supported
1030 - names should be unique
924 1031
925 **Options** 1032 **Options**
926 1033
927 - m/z of interest (e.g. internal calibrants) and the ppm range are used for m/z heatmaps (x-y grid), heatmap of number of calibrants per spectrum (x-y grid), zoomed in mass spectra, m/z accuracy plots 1034 - m/z of interest (e.g. internal calibrants) and the ppm range are used for m/z heatmaps (x-y grid), heatmap of number of calibrants per spectrum (x-y grid), zoomed in mass spectra, m/z accuracy plots
928 - Optional fold change plot: draws a heatmap (x-y grid) for the fold change of two m/z (log2(intensity ratio)) 1035 - Optional fold change plot: draws a heatmap (x-y grid) for the fold change of two m/z (log2(intensity ratio))
954 1061
955 - (annot) Spatial orientation of annotated pixel: All pixels of one annotation group have the same colour. 1062 - (annot) Spatial orientation of annotated pixel: All pixels of one annotation group have the same colour.
956 - Pixel order: Shows the order of the pixels in the provided file. Depending on the instrument this can represent the acquisition order. If annotation file is provided pixels are ordered according to annotation groups. 1063 - Pixel order: Shows the order of the pixels in the provided file. Depending on the instrument this can represent the acquisition order. If annotation file is provided pixels are ordered according to annotation groups.
957 - (cal) Number of calibrants per pixel: In every spectrum the calibrant m/z window (calibrant m/z plusminus 'ppm range') is searched for peaks (intensity > 0). Calibrants are considered present in a spectrum when they have at least one peak in their m/z window. 1064 - (cal) Number of calibrants per pixel: In every spectrum the calibrant m/z window (calibrant m/z plusminus 'ppm range') is searched for peaks (intensity > 0). Calibrants are considered present in a spectrum when they have at least one peak in their m/z window.
958 - (FC) Control of fold change plot: For both input m/z a zoomed in average spectrum is drawn with the input m/z as blue dashed line, the m/z range as blue dotted lines and the maximum intensity in the m/z window with a red line. 1065 - (FC) Control of fold change plot: For both input m/z a zoomed in average spectrum is drawn with the input m/z as blue dashed line, the m/z range as blue dotted lines and the maximum intensity in the m/z window with a red line.
959 - (FC) Fold change image: For each spectrum the intensities of the two optimal m/z features (red lines in control plots) are divided and log2 transformed to obtain the fold change, which is then plotted as a heatmap. 1066 - (FC) Fold change image: For each input m/z the average intensity within the given ppm range is calculated, then the log2 fold change of both average intensities is taken and plotted as heatmap.
960 - (cal) Intensity heatmaps for the m/z value that is closest to the calibrant m/z. The intensities are averaged within the calibrant m/z window (ppm range). 1067 - (cal) Intensity heatmaps for the m/z value that is closest to the calibrant m/z. The intensities are averaged within the calibrant m/z window (ppm range).
961 - Number of peaks per spectrum: For each spectrum the number of m/z values with intensity > 0 is calculated and plotted as heatmap. 1068 - Number of peaks per spectrum: For each spectrum the number of m/z values with intensity > 0 is calculated and plotted as heatmap.
962 - Total ion chromatogram: For each spectrum all intensities are summed up to obtain the TIC which is plotted as heatmap. 1069 - Total ion chromatogram: For each spectrum all intensities are summed up to obtain the TIC which is plotted as heatmap.
963 - Median intensity: For each spectrum the median intensity is plotted as heatmap. 1070 - Median intensity: For each spectrum the median intensity is plotted as heatmap.
1071 - Maximum intensity: For each spectrum the maximum intensity is plotted as heatmap.
964 - Most abundant m/z in each spectrum: For each spectrum the m/z value with the highest intensity is plotted. 1072 - Most abundant m/z in each spectrum: For each spectrum the m/z value with the highest intensity is plotted.
965 - PCA for two components: Result of a principal component analysis (PCA) for two components is given. The loading plot depicts the contribution of each m/z value and the x-y image represents the differences between the pixels. 1073 - PCA for two components: Result of a principal component analysis (PCA) for two components is given. The loading plot depicts the contribution of each m/z value and the x-y image represents the differences between the pixels, principal components 1 and 2 are also plotted as x-y image.
966 1074
967 **Properties over spectra/pixels** 1075 **Properties over spectra/pixels**
968 1076
969 - Number of peaks per spectrum: Scatter plot and histogram showing the number of intensities > 0 for each spectrum. If annotation tabular file is provided, the pixels are sorted according to annotation groups and the dotted lines in the scatter plot separate spectra of different annotation groups. 1077 - Number of peaks per spectrum: Scatter plot and histogram showing the number of intensities > 0 for each spectrum. If annotation tabular file is provided, the pixels are sorted according to annotation groups and the dotted lines in the scatter plot separate spectra of different annotation groups.
970 - (annot) Number of peaks per spectrum and annotation group: Same histogram as in plot before but with colours to show the contribution of each pixel annotation group. 1078 - (annot) Number of peaks per spectrum and annotation group: Same histogram as in plot before but with colours to show the contribution of each pixel annotation group.
971 - TIC per spectrum: Scatter plot and histogram showing the sum of all intensities per spectrum (TIC). Dotted lines in the scatter plot separate spectra of different annotation groups. 1079 - TIC per spectrum: Scatter plot and histogram showing the sum of all intensities per spectrum (TIC). Dotted lines in the scatter plot separate spectra of different annotation groups.
972 - (annot) TIC per spectrum and annotation group: Same histogram as in plot before but with colours to show the contribution of each pixel annotation group. 1080 - (annot) TIC per spectrum and annotation group: Same histogram as in plot before but with colours to show the contribution of each pixel annotation group. Only the length of the coloured bar is important and not its height from zero, as bars are added up and not overlayed.
973 1081
974 **Properties over m/z features** 1082 **Properties over m/z features**
975 1083
976 - Histogram of m/z values: Histogram of all m/z values (complete m/z axis) 1084 - Histogram of m/z values: Histogram of all m/z values (complete m/z axis)
977 - Number of peaks per m/z: Scatter plot and histogram giving the number of intensities > 0 for each m/z. 1085 - Number of peaks per m/z: Scatter plot and histogram giving the number of intensities > 0 for each m/z.
978 - Sum of intensities per m/z: Scatter plot and histogram of the sum of all intensities per m/z. 1086 - Sum of intensities per m/z: Scatter plot and histogram of the sum of all intensities per m/z.
979 1087
980 **Intensity plots** 1088 **Intensity plots**
981 1089
982 - Median intensity per spectrum: Scatter plot in which each point represents the median intensity for one spectrum. Dotted lines in the scatter plot separate spectra of different annotation groups. 1090 - Median intensity per spectrum: Scatter plot in which each point represents the median intensity for one spectrum. Dotted lines in the scatter plot separate spectra of different annotation groups.
983 - Log2-transformed intensities: Histogram of log2-transformed intensities. 1091 - Histogram of intensities.
984 - (annot) log2-transformed intensities per annotation group: Same histogram as before but with colours to show the contribution of each pixel annotation group. 1092 - (annot) Intensities per annotation group: Same histogram as before but with colours to show the contribution of each pixel annotation group.
985 - (annot) Mean intensities per m/z and annotation group: For all pixels of an annotation group the mean intensity for each m/z is calculated and shown as boxplot. 1093 - (annot) Mean intensities per m/z and annotation group: For all pixels of an annotation group the mean intensity for each m/z is calculated and shown as boxplot.
986 - (annot) Pearson correlation between annotation groups based on mean intensities and shown as heatmap. 1094 - (annot) Pearson correlation between annotation groups (needs at least 2 groups) based on mean intensities and shown as heatmap.
987 1095
988 **Mass spectra and m/z accuracy** 1096 **Mass spectra and m/z accuracy**
989 1097
990 - Mass spectra over the full m/z range: First plot shows the average intensities over all spectra. The other three mass spectra are from random individual pixels (spectra). 1098 - Average mass spectra: First plot shows the average spectrum over the full m/z range, the other three plots zoom into the m/z axis.
991 - (cal) For each calibrant four zoomed in mass spectrum are drawn: The first two mass spectra show the average intensities over all spectra and the other two specra are from random individual pixels. The theoretical calibrant m/z (taken from the input file) is represented by the dashed blue line. The dotted blue lines show the given ppm range. The green line is the m/z value that is closest to the theoretical calibrant and the red line is the m/z with the highest average intensity in the m/z window. In the second average spectra plot each blue plot indicates one data point. 1099 - (cal) For each calibrant four zoomed average mass spectrum are drawn with different zooming level. The theoretical calibrant m/z (taken from the input file) is represented by the dashed blue line. The dotted blue lines show the given ppm range. The green line is the m/z value that is closest to the theoretical calibrant and the red line is the m/z with the highest average intensity in the m/z window. In the second spectrum each blue dot indicates one data point.
992 - (annot) Average spectrum per annotation group: For each calibrant a zoomed in mass spectrum is plotted this time with the average intensities for each annotation group separately. 1100 - (annot) Average spectrum per annotation group: For each calibrant a zoomed in mass spectrum is plotted this time with the average intensities for each annotation group separately.
993 - (cal) Difference m/z with max. average intensity vs. theor. calibrant m/z: The difference in ppm between the m/z with the highest average intensity and the theoretical m/z are plotted for each calibrant. This corresponds to the difference between the dashed blue line and the red line in the zoomed in mass spectra. 1101 - (cal) Difference m/z with max. average intensity vs. theor. calibrant m/z: The difference in ppm between the m/z with the highest average intensity and the theoretical m/z are plotted for each calibrant. This corresponds to the difference between the dashed blue line and the red line in the zoomed in mass spectra.
994 - (cal) Difference closest measured m/z vs. theor. calibrant m/z: The difference in ppm between the closest m/z value and the theoretical m/z values are plotted for each calibrant. This corresponds to the difference between the dashed blue line and the green line in the zoomed in mass spectra. 1102 - (cal) Difference closest measured m/z vs. theor. calibrant m/z: The difference in ppm between the closest m/z value and the theoretical m/z values are plotted for each calibrant. This corresponds to the difference between the dashed blue line and the green line in the zoomed in mass spectra.
995 - (cal) Difference m/z with max. average intensity vs. theor. m/z (per spectrum): For each spectrum the ppm difference between the m/z with the highest average intensity and the theoretical m/z are plotted. The calibrants have different plotting colours. Dashed lines separate spectra of different annotation groups. 1103 - (cal) Difference m/z with max. average intensity vs. theor. m/z (per spectrum): For each spectrum the ppm difference between the m/z with the highest average intensity and the theoretical m/z are plotted. The calibrants have different plotting colours. Dashed lines separate spectra of different annotation groups.
1104 - (cal) Same m/z accuracy in ppm is plotted per calibrant and per spectrum as image in x-y dimension.
996 1105
997 1106
998 ]]> 1107 ]]>
999 </help> 1108 </help>
1000 <expand macro="citations"/> 1109 <expand macro="citations"/>