# Clustering Mass Spectra from Low Resolution LC-MS/MS Data Using CluMSID

## Introduction

As described in the GC-EI-MS tutorial, CluMSID can also be used to analyse low resolution data – although using low resolution data comes at a cost.

In this example, we will use a similar sample (1uL Pseudomonas aeruginosa PA14 cell extract) as in the General Tutorial, measured with similar chromatography but on a different mass spectrometer, a Bruker amaZon ion trap instrument operated in ESI-(+) mode with auto-MS/MS. In addition to introducing a workflow for low resolution LC-MS/MS data, this example also demonstrates that CluMSID can work with data from different types of mass spectrometers.

## Data import

We load the file from the `CluMSIDdata` package:

    library(CluMSID)
    library(CluMSIDdata)

    lowresfile <- system.file("extdata",
                            "PA14_amazon_lowres.mzXML",
                            package = "CluMSIDdata")

## Data preprocessing

The extraction of spectra works the same way as with high resolution LC-MS/MS data:

    ms2list <- extractMS2spectra(lowresfile)
    length(ms2list)
    #> [1] 1989

Like in the GC-EI-MS example, we have to adjust `mz_tolerance` to a much higher value compared to high resolution data, while the retention time tolerance can remain unchanged.

    featlist <- mergeMS2spectra(ms2list, mz_tolerance = 0.02)

    length(featlist)
    #> [1] 525

We see that we have similar numbers of spectra as in the General Tutorial, because we tried to keep all parameters except for the mass spectrometer type comparable.

## Generation of distance matrix

As we do not have low resolution spectral libraries at hand, we skip the integration of previous knowledge on feature identities in this example and generate a distance matrix right away:

    distmat <- distanceMatrix(featlist)

## Data exploration

Starting from this distance matrix, we can use all the data exploration functions that `CluMSID` offers.

When we now make an MDS plot, we learn that the similarity data is very different from the comparable high resolution data:

    MDSplot(distmat)

Figure 1: Multidimensional scaling plot as a visualisation of MS2 spectra similarities of the low resolution LC-MS/MS example data set. Black dots signify spectra from unknown metabolites.

To get a better overview of the data and the general similarity behaviour, we create a heat map of the distance matrix:

    HCplot(distmat, type = "heatmap",
                    cexRow = 0.1, cexCol = 0.1,
                    margins = c(6,6))

Figure 2: Symmetric heat map of the distance matrix displaying MS2 spectra similarities of the low resolution LC-MS/MS example data set. along with dendrograms resulting from hierarchical clustering based on the distance matrix. The colour encoding is shown in the top-left insert.

We clearly see that the heat map is generally a lot “warmer” than in the General Tutorial (an intuition that is supported by the histogram in the top-left corner), i.e. we have a higher general degree of similarity between spectra. That is not surprising as the m/z information has much fewer levels than in high resolution data and fragments of different sum formula are more likely to have indistinguishable mass-to-charge ratios.

We also see that some more or less compact clusters can be identified. This is easier to inspect in the dendrogram visualisation:

    HCplot(distmat, h = 0.8, cex = 0.3)

Figure 3: Circularised dendrogram as a result of agglomerative hierarchical clustering with average linkage as agglomeration criterion based on MS2 spectra similarities of the low resolution LC-MS/MS example data set. Each leaf represents one feature and colours encode cluster affiliation of the features. Leaf labels display feature IDs. Distance from the central point is indicative of the height of the dendrogram.

In conclusion, CluMSID is capable of processing low resolution LC-MS/MS data and if high resolution data is not available, it can be very useful to provide an overview of spectral similarities in low resolution data, thereby helping metabolite annotation if some individual metabolites can be identified by comparison to authentic standards. However, concerning feature annotation, high resolution methods should always be favoured for the many benefits they provide.

# Session Info

    sessionInfo()
    #> R version 4.6.0 (2026-04-24)
    #> Platform: x86_64-pc-linux-gnu
    #> Running under: Ubuntu 24.04.4 LTS
    #>
    #> Matrix products: default
    #> BLAS:   /usr/lib/x86_64-linux-gnu/openblas-pthread/libblas.so.3
    #> LAPACK: /usr/lib/x86_64-linux-gnu/openblas-pthread/libopenblasp-r0.3.26.so;  LAPACK version 3.12.0
    #>
    #> locale:
    #>  [1] LC_CTYPE=en_US.UTF-8       LC_NUMERIC=C
    #>  [3] LC_TIME=en_US.UTF-8        LC_COLLATE=en_US.UTF-8
    #>  [5] LC_MONETARY=en_US.UTF-8    LC_MESSAGES=en_US.UTF-8
    #>  [7] LC_PAPER=en_US.UTF-8       LC_NAME=C
    #>  [9] LC_ADDRESS=C               LC_TELEPHONE=C
    #> [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
    #>
    #> time zone: Etc/UTC
    #> tzcode source: system (glibc)
    #>
    #> attached base packages:
    #> [1] stats     graphics  grDevices utils     datasets  methods   base
    #>
    #> other attached packages:
    #>  [1] metaMSdata_1.46.0   metaMS_1.46.0       CAMERA_1.68.0
    #>  [4] xcms_4.10.0         BiocParallel_1.46.0 Biobase_2.72.0
    #>  [7] BiocGenerics_0.58.0 generics_0.1.4      CluMSIDdata_1.26.0
    #> [10] CluMSID_1.28.0      rmarkdown_2.31
    #>
    #> loaded via a namespace (and not attached):
    #>   [1] RColorBrewer_1.1-3          rstudioapi_0.18.0
    #>   [3] sys_3.4.3                   jsonlite_2.0.0
    #>   [5] MultiAssayExperiment_1.38.0 magrittr_2.0.5
    #>   [7] farver_2.1.2                MALDIquant_1.22.3
    #>   [9] fs_2.1.0                    vctrs_0.7.3
    #>  [11] base64enc_0.1-6             htmltools_0.5.9
    #>  [13] S4Arrays_1.12.0             progress_1.2.3
    #>  [15] SparseArray_1.12.0          Formula_1.2-5
    #>  [17] mzID_1.50.0                 sass_0.4.10
    #>  [19] KernSmooth_2.23-26          bslib_0.10.0
    #>  [21] htmlwidgets_1.6.4           plyr_1.8.9
    #>  [23] impute_1.86.0               plotly_4.12.0
    #>  [25] cachem_1.1.0                buildtools_1.0.0
    #>  [27] igraph_2.3.0                lifecycle_1.0.5
    #>  [29] iterators_1.0.14            pkgconfig_2.0.3
    #>  [31] Matrix_1.7-5                R6_2.6.1
    #>  [33] fastmap_1.2.0               MatrixGenerics_1.24.0
    #>  [35] clue_0.3-68                 digest_0.6.39
    #>  [37] colorspace_2.1-2            pcaMethods_2.4.0
    #>  [39] GGally_2.4.0                S4Vectors_0.50.0
    #>  [41] Hmisc_5.2-5                 GenomicRanges_1.64.0
    #>  [43] labeling_0.4.3              Spectra_1.22.0
    #>  [45] httr_1.4.8                  abind_1.4-8
    #>  [47] compiler_4.6.0              withr_3.0.2
    #>  [49] doParallel_1.0.17           backports_1.5.1
    #>  [51] htmlTable_2.5.0             S7_0.2.2
    #>  [53] DBI_1.3.0                   ggstats_0.13.0
    #>  [55] gplots_3.3.0                MASS_7.3-65
    #>  [57] MsExperiment_1.14.0         DelayedArray_0.38.0
    #>  [59] gtools_3.9.5                caTools_1.18.3
    #>  [61] mzR_2.46.0                  tools_4.6.0
    #>  [63] PSMatch_1.14.0              foreign_0.8-91
    #>  [65] otel_0.2.0                  ape_5.8-1
    #>  [67] nnet_7.3-20                 glue_1.8.1
    #>  [69] dbscan_1.2.4                nlme_3.1-169
    #>  [71] QFeatures_1.22.0            grid_4.6.0
    #>  [73] checkmate_2.3.4             cluster_2.1.8.2
    #>  [75] reshape2_1.4.5              gtable_0.3.6
    #>  [77] preprocessCore_1.74.0       tidyr_1.3.2
    #>  [79] sna_2.8                     data.table_1.18.2.1
    #>  [81] hms_1.1.4                   MetaboCoreUtils_1.20.0
    #>  [83] XVector_0.52.0              foreach_1.5.2
    #>  [85] pillar_1.11.1               stringr_1.6.0
    #>  [87] limma_3.68.0                robustbase_0.99-7
    #>  [89] dplyr_1.2.1                 lattice_0.22-9
    #>  [91] tidyselect_1.2.1            RBGL_1.88.0
    #>  [93] maketools_1.3.2             knitr_1.51
    #>  [95] gridExtra_2.3               IRanges_2.46.0
    #>  [97] Seqinfo_1.2.0               ProtGenerics_1.44.0
    #>  [99] SummarizedExperiment_1.42.0 stats4_4.6.0
    #> [101] xfun_0.57                   statmod_1.5.1
    #> [103] MSnbase_2.36.0              matrixStats_1.5.0
    #> [105] DEoptimR_1.1-4              stringi_1.8.7
    #> [107] statnet.common_4.13.0       lazyeval_0.2.3
    #> [109] yaml_2.3.12                 evaluate_1.0.5
    #> [111] codetools_0.2-20            MsCoreUtils_1.24.0
    #> [113] tibble_3.3.1                BiocManager_1.30.27
    #> [115] graph_1.90.0                cli_3.6.6
    #> [117] affyio_1.82.0               rpart_4.1.27
    #> [119] jquerylib_0.1.4             network_1.20.0
    #> [121] Rcpp_1.1.1-1.1              MassSpecWavelet_1.78.0
    #> [123] coda_0.19-4.1               XML_3.99-0.23
    #> [125] parallel_4.6.0              ggplot2_4.0.3
    #> [127] prettyunits_1.2.0           AnnotationFilter_1.36.0
    #> [129] bitops_1.0-9                viridisLite_0.4.3
    #> [131] MsFeatures_1.18.0           scales_1.4.0
    #> [133] affy_1.90.0                 ncdf4_1.24
    #> [135] purrr_1.2.2                 crayon_1.5.3
    #> [137] rlang_1.2.0                 vsn_3.80.0