From 9adc91718c92fecaf7eadb0d3ab73bcfed876dd7 Mon Sep 17 00:00:00 2001 From: matteopilz Date: Tue, 15 Aug 2023 15:00:13 +0200 Subject: [PATCH 1/8] fix broken links --- docs/contribute-to-openms/pull-request-checklist.md | 2 +- docs/introduction.md | 6 +++--- .../openms-applications/swathwizard.md | 2 +- docs/run-workflows-with-openms-tools/knime/installation.md | 4 ++-- docs/run-workflows-with-openms-tools/knime/tutorial.md | 6 +++--- docs/topp-and-utils/swathwizard.md | 2 +- .../guides/contributors-quickstart-guide.md | 4 ++-- .../tutorials-and-quickstart-guides/openms-user-tutorial.md | 6 +++--- docs/tutorials/KNIME/KNIME-tutorial.md | 4 ++-- 9 files changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/contribute-to-openms/pull-request-checklist.md b/docs/contribute-to-openms/pull-request-checklist.md index 456d9668..3afaf661 100644 --- a/docs/contribute-to-openms/pull-request-checklist.md +++ b/docs/contribute-to-openms/pull-request-checklist.md @@ -8,7 +8,7 @@ Before opening a pull request, check the following: Windows). 2. **Do all tests pass?** To check if all tests have passed, execute `ctest`. - If a test that is unrelated to your changes fails, check the [nightly builds](http://cdash.openms.de/index.php?project=OpenMS) + If a test that is unrelated to your changes fails, check the [nightly builds](https://cdash.openms.de/index.php?project=OpenMS) to see if the error is also in `develop`. If the error is in develop, [create a github issue](write-and-label-github-issues.md). 3. **Is the code documented?** Document all new classes, including their methods and parameters. diff --git a/docs/introduction.md b/docs/introduction.md index 92bee794..28aff7a0 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -100,17 +100,17 @@ Get started with installing OpenMS using the installers available for different ```{tab} GNU/Linux ```bash -wget https://abibuilder.cs.uni-tuebingen.de/archive/openms/OpenMSInstaller/release/latest/OpenMS-2.8.0-Debian-Linux-x86_64.deb +wget https://abibuilder.cs.uni-tuebingen.de/archive/openms/OpenMSInstaller/release/2.8.0/OpenMS-2.8.0-Debian-Linux-x86_64.deb ``` ```{tab} Windows ```bash -wget https://abibuilder.cs.uni-tuebingen.de/archive/openms/OpenMSInstaller/release/latest/OpenMS-2.8.0-Win64.exe +wget https://abibuilder.cs.uni-tuebingen.de/archive/openms/OpenMSInstaller/release/2.8.0/OpenMS-2.8.0-Win64.exe ``` ```{tab} macOS ```bash -wget https://abibuilder.cs.uni-tuebingen.de/archive/openms/OpenMSInstaller/release/latest/OpenMS-2.8.0-macOS.dmg +wget https://abibuilder.cs.uni-tuebingen.de/archive/openms/OpenMSInstaller/release/2.8.0/OpenMS-2.8.0-macOS.dmg ``` diff --git a/docs/openms-applications-and-tools/openms-applications/swathwizard.md b/docs/openms-applications-and-tools/openms-applications/swathwizard.md index a91bffca..ed2ffebd 100644 --- a/docs/openms-applications-and-tools/openms-applications/swathwizard.md +++ b/docs/openms-applications-and-tools/openms-applications/swathwizard.md @@ -7,7 +7,7 @@ SwathWizard SwathWizard is an assistant for Swath analysis. The Wizard takes the user through the whole analysis pipeline for SWATH proteomics data analysis, i.e. the -[TOPP Documentation: OpenSwathWorkflow](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_OpenSwathWorkflow.html) tool, including downstream tools such as [GitHub:PyProphet/pyProphet](https://github.com/PyProphet/pyprophet) and the [GitHub:msproteomicstools/TRIC alignment](https://github.com/msproteomicstools/msproteomicstools) tool. +[TOPP Documentation: OpenSwathWorkflow](https://openms.readthedocs.io/en/latest/tutorials-and-quickstart-guides/openms-user-tutorial.html#id44) tool, including downstream tools such as [GitHub:PyProphet/pyProphet](https://github.com/PyProphet/pyprophet) and the [GitHub:msproteomicstools/TRIC alignment](https://github.com/msproteomicstools/msproteomicstools) tool. Since the downstream tools require Python and the respective modules, the Wizard will check their proper installation status and warn the user if a component is missing. diff --git a/docs/run-workflows-with-openms-tools/knime/installation.md b/docs/run-workflows-with-openms-tools/knime/installation.md index efb76083..deed7eb7 100644 --- a/docs/run-workflows-with-openms-tools/knime/installation.md +++ b/docs/run-workflows-with-openms-tools/knime/installation.md @@ -51,10 +51,10 @@ Installation of OpenMS in {term}`KNIME` is platform-independent across Windows, ## Creating workflows with KNIME Download Introduction to OpenMS in KNIME [user tutorial](../../tutorials-and-quickstart-guides/openms-user-tutorial.md) containing hands-on training material covering also basic -usage of KNIME. See the official [KNIME Getting Started Guide](https://tech.knime.org/knime) for a more in-depth view of +usage of KNIME. See the official [KNIME Getting Started Guide](https://www.knime.com/getting-started-guide) for a more in-depth view of the KNIME functionality besides OpenMS. -If you face any issues, please [contact us](/quick-reference/contact-us.md) and specifically for the usage of OpenMS in KNIME, the KNIME community contribution [forum](https://forum.knime.com/c/community-extensions/openms/40). +If you face any issues, please [contact us](/quick-reference/contact-us.md) and specifically for the usage of OpenMS in KNIME, the KNIME community contribution [forum](https://forum.knime.com/tag/openms). ## Creating your own Generic KNIME Nodes diff --git a/docs/run-workflows-with-openms-tools/knime/tutorial.md b/docs/run-workflows-with-openms-tools/knime/tutorial.md index 408153c2..f65c242c 100644 --- a/docs/run-workflows-with-openms-tools/knime/tutorial.md +++ b/docs/run-workflows-with-openms-tools/knime/tutorial.md @@ -2493,7 +2493,7 @@ Now launch ”Spyder” (python IDE) in the home menu. ### Build instructions -Instructions on how to build pyOpenMS can be found [online](https://pyopenms.readthedocs.io/en/latest/build_from_source.html). +Instructions on how to build pyOpenMS can be found [online](https://pyopenms.readthedocs.io/en/latest/community/build_from_source.html). ### Scripting with pyOpenMS @@ -2559,7 +2559,7 @@ for iso in isotopes.getContainer(): print (iso.getMZ(), ":", iso.getIntensity()) ``` -For further examples and the pyOpenMS data structures please see the following [link](https://pyopenms.readthedocs.io/en/latest/ms_data.html). +For further examples and the pyOpenMS data structures please see the following [link](https://pyopenms.readthedocs.io/en/latest/user_guide/ms_data.html). ### Tool development with pyOpenMS @@ -2964,7 +2964,7 @@ You can look up temporary files that are created by OpenMS nodes not connected t **Q:** Why is my configuration dialog closing right away when I double-click or try to configure it? Or why is my GUI responding so slow? -**A:** If you have any problems with the KNIME GUI or the opening of dialogues under Linux you might be affected by a GTK bug. See the KNIME forum (e.g. [here](https://tech.knime.org/forum/knime-general/ubuntu-1604-slow-performance) or [here](https://tech.knime.org/forum/knime-users/knime-300-crashes-after-splash-screen)) for a discussion and a possible solution. In short: set environment variable by calling `export SWT_GTK3=0` or edit `knime.ini` to make Eclipse use GTK2 by adding the following two lines: +**A:** If you have any problems with the KNIME GUI or the opening of dialogues under Linux you might be affected by a GTK bug. See the KNIME forum (e.g. [here](https://forum.knime.com/t/ubuntu-16-04-slow-performance/4345) or [here](https://forum.knime.com/t/knime-3-0-0-crashes-after-splash-screen/8370)) for a discussion and a possible solution. In short: set environment variable by calling `export SWT_GTK3=0` or edit `knime.ini` to make Eclipse use GTK2 by adding the following two lines: ```xml –launcher.GTK_version 2 diff --git a/docs/topp-and-utils/swathwizard.md b/docs/topp-and-utils/swathwizard.md index 9b7e80d3..9c049dd8 100644 --- a/docs/topp-and-utils/swathwizard.md +++ b/docs/topp-and-utils/swathwizard.md @@ -7,7 +7,7 @@ SwathWizard An assistant for Swath analysis. The Wizard takes the user through the whole analysis pipeline for SWATH proteomics data analysis, i.e. the -[TOPP Documentation: OpenSwathWorkflow](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/TOPP_OpenSwathWorkflow.html) tool, including downstream tools such as [GitHub:PyProphet/pyProphet](https://github.com/PyProphet/pyprophet) and the [GitHub:msproteomicstools/TRIC alignment](https://github.com/msproteomicstools/msproteomicstools) tool. +[TOPP Documentation: OpenSwathWorkflow](https://openms.readthedocs.io/en/latest/tutorials-and-quickstart-guides/openms-user-tutorial.html#id44) tool, including downstream tools such as [GitHub:PyProphet/pyProphet](https://github.com/PyProphet/pyprophet) and the [GitHub:msproteomicstools/TRIC alignment](https://github.com/msproteomicstools/msproteomicstools) tool. Since the downstream tools require Python and the respective modules, the Wizard will check their proper installation status and warn the user if a component is missing. diff --git a/docs/tutorials-and-quickstart-guides/guides/contributors-quickstart-guide.md b/docs/tutorials-and-quickstart-guides/guides/contributors-quickstart-guide.md index cb523edf..87a0e72a 100644 --- a/docs/tutorials-and-quickstart-guides/guides/contributors-quickstart-guide.md +++ b/docs/tutorials-and-quickstart-guides/guides/contributors-quickstart-guide.md @@ -5,7 +5,7 @@ To contribute to OpenMS: - Familiarise yourself with the [OpenMS online documentation](../../index.rst). - Learn how to [build OpenMS](../../develop-with-openms/build-openms-from-source.md). -- Check out the [OpenMS tutorial for developers](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/release/latest/html/OpenMS_tutorial.html). +- Check out the [OpenMS tutorial for developers](https://openms.readthedocs.io/en/latest/develop-with-openms/developer-tutorial.html#developer-tutorial). For any questions, please [contact us](/quick-reference/contact-us.md). @@ -61,7 +61,7 @@ Nightly tests run on different platforms. It is recommended to test on different This saves time and increases productivity during continuous integration tests. ``` -Nightly tests: [CDASH](http://cdash.openms.de/index.php?project=OpenMS). +Nightly tests: [CDASH](https://cdash.openms.de/index.php?project=OpenMS). ## Further contributor resources diff --git a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md index 049f7e82..1a14a3ef 100644 --- a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md +++ b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md @@ -2492,7 +2492,7 @@ Now launch ”Spyder” (python IDE) in the home menu. ### Build instructions -Instructions on how to build pyOpenMS can be found [online](https://pyopenms.readthedocs.io/en/latest/build_from_source.html). +Instructions on how to build pyOpenMS can be found [online](https://pyopenms.readthedocs.io/en/latest/community/build_from_source.html). ### Scripting with pyOpenMS @@ -2558,7 +2558,7 @@ for iso in isotopes.getContainer(): print (iso.getMZ(), ":", iso.getIntensity()) ``` -For further examples and the pyOpenMS data structures please see the following [link](https://pyopenms.readthedocs.io/en/latest/ms_data.html). +For further examples and the pyOpenMS data structures please see the following [link](https://pyopenms.readthedocs.io/en/latest/user_guide/ms_data.html). ### Tool development with pyOpenMS @@ -2963,7 +2963,7 @@ You can look up temporary files that are created by OpenMS nodes not connected t **Q:** Why is my configuration dialog closing right away when I double-click or try to configure it? Or why is my GUI responding so slow? -**A:** If you have any problems with the KNIME GUI or the opening of dialogues under Linux you might be affected by a GTK bug. See the KNIME forum (e.g. [here](https://tech.knime.org/forum/knime-general/ubuntu-1604-slow-performance) or [here](https://tech.knime.org/forum/knime-users/knime-300-crashes-after-splash-screen)) for a discussion and a possible solution. In short: set environment variable by calling `export SWT_GTK3=0` or edit `knime.ini` to make Eclipse use GTK2 by adding the following two lines: +**A:** If you have any problems with the KNIME GUI or the opening of dialogues under Linux you might be affected by a GTK bug. See the KNIME forum (e.g. [here](https://forum.knime.com/t/ubuntu-16-04-slow-performance/4345) or [here](https://forum.knime.com/t/knime-3-0-0-crashes-after-splash-screen/8370)) for a discussion and a possible solution. In short: set environment variable by calling `export SWT_GTK3=0` or edit `knime.ini` to make Eclipse use GTK2 by adding the following two lines: ```xml –launcher.GTK_version 2 diff --git a/docs/tutorials/KNIME/KNIME-tutorial.md b/docs/tutorials/KNIME/KNIME-tutorial.md index c4166867..808385e6 100644 --- a/docs/tutorials/KNIME/KNIME-tutorial.md +++ b/docs/tutorials/KNIME/KNIME-tutorial.md @@ -58,10 +58,10 @@ Installation of OpenMS in {term}`KNIME` is platform-independent across Windows, ## Creating workflows with KNIME Download Introduction to OpenMS in KNIME [user tutorial](../../tutorials-and-quickstart-guides/openms-user-tutorial.md) containing hands-on training material covering also basic -usage of KNIME. See the official [KNIME Getting Started Guide](https://tech.knime.org/knime) for a more in-depth view of +usage of KNIME. See the official [KNIME Getting Started Guide](https://www.knime.com/getting-started-guide) for a more in-depth view of the KNIME functionality besides OpenMS. -If you face any issues, please [contact us](/quick-reference/contact-us.md) and specifically for the usage of OpenMS in KNIME, the KNIME community contribution [forum](https://forum.knime.com/c/community-extensions/openms/40). +If you face any issues, please [contact us](/quick-reference/contact-us.md) and specifically for the usage of OpenMS in KNIME, the KNIME community contribution [forum](https://forum.knime.com/tag/openms). ## Creating your own Generic KNIME Nodes From f627c6b4606c8e55d10e13cad552afb08de63f7f Mon Sep 17 00:00:00 2001 From: matteopilz Date: Tue, 15 Aug 2023 15:05:11 +0200 Subject: [PATCH 2/8] fix broken links --- docs/introduction/entry-points-to-openms.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/introduction/entry-points-to-openms.md b/docs/introduction/entry-points-to-openms.md index a97055ce..de0a5989 100644 --- a/docs/introduction/entry-points-to-openms.md +++ b/docs/introduction/entry-points-to-openms.md @@ -36,7 +36,7 @@ The following entry points for OpenMS and its TOPP tools are available for users ::: :::{grid-item-card} {fab}`python;sd-text-info fa-xl` **pyOpenMS**
Use the pyOpenMS python library to rapidly prototype methods and scripts - :link: https://pyopenms.readthedocs.io/en/latest/installation.html + :link: https://pyopenms.readthedocs.io/en/latest/user_guide/installation.html :link-type: url :class-title: flex From 7bebec45f840da7f67eeacad2ff4a4eb4dff912b Mon Sep 17 00:00:00 2001 From: matteopilz Date: Mon, 2 Oct 2023 17:28:18 +0200 Subject: [PATCH 3/8] relink developer quickstart guide --- docs/develop-with-openms/developer-tutorial.md | 4 ---- docs/index.rst | 2 +- 2 files changed, 1 insertion(+), 5 deletions(-) delete mode 100644 docs/develop-with-openms/developer-tutorial.md diff --git a/docs/develop-with-openms/developer-tutorial.md b/docs/develop-with-openms/developer-tutorial.md deleted file mode 100644 index 783425a7..00000000 --- a/docs/develop-with-openms/developer-tutorial.md +++ /dev/null @@ -1,4 +0,0 @@ -Developer Tutorial -================== - -This page is under construction. diff --git a/docs/index.rst b/docs/index.rst index 6c633a8c..9ddd9eaa 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -76,12 +76,12 @@ Contents :maxdepth: 2 :caption: Develop with OpenMS + Developer Quickstart Guide develop-with-openms/openms-core-cplusplus-library.md OpenMS API Reference pyOpenMS develop-with-openms/build-openms-from-source.md develop-with-openms/link-external-code-to-openms.md - develop-with-openms/developer-tutorial.md .. toctree:: :maxdepth: 2 From a5c332f77ffc2eae48aba491f797f4d2395ca6da Mon Sep 17 00:00:00 2001 From: matteopilz Date: Sat, 17 Feb 2024 12:03:45 +0200 Subject: [PATCH 4/8] update TOPPView intensity mode description --- docs/run-workflows-with-openms-tools/knime/tutorial.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/run-workflows-with-openms-tools/knime/tutorial.md b/docs/run-workflows-with-openms-tools/knime/tutorial.md index 3b7d2fc6..8d459552 100644 --- a/docs/run-workflows-with-openms-tools/knime/tutorial.md +++ b/docs/run-workflows-with-openms-tools/knime/tutorial.md @@ -183,8 +183,8 @@ also resets the zoom history). the mouse to another peak to measure the distance between peaks. - This mode is implemented in the 1D and 2D mode only. - Right click on your 2D map and select **Switch to 3D mode** and examine your data in 3D mode (see Fig. 4). -- Go back to the 2D view. In 2D mode, visualize your data in different intensity normalization modes, use linear , percentage, snap and log-view (icons on -the upper left tool bar). You can hover over the icons for additional information. +- Visualize your data in different intensity normalization modes, use linear, percentage (set intensity axis scale to percentage), snap and log-view (icons on + the upper left tool bar). You can hover over the icons for additional information. ```{note} On macOS, due to a bug in one of the external libraries used by From 5d9874c047f863fd728a74fa76da1daf87855d10 Mon Sep 17 00:00:00 2001 From: matteopilz Date: Sat, 17 Feb 2024 18:33:35 +0200 Subject: [PATCH 5/8] update tutorials --- .../labelfree/PepQuantId.png | Bin 58508 -> 38639 bytes .../labelfree/PepQuantIdNoAlign.png | Bin 46395 -> 74660 bytes .../feature-detection-on-centroided-data.md | 2 +- .../types-of-topp-tools/file-handling.md | 2 +- .../knime/tutorial.md | 357 +++++++++--------- .../consensus-peptide-identification.md | 2 +- .../openms-user-tutorial.md | 52 +-- .../tutorials.md | 2 +- 8 files changed, 202 insertions(+), 215 deletions(-) diff --git a/docs/images/openms-user-tutorial/labelfree/PepQuantId.png b/docs/images/openms-user-tutorial/labelfree/PepQuantId.png index 15c62c000d2ceb50b55796fd1c951cbb76484975..94bc8428ae5f1bd30c80744c48b136d1797713b8 100644 GIT binary patch literal 38639 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

**Task**

- Select multiple nodes (e.g. all nodes of the ZipLoop including the start and end node). To select a set of nodes, draw a rectangle around them with the left mouse button or hold Ctrl to add/remove single nodes from the selection. + Select multiple nodes (e.g. all nodes of the **ZipLoop** including the start and end node). To select a set of nodes, draw a rectangle around them with the left mouse button or hold Ctrl to add/remove single nodes from the selection.

**Tip**

There is a **Select Scope** option when you right-click a node in a loop, that does exactly that for you. Then, open the @@ -597,16 +597,17 @@ improve handling and clarity of large workflows:

**Task**

Create the Metanode to let it behave like an encapsulated single node. First select the **Metanode**, open the context -menu (right-click) and select **Metanode** > **Wrap**. The differences between Metanodes and their wrapped counterparts -are marginal (and only apply when exposing user inputs and workflow variables). Therefore we suggest to use standard +menu (right-click) and select **Metanode** > **Convert to Component**. The differences between Metanodes and components +are marginal (Metanodes allow exposing user inputs, workflow variables and contained nodes). Therefore, we suggest to use standard Metanodes to clean up your workflow and cluster common subparts until you actually notice their limits.

**Task**

-Undo the packaging. First select the (**Wrapped**) **Metanode**, open the context menu (right-click) and select **(Wrapped) Metanode** > **Expand**. +Undo the packaging. First select the **Metanode/Component**, open the context menu (right-click) and select **Metanode/Component** > **Expand**.
+ -#### Advanced topic: R integration - -KNIME provides a large number of nodes for a wide range of statistical analysis, machine learning, data processing, and -visualization. Still, more recent statistical analysis methods, specialized visualizations or cutting edge algorithms -may not be covered in KNIME. In order to expand its capabilities beyond the readily available nodes, external scripting -languages can be integrated. In this tutorial, we primarily use scripts of the powerful statistical computing language R. -Note that this part is considered advanced and might be difficult to follow if you are not familiar with R. In this case -you might skip this part. - -**R View (Table)** allows to seamlessly include R scripts into KNIME. We will -demonstrate on a minimal example how such a script is integrated. - -
-

**Task**

-

-First we need some example data in KNIME, which we will generate using the **Data Generator** node (**IO** > **Other** > **Data Generator**). -You can keep the default settings and execute the node. The table contains four columns, each containing random coordinates and one column -containing a cluster number (Cluster_0 to Cluster_3). Now place a **R View (Table)** node into the workflow and connect -the upper output port of the **Data Generator** node to the input of the **R View (Table)** node. Right-click and -configure the node. If you get an error message like `Execute failed: R_HOME does not contain a folder with name ’bin’.` -or `Execution failed: R Home is invalid.`: please change the R settings in the preferences. To do so open **File** > -**Preferences** > **KNIME** > **R** and enter the path to your R installation (the folder that contains the bin -directory. e.g., {path}`C:,Program Files,R,R-3.4.3`). -

-

-If you get an error message like: ”Execute failed: Could not find Rserve package. Please install it in your R -installation by running ”install.packages(’Rserve’)”.” You may need to run your R binary as administrator (In windows -explorer: right-click ”Run as administrator”) and enter install.packages(’Rserve’) to install the package. -

-

-If R is correctly recognized we can start writing an R script. Consider that we are interested in plotting the first and -second coordinates and color them according to their cluster number. In R this can be done in a single line. In the -**R view (Table)** text editor, enter the following code: -```r -plot(x=knime.in$Universe_0_0, y=knime.in$Universe_0_1, main="Plotting column Universe_0_0 vs. Universe_0_1", col=knime.in$"Cluster Membership") -``` -

-

-**Explanation:** The table provided as input to the **R View (Table)** node is available as R **data.frame** with name -`knime.in`. Columns (also listed on the left side of the R View window) can be accessed in the usual R way by first -specifying the `data.frame` name and then the column name (e.g., `knime.in$Universe_0_0`). `plot` is the plotting function -we use to generate the image. We tell it to use the data in column `Universe_0_0` of the dataframe object **knime.in** -(denoted as `knime.in$Universe_0_0`) as x-coordinate and the other column `knime.in$Universe_0_1` as y-coordinate in the -plot. `main` is simply the main title of the plot and `col` the column that is used to determine the color (in this case -it is the `Cluster Membership` column). -

-

-Now press the Eval script and Show plot buttons. -

-
- -```{note} -Note that we needed to put some extra quotes around `Cluster Membership`. If we omit those, R would interpret the column -name only up to the first space `(knime.in$Cluster)` which is not present in the table and leads to an error. Quotes are -regularly needed if column names contain spaces, tabs or other special characters like $ itself. -``` - ## Label-free quantification of peptides ### Introduction @@ -727,12 +672,12 @@ As a start, we will extend the minimal workflow so that it performs a peptide id engine. Comet is included in the OpenMS installation, so you do not need to download and install it yourself. -Let’s start by replacing the input files in our **Input Files** node by the three mzML files in +Let’s start by replacing the input files in our `Input Files` node by the three mzML files in **Example Data** > **Labelfree** > **datasets** > **lfqxspikeinxdilutionx1-3.mzML**. This is a reduced toy dataset where each of the three runs contains a constant background of `S. pyogenes` peptides as well as human spike-in peptides in different concentrations. [^10] -- Instead of FileInfo, we want to perform Comet identification, so we simply replace the `FileInfo` node with the +- Instead of `FileFilter`, we want to perform Comet identification, so we simply replace the `FileFilter` node with the `CometAdapter` node **Community Nodes** > **OpenMSThirdParty** > **Identification**, and we are almost done. Just make sure you have connected the `ZipLoopStart` node with the `in` (top) port of the `CometAdapter` node. - Comet, like most mass spectrometry identification engines, relies on searching the input spectra against sequence @@ -740,7 +685,7 @@ different concentrations. [^10] our input files, we can just add a single `File Importer` node to the workflow and connect it directly with the `CometAdapter database` (middle) port. KNIME will automatically reuse this Input node each time a new ZipLoop iteration is started. In order to specify the database, [select](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Labelfree/databases/s_pyo_sf370_potato_human_target_decoy_with_contaminants.fasta) {path}`Example_Data,Labelfree,databases,/break,s_pyo_sf370_potato_human_target_decoy_with_contaminants.fasta` -- Connect the **out** port of the **CometAdapter** to **ZipLoopEnd** and we have a very basic peptide identification workflow. +- Connect the **out** port of the `CometAdapter` to `ZipLoopEnd` and we have a very basic peptide identification workflow. ```{note} You might also want to save your new identification workflow under a different name. Have a look at
duplicating workflows @@ -748,15 +693,15 @@ different concentrations. [^10] ``` - The result of a single Comet run is basically a number of peptide-spectrum-matches (PSM) with a score each, and these will be stored in an idXML file. Now we can run the pipeline and after execution is finished, we can have a first look - at the the results: just open the ouput folder with a file browser and from there open one of the three input mzML's in **TOPPView**. + at the the results: just open the output folder with a file browser and from there open one of the three input mzML's in **TOPPView**. - Here, annotate this spectrum data file with the peptide identification results. Choose **Tools** > **Annonate with identification** - from the menu and select the idXML file that **CometAdapter** generated (it is located within the output directory that + from the menu and select the idXML file that `CometAdapter` generated (it is located within the output directory that you specified when starting the pipeline). - On the right, select the tab **Identification view**. All identified peptides can be seen using this view. User can also browse the corresponding MS2 spectra. ```{note} - Opening the output file of `CometAdapter` (the idXML file) directly is also possible, but unless you REALLY like XML reading + Opening the output file of `CometAdapter` (the idXML file) directly is also possible, but unless you REALLY like XML, reading idXML files is less useful. ``` - The search results stored in the idXML file can also be read back into a KNIME table for inspection and subsequent @@ -764,7 +709,7 @@ different concentrations. [^10] connect the output port of your `CometAdapter` (the same port `ZipLoopEnd` is connected to) to its input port. This tool will convert the idXML file to a more human-readable text file which can also be read into a KNIME table using the `IDTextReader` node. Add an `IDTextReader` node(**Community Nodes** > **OpenMS** > **Conversion**) after - **TextExporter** and execute it. Now you can right click `IDTextReader` and select **ID Table** to browse your peptide + `TextExporter` and execute it. Now you can right click `IDTextReader` and select **ID Table** to browse your peptide identifications. - From here, you can use all the tools KNIME offers for analyzing the data in this table. As a simple example, add a `Histogram` node (from category **Views**) node after `IDTextReader`, double-click it, select @@ -772,19 +717,18 @@ different concentrations. [^10] of your identifications. In the next step, we will tweak the parameters of Comet to better reflect the instrument’s accuracy. Also, we will -extend our pipeline with a false discovery rate (FDR) filter to retain only those identifications that will yeild an +extend our pipeline with a false discovery rate (FDR) filter to retain only those identifications that will yield an FDR of < 1 %. - Open the configuration dialog of `CometAdapter`. The dataset was recorded using an LTQ Orbitrap XL mass spectrometer, - set the precursor mass tolerance to a smaller value, say 5 ppm. Set `precursor_mass_tolerance` to 5 and - `precursor_error_units` to `ppm`. + set the `precursor_mass_tolerance` to 5 and `precursor_error_units` to `ppm`. ```{note} Whenever you change the configuration of a node, the node as well as all its successors will be reset to the Configured state (all node results are discarded and need to be recalculated by executing the nodes again). ``` -- Add `Carbamidomethyl (C)` as fixed modification and `Oxidation(M)` as variable modification. +- Make sure that `Carbamidomethyl (C)` is set as fixed modification and `Oxidation(M)` as variable modification. ```{note} To add a modification click on the empty value field in the configuration dialog to open the list editor dialog. In the @@ -811,13 +755,6 @@ FDR of < 1 %. - Execute your workflow and inspect the results using `IDTextReader` like you did before. How many peptides did you identify at this FDR threshold? - ```{note} - The finished identification workflow is now sufficiently complex that we might want to encapsulate it in a Metanode. - For this, select all nodes inside the ZipLoop (including the **File Importer** node) and right-click to select - **Collapse into Metanode** and name it ID. Metanodes are useful when you construct even larger workflows and want to - keep an overview. - - ``` The below images shows Comet ID pipeline including FDR filtering. @@ -861,21 +798,20 @@ In the end, the ID processing part of the workflow can be collapsed into a Metan |:--:| |Figure 13: Complete consensus identification workflow| -### Quantification +### Feature Mapping -Now that we have successfully constructed a peptide identification pipeline, we can -add quantification capabilities to our workflow. +Now that we have successfully constructed a peptide identification pipeline, we can assign this information to the corresponding feature signals. -- Add a **FeatureFinderCentroided** node from **Community Nodes** > **OpenMS** > **Quantitation** -which gets input from the first output port of the **ZipLoopStart** node. Also, add -an **IDMapper** node (from **Community Nodes** > **OpenMS** > **Identification Processing** ) which receives -input from the **FeatureFinderCentroided** node (Port 1) and the ID Metanode (or **IDFilter** node (Port 0) if you haven’t used the Metanode). The output of the **IDMapper** node is then connected to an in port of the **ZipLoopEnd** node. +- Add a `FeatureFinderCentroided` node from **Community Nodes** > **OpenMS** > **Quantitation** +which gets input from the first output port of the `ZipLoopStart` node. Also, add +an `IDMapper` node (from **Community Nodes** > **OpenMS** > **Identification Processing** ) which receives +input from the `FeatureFinderCentroided` node (Port 1) and the `IDFilter` node (Port 0). The output of the `IDMapper` node is then connected to an in port of the `ZipLoopEnd` node. - `FeatureFinderCentroided` finds and quantifies peptide ion signals contained in the MS1 data. It reduces the entire signal, i.e., all peaks explained by one and the same peptide ion signal, to a single peak at the maximum of the chromatographic elution profile of the monoisotopic mass trace of this peptide ion and assigns an overall intensity. -- `FeatureFinderCentroided` produces a featureXML file as output, containing only quantitative information of so-far unidentified peptide signals. In order to annotate these with the corresponding ID information, we need the **IDMapper** node. -- Run your pipeline and inspect the results of the **IDMapper** node in TOPPView. Open the mzML file of your data to display the raw peak intensities. +- `FeatureFinderCentroided` produces a featureXML file as output, containing only quantitative information of so-far unidentified peptide signals. In order to annotate these with the corresponding ID information, we need the `IDMapper` node. +- Run your pipeline and inspect the results of the `IDMapper` node in TOPPView. Open the mzML file of your data to display the raw peak intensities. - To assess how well the feature finding worked, you can project the features contained in the featureXML file on the raw data contained in the mzML file. To this end, open the featureXML file in TOPPView by clicking on File Open file and add it to a new layer ( Open in New layer ). The features are now visualized on top of your raw data. If you zoom in on a small region, you should be able to see the individual boxes around features that have been detected (see Fig. 14). If you hover over the the feature centroid (small circle indicating the chromatographic apex of monoisotopic trace) additional information of the feature is displayed. @@ -896,28 +832,29 @@ click on the small triangle next to that icon and select **Peptide identificatio The following image shows the final constructed workflow: -|![Extended workflow featuring peptide identification and quantification](/images/openms-user-tutorial/labelfree/PepQuantIdNoAlign.png)| -|:--:| -|Figure 15: Extended workflow featuring peptide identification and quantification| +| ![Extended workflow featuring peptide identification and quantification](/images/openms-user-tutorial/labelfree/PepQuantIdNoAlign.png) | +|:--------------------------------------------------------------------------------------------------------------------------------------:| +| Figure 15: Extended workflow featuring peptide identification and feature mapping. | -### Combining quantitative information across several label-free experiments +### Combining features across several label-free experiments -So far, we successfully performed peptide identification as well as quantification on -individual LC-MS runs. For differential label-free analyses, however, we need to identify and quantify corresponding signals in different experiments and link them together to compare their intensities. Thus, we will now run our pipeline on all three +So far, we successfully performed peptide identification as well as feature mapping on +individual LC-MS runs. For differential label-free analyses, however, we need to identify and map corresponding signals in different experiments and link them together to compare their intensities. Thus, we will now run our pipeline on all three available input files and extend it a bit further, so that it is able to find and link features across several runs. -|![Complete identification and label-free quantification workflow](/images/openms-user-tutorial/labelfree/PepQuantId.png)| -|:--:| -|Figure 16: Complete identification and label-free quantification workflow| +| ![Complete identification and label-free quantification workflow](/images/openms-user-tutorial/labelfree/PepQuantId.png) | +|:-----------------------------------------------------------------------------------------------------------------------------------------:| +| Figure 16: Complete identification and label-free feature mapping workflow. The identification nodes are grouped together as ID metanode. | -- To find features across several maps, we first have to align them to correct for retention time shifts between the different label-free measurements. With the **MapAlignerPoseClustering** node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can align corresponding peptide signals to each other as closely as possible by applying a transformation in the RT dimension. +- To link features across several maps, we first have to align them to correct for retention time shifts between the different label-free measurements. With the `MapAlignerPoseClustering` node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can align corresponding peptide signals to each other as closely as possible by applying a transformation in the RT dimension. ```{note} `MapAlignerPoseClustering` consumes several featureXML files and its output should still be several featureXML files containing the same features, but with the transformed RT values. In its configuration dialog, make sure that **OutputTypes** is set to **featureXML**. ``` -- With the **FeatureLinkerUnlabeledQT** node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can then perform the actual linking of corresponding features. Its output is a consensusXML file containing linked groups of corresponding features across the different experiments. +- With the `FeatureLinkerUnlabeledQT` node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can then perform the actual linking of corresponding features. Its output is a consensusXML file containing linked groups of corresponding features across the different experiments. - Since the overall intensities can vary a lot between different measurements (for example, because the amount of injected analytes was different), we apply the **ConsensusMapNormalizer** node in **Community Node** > **OpenMS** > **Map Alignment** as a last processing step. Configure its parameters with setting `algorithm_type` to `median`. It will then normalize the maps in such a way that the median intensity of all input maps is equal. -- Finally, export the resulting normalized consensusXML file to a csv format using the **TextExporter** node. Connect its out port to a new **Output Folder** node. +- Export the resulting normalized consensusXML file to a csv format using the **TextExporter** node. +- Use the `ConsensusTextReader` node in **Community Nodes** > **OpenMS** > **Conversion** to convert the output into a KNIME table. After running the node you can view the KNIME table by right-clicking on the `ConsensusTextReader` node and selecting `Consensus Table`. Every row in this table corresponds to a so-called consensus feature, i.e., a peptide signal quantified across several runs. The first couple of columns describe the consensus feature as a whole (average RT and m/z across the maps, charge, etc.). The remaining columns describe the exact positions and intensities of the quantified features separately for all input samples (e.g., intensity_0 is the intensity of the feature in the first input file). The last 11 columns contain information on peptide identification. ```{note} You can specify the desired column separation character in the parameter settings (by default, it is set to “ ” (a space)). The output file of `TextExporter` can also be opened with external tools, e.g., Microsoft Excel, for downstream statistical analyses. @@ -925,13 +862,13 @@ available input files and extend it a bit further, so that it is able to find an #### Basic data analysis in KNIME -For downstream analysis of the quantification results within the KNIME environment, you can use the **ConsensusTextReader** node in **Community Nodes** > **OpenMS** > **Conversion** instead of the **Output Folder** node to convert the output into a KNIME table (indicated by a triangle as output port). After running the node you can view the KNIME table by right-clicking on the **ConsensusTextReader** node and selecting `Consensus Table`. Every row in this table corresponds to a so-called consensus feature, i.e., a peptide signal quantified across several runs. The first couple of columns describe the consensus feature as a whole (average RT and m/z across the maps, charge, etc.). The remaining columns describe the exact positions and intensities of the quantified features separately for all input samples (e.g., intensity_0 is the intensity of the feature in the first input file). The last 11 columns contain information on peptide identification. +In this section we are going to use the output of the `ConsensusTextReader` for downstream analysis of the quantification results: -- Now, let’s say we want to plot the log intensity distributions of the human spike-in peptides for all input files. In addition, we will plot the intensity distributions of the background peptides. -- As shown in Fig. 17, add a **Row Splitter** node (**Data Manipulation** > **Row** > **Filter**) after the **ConsensusTextReader** node. Double-click it to configure. The human spike-in peptides have accessions starting with “hum”. Thus, set the column to apply the test to: accessions, select pattern matching as matching criterion, enter `hum` into the corresponding text field, and check the contains wild cards box. Press **OK** and execute the node. -- **Row Splitter** produces two output tables: the first one contains all rows from the input table matching the filter criterion, and the second table contains all other rows. You can inspect the tables by right-clicking and selecting **Filtered** and **Filtered Out**. The former table should now only contain peptides with a human accession, whereas the latter should contain all remaining peptides (including unidentified ones). -- Now, since we only want to plot intensities, we can add a **Column Filter** node by going to **Data Manipulation** > **Column Filter**. Connect its input port to the **Filtered output** port of the **Row Filter** node, and open its configuration dialog. We could either manually select the columns we want to keep, or, more elegantly, select **Wildcard/Regex Selection** and enter `intensity_?` as the pattern. KNIME will interactively show you which columns your pattern applies to while you’re typing. -- Since we want to plot log intensities, we will now compute the log of all intensity values in our table. The easiest way to do this in KNIME is a small piece of R code. Add an **R Snippet** node `R` after **Column Filter** and double-click to configure. In the R Script text editor, enter the following code: +- Let’s say we want to plot the log intensity distributions of the human spike-in peptides for all input files. In addition, we will plot the intensity distributions of the background peptides. +- As shown in Fig. 17, add a `Row Splitter` node (**Data Manipulation** > **Row** > **Filter**) after the `ConsensusTextReader` node. Double-click it to configure. The human spike-in peptides have accessions starting with “hum”. Thus, set the column to apply the test to `accessions`, select pattern matching as matching criterion, enter `hum*` into the corresponding text field, and check the contains wild cards box. Press **OK** and execute the node. +- `Row Splitter` produces two output tables: the first one contains all rows from the input table matching the filter criterion, and the second table contains all other rows. You can inspect the tables by right-clicking and selecting **Filtered** and **Filtered Out**. The former table should now only contain peptides with a human accession, whereas the latter should contain all remaining peptides (including unidentified ones). +- Now, since we only want to plot intensities, we can add a `Column Filter` node by going to **Data Manipulation** > `Column Filter`. Connect its input port to the **Filtered output** port of the **Row Filter** node, and open its configuration dialog. We could either manually select the columns we want to keep, or, more elegantly, select **Wildcard/Regex Selection** and enter `intensity_?` as the pattern. KNIME will interactively show you which columns your pattern applies to while you’re typing. +- Since we want to plot log intensities, we will now compute the log of all intensity values in our table. The easiest way to do this in KNIME is a small piece of R code. Add an **R Snippet** node `R` after `Column Filter` and double-click to configure. In the R Script text editor, enter the following code: ```r x <- knime.in # store copy of input table in x @@ -941,10 +878,10 @@ For downstream analysis of the quantification results within the KNIME environme x <- log10(x) # compute log of all values knime.out <- x # write result to output table ``` -- Now we are ready to plot! Add a **Box Plot (local)** node `Views -Swing (local)` after the **R Snippet** node, execute it, and open its view. If everything went well, you should see a significant fold change of your human peptide intensities across the three runs. -- To verify that the concentration of background peptides is constant in all three runs, copy and paste the three nodes after **Row Splitter** and connect the duplicated **Column Filter** to the second output port (Filtered Out) of **Row Splitter**, as shown in Fig. 17. Execute and open the view of your second **Box Plot**. +- Now we are ready to plot! Add a `Box Plot (JavaScript)` node `Views -JavaScript` after the **R Snippet** node, execute it, and open its view. If everything went well, you should see a significant fold change of your human peptide intensities across the three runs. +- To verify that the concentration of background peptides is constant in all three runs, copy and paste the three nodes after `Row Splitter` and connect the duplicated `Column Filter` to the second output port (Filtered Out) of `Row Splitter`, as shown in Fig. 17. Execute and open the view of your second **Box Plot**. -You have now constructed an entire identification and label-free quantification workflow including a simple data analysis using KNIME. The final workflow should like the workflow shown in the following image: +You have now constructed an entire identification and label-free feature mapping workflow including a simple data analysis using KNIME. The final workflow should like the workflow shown in the following image: |![Simple KNIME data analysis example for LFQ](/images/openms-user-tutorial/labelfree/data_analysis.png)| |:--:| @@ -1005,15 +942,15 @@ quantities [fmols] |:--:| |Figure 18: KNIME data analysis of iPRG LFQ data.| -The iPRG LFQ workflow (Fig. 18) consists of an identification and a quantification part. The identification is achieved by searching the computationally calculated MS2 spectra from a sequence database (**File Importer** node, here with the given database from iPRG: +The iPRG LFQ workflow (Fig. 18) consists of an identification and a quantification part. The identification is achieved by searching the computationally calculated MS2 spectra from a sequence database (`File Importer` node, here with the given database from iPRG: {path}`ExampleData,iPRG2015,database,iPRG2015targetdecoynocontaminants.fasta` -against the MS2 from the original data (**Input Files** node with all mzMLs following {path}`ExampleData,iPRG2015,datasets,JD06232014sample*.mzML` using the `CometAdapter`. +against the MS2 from the original data (`Input Files` node with all mzMLs following {path}`ExampleData,iPRG2015,datasets,JD06232014sample*.mzML` using the `CometAdapter`. ```{note} If you want to reproduce the results at home, you have to download the iPRG data in mzML format and perform peak picking on it or convert and pick the raw data with `msconvert`. ``` -Afterwards, the results are scored using the **FalseDiscoveryRate** node and filtered to obtain only unique peptides (**IDFilter**) since `MSstats` does not support shared peptides, yet. The quantification is achieved by using the **FeatureFinderCentroided** node, which performs the feature detection on the samples (maps). In the end the quantification results are combined with the filtered identification results (**IDMapper**). In addition, a linear retention time alignment is performed (**MapAlignerPoseClustering**), followed by the feature linking process (**FeatureLinkerUnlabledQT**). The **ConsensusMapNormalizer**s is used to normalize the intensities via robust regression over a set of maps and the **IDConflictResolver** assures that only one identification (best score) is associated with a feature. The output of this workflow is a consensusXML file, which can now be converted using the **MSstatsConverter** (see Conversion and downstream analysis section). +Afterwards, the results are scored using the **FalseDiscoveryRate** node and filtered to obtain only unique peptides (`IDFilter`) since `MSstats` does not support shared peptides, yet. The quantification is achieved by using the `FeatureFinderCentroided` node, which performs the feature detection on the samples (maps). In the end the quantification results are combined with the filtered identification results (`IDMapper`). In addition, a linear retention time alignment is performed (`MapAlignerPoseClustering`), followed by the feature linking process (**FeatureLinkerUnlabledQT**). The **ConsensusMapNormalizer**s is used to normalize the intensities via robust regression over a set of maps and the `IDConflictResolver` assures that only one identification (best score) is associated with a feature. The output of this workflow is a consensusXML file, which can now be converted using the `MSStatsConverter` (see Conversion and downstream analysis section). #### Experimental design @@ -1096,7 +1033,7 @@ The conditions are highly dependent on the type of experiment and on which kind #### Conversion and downstream analysis -Conversion of the OpenMS-internal consensusXML format (which is an aggregation of quantified and possibly identified features across several MS-maps) to a table (in MSstats-conformant CSV format) is very easy. First, create a new KNIME workflow. Then, run the **MSstatsConverter** node with a consensusXML and the manually created (e.g. in Excel) experimental design as inputs (loaded via **File Importer** nodes). The first input can be found in: +Conversion of the OpenMS-internal consensusXML format (which is an aggregation of quantified and possibly identified features across several MS-maps) to a table (in MSstats-conformant CSV format) is very easy. First, create a new KNIME workflow. Then, run the `MSStatsConverter` node with a consensusXML and the manually created (e.g. in Excel) experimental design as inputs (loaded via `File Importer` nodes). The first input can be found in: {path}`ExampleData,iPRG2015,openmsLFQResults,iPRGlfq.consensusXML` @@ -1113,17 +1050,17 @@ Adjust the parameters in the config dialog of the converter to match the given e |*labeled_reference_peptides*|false| |*retention_time_summarization_method (advanced)*|sum| -The downstream analysis of the peptide ions with `MSstats` is performed in several steps. These steps are reflected by several KNIME R nodes, which consume the output of **MSstatsConverter**. The outline of the workflow is shown in Figure 19. +The downstream analysis of the peptide ions with `MSstats` is performed in several steps. These steps are reflected by several KNIME R nodes, which consume the output of `MSStatsConverter`. The outline of the workflow is shown in Figure 19. |![MSstats analysis using KNIME](/images/openms-user-tutorial/labelfree/MSstats.png)| |:--:| |Figure 19: MSstats analysis using KNIME. The individual steps (Preprocessing, Group Comparisons, Result Data Renaming, and Export) are split among several consecutive nodes.| -We load the file resulting from **MSStatsConverter** either by saving it with an **Output File** node and reloading it with the **File Reader**. Alternatively, for advanced users, you can use a URI Port to Variable node and use the variable in the File Reader config dialog (**V** button - located on the right of the **Browse** button) to read from the temporary file. +We load the file resulting from `MSStatsConverter` either by saving it with an `Output File` node and reloading it with the `File Reader`. Alternatively, for advanced users, you can use a URI Port to Variable node and use the variable in the File Reader config dialog (**V** button - located on the right of the **Browse** button) to read from the temporary file. ##### Preprocessing -The first node (**Table to R**) loads `MSstats` as well as the data from the previous KNIME node and performs a preprocessing step on the input data. The following inline R script ( needs to be pasted into the config dialog of the node): +The first node (`Table to R`) loads `MSstats` as well as the data from the previous KNIME node and performs a preprocessing step on the input data. The following inline R script ( needs to be pasted into the config dialog of the node): ```r library(MSstats) @@ -1131,7 +1068,7 @@ data <- knime.in quant <- OpenMStoMSstatsFormat(data, removeProtein_with1Feature = FALSE) ``` -The inline R script allows further preparation of the data produced by **MSstatsConverter** before the actual analysis is performed. In this example, the lines with proteins, which were identified with only one feature, were retained. Alternatively they could be removed. +The inline R script allows further preparation of the data produced by `MSStatsConverter` before the actual analysis is performed. In this example, the lines with proteins, which were identified with only one feature, were retained. Alternatively they could be removed. In the same node, most importantly, the following line transforms the data into a format that is understood by `MSstats`: ```r @@ -1312,7 +1249,7 @@ We have made the following changes compared to the original label-free quantific used the resulting protein grouping information to also quantify indistinguishable proteins. In fact, we also used a greedy method in **FidoAdapter** (parameter `greedy_group_resolution`) to uniquely assign the peptides of a group to the most probable protein(s) in the respective group. This boosts the number of quantifications but slightly raises the chances to yield distorted protein quantities. - As a prerequisite for using **FidoAdapter**, we have added an **IDPosteriorErrorProbability** node within the ID meta node, between the **XTandemAdapter** (note the replacement of OMSSA because of ill-calibrated scores) and **PeptideIndexer**. We have set its parameter `prob_correct` to `true`, so it computes posterior probabilities instead of posterior error probabilities (1 - PEP). These are stored in the resulting idXML file and later on used by the Fido algorithm. Also note that we excluded FDR filtering from the standard meta node. Harsh filtering before inference impacts the calibration of the results. Since we filter peptides before quantification though, no potentially random peptides will be included in the results anyway. -- Next, we have added a third outgoing connection to our ID meta node and connected it to the second input port of **ZipLoopEnd**. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. +- Next, we have added a third outgoing connection to our ID meta node and connected it to the second input port of `ZipLoopEnd`. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. - Instead of the meta node **Protein inference** with **FidoAdapter**, we could have just used a **FidoAdapter** node ( **Community Nodes** > **OpenMS** > **Identification Processing**). However, the meta node contains an additional subworkflow which, besides calling **FidoAdapter**, performs a statistical validation (e.g. (pseudo) receiver operating curves; ROCs) of the protein inference results using some of the more advanced KNIME and R nodes. The meta node also shows how to use **MzTabExporter** and **MzTabReader**. ### Statistical validation of protein inference results @@ -1375,11 +1312,11 @@ Let’s have a look at the workflow (see Fig 23). The full analysis workflow can be found here: {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` -The workflow has four input nodes. The first for the experimental design to allow for MSstatsTMT compatible export (**MSstatsConverter**). The second for the `.mzML` files with the centroided spectra from the isobaric labeling experiment and the third one for the `.fasta` database used for identification. The last one allows to specify an output path for the plots generated by the R View, which runs MSstatsTMT (I). The quantification (A) is performed using the **IsobaricAnalzyer**. The tool is able to extract and normalize quantitative information from TMT and iTRAQ data. The values can be assessed from centroided MS2 or MS3 spectra (if available). Isotope correction is performed based on the specified correction matrix (as provided by the manufacturer). The identification (C) is applied as known from the previous chapters by using database search and a target-decoy database. +The workflow has four input nodes. The first for the experimental design to allow for MSstatsTMT compatible export (`MSStatsConverter`). The second for the `.mzML` files with the centroided spectra from the isobaric labeling experiment and the third one for the `.fasta` database used for identification. The last one allows to specify an output path for the plots generated by the R View, which runs MSstatsTMT (I). The quantification (A) is performed using the **IsobaricAnalzyer**. The tool is able to extract and normalize quantitative information from TMT and iTRAQ data. The values can be assessed from centroided MS2 or MS3 spectra (if available). Isotope correction is performed based on the specified correction matrix (as provided by the manufacturer). The identification (C) is applied as known from the previous chapters by using database search and a target-decoy database. -To reduce the complexity of the data for later inference the q-value estimation and FDR filtering is performed on PSM level for each file individually (B). Afterwards the identification (PSM) and quantiative information is combined using the **IDMapper**. After the processing of all available files, the intermediate results are aggregated (**FileMerger** - D). All PSM results are used for score estimation and protein inference (**Epifany**) (E). For detailed information about protein inference please see Chaper 4. Then, decoys are removed and the inference results are filtered via a protein group FDR. Peptide level results can be exported via **MzTabExporter** (F), protein level results can be obtained via the **ProteinQuantifier** (G) or the results can exported (**MSstatsConverter** - H) and further processed with the following R pipeline to allow for downstream processing using `MSstatsTMT`. +To reduce the complexity of the data for later inference the q-value estimation and FDR filtering is performed on PSM level for each file individually (B). Afterwards the identification (PSM) and quantiative information is combined using the `IDMapper`. After the processing of all available files, the intermediate results are aggregated (**FileMerger** - D). All PSM results are used for score estimation and protein inference (**Epifany**) (E). For detailed information about protein inference please see Chaper 4. Then, decoys are removed and the inference results are filtered via a protein group FDR. Peptide level results can be exported via **MzTabExporter** (F), protein level results can be obtained via the **ProteinQuantifier** (G) or the results can exported (`MSStatsConverter` - H) and further processed with the following R pipeline to allow for downstream processing using `MSstatsTMT`. -Please import the workflow from {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. Before you can execute the workflow, you have to correct the locations of the files in the **Input Files** nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. +Please import the workflow from {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. Before you can execute the workflow, you have to correct the locations of the files in the `Input Files` nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. ### Excursion MSstatsTMT @@ -1488,7 +1425,7 @@ The experimental design in table format allows for `MSstatsTMT` compatible expor
-After running the worklfow, the **MSstatsConverter** will convert the OpenMS output in addition with the experimental design to a file (.csv) which can be processed by using `MSstatsTMT`. +After running the worklfow, the `MSStatsConverter` will convert the OpenMS output in addition with the experimental design to a file (.csv) which can be processed by using `MSstatsTMT`. #### MSstatsTMT analysis @@ -1499,9 +1436,9 @@ Here, we depict the analysis by `MSstatsTMT` using a segment of the isobaric ana |:--:| |Figure 25: MSstatsTMT workflow segment| -There are two input nodes, the first one takes the result (.csv) from the **MSstatsConverter** and the second a path to the directory where the plots generated by `MSstatsTMT` should be saved. The **R source** node loads the required packages, such as `dplyr` for data wrangling, `MSstatsTMT` for analysis and `MSstats` for plotting. The inputs are further processed in the **R View** node. +There are two input nodes, the first one takes the result (.csv) from the `MSStatsConverter` and the second a path to the directory where the plots generated by `MSstatsTMT` should be saved. The **R source** node loads the required packages, such as `dplyr` for data wrangling, `MSstatsTMT` for analysis and `MSstats` for plotting. The inputs are further processed in the **R View** node. -Here, the data of the **File Importer** is loaded into **R** using the flow variable [”URI-0”]: +Here, the data of the `File Importer` is loaded into **R** using the flow variable [”URI-0”]: ```r file <- substr(knime.flow.in[["URI-0"]], 6, nchar(knime.flow.in[["URI-0"]])) @@ -1607,11 +1544,11 @@ why we need a different feature finder for metabolites lies in the step after tr have very different isotopic distributions. To group small molecule mass traces correctly, an aggregation model tailored to small molecules is thus needed. - Create a new workflow called for instance ”Metabolomics”. -- Add an **File Importer** node and configure it with one mzML file [from the](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/) {path}`Example_Data,Metabolomics,datasets`. -- Add a **FeatureFinderMetabo** node (from **Community Nodes** > **OpenMS** > **Quantitation**) and -connect the first output port of the **File Importer** to the **FeatureFinderMetabo**. +- Add an `File Importer` node and configure it with one mzML file [from the](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/) {path}`Example_Data,Metabolomics,datasets`. +- Add a `FeatureFinderMetabo` node (from **Community Nodes** > **OpenMS** > **Quantitation**) and +connect the first output port of the `File Importer` to the `FeatureFinderMetabo`. - For an optimal result adjust the following settings. Please note that some of these are advanced parameters. -- Connect a **Output Folder** to the output of the **FeatureFinderMetabo** (see Fig. 27). +- Connect a `Output Folder` to the output of the `FeatureFinderMetabo` (see Fig. 27). (Figure_27)= |![FeatureFinderMetabo workflow](/images/openms-user-tutorial/metabo/minimal_FFM_wf.png)| @@ -1629,14 +1566,14 @@ In the following advanced parameters will be highlighted. These parameter can be |*algorithm*→*epd*→*width_filtering*|off| |*algorithm*→*ffm*→*report_convex_hulls*|true| -The parameters change the behavior of **FeatureFinderMetabo** as follows: +The parameters change the behavior of `FeatureFinderMetabo` as follows: - **chrom_fwhm**: The expected chromatographic peak width in seconds. -- **trace_termination_criterion**: In the first stage **FeatureFinderMetabo** assembles +- **trace_termination_criterion**: In the first stage `FeatureFinderMetabo` assembles mass traces with a pre-defined mass accuracy. If this parameter is set to ’outlier’, the extension of a mass trace is stopped after a predefined number of consecutive outliers is found. If this parameter is set to ’sample_rate’, the extension of a mass trace is stopped once the ratio of collected peaks versus visited spectra falls below the ratio given by `min_sample_rate`. - **min_trace_length**: Minimal length of a mass trace in seconds. Choose a small value, if you want to identify low-intensity compounds. - **max_trace_length**: Maximal length of a mass trace in seconds. Set this parameter to -1 to disable the filtering by maximal length. -- **width_filtering**: **FeatureFinderMetabo** can remove features with unlikely peak widths from the results. If activated it will use the interval provided by the parameters `min_fwhm` and `max_fwhm`. +- **width_filtering**: `FeatureFinderMetabo` can remove features with unlikely peak widths from the results. If activated it will use the interval provided by the parameters `min_fwhm` and `max_fwhm`. - **report_convex_hulls**: If set to true, convex hulls including mass traces will be reported for all identified features. This increases the output size considerably. The output file .featureXML can be visualized with TOPPView on top of the used `.mzML` file - in a so called layer - to look at the identified features. @@ -1663,7 +1600,7 @@ First start TOPPView and open the example `.mzML` file (see **OpenMS**>**Map Alignment**), set its Output Type to featureXML, and adjust the following settings: +- After the `ZipLoopEnd` node, add a `MapAlignerPoseClustering` node (**Community Nodes**>**OpenMS**>**Map Alignment**), set its Output Type to featureXML, and adjust the following settings: |**parameter**| **value**| |:------------|:---------| @@ -1700,7 +1637,7 @@ The next step after retention time correction is the grouping of corresponding f |:--:| |Figure 33: Features A and B correspond to the same analyte. The linking of features between runs (indicated by an arrow) allows comparing feature intensities.| -- After the **MapAlignerPoseClustering** node, add a **FeatureLinkerUnlabeledQT** node (**Community Nodes** > **OpenMS**>**Map Alignment**) and adjust the following settings: +- After the `MapAlignerPoseClustering` node, add a `FeatureLinkerUnlabeledQT` node (**Community Nodes** > **OpenMS**>**Map Alignment**) and adjust the following settings: |**parameter**|**value**| |:------------|:--------| @@ -1708,14 +1645,14 @@ The next step after retention time correction is the grouping of corresponding f |*algorithm* → *distance_MZ* → *max_difference*|20| |*algorithm* → *distance_MZ* → *unit*|ppm| - The parameters change the behavior of **FeatureLinkerUnlabeledQT** as follows (similar to the parameters we adjusted for **MapAlignerPoseClustering**): + The parameters change the behavior of `FeatureLinkerUnlabeledQT` as follows (similar to the parameters we adjusted for `MapAlignerPoseClustering`): - **distance_RT → max_difference**: Features that have a larger RT difference will never be paired. - **distance_MZ → max_difference**: Features that have a larger m/z difference will never be paired. - **distance_MZ → unit**: Unit used for the parameter distance_MZ max_difference, either Da or ppm. -- After the **FeatureLinkerUnlabeledQT** node, add a **TextExporter** node (**Community Nodes** > **OpenMS** > **File Handling**). -- Add an **Output Folder** node and configure it with an output directory where you want to store the resulting files. +- After the `FeatureLinkerUnlabeledQT` node, add a **TextExporter** node (**Community Nodes** > **OpenMS** > **File Handling**). +- Add an `Output Folder` node and configure it with an output directory where you want to store the resulting files. - Run the pipeline and inspect the output. (Figure_34)= @@ -1723,9 +1660,9 @@ The next step after retention time correction is the grouping of corresponding f |:--:| |Figure 34: Label-free quantification workflow for metabolites.| -You should find a single, tab-separated file containing the information on where metabolites were found and with which intensities. You can also add **Output Folder** nodes at different stages of the workflow and inspect the intermediate results (e.g., identified metabolite features for each input map). The complete workflow can be seen in Figure 34. In the following section we will try to identify those metabolites. +You should find a single, tab-separated file containing the information on where metabolites were found and with which intensities. You can also add `Output Folder` nodes at different stages of the workflow and inspect the intermediate results (e.g., identified metabolite features for each input map). The complete workflow can be seen in Figure 34. In the following section we will try to identify those metabolites. -The **FeatureLinkerUnlabeledQT** output can be visualized in TOPPView on top of the input and output of the **FeatureFinderMetabo** (see Fig 35). +The `FeatureLinkerUnlabeledQT` output can be visualized in TOPPView on top of the input and output of the `FeatureFinderMetabo` (see Fig 35). (Figure_35)= |![Label-free quantification workflow for metabolites](/images/openms-user-tutorial/metabo/ToppView_5.png)| @@ -1738,7 +1675,7 @@ At the current state we found several metabolites in the individual maps but so - Add a **FileConverter** node (**Community Nodes** > **OpenMS** > **File Handling**) and connect the output of the FeatureLinkerUnlabeledQT to the incoming port. - Open the Configure dialog of the **FileConverter** node and select the tab **OutputTypes**. In the drop down list for FileConverter.1.out select **featureXML**. - Add an **AccurateMassSearch** node (**Community Nodes** > **OpenMS** > **Utilities**) and connect the output of the **FileConverter** node to the first port of the **AccurateMassSearch** node. -- Add four **File Importer** nodes and configure them with the following [files](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/databases/): +- Add four `File Importer` nodes and configure them with the following [files](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/databases/): - {path}`Example_Data,Metabolomics,databases,PositiveAdducts.tsv` This file specifies the list of adducts that are considered in the positive mode. Each line contains the formula and charge of an adduct separated by a semicolon (e.g. M+H;1+). The mass of the adduct is calculated automatically. - {path}`Example_Data,Metabolomics,databases,NegativeAdducts.tsv` @@ -1748,8 +1685,8 @@ At the current state we found several metabolites in the individual maps but so - {path}`Example_Data,Metabolomics,databases,HMDB2StructMapping.tsv` This file contains additional information about the identifiers in the mapping file. It has four tab-separated columns that contain the identifier, name, SMILES, and INCHI. These will be included in the result file. The identifiers in this file must match the identifiers in the `HMDBMappingFile.tsv`. - In the same order as they are given above connect them to the remaining input ports of the **AccurateMassSearch** node. -- Add an **Output Folder** node and connect the first output port of the -**AccurateMassSearch** node to the **Output Folder** node. +- Add an `Output Folder` node and connect the first output port of the +**AccurateMassSearch** node to the `Output Folder` node. The result of the **AccurateMassSearch** node is in the mzTab format[^17] so you can easily open it in a text editor or import it into Excel or KNIME, which we will do in the next section. The complete workflow from this section is shown in Figure 36. @@ -1760,7 +1697,7 @@ The result of the **AccurateMassSearch** node is in the mzTab format[^17] so you #### Convert your data into a KNIME table -The result from the TextExporter node as well as the result from the **AccurateMassSearch** node are files while standard KNIME nodes display and process only KNIME tables. To convert these files into KNIME tables we need two different nodes. For the **AccurateMassSearch** results, we use the **MzTabReader** node (**Community Nodes** > **OpenMS** > **Conversion** > **mzTab**) and its **Small Molecule Section** port. For the result of the **TextExporter**, we use the **ConsensusTextReader** (**Community Nodes** > **OpenMS** > **Conversion**). +The result from the TextExporter node as well as the result from the **AccurateMassSearch** node are files while standard KNIME nodes display and process only KNIME tables. To convert these files into KNIME tables we need two different nodes. For the **AccurateMassSearch** results, we use the **MzTabReader** node (**Community Nodes** > **OpenMS** > **Conversion** > **mzTab**) and its **Small Molecule Section** port. For the result of the **TextExporter**, we use the `ConsensusTextReader` (**Community Nodes** > **OpenMS** > **Conversion**). When executed, both nodes will import the OpenMS files and provide access to the data as KNIME tables. The retention time values are exported as a list using the **MzTabReader** based on the current PSI-Standard. This has to be parsed using the **SplitCollectionColumn**, which outputs a ”Split Value 1” based on the first entry in the rention time list, which has to be renamed to retention time using the **ColumnRename**. You can now combine both tables using the **Joiner** node (**Manipulation** > **Column** > **Split & Combine**) and configure it to match the m/z and retention time values of the respective tables. The full workflow is shown in Figure 37. (Figure_37)= @@ -1805,7 +1742,7 @@ Check out the **Molecule Type Cast** node (**Chemistry** > **Translators**) toge

**Task**

-Have a look at the **Column Filter** node to reduce the table to the interesting columns, e.g., only the Ids, chemical formula, and intensities. +Have a look at the `Column Filter` node to reduce the table to the interesting columns, e.g., only the Ids, chemical formula, and intensities.
@@ -1882,7 +1819,7 @@ Construct the workflow as shown in Fig. 42. Use the [file](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/Metabolite_DeNovoID.mzML) `MetaboliteDeNovoID.mzML` as input for your workflow.
-Below we show an example workflow for de novo identification (Fig. 42). Here, the node **FeatureFinderMetabo** is used for feature detection to annotate analytes in mz, rt, intensity and charge. This is followed by adduct grouping, trying to asses possible adducts based on the feature space using the **MetaboliteAdductDecharger**. In addition, the **HighResPrecursorMassCorrector** can use the newly generated feature information to map MS2 spectra, which were measured on one of the isotope traces to the monoisotopic precursor. This helps with feature mapping and analyte identification in the **SiriusAdapter** due to the usage of additional MS2 spectra that belong to a specific feature. +Below we show an example workflow for de novo identification (Fig. 42). Here, the node `FeatureFinderMetabo` is used for feature detection to annotate analytes in mz, rt, intensity and charge. This is followed by adduct grouping, trying to asses possible adducts based on the feature space using the **MetaboliteAdductDecharger**. In addition, the **HighResPrecursorMassCorrector** can use the newly generated feature information to map MS2 spectra, which were measured on one of the isotope traces to the monoisotopic precursor. This helps with feature mapping and analyte identification in the **SiriusAdapter** due to the usage of additional MS2 spectra that belong to a specific feature. (Figure_42)= |![De novo identification workflow](/images/openms-user-tutorial/metabo/denovoid.png)| @@ -1922,7 +1859,7 @@ Inspect the **R Snippet** by double-clicking on it. The KNIME table that is pass After we linked features across all maps, we want to identify features that are significantly deregulated between the two conditions. We will first scale and normalize the data, then perform a t-test, and finally correct the obtained p-values for multiple testing using Benjamini-Hochberg. All of these steps will be carried out in individual **R Snippet** nodes. - Double-click on the first **R Snippet** node labeled ”log scaling” to open the **R Snippet** dialog. In the middle you will see a short R script that performs the log scaling. To perform the log scaling we use a so-called regular expression (grepl) to select all columns containing the intensities in the six maps and take the log2 logarithm. -- The output of the log scaling node is also used to draw a boxplot that can be used to examine the structure of the data. Since we only want to plot the intensities in the different maps (and not m/z or rt) we first use a **Column Filter** node to keep only the columns that contain the intensities. We connect the resulting table to a **Box Plot** node which draws one box for every column in the input table. Right-click and select **View: Box Plot** +- The output of the log scaling node is also used to draw a boxplot that can be used to examine the structure of the data. Since we only want to plot the intensities in the different maps (and not m/z or rt) we first use a `Column Filter` node to keep only the columns that contain the intensities. We connect the resulting table to a **Box Plot** node which draws one box for every column in the input table. Right-click and select **View: Box Plot** - The median normalization is performed in a similar way to the log scaling. First we calculate the median intensity for each intensity column, then we subtract the median from every intensity. - Open the **Box Plot** connected to the normalization node and compare it to the box plot connected to the log scaling node to examine the effect of the median normalization. - To perform the t-test we defined the two groups we want to compare. Finally we save the p-values and fold-changes in two new columns named p-value and FC. @@ -1967,12 +1904,12 @@ install.packages commands once it was successfully installed. Even though the basic capabilities for (interactive) plots in KNIME are valuable for initial data exploration, professional looking depiction of analysis results often relies on dedicated plotting libraries. The statistics language R supports the addition of a large variety of packages, including packages providing extensive plotting capabilities. This part of the workflow shows how to use R nodes in KNIME to visualize more advanced figures. Specifically, we make use of different plotting packages to realize heatmaps. -- The used **RView (Table)** nodes combine the possibility to write R snippet code with visualization capabilities inside KNIME. Resulting images can be looked at in the output RView, or saved via the **Image Writer (Port)** node. +- The used `RView (Table)` nodes combine the possibility to write R snippet code with visualization capabilities inside KNIME. Resulting images can be looked at in the output RView, or saved via the **Image Writer (Port)** node. - The heatmap nodes make use of the `gplots` libary, which is by default part of the R Windows binaries (for full KNIME version 3.1.1 or higher). We again use regular expressions to extract all measured intensity columns for plotting. For clarity, feature names are only shown in the heatmap after filtering by fold changes. #### Data preparation for reporting -Following the identification, quantification and statistical analysis our data is merged and formatted for reporting. First we want to discard our normalized and logarithmized intensity values in favor of the original ones. To this end we first remove the intensity columns (**Column Filter**) and add the original intensities back (**Joiner**). For that, we use an Inner Join 2 with the **Joiner** node. In the dialog of the node, we add two entries for the Joining Columns and for the first column we pick `retention_time` from the top input (i.e. the **AccurateMassSearch** output) and `rt_cf` (the retention time of the consensus features) for the bottom input (the result from the quantification). For the second column you should choose `exp_mass_to_charge` and `mz_cf` respectively to make the joining unique. Note that the workflow needs to be executed up to the previous nodes for the possible selections of columns to appear. +Following the identification, quantification and statistical analysis our data is merged and formatted for reporting. First we want to discard our normalized and logarithmized intensity values in favor of the original ones. To this end we first remove the intensity columns (`Column Filter`) and add the original intensities back (**Joiner**). For that, we use an Inner Join 2 with the **Joiner** node. In the dialog of the node, we add two entries for the Joining Columns and for the first column we pick `retention_time` from the top input (i.e. the **AccurateMassSearch** output) and `rt_cf` (the retention time of the consensus features) for the bottom input (the result from the quantification). For the second column you should choose `exp_mass_to_charge` and `mz_cf` respectively to make the joining unique. Note that the workflow needs to be executed up to the previous nodes for the possible selections of columns to appear. (Figure_43)= |![Data preparation for reporting](/images/openms-user-tutorial/metabo/reporting.png)| @@ -2130,10 +2067,10 @@ OpenSwathDecoyGenerator.exe -in OpenSWATH_SGS_AssayLibrary_woDecoy.TraML -out Op An example KNIME workflow for OpenSWATH is supplied in `Workflows` (Fig. 44). The example dataset can be used for this workflow (filenames in brackets): 1. Open {path}`Workflows,OpenSWATH.knwf` in KNIME: **File** > **Import KNIME Workflow...** -2. Select the normalized retention time (iRT) assay library in TraML format by double-clicking on node **File Importer** > **iRT Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHiRTAssayLibrary.TraML`). +2. Select the normalized retention time (iRT) assay library in TraML format by double-clicking on node `File Importer` > **iRT Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHiRTAssayLibrary.TraML`). 3. Select the SWATH MS data in mzML format as input by double-clicking on node **Input File** > **SWATH-MS files**. ({path}`ExampleData,OpenSWATH,data,splitnapedroL120420x010SW-*.nf.pp.mzML`). -4. Select the target peptide assay library in TraML format as input by double-clicking on node **Input Files** > **Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHSGSAssayLibrary.TraML`). -5. Set the output destination by double-clicking on node **Output File**. +4. Select the target peptide assay library in TraML format as input by double-clicking on node `Input Files` > **Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHSGSAssayLibrary.TraML`). +5. Set the output destination by double-clicking on node `Output File`. 6. Run the workflow. The resulting output can be found at your selected path, which will be used as input for mProphet. Execute the script on the Terminal (Linux or Mac) or cmd.exe (Windows) in {path}`ExampleData,OpenSWATH,result`. Please use the absolute path to your R installation and the result file: @@ -2823,13 +2760,6 @@ Now you can run your tool in the Anaconda Terminal {path}`ExampleData,pyopenms`. python ProteinDigestor.py -in mini_example.fasta -out mini_example_out.idXML -enzyme Trypsin -min_length 6 -max_length 40 -missed_cleavages 1 ``` -#### Bonus task - -
-

**Task**

-Implement all other 184 TOPP tools using pyOpenMS. -
- ## Quality control ### Introduction @@ -2848,14 +2778,14 @@ Finally, in a qcml file, we split the metrics on a per mass-spectrometry-run bas As a start, we will build a basic qcML file for each mzML file in the label-free analysis. We are already creating the two necessary analysis files to build a basic qcML file upon each mzML file, a feature file and an identification file. We use the **QCCalculator** node from **Community** > **OpenMS** > **Utilities** where also all other QC* nodes will be found. The **QCCalculator** will create a very basic qcML file in which it will store collected and calculated quality data. - Copy your label-fee quantitation workflow into a new lfq-qc workflow and open it. -- Place the **QCCalculator** node after the **IDMapper** node. Being inside the **ZipLoop**, it will execute for each of the three mzML files the **Input** node. -- Connect the first **QCCalculator** port to the first **ZipLoopStart** outlet port, which will carry the individual mzML files. -- Connect the last’s ID outlet port (**IDFilter** or the ID metanode) to the second **QCCalculator** port for the identification file. -- Finally, connect the **IDMapper** outlet to the third **QCCalculator** port for the feature file. +- Place the **QCCalculator** node after the `IDMapper` node. Being inside the **ZipLoop**, it will execute for each of the three mzML files the **Input** node. +- Connect the first **QCCalculator** port to the first `ZipLoopStart` outlet port, which will carry the individual mzML files. +- Connect the last’s ID outlet port (`IDFilter` or the ID metanode) to the second **QCCalculator** port for the identification file. +- Finally, connect the `IDMapper` outlet to the third **QCCalculator** port for the feature file. The created qcML files will not have much to show for, basic as they are. So we will extend them with some basic plots. -- First, we will add an 2D overview image of the given mass spectrometry run as you may know it from TOPPView. Add the **ImageCreator** node from **Community Nodes** > **OpenMS** > **Utilities**. Change the width and heigth parameters to 640x640 as we don’t want it to be too big. Connect it to the first **ZipLoopStart** outlet port, so it will create an image file of the mzML’s contained run. +- First, we will add an 2D overview image of the given mass spectrometry run as you may know it from TOPPView. Add the **ImageCreator** node from **Community Nodes** > **OpenMS** > **Utilities**. Change the width and heigth parameters to 640x640 as we don’t want it to be too big. Connect it to the first `ZipLoopStart` outlet port, so it will create an image file of the mzML’s contained run. - Now we have to embed this file into the qcML file, and attach it to the right **QualityParameter**. For this, place a **QCEmbedder** node behind the **ImageCreator** and connect that to its third inlet port. Connect its first inlet port to the outlet of the **QCCalculator** node to pass on the qcML file. Now change the parameter cv_acc to QC:0000055 which designates the attached image to be of type QC:0000055 - MS experiment heatmap. Finally, change the parameter qp_att_acc to QC:0000004, to attach the image to the QualityParameter QC:0000004 - MS acquisition result details. - For a reference of which CVs are already defined for qcML, have a look at the following [link](https://github.com/qcML/qcML-development/blob/master/cv/qc-cv.obo). @@ -2888,7 +2818,7 @@ Press **Eval script** to execute the script. |Figure 51: Basic QC setup within a LFQ workflow.| ```{note} -To have a peek into what our qcML now looks like for one of the **ZipLoop** iterations, we can add an **Output Folder** node from **Community Nodes** > **GenericKnimeNodes** > **IO** and set its destination parameter to somewhere we want to find our intermediate qcML files in, for example **tmp** > **qcxlfq**. If we now connect the last metanode with the Output Folder and restart the workflow, we can start inspecting the qcML files. +To have a peek into what our qcML now looks like for one of the **ZipLoop** iterations, we can add an `Output Folder` node from **Community Nodes** > **GenericKnimeNodes** > **IO** and set its destination parameter to somewhere we want to find our intermediate qcML files in, for example **tmp** > **qcxlfq**. If we now connect the last metanode with the Output Folder and restart the workflow, we can start inspecting the qcML files. ```
@@ -2920,7 +2850,7 @@ ggplot(knime.in, aes(x=peptide_charge)) + - We can now use a **QCEmbetter** node like before to add our new metric plot into the qcML. - After looking for an appropriate target from the following [link](https://github.com/qcML/qcML-development/blob/master/cv/qc-cv.obo), we found that we can attach our plot to the MS *identification result details* by setting the parameter `qp_att_acc` to `QC:0000025`, as we are plotting the charge histogram of our identified peptides. - To have the plot later displayed properly, we assign it the parameter `cv_acc` of `QC:0000051`, a generic plot. Also we made sure in the *R Script*, that our plot carries a caption so that we know which is which, if we had more than one new plot. -- Now we redirect the **QCEmbedders** output to the **Output Folder** from before and can have a look at how our qcML is coming along after restarting the workflow. +- Now we redirect the **QCEmbedders** output to the `Output Folder` from before and can have a look at how our qcML is coming along after restarting the workflow. (Figure_52)= |![QC with new metric](/images/openms-user-tutorial/quality-control/qc_extra.png)| @@ -2934,8 +2864,8 @@ For this, we will first collect all created qcML files, merge them together and - Connect the **QCEmbedders** output from last section to the **ZipLoopEnds** second input port. - The corresponding output port will collect all qcML files from each **ZipLoop** iteration and pass them on as a list of files. -- Now we add a **QCMerger** node after the **ZipLoopEnd** and feed it that list of qcML files. In addition, we set its parameter `setname` to give our newly created set a name - say `spikein_replicates`. -- To inspect all the QCs next to each other in that created qcML file, we have to add a new **Output Folder** to which we can connect the **QCMerger** output. +- Now we add a **QCMerger** node after the `ZipLoopEnd` and feed it that list of qcML files. In addition, we set its parameter `setname` to give our newly created set a name - say `spikein_replicates`. +- To inspect all the QCs next to each other in that created qcML file, we have to add a new `Output Folder` to which we can connect the **QCMerger** output. When inspecting the set-qcML file in a browser, we will be presented another overview. After the set content listing, the basic QC parameters (like number of identifications) are each displayed in a graph. Each set member (or run) has its own section on the x-axis and each run is connected with that graph via a link in the mouseover on one of the QC parameter values. @@ -2949,6 +2879,63 @@ When inspecting the set-qcML file in a browser, we will be presented another ove For ideas on new QC metrics and parameters, as you add them in your qcML files as generic parameters, feel free to [contact us](/quick-reference/contact-us.md), so we can include them in the CV.
+## Advanced topic: R integration + +KNIME provides a large number of nodes for a wide range of statistical analysis, machine learning, data processing, and +visualization. Still, more recent statistical analysis methods, specialized visualizations or cutting edge algorithms +may not be covered in KNIME. In order to expand its capabilities beyond the readily available nodes, external scripting +languages can be integrated. In this tutorial, we primarily use scripts of the powerful statistical computing language R. +Note that this part is considered advanced and might be difficult to follow if you are not familiar with R. In this case +you might skip this part. + +**R View (Table)** allows to seamlessly include R scripts into KNIME. We will +demonstrate on a minimal example how such a script is integrated. + +
+

**Task**

+

+First we need some example data in KNIME, which we will generate using the **Data Generator** node (**IO** > **Other** > **Data Generator**). +You can keep the default settings and execute the node. The table contains four columns, each containing random coordinates and one column +containing a cluster number (Cluster_0 to Cluster_3). Now place a **R View (Table)** node into the workflow and connect +the upper output port of the **Data Generator** node to the input of the **R View (Table)** node. Right-click and +configure the node. If you get an error message like `Execute failed: R_HOME does not contain a folder with name ’bin’.` +or `Execution failed: R Home is invalid.`: please change the R settings in the preferences. To do so open **File** > +**Preferences** > **KNIME** > **R** and enter the path to your R installation (the folder that contains the bin +directory. e.g., {path}`C:,Program Files,R,R-3.4.3`). +

+

+If you get an error message like: ”Execute failed: Could not find Rserve package. Please install it in your R +installation by running ”install.packages(’Rserve’)”.” You may need to run your R binary as administrator (In windows +explorer: right-click ”Run as administrator”) and enter install.packages(’Rserve’) to install the package. +

+

+If R is correctly recognized we can start writing an R script. Consider that we are interested in plotting the first and +second coordinates and color them according to their cluster number. In R this can be done in a single line. In the +**R view (Table)** text editor, enter the following code: +```r +plot(x=knime.in$Universe_0_0, y=knime.in$Universe_0_1, main="Plotting column Universe_0_0 vs. Universe_0_1", col=knime.in$"Cluster Membership") +``` +

+

+**Explanation:** The table provided as input to the **R View (Table)** node is available as R **data.frame** with name +`knime.in`. Columns (also listed on the left side of the R View window) can be accessed in the usual R way by first +specifying the `data.frame` name and then the column name (e.g., `knime.in$Universe_0_0`). `plot` is the plotting function +we use to generate the image. We tell it to use the data in column `Universe_0_0` of the dataframe object **knime.in** +(denoted as `knime.in$Universe_0_0`) as x-coordinate and the other column `knime.in$Universe_0_1` as y-coordinate in the +plot. `main` is simply the main title of the plot and `col` the column that is used to determine the color (in this case +it is the `Cluster Membership` column). +

+

+Now press the Eval script and Show plot buttons. +

+
+ +```{note} +Note that we needed to put some extra quotes around `Cluster Membership`. If we omit those, R would interpret the column +name only up to the first space `(knime.in$Cluster)` which is not present in the table and leads to an error. Quotes are +regularly needed if column names contain spaces, tabs or other special characters like $ itself. +``` + ## Troubleshooting guide This section will show you where you can turn to when you encounter any problems with this tutorial or with our nodes in general. Please see the [FAQ](/quick-reference/contributor-faq.md) first. If your problem is not listed or the proposed solution does not work, feel free to leave us a message at the means of support that you see most fit. If that is the case, please provide us with as much information as you can. In an ideal case, that would be: diff --git a/docs/topp-command-line-tools/consensus-peptide-identification.md b/docs/topp-command-line-tools/consensus-peptide-identification.md index 8799f0a8..b34f1055 100644 --- a/docs/topp-command-line-tools/consensus-peptide-identification.md +++ b/docs/topp-command-line-tools/consensus-peptide-identification.md @@ -19,7 +19,7 @@ fed to the **ConsensusID** tool (ConsensusID is currently usable for Mascot and To combine quantitation and identification results: -Protein/peptide identifications can be annotated to quantitation results (featureXML, consensusXML) by the **IDMapper** +Protein/peptide identifications can be annotated to quantitation results (featureXML, consensusXML) by the `IDMapper` tool. The combined results can then be exported by the **TextExporter** tool: [Conversion between OpenMS XML formats and text formats](conversion-between-openms-xml-formats-and-text-formats.md). diff --git a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md index ea7a454e..5fdfc870 100644 --- a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md +++ b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md @@ -518,7 +518,7 @@ The complete workflow is shown in the below image. `FileInfo` can produce two di ```{note} Make sure to use the “tiny” version this time, not “small”, for the sake of faster workflow execution. ``` -- The **Input File** node and the **FileInfo** node should now have switched to yellow, but the **Output Folder** node is still red. +- The **Input File** node and the `FileInfo` node should now have switched to yellow, but the **Output Folder** node is still red. Double-click on the **Output Folder** node and click on **Browse** to select an output directory for the generated data. - Great! Your first workflow is now ready to be run. Press + F7 (shift key + F7; or the button with multiple green triangles in the KNIME Toolbar) to execute the complete workflow. You can also right-click @@ -541,11 +541,11 @@ same information on three different files and then write the output files to a f - To select the files we double-click on the Input Files node and click on **Add**. In the filesystem browser, we select all three files from the directory **Example_Data** > **Introduction** > **datasets** > **tiny**. And close the dialog with **Ok**. -- We now add two more nodes: the **ZipLoopStart** and the **ZipLoopEnd** node from the category +- We now add two more nodes: the `ZipLoopStart` and the `ZipLoopEnd` node from the category **Community Nodes** > **GenericKnimeNodFlow** > **Flow**. -- Afterwards we connect the **Input Files** node to the first port of the **ZipLoopStart** node, the first port of the **ZipLoopStart** +- Afterwards we connect the `Input Files` node to the first port of the `ZipLoopStart` node, the first port of the `ZipLoopStart` node to the **FileConverter** node, the first output port of the **FileConverter** node to the first input port of the - **ZipLoopEnd** node, and the first output port of the **ZipLoopEnd** node to the **Output Folder** node (NOT to the Output File). + `ZipLoopEnd` node, and the first output port of the `ZipLoopEnd` node to the **Output Folder** node (NOT to the Output File). The complete workflow is shown in the below figure. @@ -555,9 +555,9 @@ The complete workflow is shown in the below figure. Execute the workflow and inspect the output as before. -In case you had trouble to understand what **ZipLoopStart** and **ZipLoopEnd** do, here is a brief explanation: +In case you had trouble to understand what `ZipLoopStart` and `ZipLoopEnd` do, here is a brief explanation: -- The **Input Files** node passes a list of files to the ZipLoopStart node. +- The `Input Files` node passes a list of files to the ZipLoopStart node. - The ZipLoopStart node takes the files as input, but passes the single files sequentially (that is: one after the other) to the next node. - The ZipLoopEnd collects the single files that arrive at its input port. After all, files have been processed, the collected @@ -704,7 +704,7 @@ As a start, we will extend the minimal workflow so that it performs a peptide id engine. Since OpenMS version 1.10, OMSSA is included in the OpenMS installation, so you do not need to download and install it yourself. -Let’s start by replacing the input files in our **Input Files** node with the three mzML files in +Let’s start by replacing the input files in our `Input Files` node with the three mzML files in **Example Data** > **Labelfree** > **datasets** > **lfqxspikeinxdilutionx1-3.mzML**. This is a reduced toy dataset where each of the three runs contains a constant background of S. `pyogenes` peptides as well as human spike-in peptides in different concentrations. [^10] @@ -843,16 +843,16 @@ In the end, the ID processing part of the workflow can be collapsed into a Metan Now that we have successfully constructed a peptide identification pipeline, we can add quantification capabilities to our workflow. -- Add a **FeatureFinderCentroided** node from **Community Nodes** > **OpenMS** > **Quantitation** -which gets input from the first output port of the **ZipLoopStart** node. Also, add -an **IDMapper** node (from **Community Nodes** > **OpenMS** > **ID Processing** ) which receives -input from the **FeatureFinderCentroided** node (Port 1) and the ID Metanode (or **IDFilter** node (Port 0) if you haven’t used the Metanode). The output of the **IDMapper** node is then connected to an in port of the **ZipLoopEnd** node. +- Add a `FeatureFinderCentroided` node from **Community Nodes** > **OpenMS** > **Quantitation** +which gets input from the first output port of the `ZipLoopStart` node. Also, add +an `IDMapper` node (from **Community Nodes** > **OpenMS** > **ID Processing** ) which receives +input from the `FeatureFinderCentroided` node (Port 1) and the ID Metanode (or **IDFilter** node (Port 0) if you haven’t used the Metanode). The output of the `IDMapper` node is then connected to an in port of the `ZipLoopEnd` node. - `FeatureFinderCentroided` finds and quantifies peptide ion signals contained in the MS1 data. It reduces the entire signal, i.e., all peaks explained by one and the same peptide ion signal, to a single peak at the maximum of the chromatographic elution profile of the monoisotopic mass trace of this peptide ion and assigns an overall intensity. -- `FeatureFinderCentroided` produces a featureXML file as output, containing only quantitative information of so-far unidentified peptide signals. In order to annotate these with the corresponding ID information, we need the **IDMapper** node. -- Run your pipeline and inspect the results of the **IDMapper** node in TOPPView. Open the mzML file of your data to display the raw peak intensities. +- `FeatureFinderCentroided` produces a featureXML file as output, containing only quantitative information of so-far unidentified peptide signals. In order to annotate these with the corresponding ID information, we need the `IDMapper` node. +- Run your pipeline and inspect the results of the `IDMapper` node in TOPPView. Open the mzML file of your data to display the raw peak intensities. - To assess how well the feature finding worked, you can project the features contained in the featureXML file on the raw data contained in the mzML file. To this end, open the featureXML file in TOPPView by clicking on File Open file and add it to a new layer ( Open in New layer ). The features are now visualized on top of your raw data. If you zoom in on a small region, you should be able to see the individual boxes around features that have been detected (see Fig. 14). If you hover over the feature centroid (small circle indicating the chromatographic apex of the monoisotopic trace) additional information about the feature is displayed. @@ -984,13 +984,13 @@ quantities [fmols] The iPRG LFQ workflow (Fig. 18) consists of an identification and a quantification part. The identification is achieved by searching the computationally calculated MS2 spectra from a sequence database (**Input File** node, here with the given database from iPRG: {path}`ExampleData,iPRG2015,database,iPRG2015targetdecoynocontaminants.fasta` -against the MS2 from the original data (**Input Files** node with all mzMLs following {path}`ExampleData,iPRG2015,datasets,JD06232014sample*.mzML` using the `OMSSAAdapter`. +against the MS2 from the original data (`Input Files` node with all mzMLs following {path}`ExampleData,iPRG2015,datasets,JD06232014sample*.mzML` using the `OMSSAAdapter`. ```{note} If you want to reproduce the results at home, you have to download the iPRG data in mzML format and perform peak picking on it or convert and pick the raw data with `msconvert`. ``` -Afterwards, the results are scored using the **FalseDiscoveryRate** node and filtered to obtain only unique peptides (**IDFilter**) since `MSstats` does not support shared peptides, yet. The quantification is achieved by using the **FeatureFinderCentroided** node, which performs the feature detection on the samples (maps). In the end, the quantification results are combined with the filtered identification results (**IDMapper**). In addition, a linear retention time alignment is performed (**MapAlignerPoseClustering**), followed by the feature linking process (**FeatureLinkerUnlabledQT**). The **ConsensusMapNormalizer**s is used to normalize the intensities via robust regression over a set of maps and the **IDConflictResolver** assures that only one identification (best score) is associated with a feature. The output of this workflow is a consensusXML file, which can now be converted using the **MSstatsConverter** (see Conversion and downstream analysis section). +Afterwards, the results are scored using the **FalseDiscoveryRate** node and filtered to obtain only unique peptides (**IDFilter**) since `MSstats` does not support shared peptides, yet. The quantification is achieved by using the `FeatureFinderCentroided` node, which performs the feature detection on the samples (maps). In the end, the quantification results are combined with the filtered identification results (`IDMapper`). In addition, a linear retention time alignment is performed (**MapAlignerPoseClustering**), followed by the feature linking process (**FeatureLinkerUnlabledQT**). The **ConsensusMapNormalizer**s is used to normalize the intensities via robust regression over a set of maps and the **IDConflictResolver** assures that only one identification (best score) is associated with a feature. The output of this workflow is a consensusXML file, which can now be converted using the **MSstatsConverter** (see Conversion and downstream analysis section). #### Experimental design @@ -1289,7 +1289,7 @@ We have made the following changes compared to the original label-free quantific used the resulting protein grouping information to also quantify indistinguishable proteins. In fact, we also used a greedy method in **FidoAdapter** (parameter `greedy_group_resolution`) to uniquely assign the peptides of a group to the most probable protein(s) in the respective group. This boosts the number of quantifications but slightly raises the chances to yield distorted protein quantities. - As a prerequisite for using **FidoAdapter**, we have added an **IDPosteriorErrorProbability** node within the ID meta node, between the **XTandemAdapter** (note the replacement of OMSSA because of ill-calibrated scores) and **PeptideIndexer**. We have set its parameter `prob_correct` to `true`, so it computes posterior probabilities instead of posterior error probabilities (1 - PEP). These are stored in the resulting idXML file and later on, used by the Fido algorithm. Also, note that we excluded FDR filtering from the standard meta node. Harsh filtering before inference impacts the calibration of the results. Since we filter peptides before quantification though, no potentially random peptides will be included in the results anyway. -- Next, we added a third outgoing connection to our ID meta node and connected it to the second input port of **ZipLoopEnd**. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. +- Next, we added a third outgoing connection to our ID meta node and connected it to the second input port of `ZipLoopEnd`. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. - Instead of the meta node **Protein inference** with **FidoAdapter**, we could have just used a **FidoAdapter** node ( **Community Nodes** > **OpenMS** > **ID Processing**). However, the meta node contains an additional subworkflow which, besides calling **FidoAdapter**, performs a statistical validation (e.g. (pseudo) receiver operating curves; ROCs) of the protein inference results using some of the more advanced KNIME and R nodes. The meta node also shows how to use **MzTabExporter** and **MzTabReader**. ### Statistical validation of protein inference results @@ -1354,9 +1354,9 @@ The full analysis workflow can be found here: The workflow has four input nodes. The first is for the experimental design to allow for MSstatsTMT compatible export (**MSstatsConverter**). The second is for the `.mzML` files with the centroided spectra from the isobaric labeling experiment and the third one is for the `.fasta` database used for identification. The last one allows to specify an output path for the plots generated by the R View, which runs MSstatsTMT (I). The quantification (A) is performed using the **IsobaricAnalzyer**. The tool is able to extract and normalize quantitative information from TMT and iTRAQ data. The values can be assessed from centroided MS2 or MS3 spectra (if available). Isotope correction is performed based on the specified correction matrix (as provided by the manufacturer). The identification (C) is applied as known from the previous chapters by using a database search and a target-decoy database. -To reduce the complexity of the data for later inference the q-value estimation and FDR filtering is performed on PSM level for each file individually (B). Afterwards, the identification (PSM) and quantitative information is combined using the **IDMapper**. After the processing of all available files, the intermediate results are aggregated (**FileMerger** - D). All PSM results are used for score estimation and protein inference (**Epifany**) (E). For detailed information about protein inference please see Chapter 4. Then, decoys are removed and the inference results are filtered via a protein group FDR. Peptide level results can be exported via **MzTabExporter** (F), protein level results can be obtained via the **ProteinQuantifier** (G), or the results can be exported (**MSstatsConverter** - H) and further processed with the following R pipeline to allow for downstream processing using `MSstatsTMT`. +To reduce the complexity of the data for later inference the q-value estimation and FDR filtering is performed on PSM level for each file individually (B). Afterwards, the identification (PSM) and quantitative information is combined using the `IDMapper`. After the processing of all available files, the intermediate results are aggregated (**FileMerger** - D). All PSM results are used for score estimation and protein inference (**Epifany**) (E). For detailed information about protein inference please see Chapter 4. Then, decoys are removed and the inference results are filtered via a protein group FDR. Peptide level results can be exported via **MzTabExporter** (F), protein level results can be obtained via the **ProteinQuantifier** (G), or the results can be exported (**MSstatsConverter** - H) and further processed with the following R pipeline to allow for downstream processing using `MSstatsTMT`. -Please import the workflow from {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. Before you can execute the workflow, you have to correct the locations of the files in the **Input Files** nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. +Please import the workflow from {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. Before you can execute the workflow, you have to correct the locations of the files in the `Input Files` nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. ### Excursion MSstatsTMT @@ -1640,7 +1640,7 @@ First start TOPPView and open the example `.mzML` file (see **OpenMS**>**Map Alignment**), set its Output Type to featureXML, and adjust the following settings: +- After the `ZipLoopEnd` node, add a **MapAlignerPoseClustering** node (**Community Nodes**>**OpenMS**>**Map Alignment**), set its Output Type to featureXML, and adjust the following settings: |**parameter**| **value**| |:------------|:---------| @@ -2110,7 +2110,7 @@ An example KNIME workflow for OpenSWATH is supplied in `Workflows` (Fig. 2)) is listed, enabled (true) and applied to all MS levels (parameter ”1-”). Start the conversion process by clicking on the Start button.| - -Both tools are available in: {{ '{path}'+'`C:,Program Files,OpenMS-{0},share,OpenMS,THIRDPARTY,pwiz-bin`'.format(version) }}. - -You can find a small RAW file on the USB stick {path}`Example_Data,Introduction,datasets,raw`. - -#### MSConvertGUI - -`MSConvertGUI` (see Fig. 1) exposes the main parameters for data conversion in a convenient graphical user interface. - -#### msconvert - -The `msconvert` command line tool has no graphical user interface but offers more options than the application `MSConvertGUI`. Additionally, since it can be used within a batch script, it allows converting large numbers of files and can be much more easily automatized. -To convert and pick the file `raw_data_file.RAW` you may write: - -```bash -msconvert raw_data_file.RAW --filter "peakPicking true 1-" -``` - -in your command line. - -(Figure_2)= -|![profile centroided](/images/openms-user-tutorial/introduction/profilecentroided.png)| -|:--:| -|Figure 2: The amount of data in a spectra is reduced by peak picking. Here a profile spectrum (blue) is converted to centroided data (green). Most algorithms from this point on will work with centroided data.| - -To convert all RAW files in a folder may write: - -```bash -msconvert *.RAW -o my_output_dir -``` - -```{note} -To display all options you may type `msconvert --help` . Additional information is available on the `ProteoWizard` web page. -``` - -#### ThermoRawFileParser - -Recently the open-source platform independent ThermoRawFileParser tool has been developed. While Proteowizard and MSConvert are only available for Windows systems this new tool allows to also convert raw data on Mac or Linux. - -```{note} -To learn more about the `ThermoRawFileParser` and how to use it in -KNIME see A minimal workflow. -``` - -### Data visualization using TOPPView - -Visualizing the data is the first step in quality control, an essential tool in understanding the data, and of course an essential step in pipeline development. OpenMS provides a convenient viewer for some of the data: TOPPView. We will guide you through some of the basic features of TOPPView. Please familiarize yourself with the key controls and visualization methods. We will make use of these later throughout the tutorial. Let’s start with a first look at one of the files of -our tutorial data set. Note that conceptually, there are no differences in visualizing metabolomic or proteomic data. Here, we inspect a simple proteomic measurement: - -|![TOPPView](/images/openms-user-tutorial/introduction/TOPPView.png)| -|:--:| -|Figure 3: TOPPView, the graphical application for viewing mass spectra and analysis results. Top window shows a small region of a peak map. In this 2D representation of the measured spectra, signals of eluting peptides are colored according to the raw peak intensities. The lower window displays an extracted spectrum (=scan) from the peak map. On the right side, the list of spectra can be browsed.| - -|![TOPPView](/images/openms-user-tutorial/introduction/3dview.png)| -|:--:| -|Figure 4: 3D representation of the measured spectra, signals of eluting peptides are colored according to the raw peak intensities.| - -- Start TOPPView (see Windows' Start-Menu or {{ '{path}'+'`Applications,OpenMS-{0}`'.format(version) }} on macOS) - -- Go to **File** > **Open File**, navigate to the directory where you copied the contents -of the USB stick to, and [select](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Introduction/datasets/small/velos005614.mzML) {path}`Example_Data,Introduction,datasets,small,velos005614.mzML`. This file contains only a reduced LC-MS map of a label-free proteomic platelet measurement recorded on an Orbitrap velos. The other two mzML files contain technical replicates of this experiment. First, we want to -obtain a global view on the whole LC-MS map - the default option Map view 2D -is the correct one and we can click the Ok button. - -- Play around. - -- Three basic modes allow you to interact with the displayed data: scrolling, zooming and measuring: - - **Scroll mode** - - Is activated by default (though each loaded spectra file is displayed zoomed out first, so you do not need to scroll). - - Allows you to browse your data by moving around in RT and m/z range. - - When zoomed in, you can scroll through the spectra. Click-drag on the current view. - - Arrow keys can be used to scroll the view as well. - - **Zoom mode** - - Zooming into the data; either mark an area in the current view with -your mouse while holding the left mouse button plus the Ctrl key to -zoom to this area or use your mouse wheel to zoom in and out. - - All previous zoom levels are stored in a zoom history. The zoom history -can be traversed using Ctrl + + or Ctrl + - or the mouse wheel (scroll up and down). - - Pressing backspace zooms out to show the full LC-MS map (and -also resets the zoom history). - - **Measure mode** - - It is activated using the ⇧ Shift key. - - Press the left mouse button down while a peak is selected and drag -the mouse to another peak to measure the distance between peaks. - - This mode is implemented in the 1D and 2D mode only. -- Right click on your 2D map and select **Switch to 3D mode** and examine your data in 3D mode (see Fig. 4). -- Visualize your data in different intensity normalization modes, use linear, percentage (set intensity axis scale to percentage), snap and log-view (icons on - the upper left tool bar). You can hover over the icons for additional information. - - ```{note} - On macOS, due to a bug in one of the external libraries used by - OpenMS, you will see a small window of the 3D mode when switching - to 2D. Close the 3D tab in order to get rid of it. - ``` -- In TOPPView you can also execute TOPP tools. Go to **Tools** > **Apply tool (whole layer)** -and choose a TOPP tool (e.g., `FileInfo`) and inspect the results. - -Dependent on your data MS/MS spectra can be visualized as well (see Fig.5) . You can -do so, by double-click on the MS/MS spectrum shown in scan view - -|![ms2 spectrum](/images/openms-user-tutorial/introduction/ms2_introduction.png)| -|:--:| -|Figure 5: MS/MS spectrum| - -### Introduction to KNIME/OpenMS - -Using OpenMS in combination with KNIME, you can create, edit, open, save, and run workflows that combine TOPP tools with -the powerful data analysis capabilities of KNIME. Workflows can be created conveniently in a graphical user interface. -The parameters of all involved tools can be edited within the application and are also saved as part of the workflow. -Furthermore, KNIME interactively performs validity checks during the workflow editing process, to make it more -difficult to create an invalid workflow. Throughout most parts of this tutorial, you will use KNIME to create and execute -workflows. The first step is to become familiar with KNIME. Additional information on the basic usage of KNIME can be -found on the KNIME [Getting Started page](https://www.knime.com/getting-started-guide). However, the most important -concepts will also be reviewed in this tutorial. - -#### KNIME Modern and Classic UI #### - -Since version 5.0 KNIME has a new updated user interface. For the purposes of this tutorial we will continue to use the "classic user interface". -Depending on your OS KNIME may have started automatically in the Modern UI, which looks like the following: -|![ms2 spectrum](/images/openms-user-tutorial/introduction/KNIME_switch_to_classic.png)| -|:--:| -|Figure 5.5: The modern KNIME UI. To switch back to the classic UI, select "Menu" and click "Switch to classic user interface"| - -#### Plugin and dependency - -Before we can start with the tutorial, we need to install all the required extensions for KNIME. -Since KNIME 3.2.1, the program automatically -detects missing plugins when you open a workflow but to make sure that the right source for the -OpenMS plugin is chosen, please follow the instructions here. - -##### Required KNIME plugins - -First, we install some additional extensions that are -required by our OpenMS nodes or used in the Tutorials for downstream processing, visualization or reporting. - -1. In KNIME, click on **Help** > **Install New Software**. -2. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME 5.2 - https://update.knime.com/analytics-platform/5.2' -3. Now select the following KNIME core plugins from the KNIME & Extensions category - - KNIME Base Chemistry Types & Nodes - - KNIME Chemistry Add-Ons - - KNIME Interactive R Statistics Integration - - KNIME Report Designer -4. Click on **Next** and follow the instructions (it's not necessary to restart KNIME now). -5. Click again on **Help** > **Install New Software** -6. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME Community Extensions (Trusted) - https://update.knime.com/community-contributions/trusted/5.2' -7. From the "KNIME Community Contributions - Cheminformatics" category select - - RDKit Nodes Feature -8. From the "KNIME Community Extensions - Other" category select - - Generic Worfkflow Nodes for KNIME -9. Click on **Next** and follow the instructions and after a restart of KNIME the dependencies will be installed. - -##### R programming language and its KNIME integration - -In addition, we need to install `R` for the statistical downstream analysis. Choose the directory that matches your -operating system, double-click the `R` installer and follow the instructions. We recommend to use the default settings -whenever possible. On macOS you also need to install `XQuartz` from the same directory. - -Afterwards open your `R` installation. If you use Windows, you will find an ”R x64 4.3.2” icon on your desktop. If you use -macOS, you will find R in your Applications folder. In `R`, type the following lines (you might also copy them from the file -{path}`R,install_R_packages.R` on the USB stick): - -```r -install.packages('Rserve',,"http://rforge.net/",type="source") -install.packages("Cairo") - -install.packages("devtools") -install.packages("ggplot2") -install.packages("ggfortify") - -if (!requireNamespace("BiocManager", quietly = TRUE)) - install.packages("BiocManager") - -BiocManager::install() -BiocManager::install(c("MSstats")) -``` -In KNIME, click on **File** > **Preferences**, select the category **KNIME** > **R** and set the ”Path to R Home” to -your installation path. You can use the following settings, if you installed R as described above: - -- Windows: `C:\Program Files\R\R-4.3.2'` -- macOS: `/Library/Frameworks/R.framework/Versions/4.3/Resources` - -##### KNIME OpenMS plugin - -You are now ready to install the OpenMS nodes. -- In KNIME, click on **Help** > **Install New Software** - -You now have to choose an _update site_ to install the OpenMS plugin from. Which _update site_ to choose depends on if you received an USB stick -in a hands-on Tutorial or if you are doing this Tutorial online. - -::::{tab-set} - -:::{tab-item} Online -:sync: online - -To install the OpenMS KNIME plugin from the internet, do the following: - -1. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME Community Extensions (Trusted) - https://update.knime.com/community-contributions/trusted/5.2' -2. Now select the following plugin from the "KNIME Community Contributions - Bioinformatics & NGS" category - - OpenMS - - OpenMSThirdParty -3. Click on **Next** and follow the instructions and after a restart of KNIME the OpenMS nodes will be available in the Node repository under - "Community Nodes". - -```{note} -If this does not work for you, report it and while waiting for a reply/fix, try to use an _update site_ of an older KNIME version by editing the KNIME -version number in the URL or by using our inofficial _update site_ at https://abibuilder.cs.uni-tuebingen.de/archive/openms/knime-plugin/updateSite/release/latest -``` - -::: - -:::{tab-item} USB -:sync: usb - -We included a custom KNIME update site to install the OpenMS KNIME plugins from the USB stick. If you do not have a stick available, please see below. - -- In the now open dialog choose **Add** (in the upper right corner of the dialog) to define a new update site. In the - opening dialog enter the following details. - - **Name:** OpenMS {{ version }} UpdateSite - - **Location:** {{ '`file:/KNIMEUpdateSite/{0}/`'.format(version) }} -- After pressing **OK** KNIME will show you all the contents of the added Update Site. - -```{note} -From now on, you can use this repository for plugins in the **Work with**: drop-down list. -``` - -- Select the OpenMS nodes in the ”Uncategorized” category and click **Next**. -- Follow the instructions and after a restart of KNIME the OpenMS nodes will be available in the Node repository under - "Community Nodes”. - -::: - -:::{tab-item} Online experimental -:sync: onlineexp - -To install the nightly/experimental version of the OpenMS KNIME plugin from the internet, do the following: - -- In the now open dialog, choose **Add** (in the upper right corner of the dialog) to define a new _update site_. In the opening dialog enter the following details. - - **Name:** OpenMS {{ version }} UpdateSite - - **Location:** https://abibuilder.cs.uni-tuebingen.de/archive/openms/knime-plugin/updateSite/nightly/ -- After pressing **OK** KNIME will show you all the contents of the added Update Site. - -```{note} -From now on, you can use this repository for plugins in the **Work with:** drop-drown list. -``` -- Select the OpenMS nodes in the "Uncategorized" category and click **Next**. -- Follow the instructions and after a restart of KNIME the OpenMS nodes will be available in the Node repository under - "Community Nodes". - -::: - -:::: - -#### KNIME concepts - -A workflow is a sequence of computational steps applied to a single or multiple input data to process and analyze the -data. In KNIME such workflows are implemented graphically by connecting so-called nodes. A node represents a single -analysis step in a workflow. Nodes have input and output ports where the data enters the node or the results are provided -for other nodes after processing, respectively. KNIME distinguishes between different port types, representing different -types of data. The most common representation of data in KNIME are tables (similar to an excel sheet). Ports that accept -tables are marked with a small triangle. For OpenMS nodes, we use a different port type, so called file ports, representing -complete files. Those ports are marked by a small blue box. Filled blue boxes represent mandatory inputs and empty blue -boxes optional inputs. The same holds for output ports, except that you can deactivate them in the configuration dialog -(double-click on node) under the **OutputTypes** tab. After execution, deactivated ports will be marked with a red cross and -downstream nodes will be inactive (not configurable). - -A typical OpenMS workflow in KNIME can be divided in two conceptually different parts: - -- Nodes for signal and data processing, filtering and data reduction. Here, files are passed between nodes. Execution - times of the individual steps are typically longer for these types of nodes as they perform the main computations. -- Downstream statistical analysis and visualization. Here, tables are passed between nodes and mostly internal KNIME - nodes or nodes from third-party statistics plugins are used. The transfer from files (produced by OpenMS) and tables - usually happens with our provided Exporter and Reader nodes (e.g. MzTabExporter followed by MzTabReader). - -Nodes can have three different states, indicated by the small traffic light below the node. -- Inactive, failed, and not yet fully configured nodes are marked red. -- Configured but not yet executed nodes are marked yellow. -- Successfully executed nodes are marked green. - -If the node execution fails, the node will switch to the red state. Other anomalies and warnings like missing information -or empty results will be presented with a yellow exclamation mark above the traffic light. Most nodes will be configured -as soon as all input ports are connected. Some nodes need to know about the output of the predecessor and may stay red -until the predecessor was executed. If nodes still remain in a red state, probably additional parameters have to be -provided in the configuration dialog that can neither be guessed from the data nor filled with sensible defaults. In -this case, or if you want to customize the default configuration in general, you can open the configuration dialog of a -node with a double-click on the node. For all OpenMS nodes you will see a configuration dialog like the one shown in -below figure. - -|![Node configuration dialog of an OpenMS node](/images/openms-user-tutorial/knime-setup/knime_configure_dialog.png)| -|:--:| -|Figure 6: Node configuration dialog of an OpenMS node| - -```{tip} -OpenMS distinguishes between normal parameters and advanced parameters. Advanced parameters are by default hidden from -the users since they should only rarely be customized. In case you want to have a look at the parameters or need to -customize them in one of the tutorials you can show them by clicking on the checkbox **Show advanced parameter** -in the lower part of the dialog. Afterwards the parameters are shown in a light gray color. -``` - -The dialog shows the individual parameters, their current value and type, and, in the lower part of the dialog, the -documentation for the currently selected parameter. Please also note the tabs on the top of the configuration dialog. -In the case of OpenMS nodes, there will be another tab called OutputTypes. It contains dropdown menus for every output -port that let you select the output filetype that you want the node to return (if the tool supports it). For optional -output ports you can select Inactive such that the port is crossed out after execution and the associated generation of -the file and possible additional computations are not performed. Note that this will deactivate potential downstream -nodes connected to this port. - -#### Overview of the graphical user interface - -|![The KNIME workbench](/images/openms-user-tutorial/knime-setup/knime_workbench_marked.png)| -|:--:| -|Figure 7: The KNIME workbench| - -The graphical user interface (GUI) of KNIME consists of different components or so-called panels that are shown in -above image. We will briefly introduce the individual panels and their purposes below. - -##### Workflow Editor - -The workflow editor is the central part of the KNIME GUI. Here you assemble the workflow by adding nodes from the Node -Repository via ”drag & drop”. For quick creation of a workflow, note that double-clicking on a node in the repository -automatically connects it to the selected node in the workbench (connecting all the inputs with as many fitting outputs -of the last node). Manually, nodes can be connected by clicking on the output port of one node and dragging the edge -until releasing the mouse at the desired input port of the next node. Deletions are possible by selecting nodes and/or -edges and pressing DEL or Fn + Backspace depending on your OS and settings. Multiselection -happens via dragging rectangles with the mouse or adding elements to the selection by clicking them while holding down -Ctrl. - -##### KNIME Explorer - -Shows a list of available workflows (also called workflow projects). You can open a workflow by double-clicking it. A -new workflow can be created with a right-click in the Workflow Explorer followed by choosing **New KNIME Workflow** -from the appearing context menu. Remember to save your workflow often with the Ctrl + S shortcut. - -##### Workflow Coach - -Shows a list of suggested following nodes, based on the last added/clicked nodes. When you are not sure which node to -choose next, you have a reasonable suggestion based on other users behavior there. Connect them to the last node with a -double-click. - -##### Node Repository - -Shows all nodes that are available in your KNIME installation. Every plugin you install will provide new nodes that can -be found here. The OpenMS nodes can be found in **Community Node** > **OpenMS** Nodes to hook up to external search engines -and the RawFileConverter are found under **Community Node** > **OpenMSThirdParty** Nodes for managing files (e.g., Input -Files or Output Folders) can be found in **Community Nodes** > **GenericKnimeNode**. You can search the node repository -by typing the node name into the small text box in the upper part of the node repository. - -##### Outline - -The Outline panel contains a small overview of the complete workflow. While of limited use when working on a small -workflow, this feature is very helpful as soon as the workflows get bigger. You can adjust the zoom level of the explorer -by adjusting the percentage in the toolbar at the top of KNIME. - -##### Console - -In the console panel, warning and error messages are shown. This panel will provide helpful information if one of the -nodes failed or shows a warning sign. - -##### Node Description - -As soon as a node is selected, the Node Description window will show the documentation of the node including -documentation for all its parameters and especially their in- and outputs, such that you know what types of data nodes -may produce or expect. For OpenMS nodes you will also find a link to the tool page of the online documentation. - -#### Creating workflows - -Workflows can easily be created by a right click in the Workflow Explorer followed by clicking on **New KNIME workflow**. - -#### Sharing workflows - -To be able to share a workflow with others, KNIME supports the import and export of complete workflows. To export a -workflow, select it in the Workflow Explorer and select **File** > **Export KNIME Workflow**. KNIME will export -workflows as a _knwf_ file containing all the information on nodes, their connections, and their parameter configuration. - -Those *knwf* files can again be imported by selecting: **File** > **Import KNIME Workflow** - -```{note} -For your convenience we added all workflows discussed in this tutorial to the **Workflows** folder on the USB Stick. - Additionally, the workflow files can be found on workflow downloads. If you want to check - your own workflow by comparing it to the solution or got stuck, simply import the full workflow from the corresponding - *knwf* file and after that double-click it in your KNIME Workflow repository to open it. -``` - -#### Duplicating workflows - -In this tutorial, a lot of the workflows will be created based on the workflow from a previous task. To keep the -intermediate workflows, we suggest you create copies of your workflows so you can see the progress. To create a copy of -your workflow, save it, close it and follow the next steps. - -- Right click on the workflow you want to create a copy of in the Workflow Explorer and select **Copy**. -- Right click again somewhere on the workflow explorer and select **Paste**. -- This will create a workflow with same name as the one you copied with a (2) appended. -- To distinguish them later on you can easily rename the workflows in the Workflow Explorer by right clicking on the - workflow and selecting **Rename**. - -```{note} -To rename a workflow it has to be closed. -``` - -#### A minimal workflow - -Let us now start with the creation of a simple workflow. As a first step, we will gather some basic -information about the data set before starting the actual development of a data analysis workflow. This minimal workflow -can also be used to check if all requirements are met and that your system is compatible. - -- Create a new workflow. -- Add an `File Importer` node and an `Output Folder` node (found in **Community Nodes** > **GenericKnimeNodes** > **IO**) - and a `FileInfo` node (to be found in the category **Community Node** > **OpenMS** > **File Handling**) to the workflow. -- Connect the File Importer node to the FileInfo node, and the first output port of the FileInfo node to the Output Folder - node. - -```{tip} -In case you are unsure about which node port to use, hovering the cursor over the port in question will display the port -name and what kind of input it expects. -``` -The complete workflow is shown in below image. `FileInfo` can produce two different kinds of output files. - -|![A minimal workflow calling FileInfo on a single file.](/images/openms-user-tutorial/knime-setup/minimal_FileInfo.png)| -|:--:| -|Figure 8: A minimal workflow calling `FileInfo` on a single file.| - -- All nodes are still marked red, since we are missing an actual input file. Double-click the File Importer node and select - **Browse**. In the file system browser [select](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Introduction/datasets/tiny/velos005614.mzML) {path}`Example_Data,Introduction,datasets,tiny,velos005614.mzML` - and click **Open**. Afterwards close the dialog by clicking **Ok**. - -- The `File Importer` node and the `FileInfo` node should now have switched to yellow, but the `Output Folder` node is still red. - Double-click on the `Output Folder` node and click on **Browse** to select an output directory for the generated data. -- Great! Your first workflow is now ready to be run. Press + F7 (shift key + F7; or the - button with multiple green triangles in the KNIME Toolbar) to execute the complete workflow. You can also right click - on any node of your workflow and select Execute from the context menu. -- The traffic lights tell you about the current status of all nodes in your workflow. Currently running tools show either - a progress in percent or a moving blue bar, nodes waiting for data show the small word “queued”, and successfully - executed ones become green. If something goes wrong (e.g., a tool crashes), the light will become red. -- In order to inspect the results, you can just right-click the Output Folder node and select **View: Open the output folder** - You can then open the text file and inspect its contents. You will find some basic information of the data contained - in the mzML file, e.g., the total number of spectra and peaks, the RT and m/z range, and how many MS1 and MS2 spectra - the file contains. - -Workflows are typically constructed to process a large number of files automatically. As a simple example, consider you -would like to filter multiple mzML files to only include MS1 spectra. We will now modify the workflow to compute the -same information on three different files and then write the output files to a folder. - -- We start from the previous workflow. -- First we need to replace our single input file with multiple files. Therefore we add the `Input Files` node from the - category **Community Nodes** > **GenericKnimeNodes** > **IO**. -- To select the files we double-click on the `Input Files` node and click on **Add**. In the filesystem browser we select - all three files from the [directory](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Introduction/datasets/tiny) **Example_Data** > **Introduction** > **datasets** > **tiny**. And close the dialog - with **Ok**. -- We now add two more nodes: the `ZipLoopStart` and the `ZipLoopEnd` node from the category - **Community Nodes** > **GenericKnimeNodes* > **Flow** and replace the `FileInfo` node with `FileFilter` from **Community Nodes** > **OpenMS** > **File Handling**. -- Afterwards we connect the `Input Files` node to the first port of the `ZipLoopStart` node, the first port of the `ZipLoopStart` - node to the **FileConverter** node, the first output port of the **FileConverter** node to the first input port of the - `ZipLoopEnd` node, and the first output port of the `ZipLoopEnd` node to the `Output Folder` node. - -The complete workflow is shown in the top right of the figure below. - -|![A minimal workflow calling the FileFilter on multiple mzML files in a loop](/images/openms-user-tutorial/knime-setup/KNIME_annotated_FileFilter.png)| -|:--:| -|Figure 9: The FileFilter workflow. Showing the configure dialog for `FileFilter`, and the level selector pane. - -Now we need to configure the `FileFilter` to only store MS1 data. To do this we double click on the `FileFilter` node to open the configuration dialog (see left pane above), double click "level", select 2 -from the sub-pane (see bottom right panel above), and click delete. Repeat the process for 3. Select OK to exit the sub-pane, and then OK again in the configuration dialog. - -Execute the workflow and inspect the output as before. - -Now, if you open the resulting files in TOPPView, you can see that only the MS1 spectra remain. - -In case you had trouble to understand what `ZipLoopStart` and `ZipLoopEnd` do, here is a brief explanation: - -- The `Input Files` node passes a list of files to the `ZipLoopStart` node. -- The `ZipLoopStart` node takes the files as input, but passes the single files sequentially (that is: one after the other) - to the next node. -- The `ZipLoopEnd` collects the single files that arrive at its input port. After all files have been processed, the collected - files are passed again as file list to the next node that follows. - -#### Advanced topic: Metanodes - -Workflows can get rather complex and may contain dozens or even hundreds of nodes. KNIME provides a simple way to -improve handling and clarity of large workflows: - -**Metanodes** allow to bundle several nodes into a single **Metanode**. - -
-

**Task**

- Select multiple nodes (e.g. all nodes of the **ZipLoop** including the start and end node). To select a set of nodes, draw a rectangle around them with the left mouse button or hold Ctrl to add/remove single nodes from the selection. -
-

**Tip**

- There is a **Select Scope** option when you right-click a node in a loop, that does exactly that for you. Then, open the - context menu (right-click on a node in the selection) and select **Create Metanode**. Enter a caption for the **Metanode**. - The previously selected nodes are now contained in the **Metanode**. Double-clicking on the **Metanode** will display - the contained nodes in a new tab window. -
-
- -
-

**Task**

-Create the Metanode to let it behave like an encapsulated single node. First select the **Metanode**, open the context -menu (right-click) and select **Metanode** > **Convert to Component**. The differences between Metanodes and components -are marginal (Metanodes allow exposing user inputs, workflow variables and contained nodes). Therefore, we suggest to use standard -Metanodes to clean up your workflow and cluster common subparts until you actually notice their limits. -
- -
-

**Task**

-Undo the packaging. First select the **Metanode/Component**, open the context menu (right-click) and select **Metanode/Component** > **Expand**. -
- - - - -## Label-free quantification of peptides - -### Introduction - -In the following chapter, we will build a workflow with OpenMS / KNIME to quantify a label-free experiment. Label-free -quantification is a method aiming to compare the relative amounts of proteins or peptides in two or more samples. We will -start from the minimal workflow of the last chapter and, step-by-step, build a label-free quantification workflow. - -The complete workflow can be downloaded [here](https://hub.knime.com/openms-team/spaces/Tutorial%20Workflows%20OpenMS%203.0/Proteomics_LFQ~MvMoVSrTZKLI6H3B/current-state) as well. - -### Peptide identification - -As a start, we will extend the minimal workflow so that it performs a peptide identification using the Comet search -engine. Comet is included in the OpenMS installation, so you do not need to download and -install it yourself. - -Let’s start by replacing the input files in our `Input Files` node by the three mzML files in -**Example Data** > **Labelfree** > **datasets** > **lfqxspikeinxdilutionx1-3.mzML**. This is a reduced toy dataset where -each of the three runs contains a constant background of `S. pyogenes` peptides as well as human spike-in peptides in -different concentrations. [^10] - -- Instead of `FileFilter`, we want to perform Comet identification, so we simply replace the `FileFilter` node with the - `CometAdapter` node **Community Nodes** > **OpenMSThirdParty** > **Identification**, and we are almost done. Just make sure you - have connected the `ZipLoopStart` node with the `in` (top) port of the `CometAdapter` node. -- Comet, like most mass spectrometry identification engines, relies on searching the input spectra against sequence - databases. Thus, we need to introduce a search database input. As we want to use the same search database for all of - our input files, we can just add a single `File Importer` node to the workflow and connect it directly with the - `CometAdapter database` (middle) port. KNIME will automatically reuse this Input node each time a new ZipLoop iteration is - started. In order to specify the database, [select](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Labelfree/databases/s_pyo_sf370_potato_human_target_decoy_with_contaminants.fasta) {path}`Example_Data,Labelfree,databases,/break,s_pyo_sf370_potato_human_target_decoy_with_contaminants.fasta` -- Connect the **out** port of the `CometAdapter` to `ZipLoopEnd` and we have a very basic peptide identification workflow. - - ```{note} - You might also want to save your new identification workflow under a different name. Have a look at duplicating workflows - for information on how to create copies of workflows. - ``` -- The result of a single Comet run is basically a number of peptide-spectrum-matches (PSM) with a score each, and these - will be stored in an idXML file. Now we can run the pipeline and after execution is finished, we can have a first look - at the the results: just open the output folder with a file browser and from there open one of the three input mzML's in **TOPPView**. -- Here, annotate this spectrum data file with the peptide identification results. Choose **Tools** > **Annonate with identification** - from the menu and select the idXML file that `CometAdapter` generated (it is located within the output directory that - you specified when starting the pipeline). -- On the right, select the tab **Identification view**. All identified peptides can be seen using this view. User can also - browse the corresponding MS2 spectra. - - ```{note} - Opening the output file of `CometAdapter` (the idXML file) directly is also possible, but unless you REALLY like XML, reading - idXML files is less useful. - ``` -- The search results stored in the idXML file can also be read back into a KNIME table for inspection and subsequent - analyses: Add a `TextExporter` node from **Community Nodes** > **OpenMS** > **File Handling** to your workflow and - connect the output port of your `CometAdapter` (the same port `ZipLoopEnd` is connected to) to its input port. This - tool will convert the idXML file to a more human-readable text file which can also be read into a KNIME table using - the `IDTextReader` node. Add an `IDTextReader` node(**Community Nodes** > **OpenMS** > **Conversion**) after - `TextExporter` and execute it. Now you can right click `IDTextReader` and select **ID Table** to browse your peptide - identifications. -- From here, you can use all the tools KNIME offers for analyzing the data in this table. As a simple example, add a - `Histogram` node (from category **Views**) node after `IDTextReader`, double-click it, select - `peptide_charge` as Dimension, click **Save and Execute** to generate a plot showing the charge state distribution - of your identifications. - -In the next step, we will tweak the parameters of Comet to better reflect the instrument’s accuracy. Also, we will -extend our pipeline with a false discovery rate (FDR) filter to retain only those identifications that will yield an -FDR of < 1 %. - -- Open the configuration dialog of `CometAdapter`. The dataset was recorded using an LTQ Orbitrap XL mass spectrometer, - set the `precursor_mass_tolerance` to 5 and `precursor_error_units` to `ppm`. - - ```{note} - Whenever you change the configuration of a node, the node as well as all its successors will be reset to the Configured - state (all node results are discarded and need to be recalculated by executing the nodes again). - ``` - -- Make sure that `Carbamidomethyl (C)` is set as fixed modification and `Oxidation(M)` as variable modification. - - ```{note} - To add a modification click on the empty value field in the configuration dialog to open the list editor dialog. In the - new dialog click **Add**. Then select the newly added modification to open the drop down list where you can select the - the correct modification. - ``` -- A common step in analysis is to search not only against a regular protein database, but to also search against a decoy - database for FDR estimation. The fasta file we used before already contains such a decoy database. For OpenMS to know - which Comet PSM came from which part of the file (i.e. target versus decoy), we have to index the results. To this end, - extend the workflow with a `PeptideIndexer` node **Community Nodes** > **OpenMS** > **ID Processing**. This node needs - the idXML as input as well as the database file (see below figure). - - ```{tip} - You can direct the files of an `File Importer` node to more than just one destination port. - ``` -- The decoys in the database are prefixed with “DECOY_”, so we have to set `decoy_string` to `DECOY_` and `decoy_string_position` - to `prefix` in the configuration dialog of `PeptideIndexer`. -- Now we can go for the FDR estimation, which the `FalseDiscoveryRate` node will calculate for us (you will find it in - **Community Nodes** > **OpenMS** > **Identification Processing**). `FalseDiscoveryRate` is meant to be run on data with protein inferencences - (more on that later), in order to just use it for peptides, open the configure window, select "show advanced parameter" and toggle "force" to true. -- In order to set the FDR level to 1%, we need an `IDFilter` node from **Community Nodes** > **OpenMS** > **Identification Processing**. - Configuring its parameter `score→pep` to 0.01 will do the trick. The FDR calculations (embedded in the idXML) from - the `FalseDiscoveryRate` node will go into the *in* port of the `IDFilter` node. -- Execute your workflow and inspect the results using `IDTextReader` like you did before. How many peptides did you - identify at this FDR threshold? - - - The below images shows Comet ID pipeline including FDR filtering. - - |![Comet ID pipeline including FDR filtering](/images/openms-user-tutorial/labelfree/PepIdFDR.png)| - |:--:| - |Figure 12: Comet ID pipeline including FDR filtering| - - -#### Bonus task: Identification using several search engines - -```{note} -If you are ahead of the tutorial or later on, you can further improve your FDR identification workflow by a so-called -consensus identification using several search engines. Otherwise, just continue with quantification. -``` - -It has become widely accepted that the parallel usage of different search engines can increase peptide identification -rates in shotgun proteomics experiments. The ConsensusID algorithm is based on the calculation of posterior error -probabilities (PEP) and a combination of the normalized scores by considering missing peptide sequences. - -- Next to the `CometAdapter` add a `XTandemAdapter` **Community Nodes** > **OpenMSThirdParty** > **Identification of Proteins** > **Peptides(SearchEngines)** node and set - its parameters and ports analogously to the `CometAdapter`. In XTandem, to get more evenly distributed scores, we - decrease the number of candidates a bit by setting the precursor mass tolerance to 5 ppm and the fragment mass - tolerance to 0.1 Da. -- To calculate the PEP, introduce a `IDPosteriorErrorProbability` **Community Nodes** > **OpenMS** > **Identification Processing** - node to the output of each ID engine adapter node. This will calculate the PEP to each hit and output an updated idXML. -- To create a consensus, we must first merge these two files with a `FileMerger` node **Community Nodes** > - **GenericKnimeNode** > **Flow** so we can then merge the corresponding IDs with a `IDMerger` **Community Nodes** > - **OpenMS** > **File Handling**. -- Now we can create a consensus identification with the `ConsensusID` **Community Nodes** > **OpenMS** > **Identification Processing** - node. We can connect this to the `PeptideIndexer` and go along with our existing FDR filtering. - - ```{note} - By default, X!Tandem takes additional enzyme cutting rules into consideration (besides the specified tryptic digest). - Thus for the tutorial files, you have to set PeptideIndexer’s `enzyme→specificity` parameter to `none` to accept - X!Tandem's non-tryptic identifications as well. - ``` - -In the end, the ID processing part of the workflow can be collapsed into a Metanode to keep the structure clean (see below figure which shows complete consensus identification workflow). - -|![Complete consensus identification workflow](/images/openms-user-tutorial/labelfree/PepConsensusId.png)| -|:--:| -|Figure 13: Complete consensus identification workflow| - -### Feature Mapping - -Now that we have successfully constructed a peptide identification pipeline, we can assign this information to the corresponding feature signals. - -- Add a `FeatureFinderCentroided` node from **Community Nodes** > **OpenMS** > **Quantitation** -which gets input from the first output port of the `ZipLoopStart` node. Also, add -an `IDMapper` node (from **Community Nodes** > **OpenMS** > **Identification Processing** ) which receives -input from the `FeatureFinderCentroided` node (Port 1) and the `IDFilter` node (Port 0). The output of the `IDMapper` node is then connected to an in port of the `ZipLoopEnd` node. -- `FeatureFinderCentroided` finds and quantifies peptide ion signals contained in -the MS1 data. It reduces the entire signal, i.e., all peaks explained by one and -the same peptide ion signal, to a single peak at the maximum of the chromatographic elution profile of the monoisotopic mass trace of this peptide ion and -assigns an overall intensity. -- `FeatureFinderCentroided` produces a featureXML file as output, containing only quantitative information of so-far unidentified peptide signals. In order to annotate these with the corresponding ID information, we need the `IDMapper` node. -- Run your pipeline and inspect the results of the `IDMapper` node in TOPPView. Open the mzML file of your data to display the raw peak intensities. -- To assess how well the feature finding worked, you can project the features contained in the featureXML file on the raw data contained in the mzML file. To -this end, open the featureXML file in TOPPView by clicking on File Open file and add it to a new layer ( Open in New layer ). The features are now visualized on top of your raw data. If you zoom in on a small region, you should be able to see the individual boxes around features that have been detected (see Fig. 14). If you -hover over the the feature centroid (small circle indicating the chromatographic apex of monoisotopic trace) additional information of the feature is displayed. - - |![Visualization of detected features (boxes) in TOPPView](/images/openms-user-tutorial/labelfree/featureXML.png)| - |:--:| - |Figure 14: Visualization of detected features (boxes) in TOPPView| - - ```{note} - The chromatographic RT range of a feature is about 30-60 s and - its m/z range around 2.5 m/z in this dataset. If you have trouble zooming in on a feature, select the full RT range and zoom only into the - m/z dimension by holding down Ctrl ( cmd ⌘ on macOS) and repeatedly - dragging a narrow box from the very left to the very right - ``` -- You can see which features were annotated with a peptide identification by first -selecting the featureXML file in the **Layers** window on the upper right side and then clicking on the icon with the letters A, B and C on the upper icon bar. Now, -click on the small triangle next to that icon and select **Peptide identification**. - -The following image shows the final constructed workflow: - -| ![Extended workflow featuring peptide identification and quantification](/images/openms-user-tutorial/labelfree/PepQuantIdNoAlign.png) | -|:--------------------------------------------------------------------------------------------------------------------------------------:| -| Figure 15: Extended workflow featuring peptide identification and feature mapping. | - -### Combining features across several label-free experiments - -So far, we successfully performed peptide identification as well as feature mapping on -individual LC-MS runs. For differential label-free analyses, however, we need to identify and map corresponding signals in different experiments and link them together to compare their intensities. Thus, we will now run our pipeline on all three -available input files and extend it a bit further, so that it is able to find and link features across several runs. - -| ![Complete identification and label-free quantification workflow](/images/openms-user-tutorial/labelfree/PepQuantId.png) | -|:-----------------------------------------------------------------------------------------------------------------------------------------:| -| Figure 16: Complete identification and label-free feature mapping workflow. The identification nodes are grouped together as ID metanode. | - -- To link features across several maps, we first have to align them to correct for retention time shifts between the different label-free measurements. With the `MapAlignerPoseClustering` node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can align corresponding peptide signals to each other as closely as possible by applying a transformation in the RT dimension. - - ```{note} - `MapAlignerPoseClustering` consumes several featureXML files and its output should still be several featureXML files containing the same features, but with the transformed RT values. In its configuration dialog, make sure that **OutputTypes** is set to **featureXML**. - ``` -- With the `FeatureLinkerUnlabeledQT` node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can then perform the actual linking of corresponding features. Its output is a consensusXML file containing linked groups of corresponding features across the different experiments. -- Since the overall intensities can vary a lot between different measurements (for example, because the amount of injected analytes was different), we apply the **ConsensusMapNormalizer** node in **Community Node** > **OpenMS** > **Map Alignment** as a last processing step. Configure its parameters with setting `algorithm_type` to `median`. It will then normalize the maps in such a way that the median intensity of all input maps is equal. -- Export the resulting normalized consensusXML file to a csv format using the **TextExporter** node. -- Use the `ConsensusTextReader` node in **Community Nodes** > **OpenMS** > **Conversion** to convert the output into a KNIME table. After running the node you can view the KNIME table by right-clicking on the `ConsensusTextReader` node and selecting `Consensus Table`. Every row in this table corresponds to a so-called consensus feature, i.e., a peptide signal quantified across several runs. The first couple of columns describe the consensus feature as a whole (average RT and m/z across the maps, charge, etc.). The remaining columns describe the exact positions and intensities of the quantified features separately for all input samples (e.g., intensity_0 is the intensity of the feature in the first input file). The last 11 columns contain information on peptide identification. - - ```{note} - You can specify the desired column separation character in the parameter settings (by default, it is set to “ ” (a space)). The output file of `TextExporter` can also be opened with external tools, e.g., Microsoft Excel, for downstream statistical analyses. - ``` - -#### Basic data analysis in KNIME - -In this section we are going to use the output of the `ConsensusTextReader` for downstream analysis of the quantification results: - -- Let’s say we want to plot the log intensity distributions of the human spike-in peptides for all input files. In addition, we will plot the intensity distributions of the background peptides. -- As shown in Fig. 17, add a `Row Splitter` node (**Data Manipulation** > **Row** > **Filter**) after the `ConsensusTextReader` node. Double-click it to configure. The human spike-in peptides have accessions starting with “hum”. Thus, set the column to apply the test to `accessions`, select pattern matching as matching criterion, enter `hum*` into the corresponding text field, and check the contains wild cards box. Press **OK** and execute the node. -- `Row Splitter` produces two output tables: the first one contains all rows from the input table matching the filter criterion, and the second table contains all other rows. You can inspect the tables by right-clicking and selecting **Filtered** and **Filtered Out**. The former table should now only contain peptides with a human accession, whereas the latter should contain all remaining peptides (including unidentified ones). -- Now, since we only want to plot intensities, we can add a `Column Filter` node by going to **Data Manipulation** > `Column Filter`. Connect its input port to the **Filtered output** port of the **Row Filter** node, and open its configuration dialog. We could either manually select the columns we want to keep, or, more elegantly, select **Wildcard/Regex Selection** and enter `intensity_?` as the pattern. KNIME will interactively show you which columns your pattern applies to while you’re typing. -- Since we want to plot log intensities, we will now compute the log of all intensity values in our table. The easiest way to do this in KNIME is a small piece of R code. Add an **R Snippet** node `R` after `Column Filter` and double-click to configure. In the R Script text editor, enter the following code: - - ```r - x <- knime.in # store copy of input table in x - - x[x == 0] <- NA # replace all zeros by NA (= missing value) - - x <- log10(x) # compute log of all values - knime.out <- x # write result to output table - ``` -- Now we are ready to plot! Add a `Box Plot (JavaScript)` node `Views -JavaScript` after the **R Snippet** node, execute it, and open its view. If everything went well, you should see a significant fold change of your human peptide intensities across the three runs. -- To verify that the concentration of background peptides is constant in all three runs, copy and paste the three nodes after `Row Splitter` and connect the duplicated `Column Filter` to the second output port (Filtered Out) of `Row Splitter`, as shown in Fig. 17. Execute and open the view of your second **Box Plot**. - -You have now constructed an entire identification and label-free feature mapping workflow including a simple data analysis using KNIME. The final workflow should like the workflow shown in the following image: - -|![Simple KNIME data analysis example for LFQ](/images/openms-user-tutorial/labelfree/data_analysis.png)| -|:--:| -|Figure 17: Simple KNIME data analysis example for LFQ| - -### Identification and quantification of the iPRG2015 data with subsequent MSstats analysis - -Advanced downstream data analysis of quantitative mass spectrometry-based proteomics data can be performed using MSstats[^11]. This tool can be combined with -an OpenMS preprocessing pipeline (e.g. in KNIME). The OpenMS experimental design is used to present the data in an MSstats-conformant way for the analysis. Here, -we give an example how to utilize these resources when working with quantitative label-free data. We describe how to use OpenMS and MSstats for the analysis of the -ABRF iPRG2015 dataset[^12]. - -```{note} -Reanalysing the full dataset from scratch would take too long. In the following tutorial, we will focus on just the conversion process and the downstream analysis. -``` - -#### Excursion MSstats - -The R package `MSstats` can be used for statistical relative quantification of proteins and peptides in mass spectrometry-based proteomics. Supported are label-free as well as labeled experiments in combination with data-dependent, targeted and data independent acquisition. Inputs can be identified and quantified entities (peptides or proteins) and the output is a list of differentially abundant entities, or summaries of their relative abundance. It depends on accurate feature detection, identification -and quantification which can be performed e.g. by an OpenMS workflow. MSstats can be used for data processing & visualization, as well as statistical modeling & inference. Please see [^11] and the [MSstats](http://msstats.org) website for further -information. - -#### Dataset - -The iPRG (Proteome Informatics Research Group) dataset from the study in 2015, as -described in [^12], aims at evaluating the effect of statistical analysis software on the -accuracy of results on a proteomics label-free quantification experiment. The data is -based on four artificial samples with known composition (background: 200 ng *S. cerevisiae*). These were spiked with different quantities of individual digested proteins, -whose identifiers were masked for the competition as yeast proteins in the provided -database (see Table 1). - -
- -

- - - -
Table 1: Samples (background: 200 ng S. cerevisiae) with spiked-in proteins
in different -quantities [fmols]
-
- - - - - - - - -
Samples
-
Name
Origin
Molecular Weight
1
2 3 4
A Ovalbumin Egg White 45 KD 65 55 15 2
B Myoglobin Equine Heart 17 KD 55 15 2 65
C Phosphorylase b Rabbit Muscle 97 KD 15 2 65 55
D Beta-Glactosidase Escherichia Coli 116 KD 2 65 55 15
E Bovine Serum Albumin Bovine Serum 66 KD 11 0.6 10 500
F Carbonic Anhydrase Bovine Erythrocytes 29 KD 10 500 11 0.6
- -
-
- -#### Identification and quantification - -|![KNIME data analysis of iPRG LFQ data](/images/openms-user-tutorial/labelfree/iPRG_lfq.png)| -|:--:| -|Figure 18: KNIME data analysis of iPRG LFQ data.| - -The iPRG LFQ workflow (Fig. 18) consists of an identification and a quantification part. The identification is achieved by searching the computationally calculated MS2 spectra from a sequence database (`File Importer` node, here with the given database from iPRG: -{path}`ExampleData,iPRG2015,database,iPRG2015targetdecoynocontaminants.fasta` -against the MS2 from the original data (`Input Files` node with all mzMLs following {path}`ExampleData,iPRG2015,datasets,JD06232014sample*.mzML` using the `CometAdapter`. - -```{note} -If you want to reproduce the results at home, you have to download the iPRG data in mzML format and perform peak picking on it or convert and pick the raw data with `msconvert`. -``` - -Afterwards, the results are scored using the **FalseDiscoveryRate** node and filtered to obtain only unique peptides (`IDFilter`) since `MSstats` does not support shared peptides, yet. The quantification is achieved by using the `FeatureFinderCentroided` node, which performs the feature detection on the samples (maps). In the end the quantification results are combined with the filtered identification results (`IDMapper`). In addition, a linear retention time alignment is performed (`MapAlignerPoseClustering`), followed by the feature linking process (**FeatureLinkerUnlabledQT**). The **ConsensusMapNormalizer**s is used to normalize the intensities via robust regression over a set of maps and the `IDConflictResolver` assures that only one identification (best score) is associated with a feature. The output of this workflow is a consensusXML file, which can now be converted using the `MSStatsConverter` (see Conversion and downstream analysis section). - -#### Experimental design - -As mentioned before, the downstream analysis can be performed using `MSstats`. In this case, an experimental design has to be specified for the OpenMS workflow. The structure of the experimental design used in OpenMS in case of the iPRG dataset is specified in Table 2. - -
- - -

- - - - -
Table 2: OpenMS Experimental design for the iPRG2015 dataset.
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
Fraction_Group Fraction Spectra_Filepath Label Sample
1 1 Sample1-A 1 1
2 1 Sample1-B 1 2
3 1 Sample1-C 1 3
4 1 Sample2-A 1 4
5 1 Sample2-B 1 5
6 1 Sample2-C 1 6
7 1 Sample3-A 1 7
8 1 Sample3-B 1 8
9 1 Sample3-C 1 9
10 1 Sample4-A 1 10
11 1 Sample4-B 1 11
12 1 Sample4-C 1 12
Sample MSstats_Condition MSstats_BioReplicate
1 1 1
2 1 2
3 1 3
4 2 4
5 2 5
6 2 6
7 3 7
8 3 8
9 3 9
10 4 10
11 4 11
12 4 12
- - -
-
- -An explanation of the variables can be found in Table 3. - -
- - -

- - - - -
Table 3: Explanation of the column of the experimental design table
- - - - - - - - - - - -
variables

value

Fraction_Group

Index used to group fractions and source files.

Fraction

1st, 2nd, .., fraction. Note: All runs must have the same number of - fractions.

Spectra_Filepath

Path to mzML files

Label

label-free: always 1

TMT6Plex: 1...6

SILAC with light and heavy: 1..2

Sample

Index of sample measured in the specified label X, in fraction Y of - fraction group Z.

Conditions

Further specification of different conditions (e.g. MSstats_Condition; - MSstats_BioReplicate)

- - -
-
- -The conditions are highly dependent on the type of experiment and on which kind of analysis you want to perform. For the `MSstats` analysis the information which sample belongs to which condition and if there are biological replicates are mandatory. This can be specified in further condition columns as explained in Table 3. For a detailed description of the MSstats-specific terminology, see their documentation e.g. in the R vignette. - -#### Conversion and downstream analysis - -Conversion of the OpenMS-internal consensusXML format (which is an aggregation of quantified and possibly identified features across several MS-maps) to a table (in MSstats-conformant CSV format) is very easy. First, create a new KNIME workflow. Then, run the `MSStatsConverter` node with a consensusXML and the manually created (e.g. in Excel) experimental design as inputs (loaded via `File Importer` nodes). The first input can be found in: - -{path}`ExampleData,iPRG2015,openmsLFQResults,iPRGlfq.consensusXML` - -This file was generated by using the {path}`Workflows,openmsLFQiPRG2015.knwf` workflow (seen in Fig. 18). The second input is specified in: - -{path}`ExampleData,iPRG2015,experimentaldesign.tsv` - -Adjust the parameters in the config dialog of the converter to match the given experimental design file and to use a simple summing for peptides that elute in multiple features (with the same charge state, i.e. m/z value). - -|**parameter**|**value**| -|------------:|:--------| -|*msstats_bioreplicate*|MSstats_Bioreplicate| -|*msstats_condition*|MSstats_Condition| -|*labeled_reference_peptides*|false| -|*retention_time_summarization_method (advanced)*|sum| - -The downstream analysis of the peptide ions with `MSstats` is performed in several steps. These steps are reflected by several KNIME R nodes, which consume the output of `MSStatsConverter`. The outline of the workflow is shown in Figure 19. - -|![MSstats analysis using KNIME](/images/openms-user-tutorial/labelfree/MSstats.png)| -|:--:| -|Figure 19: MSstats analysis using KNIME. The individual steps (Preprocessing, Group Comparisons, Result Data Renaming, and Export) are split among several consecutive nodes.| - -We load the file resulting from `MSStatsConverter` either by saving it with an `Output File` node and reloading it with the `File Reader`. Alternatively, for advanced users, you can use a URI Port to Variable node and use the variable in the File Reader config dialog (**V** button - located on the right of the **Browse** button) to read from the temporary file. - -##### Preprocessing - -The first node (`Table to R`) loads `MSstats` as well as the data from the previous KNIME node and performs a preprocessing step on the input data. The following inline R script ( needs to be pasted into the config dialog of the node): - -```r -library(MSstats) -data <- knime.in -quant <- OpenMStoMSstatsFormat(data, removeProtein_with1Feature = FALSE) -``` - -The inline R script allows further preparation of the data produced by `MSStatsConverter` before the actual analysis is performed. In this example, the lines with proteins, which were identified with only one feature, were retained. Alternatively they could be removed. -In the same node, most importantly, the following line transforms the data into a format that is understood by `MSstats`: - -```r -processed.quant <- dataProcess(quant, censoredInt = 'NA') -``` -Here, `dataProcess` is one of the most important functions that the R package provides. The function performs the following steps: - -1. Logarithm transformation of the intensities -2. Normalization -3. Feature selection -4. Missing value imputation -5. Run-level summarization - -In this example, we just state that missing intensity values are represented by the `NA` string. - -##### Group Comparison - -The goal of the analysis is the determination of differentially-expressed proteins among the different conditions C1-C4. We can specify the comparisons that we want to make in a *comparison* matrix. For this, let’s consider the following example: - -![comparison matrix](/images/openms-user-tutorial/labelfree/handout-clean129x.svg) - -This matrix has the following properties: - -- The number of rows equals the number of comparisons that we want to perform, the number of columns equals the number of conditions (here, column 1 refers to C1, column 2 to C2 and so forth). -- The entries of each row consist of exactly one 1 and one -1, the others must be 0. -- The condition with the entry `1` constitutes the enumerator of the log2 fold-change. The one with entry `-1` denotes the denominator. Hence, the first row states that we want calculate: -```{math} - \begin{equation} \log_2 \frac{C_{2}}{C_{1}} \end{equation} -``` -We can generate such a matrix in R using the following code snippet in (for example) a new **R to R** node that takes over the R workspace from the previous node with all its variables: - -```r -comparison1<-matrix(c(-1,1,0,0),nrow=1) -comparison2<-matrix(c(-1,0,1,0),nrow=1) - -comparison3<-matrix(c(-1,0,0,1),nrow=1) -comparison4<-matrix(c(0,-1,1,0),nrow=1) - -comparison5<-matrix(c(0,-1,0,1),nrow=1) -comparison6<-matrix(c(0,0,-1,1),nrow=1) - -comparison <- rbind(comparison1, comparison2, comparison3, comparison4, comparison5, comparison6) -row.names(comparison)<-c("C2-C1","C3-C1","C4-C1","C3-C2","C4-C2","C4-C3") -``` - -Here, we assemble each row in turn, concatenate them at the end, and provide row names for labeling the rows with the respective condition. -In MSstats, the group comparison is then performed with the following line: - -```r -test.MSstats <- groupComparison(contrast.matrix=comparison, data=processed.quant) -``` -No more parameters need to be set for performing the comparison. - -##### Result processing - -In a next R to R node, the results are being processed. The following code snippet will rename the spiked-in proteins to A,B,C,D,E, and F and remove the names of other proteins, which will be beneficial for the subsequent visualization, as for example performed in Figure 20: - -```r - test.MSstats.cr <- test.MSstats$ComparisonResult - - - # Rename spiked ins to A,B,C.... - pnames <- c("A", "B", "C", "D", "E", "F") - - names(pnames) <- c( - "sp|P44015|VAC2_YEAST", - "sp|P55752|ISCB_YEAST", - - "sp|P44374|SFG2_YEAST", - "sp|P44983|UTR6_YEAST", - "sp|P44683|PGA4_YEAST", - - "sp|P55249|ZRT4_YEAST" - ) - - test.MSstats.cr.spikedins <- bind_rows( - - test.MSstats.cr[grep("P44015", test.MSstats.cr$Protein),], - - test.MSstats.cr[grep("P55752", test.MSstats.cr$Protein),], - - test.MSstats.cr[grep("P44374", test.MSstats.cr$Protein),], - - test.MSstats.cr[grep("P44683", test.MSstats.cr$Protein),], - - test.MSstats.cr[grep("P44983", test.MSstats.cr$Protein),], - - test.MSstats.cr[grep("P55249", test.MSstats.cr$Protein),] - ) - # Rename Proteins - - test.MSstats.cr.spikedins$Protein <- sapply(test.MSstats.cr.spikedins$Protein, function(x) {pnames[as.character(x)]}) - - - - test.MSstats.cr$Protein <- sapply(test.MSstats.cr$Protein, function(x) { - - - x <- as.character(x) - - if (x %in% names(pnames)) { - - - return(pnames[as.character(x)]) - } else { - return("") - - } - }) - -``` - -##### Export - -The last four nodes, each connected and making use of the same workspace from the last node, will export the results to a textual representation and volcano plots for further inspection. Firstly, quality control can be performed with the following snippet: - -```r -qcplot <- dataProcessPlots(processed.quant, type="QCplot", - ylimDown=0, - -which.Protein = 'allonly', -width=7, height=7, address=F) -``` - -The code for this snippet is embedded in the first output node of the workflow. The resulting boxplots show the log2 intensity distribution across the MS runs. -The second node is an **R View (Workspace)** node that returns a Volcano plot which displays differentially expressed proteins between conditions C2 vs. C1. The plot is described in more detail in the following Result section. This is how you generate it: - -```r -groupComparisonPlots(data=test.MSstats.cr, type="VolcanoPlot", - - width=12, height=12,dot.size = 2,ylimUp = 7, - - which.Comparison = "C2-C1", - address=F) -``` -The last two nodes export the `MSstats` results as a KNIME table for potential further analysis or for writing it to a (e.g. csv) file. Note that you could also write output inside the Rscript if you are familiar with it. Use the following for an **R to Table** node exporting all results: - -```r -knime.out <- test.MSstats.cr -``` -And this for an **R to Table** node exporting only results for the spike-ins: - -```r -knime.out <- test.MSstats.cr.spikedins -``` - -#### Result - -An excerpt of the main result of the group comparison can be seen in Figure 20. - -|![Volcano plots c2_c1](/images/openms-user-tutorial/labelfree/c2_c1-.png) ![Volcano plots c3_c2](/images/openms-user-tutorial/labelfree/c3_c2-.png)| -|:--:| -|Figure 20: Volcano plots produced by the Group Comparison in MSstats The dotted line indicates an adjusted p-value threshold| - -The Volcano plots show differently expressed spiked-in proteins. In the left plot, which shows the fold-change C2-C1, we can see the proteins D and F (`sp|P44983|UTR6_YEAST` and `sp|P55249|ZRT4_YEAST`) are significantly over-expressed in C2, while the proteins B,C, and E (`sp|P55752|ISCB_YEAST`, `sp|P55752|ISCB_YEAST`, and `sp|P44683|PGA4_YEAST`) are under-expressed. In the right plot, which shows the fold-change ratio of C3 vs. C2, we can see the proteins E and C (`sp|P44683|PGA4_YEAST` and `sp|P44374|SFG2_YEAST`) over-expressed and the proteins A and F (`sp|P44015|VAC2_YEAST` and `sp|P55249|ZRT4_YEAST`) under-expressed. The plots also show further differentially-expressed proteins, which do not belong to the spiked-in proteins. - -The full analysis workflow can be found under: -{path}`Workflows,MSstatsstatPostProcessingiPRG2015.knwf` - -## Protein inference - -In the last chapter, we have successfully quantified peptides in a label-free experiment. As a next step, we will further extend this label-free quantification workflow by protein inference and protein quantification capabilities. This workflow uses some of the more advanced concepts of KNIME, as well as a few more nodes containing R code. For these reasons, you will not have to build it yourself. Instead, we have already prepared and copied this workflow to the USB sticks. Just import {path}`Workflows,labelfree_with_protein_quantification.knwf` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. - -Before you can execute the workflow, you again have to correct the locations of -the files in the Input Files nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. - -### Extending the LFQ workflow by protein inference and quantification - -We have made the following changes compared to the original label-free quantification workflow from the last chapter: - -- First, we have added a **ProteinQuantifier** node and connected its input port to the output port of the **ConsensusMapNormalizer** node. -- This already enables protein quantification. **ProteinQuantifier** quantifies peptides by summarizing over all observed charge states and proteins by summarizing over their quantified peptides. It stores two output files, one for the quantified peptides and one for the proteins. -- In this example, we consider only the protein quantification output file, which is written to the first output port of **ProteinQuantifier**. -- Because there is no dedicated node in KNIME to read back the **ProteinQuantifier** output file format into a KNIME table, we have to use a workaround. Here, we have added an additional URI Port to Variable node which converts the name of the output file to a so-called “flow variable” in KNIME. This variable is passed on to the next node **CSV Reader**, where it is used to specify the name of the input file to be read. If you double-click on **CSV Reader**, you will see that the text field, where you usually enter the location of the CSV file to be read, is greyed out. Instead, the flow variable is used to specify the location, as indicated by the small green button with the “v=?” label on the right. -- The table containing the **ProteinQuantifier** results is filtered one more time in order to remove decoy proteins. You can have a look at the final list of quantified protein groups by right-clicking the **Row Filter** and selecting **Filtered**. -- By default, i.e., when the second input port `protein_groups` is not used, **ProteinQuantifier** quantifies proteins using only the unique peptides, which usually results in rather low numbers of quantified proteins. -- In this example, however, we have performed protein inference using Fido and -used the resulting protein grouping information to also quantify indistinguishable proteins. In fact, we also used a greedy method in **FidoAdapter** (parameter `greedy_group_resolution`) to uniquely assign the peptides of a group to the most probable protein(s) in the respective group. This boosts the number of quantifications but slightly raises the chances to yield distorted protein quantities. -- As a prerequisite for using **FidoAdapter**, we have added an **IDPosteriorErrorProbability** node within the ID meta node, between the **XTandemAdapter** (note the replacement of OMSSA because of ill-calibrated scores) and **PeptideIndexer**. We have -set its parameter `prob_correct` to `true`, so it computes posterior probabilities instead of posterior error probabilities (1 - PEP). These are stored in the resulting idXML file and later on used by the Fido algorithm. Also note that we excluded FDR filtering from the standard meta node. Harsh filtering before inference impacts the calibration of the results. Since we filter peptides before quantification though, no potentially random peptides will be included in the results anyway. -- Next, we have added a third outgoing connection to our ID meta node and connected it to the second input port of `ZipLoopEnd`. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. -- Instead of the meta node **Protein inference** with **FidoAdapter**, we could have just used a **FidoAdapter** node ( **Community Nodes** > **OpenMS** > **Identification Processing**). However, the meta node contains an additional subworkflow which, besides calling **FidoAdapter**, performs a statistical validation (e.g. (pseudo) receiver operating curves; ROCs) of the protein inference results using some of the more advanced KNIME and R nodes. The meta node also shows how to use **MzTabExporter** and **MzTabReader**. - -### Statistical validation of protein inference results - -In the following section, we will explain the subworkflow contained in the **Protein inference with FidoAdapter** meta node. - -#### Data preparation - -For downstream analysis on the protein ID level in KNIME, it is again necessary to convert the idXML-file-format result generated from **FidoAdapter** into a KNIME table. - -- We use the **MzTabExporter** to convert the inference results from **FidoAdapter** to a human readable, tab-separated mzTab file. mzTab contains multiple sections, -that are all exported by default, if applicable. This file, with its different sections can again be read by the **MzTabReader** that produces one output in KNIME table -format (triangle ports) for each section. Some ports might be empty if a section did not exist. Of course, we continue by connecting the downstream nodes with the protein section output (second port). -- Since the protein section contains single proteins as well as protein groups, we filter them for single proteins with the standard **Row Filter**. - -#### ROC curve of protein ID - -ROC Curves (Receiver Operating Characteristic curves) are graphical plots that visualize sensitivity (true-positive rate) against fall-out (false positive rate). They are often used to judge the quality of a discrimination method like e.g., peptide or protein identification engines. ROC Curve already provides the functionality of drawing ROC curves for binary classification problems. When configuring this node, select the `opt_global_target_decoy` column as the class (i.e. target outcome) column. We want to find out, how good our inferred protein probability discriminates between them, -therefore add `best_search_engine_score[1]` (the inference engine score is treated like a peptide search engine score) to the list of *”Columns containing positive class probabilities”*. View the plot by right-clicking and selecting **View: ROC Curves**. A perfect classifier has -an area under the curve (AUC) of 1.0 and its curve touches the upper left of the plot. However, in protein or peptide identification, the ground-truth (i.e., which target -identifications are true, which are false) is usually not known. Instead, so called pseudoROC Curves are regularly used to plot the number of target proteins against the false -discovery rate (FDR) or its protein-centric counterpart, the q-value. The FDR is approximated by using the target-decoy estimate in order to distinguish true IDs from -false IDs by separating target IDs from decoy IDs. - -#### Posterior probability and FDR of protein IDs - -ROC curves illustrate the discriminative capability of the scores of IDs. In the case of protein identifications, Fido produces the posterior probability of each protein as -the output score. However, a perfect score should not only be highly discriminative (distinguishing true from false IDs), it should also be “calibrated” (for probability indicating that all IDs with reported posterior probability scores of 95% should roughly have a 5% probability of being false. This implies that the estimated number of false -positives can be computed as the sum of posterior error probabilities ( = 1 - posterior probability) in a set, divided by the number of proteins in the set. Thereby a -posterior-probability-estimated FDR is computed which can be compared to the actual target-decoy FDR. We can plot calibration curves to help us visualize the quality of -the score (when the score is interpreted as a probability as Fido does), by comparing how similar the target-decoy estimated FDR and the posterior probability estimated -FDR are. Good results should show a close correspondence between these two measurements, although a non-correspondence does not necessarily indicate wrong results. - -The calculation is done by using a simple R script in R snippet. First, the target decoy protein FDR is computed as the proportion of decoy proteins among all significant protein IDs. Then posterior probabilistic-driven FDR is estimated by the average of the posterior error probability of all significant protein IDs. Since FDR is the property for a group of protein IDs, we can also calculate a local property for each protein: the q-value of a certain protein ID is the minimum FDR of any groups of protein IDs -that contain this protein ID. We plot the protein ID results versus two different kinds of FDR estimates in R View(Table) (see Fig. 22). -(Figure_21)= -|![The workflow of statistical analysis of protein inference results](/images/openms-user-tutorial/protein-inference/inference_metanode.png)| -|:--:| -|Figure 21: The workflow of statistical analysis of protein inference results| -(Figure_22)= -|![The pseudo-ROC Curve of protein IDs](/images/openms-user-tutorial/protein-inference/proteinFDR.png)| -|:--:| -|Figure 22: The pseudo-ROC Curve of protein IDs. The accumulated number of protein IDs is plotted on two kinds of scales: target-decoy protein FDR and Fido posterior probability estimated FDR. The largest value of posterior probability estimated FDR is already smaller than 0.04, this is because the posterior probability output from Fido is generally very high| - -## Isobaric analysis - -In the last chapters, we identified and quantified peptides in a label-free experiment. - -In this section, we would like to introduce a possible workflow for the analysis of isobaric data. - -### Isobaric analysis workflow - -Let’s have a look at the workflow (see Fig 23). - -(Figure_23)= -|![Workflow for the analysis of isobaric data](/images/openms-user-tutorial/isobaric/isobaric_inference_wf.png)| -|:--:| -|Figure 23: Workflow for the analysis of isobaric data| - -The full analysis workflow can be found here: -{path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` - -The workflow has four input nodes. The first for the experimental design to allow for MSstatsTMT compatible export (`MSStatsConverter`). The second for the `.mzML` files with the centroided spectra from the isobaric labeling experiment and the third one for the `.fasta` database used for identification. The last one allows to specify an output path for the plots generated by the R View, which runs MSstatsTMT (I). The quantification (A) is performed using the **IsobaricAnalzyer**. The tool is able to extract and normalize quantitative information from TMT and iTRAQ data. The values can be assessed from centroided MS2 or MS3 spectra (if available). Isotope correction is performed based on the specified correction matrix (as provided by the manufacturer). The identification (C) is applied as known from the previous chapters by using database search and a target-decoy database. - -To reduce the complexity of the data for later inference the q-value estimation and FDR filtering is performed on PSM level for each file individually (B). Afterwards the identification (PSM) and quantiative information is combined using the `IDMapper`. After the processing of all available files, the intermediate results are aggregated (**FileMerger** - D). All PSM results are used for score estimation and protein inference (**Epifany**) (E). For detailed information about protein inference please see Chaper 4. Then, decoys are removed and the inference results are filtered via a protein group FDR. Peptide level results can be exported via **MzTabExporter** (F), protein level results can be obtained via the **ProteinQuantifier** (G) or the results can exported (`MSStatsConverter` - H) and further processed with the following R pipeline to allow for downstream processing using `MSstatsTMT`. - -Please import the workflow from {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. Before you can execute the workflow, you have to correct the locations of the files in the `Input Files` nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. - -### Excursion MSstatsTMT - -The R package `MSstatsTMT` can be used for protein significance analysis in shotgun mass spectrometry-based proteomic experiments with tandem mass tag (TMT) labeling. `MSstatsTMT` provides functionality for two types of analysis & their visualization: Protein summarization based on peptide quantification and Model-based group comparison to detect significant changes in abundance. It depends on accurate feature detection, identification and quantification which can be performed e.g. by an OpenMS workflow. - -In general, `MSstatsTMT` can be used for data processing & visualization, as well as statistical modeling. Please see [^13] and the [MSstats](http://msstats.org/msstatstmt/) website for further information. - -There is also an [online lecture](https://youtu.be/3CDnrQxGLbA) and tutorial for `MSstatsTMT` from the May Institute Workshop 2020. - -### Dataset and experimental design - -We are using the MSV000084264 ground truth dataset, which consists of TMT10plex controlled mixes of different concentrated UPS1 peptides spiked into SILAC HeLa peptides measured in a dilution series https://www.omicsdi.org/dataset/massive/MSV000084264. Figure 24 shows the experimental design. In this experiment, 5 different TMT10plex mixtures – different labeling strategies – were analysed. These were measured in triplicates represented by the 15 MS runs (3 runs each). The example data, database and experimental design to run the workflow can be found [here](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Data/isobaric_MSV000084264/). - -(Figure_24)= -|![Experimental Design](/images/openms-user-tutorial/isobaric/isobaric_experimental_design.jpeg)| -|:--:| -|Figure 24: Experimental Design| - -The experimental design in table format allows for `MSstatsTMT` compatible export. The design is represented by two tables. The first one 4 represents the overall structure of the experiment in terms of samples, fractions, labels and fraction groups. The second one 5 adds to the first by specifying specific conditions, biological replicates as well as mixtures and label for each channel. For additional information about the experimental design please see Table 3. - -
- - -

- - - - -
Table 4: Experimental Design 1 -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Spectra_Filepath Fraction Label Fraction_Group Sample
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 1 1 1
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 2 1 2
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 3 1 3
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 4 1 4
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 5 1 5
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 6 1 6
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 7 1 7
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 8 1 8
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 9 1 9
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_01.mzML 1 10 1 10
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 1 2 11
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 2 2 12
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 3 2 13
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 4 2 14
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 5 2 15
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 6 2 16
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 7 2 17
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 8 2 18
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 9 2 19
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_02.mzML 1 10 2 20
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 1 3 21
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 2 3 22
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 3 3 23
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 4 3 24
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 5 3 25
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 6 3 26
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 7 3 27
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 8 3 28
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 9 3 29
161117_SILAC_HeLa_UPS1_TMT10_SPS_MS3_Mixture1_03.mzML 1 10 3 30
-
-
- - -
- - -

- - - - -
Table 5: Experimental Design 2
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Sample MSstats_Condition MSstats_BioReplicate MSstats_Mixture LabelName
1 Norm Norm 1 126
2 0.667 0.667 1 127N
3 0.125 0.125 1 127C
4 0.5 0.5 1 128N
5 1 1 1 128C
6 0.125 0.125 1 129N
7 0.5 0.5 1 129C
8 1 1 1 130N
9 0.667 0.667 1 130C
10 Norm Norm 1 131
11 Norm Norm 1 126
12 0.667 0.667 1 127N
13 0.125 0.125 1 127C
14 0.5 0.5 1 128N
15 1 1 1 128C
16 0.125 0.125 1 129N
17 0.5 0.5 1 129C
18 1 1 1 130N
19 0.667 0.667 1 130C
20 Norm Norm 1 131
21 Norm Norm 1 126
22 0.667 0.667 1 127N
23 0.125 0.125 1 127C
24 0.5 0.5 1 128N
25 1 1 1 128C
26 0.125 0.125 1 129N
27 0.5 0.5 1 129C
28 1 1 1 130N
29 0.667 0.667 1 130C
30 Norm Norm 1 131
-
-
- -After running the worklfow, the `MSStatsConverter` will convert the OpenMS output in addition with the experimental design to a file (.csv) which can be processed by using `MSstatsTMT`. - -#### MSstatsTMT analysis - -Here, we depict the analysis by `MSstatsTMT` using a segment of the isobaric analysis workflow (Fig. 25). The segment is available as {path}`Workflows,MSstatsTMT.knwf`. - -(Figure_25)= -|![MSstatsTMT workflow segment](/images/openms-user-tutorial/isobaric/isobaric_msstatstmt_wf.png)| -|:--:| -|Figure 25: MSstatsTMT workflow segment| - -There are two input nodes, the first one takes the result (.csv) from the `MSStatsConverter` and the second a path to the directory where the plots generated by `MSstatsTMT` should be saved. The **R source** node loads the required packages, such as `dplyr` for data wrangling, `MSstatsTMT` for analysis and `MSstats` for plotting. The inputs are further processed in the **R View** node. - -Here, the data of the `File Importer` is loaded into **R** using the flow variable [”URI-0”]: - -```r -file <- substr(knime.flow.in[["URI-0"]], 6, nchar(knime.flow.in[["URI-0"]])) - -MSstatsConverter_OpenMS_out <- read.csv(file) -data <- MSstatsConverter_OpenMS_out -``` - -The `OpenMStoMSstatsTMTFormat` function preprocesses the OpenMS report and converts it into the required input format for `MSstatsTMT`, by filtering based on unique peptides and measurements in each MS run. - -```r -processed.data <- OpenMStoMSstatsTMTFormat(data) -``` - -Afterwards different normalization steps are performed (global, protein, runs) as well as data imputation by using the msstats method. In addition peptide level data is summarized to protein level data. - -```r -quant.data <- proteinSummarization(processed.data, - method="msstats", - - global_norm=TRUE, - reference_norm=TRUE, - - MBimpute = TRUE, - maxQuantileforCensored = NULL, - - remove_norm_channel = TRUE, - remove_empty_channel = TRUE) -``` - -There a lot of different possibilities to configure this method please have a look at the MSstatsTMT package for [additional detailed information](http://bioconductor.org/packages/release/bioc/html/MSstatsTMT.html). - -The next step is the comparions of the different conditions, here either a pairwise comparision can be performed or a confusion matrix can be created. The goal is to detect and compare the UPS peptides spiked in at different concentrations. - -```r -# prepare contrast matrix -unique(quant.data$Condition) - -comparison<-matrix(c(-1,0,0,1, - - 0,-1,0,1, - 0,0,-1,1, - - 0,1,-1,0, - 1,-1,0,0), nrow=5, byrow = T) - - -# Set the names of each row -row.names(comparison)<- contrasts <- c("1-0125", - - "1-05", - "1-0667", - - "05-0667", - "0125-05") - -# Set the column names -colnames(comparison)<- c("0.125", "0.5", "0.667", "1") -``` - -The constructed confusion matrix is used in the `groupComparisonTMT` function to test for significant changes in protein abundance across conditions based on a family of linear mixed-effects models in TMT experiments. - -```r -data.res <- groupComparisonTMT(data = quant.data, - contrast.matrix = comparison, - - moderated = TRUE, # do moderated t test - - adj.method = "BH") # multiple comparison adjustment -data.res <- data.res %>% filter(!is.na(Protein)) -``` - -In the next step the comparison can be plotted using the `groupComparisonPlots` function by `MSstats`. - -```r -library(MSstats) -groupComparisonPlots(data=data.res.mod, type="VolcanoPlot", address=F, which.Comparison = "0125-05", sig = 0.05) -``` - -Here, we have a example output of the **R View**, which depicts the significant regulated UPS proteins in the comparison of 125 to 05 (Fig. 26). - -(Figure_26)= -|![Volcanoplot of the group comparison regarding 0125 to 05](/images/openms-user-tutorial/isobaric/isobaric_img_output_knime.png)| -|:--:| -|Figure 26: Volcanoplot of the group comparison regarding 0125 to 05| - -All plots are saved to the in the beginning specified output directory in addition. - -### Note - -The isobaric analysis does not always has to be performed on protein level, for example for phosphoproteomics studies one is usually interested on the peptide level - in addition inference on peptides with post-translational modification is not straight forward. Here, we present and additonal workflow on peptide level, which can potentially be adapted and used for such cases. Please see {path}`Workflows,IdentificationquantificationisobaricMSstatsTMT` - -## Label-free quantification of metabolites - -### Introduction - -Quantification and identification of chemical compounds are basic tasks in metabolomic studies. In this tutorial session we construct a UPLC-MS based, label-free quantification and identification workflow. Following quantification and identification we then perform statistical downstream analysis to detect quantification values that differ significantly between two conditions. This approach can, for example, be used to detect biomarkers. Here, we use two spike-in conditions of a dilution series (0.5 mg/l and 10.0 mg/l, male blood background, measured in triplicates) comprising seven isotopically labeled compounds. The goal of this tutorial is to detect and quantify these differential spike-in compounds against the complex background. - -### Basics of non-targeted metabolomics data analysis - -For the metabolite quantification we choose an approach similar to the one used for peptides, but this time based on the OpenMS `FeatureFinderMetabo` method. This feature finder again collects peak picked data into individual mass traces. The reason -why we need a different feature finder for metabolites lies in the step after trace detection: the aggregation of isotopic traces belonging to the same compound ion into the same feature. Compared to peptides with their averagine model, small molecules -have very different isotopic distributions. To group small molecule mass traces correctly, an aggregation model tailored to small molecules is thus needed. - -- Create a new workflow called for instance ”Metabolomics”. -- Add an `File Importer` node and configure it with one mzML file [from the](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/) {path}`Example_Data,Metabolomics,datasets`. -- Add a `FeatureFinderMetabo` node (from **Community Nodes** > **OpenMS** > **Quantitation**) and -connect the first output port of the `File Importer` to the `FeatureFinderMetabo`. -- For an optimal result adjust the following settings. Please note that some of these are advanced parameters. -- Connect a `Output Folder` to the output of the `FeatureFinderMetabo` (see Fig. 27). - -(Figure_27)= -|![FeatureFinderMetabo workflow](/images/openms-user-tutorial/metabo/minimal_FFM_wf.png)| -|:--:| -|Figure 27: FeatureFinderMetabo workflow| - -In the following advanced parameters will be highlighted. These parameter can be altered if the `Show advanced parameter` field in the specific tool is activated. - -|**parameter**|**value**| -|:------------|:--------| -|*algorithm*→*common*→*chrom_fwhm*|8.0| -|*algorithm*→*mtd*→*trace_termination_criterion*|sample_rate| -|*algorithm*→*mtd*→*min_trace_length*|3.0| -|*algorithm*→*mtd*→*max_trace_length*|600.0| -|*algorithm*→*epd*→*width_filtering*|off| -|*algorithm*→*ffm*→*report_convex_hulls*|true| - -The parameters change the behavior of `FeatureFinderMetabo` as follows: - -- **chrom_fwhm**: The expected chromatographic peak width in seconds. -- **trace_termination_criterion**: In the first stage `FeatureFinderMetabo` assembles -mass traces with a pre-defined mass accuracy. If this parameter is set to ’outlier’, the extension of a mass trace is stopped after a predefined number of consecutive outliers is found. If this parameter is set to ’sample_rate’, the extension of a mass trace is stopped once the ratio of collected peaks versus visited spectra falls below the ratio given by `min_sample_rate`. -- **min_trace_length**: Minimal length of a mass trace in seconds. Choose a small value, if you want to identify low-intensity compounds. -- **max_trace_length**: Maximal length of a mass trace in seconds. Set this parameter to -1 to disable the filtering by maximal length. -- **width_filtering**: `FeatureFinderMetabo` can remove features with unlikely peak widths from the results. If activated it will use the interval provided by the parameters `min_fwhm` and `max_fwhm`. -- **report_convex_hulls**: If set to true, convex hulls including mass traces will be reported for all identified features. This increases the output size considerably. - -The output file .featureXML can be visualized with TOPPView on top of the used `.mzML` file - in a so called layer - to look at the identified features. - -First start TOPPView and open the example `.mzML` file (see Fig. 28). Afterwards open the `.featureXML` output as new layer (see Fig. 29). The overlay is depicted in Figure 30. The zoom of the `.mzML` - `.featureXML` overlay shows the individual mass traces and the assembly of those in a feature (see Fig. 31). - -(Figure_28)= -|![Opened .mzML in TOPPView](/images/openms-user-tutorial/metabo/ToppView_1.png)| -|:--:| -|Figure 28: Opened .mzML in TOPPView| - -(Figure_29)= -|![Add new layer in TOPPView](/images/openms-user-tutorial/metabo/ToppView_2.png)| -|:--:| -|Figure 29: Add new layer in TOPPView| - -(Figure_30)= -|![Overlay of the .mzML layer with the .featureXML layer](/images/openms-user-tutorial/metabo/ToppView_3.png)| -|:--:| -|Figure 30: Overlay of the .mzML layer with the .featureXML layer| - -(Figure_31)= -|![Zoom of the overlay of the .mzML with the .featureXML layer](/images/openms-user-tutorial/metabo/ToppView_4.png)| -|:--:| -|Figure 31: Zoom of the overlay of the .mzML with the .featureXML layer. Here the individual isotope traces (blue lines) are assembled into a feature here shown as convex hull (rectangular box).| - -The workflow can be extended for multi-file analysis, here an `Input Files` node is to be used instead of the `File Importer` node. In front of the `FeatureFinderMetabo`, a `ZipLoopStart` and behind `ZipLoopEnd` has to be used, since `FeatureFinderMetabo` will analysis on file to file bases. - -To facilitate the collection of features corresponding to the same compound ion across different samples, an alignment of the samples’ feature maps along retention time is often helpful. In addition to local, small-scale elution differences, one can often see constant retention time shifts across large sections between samples. We can use linear transformations to correct for these large scale retention differences. This brings the majority of corresponding compound ions close to each other. Finding the correct corresponding ions is then faster and easier, as we don’t have to search as far around individual features. - -(Figure_32)= -|![map alignment example](/images/openms-user-tutorial/metabo/align.png)| -|:--:| -|Figure 32: The first feature map is used as a reference to which other maps are aligned. The calculated transformation brings corresponding features into close retention time proximity. Linking of these features form a so-called consensus features of a consensus map.| - -- After the `ZipLoopEnd` node, add a `MapAlignerPoseClustering` node (**Community Nodes**>**OpenMS**>**Map Alignment**), set its Output Type to featureXML, and adjust the following settings: - -|**parameter**| **value**| -|:------------|:---------| -|*algorithm* → *max_num_peaks_considered*| −1| -|*algorithm* → *superimposer* → *mz_pair_max_distance*| 0.005| -|*algorithm* → *superimposer* → *num_used_points*| 10000| -|*algorithm* → *pairfinder* → *distance_RT* → *max_difference*| 20.0| -|*algorithm* → *pairfinder* → *distance_MZ* → *max_difference*| 20.0| -|*algorithm* → *pairfinder* → *distance_MZ* → *unit*| ppm| - -`MapAlignerPoseClustering` provides an algorithm to align the retention time scales of multiple input files, correcting shifts and distortions between them. Retention time adjustment may be necessary to correct for chromatography differences e.g. before data from multiple LC-MS runs can be combined (feature linking). The alignment algorithm implemented here is the pose clustering algorithm. - -The parameters change the behavior of `MapAlignerPoseClustering` as follows: -- **max_num_peaks_considered**: The maximal number of peaks/features to be considered per map. To use all, set this parameter to -1. -- **mz_pair_max_distance**: Maximum of m/z deviation of corresponding elements in different maps. This condition applies to the pairs considered in hashing. -- **num_used_points**: Maximum number of elements considered in each map (selected by intensity). Use a smaller number to reduce the running time and to disregard weak signals during alignment. -- **distance_RT → max_difference**: Features that have a larger RT difference will never be paired. -- **distance_MZ →max_difference**: Features that have a larger m/z difference will never be paired. -- **distance_MZ →unit**: Unit used for the parameter distance_MZ max_difference, either Da or ppm. - -The next step after retention time correction is the grouping of corresponding features in multiple samples. In contrast to the previous alignment, we assume no linear relations of features across samples. The used method is tolerant against local swaps in elution order. - -(Figure_33)= -|![feature linking example](/images/openms-user-tutorial/metabo/link.png)| -|:--:| -|Figure 33: Features A and B correspond to the same analyte. The linking of features between runs (indicated by an arrow) allows comparing feature intensities.| - -- After the `MapAlignerPoseClustering` node, add a `FeatureLinkerUnlabeledQT` node (**Community Nodes** > **OpenMS**>**Map Alignment**) and adjust the following settings: - - |**parameter**|**value**| - |:------------|:--------| - |*algorithm* → *distance_RT* → *max_difference*|40| - |*algorithm* → *distance_MZ* → *max_difference*|20| - |*algorithm* → *distance_MZ* → *unit*|ppm| - - The parameters change the behavior of `FeatureLinkerUnlabeledQT` as follows (similar to the parameters we adjusted for `MapAlignerPoseClustering`): - - - **distance_RT → max_difference**: Features that have a larger RT difference will never be paired. - - **distance_MZ → max_difference**: Features that have a larger m/z difference will never be paired. - - **distance_MZ → unit**: Unit used for the parameter distance_MZ max_difference, either Da or ppm. - -- After the `FeatureLinkerUnlabeledQT` node, add a **TextExporter** node (**Community Nodes** > **OpenMS** > **File Handling**). -- Add an `Output Folder` node and configure it with an output directory where you want to store the resulting files. -- Run the pipeline and inspect the output. - -(Figure_34)= -|![Label-free quantification workflow for metabolites](/images/openms-user-tutorial/metabo/metabo_part1_with_labels.png)| -|:--:| -|Figure 34: Label-free quantification workflow for metabolites.| - -You should find a single, tab-separated file containing the information on where metabolites were found and with which intensities. You can also add `Output Folder` nodes at different stages of the workflow and inspect the intermediate results (e.g., identified metabolite features for each input map). The complete workflow can be seen in Figure 34. In the following section we will try to identify those metabolites. - -The `FeatureLinkerUnlabeledQT` output can be visualized in TOPPView on top of the input and output of the `FeatureFinderMetabo` (see Fig 35). - -(Figure_35)= -|![Label-free quantification workflow for metabolites](/images/openms-user-tutorial/metabo/ToppView_5.png)| -|:--:| -|Figure 35: Visualization of .consensusXML output over the .mzML and .featureXML ’layer’.| - -### Basic metabolite identification -At the current state we found several metabolites in the individual maps but so far don’t know what they are. To identify metabolites, OpenMS provides multiple tools, including search by mass: the AccurateMassSearch node searches observed masses against the Human Metabolome Database (HMDB)[^14], [^15], [^16]. We start with the workflow from the previous section (see Figure 34). - -- Add a **FileConverter** node (**Community Nodes** > **OpenMS** > **File Handling**) and connect the output of the FeatureLinkerUnlabeledQT to the incoming port. -- Open the Configure dialog of the **FileConverter** node and select the tab **OutputTypes**. In the drop down list for FileConverter.1.out select **featureXML**. -- Add an **AccurateMassSearch** node (**Community Nodes** > **OpenMS** > **Utilities**) and connect the output of the **FileConverter** node to the first port of the **AccurateMassSearch** node. -- Add four `File Importer` nodes and configure them with the following [files](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/databases/): - - {path}`Example_Data,Metabolomics,databases,PositiveAdducts.tsv` - This file specifies the list of adducts that are considered in the positive mode. Each line contains the formula and charge of an adduct separated by a semicolon (e.g. M+H;1+). The mass of the adduct is calculated automatically. - - {path}`Example_Data,Metabolomics,databases,NegativeAdducts.tsv` - This file specifies the list of adducts that are considered in the negative mode analogous to the positive mode. - - {path}`Example_Data,Metabolomics,databases,HMDBMappingFile.tsv` - This file contains information from a metabolite database in this case from HMDB. It has three (or more) tab-separated columns: mass, formula, and identifier(s). This allows for an efficient search by mass. - - {path}`Example_Data,Metabolomics,databases,HMDB2StructMapping.tsv` - This file contains additional information about the identifiers in the mapping file. It has four tab-separated columns that contain the identifier, name, SMILES, and INCHI. These will be included in the result file. The identifiers in this file must match the identifiers in the `HMDBMappingFile.tsv`. -- In the same order as they are given above connect them to the remaining input ports of the **AccurateMassSearch** node. -- Add an `Output Folder` node and connect the first output port of the -**AccurateMassSearch** node to the `Output Folder` node. - -The result of the **AccurateMassSearch** node is in the mzTab format[^17] so you can easily open it in a text editor or import it into Excel or KNIME, which we will do in the next section. The complete workflow from this section is shown in Figure 36. - -(Figure_36)= -|![Label-free quantification and identification workflow for metabolites](/images/openms-user-tutorial/metabo/metabo_part2.png)| -|:--:| -|Figure 36: Label-free quantification and identification workflow for metabolites.| - -#### Convert your data into a KNIME table - -The result from the TextExporter node as well as the result from the **AccurateMassSearch** node are files while standard KNIME nodes display and process only KNIME tables. To convert these files into KNIME tables we need two different nodes. For the **AccurateMassSearch** results, we use the **MzTabReader** node (**Community Nodes** > **OpenMS** > **Conversion** > **mzTab**) and its **Small Molecule Section** port. For the result of the **TextExporter**, we use the `ConsensusTextReader` (**Community Nodes** > **OpenMS** > **Conversion**). -When executed, both nodes will import the OpenMS files and provide access to the data as KNIME tables. The retention time values are exported as a list using the **MzTabReader** based on the current PSI-Standard. This has to be parsed using the **SplitCollectionColumn**, which outputs a ”Split Value 1” based on the first entry in the rention time list, which has to be renamed to retention time using the **ColumnRename**. You can now combine both tables using the **Joiner** node (**Manipulation** > **Column** > **Split & Combine**) and configure it to match the m/z and retention time values of the respective tables. The full workflow is shown in Figure 37. - -(Figure_37)= -|![Label-free quantification and identification workflow for metabolites that loads the results into KNIME and joins the tables](/images/openms-user-tutorial/metabo/metabo_part3.png)| -|:--:| -|Figure 37: Label-free quantification and identification workflow for metabolites that loads the results into KNIME and joins the tables.| - -#### Adduct grouping - -Metabolites commonly co-elute as ions with different adducts (e.g., glutathione+H, glutathione+Na) or with charge-neutral modifications (e.g., water loss). Grouping such related ions allows to leverage information across features. For example, a low intensity, single trace feature could still be assigned a charge and adduct due to a matching high-quality feature. Several OpenMS tools, such as **AccurateMassSearch**, can use this information to, for example, narrow down candidates for identification. - -For this grouping task, we provide the **MetaboliteAdductDecharger** node. Its method explores the combinatorial space of all adduct combinations in a charge range for optimal explanations. Using defined adduct probabilities, it assigns co-eluting features having suitable mass shifts and charges those adduct combinations which maximize overall ion probabilities. - -The tool works natively with featureXML data, allowing the use of reported convex hulls. On such a single-sample level, co-elution settings can be chosen more stringently, as ionization-based adducts should not influence the elution time: Instead, elution differences of related ions should be due to slightly differently estimated times for their feature centroids. - -Alternatively, consensusXML data from feature linking can be converted for use, though with less chromatographic information. Here, the elution time averaging for features linked across samples, motivates wider co-elution tolerances. - -The two main tool outputs are a consensusXML file with compound groups of related input ions, and a featureXML containing the input file but annotated with inferred adduct information and charges. - -Options to respect or replace ion charges or adducts allow for example: -- Heuristic but faster, iterative adduct grouping(**MetaboliteAdductDecharger → MetaboliteFeatureDeconvolution → q_try** set to “feature”) by chaining multiple **MetaboliteAdductDecharger** nodes with growing adduct sets, charge ranges or otherwise relaxed tolerances. -- More specific feature linking (**FeatureLinkerUnlabeledQT → algorithm → ignore_adduct** set to “false”) - -(Figure_38)= -|![Metabolite Adduct Decharger adduct grouping workflow](/images/openms-user-tutorial/metabo/mad.png)| -|:--:| -|Figure 38: Metabolite Adduct Decharger adduct grouping workflow. | - -
-

**Task**

-A modified metabolomics workflow with exemplary MetaboliteAdductDecharger use and parameters is provided in {path}`Workflows,MetaboliteAdductGrouping.knwf`. Run the workflow, inspect tool outputs and compare **AccurateMassSearch** results with and without adduct grouping. -
- -#### Visualizing data - -Now that you have your data in KNIME you should try to get a feeling for the capabilities of KNIME. - -
-

**Task**

-Check out the **Molecule Type Cast** node (**Chemistry** > **Translators**) together with subsequent cheminformatics nodes (e.g. **RDKit From Molecule**(**Community Nodes** > **RDKit** > **Converters**)) to render the structural formula contained in the result table. -
- -
-

**Task**

-Have a look at the `Column Filter` node to reduce the table to the interesting columns, e.g., only the Ids, chemical formula, and intensities. -
- -
-

**Task**

-Try to compute and visualize the m/z and retention time error of the different feature elements (from the input maps) of each consensus feature. Hint: A nicely configured **Math Formula (Multi Column)** node should suffice. -
- -#### Spectral library search - -Identifying metabolites using only the accurate mass may lead to ambiguous results. In practice, additional information (e.g. the retention time) is used to further narrow down potential candidates. Apart from MS1-based features, tandem mass spectra (MS2) of metabolites provide additional information. In this part of the tutorial, we take a look on how metabolite spectra can be identified using a library of previously identified spectra. - -Because these libraries tend to be large we don’t distribute them with OpenMS. - -
-

**Task**

-Construct the workflow as shown in Fig. 39. Use the file {path}`ExampleData,Metabolomics,datasets,MetaboliteIDSpectraDBpositive.mzML` as input for your workflow. You can use the spectral library from {path}`ExampleData,Metabolomics,databases,MetaboliteSpectralDB.mzML` as second input. The first input file contains tandem spectra that are identified by the **MetaboliteSpectralMatcher**. The resulting mzTab file is read back into a KNIME table The retention time values are exported as a list based on the current PSI-Standard. This has to be parsed using the **SplitCollectionColumn**, which outputs a ”Split Value 1” based on the first entry in the rention time list, which has to be renamed to retention time using the **ColumnRename** before it is stored in an Excel table. Make sure that you connect the **MzTabReader** port corresponding to the Small Molecule Section to the **Excel writer (XLS)**. Please select the ”add column headers” option in the **Excel writer (XLS)**). -
- -(Figure_39)= -|![Spectral library identification workflow](/images/openms-user-tutorial/metabo/speclib.png)| -|:--:| -|Figure 39: Spectral library identification workflow.| - -Run the workflow and inspect the output. - -#### Manual validation - -In metabolomics, matches between tandem spectra and spectral libraries are manually validated. Several commercial and free online resources exist which help in that task. Some examples are: - -- mzCloud contains only spectra from Thermo Orbitrap instruments. The webpage requires Microsoft Silverlight which currently does not work in modern browsers (see the following [link](https://www.mzcloud.org/DataViewer). -- MassBank North America (MoNA) has spectra from different instruments but falls short in number of spectra (compared to Metlin and mzCloud). See the following [link](http://mona.fiehnlab.ucdavis.edu/spectra/display/KNA00122). -- METLIN includes 961,829 molecules ranging from lipids, steroids, metabolites, small peptides, carbohydrates, exogenous drugs and toxicants. In total over 14,000 metabolites. - -Here, we will use METLIN to manually validate metabolites. - -
-

**Task**

-Check in the .xlsx output from the Excel writer (XLS) if you can find glutathione. Use the retention time column to find the spectrum in the mzML file. Here open the [file](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/Metabolite_ID_SpectraDB_positive.mzML) in the {path}`Example_Data,Metabolomics,datasets,MetaboliteIDSpectraDBpositive.mzML` in TOPPView. The MSMS spectrum with the retention time of 67.6 s is used as example. The spectrum can be selected based on the retention time in the scan view window. Therefore the MS1 spectrum with the retention time of 66.9 s has to be double clicked and the MSMS spectra recorded in this time frame will show up. Select the tandem spectrum of Glutathione, but do not close TOPPView, yet. -
- -(Figure_40)= -|![Tandem spectrum of glutathione. Visualized in TOPPView.](/images/openms-user-tutorial/metabo/glutathioneTV.png)| -|:--:| -|Figure 40: Tandem spectrum of glutathione. Visualized in TOPPView.| - -
-

**Task**

-On the METLIN homepage search for **Name** Glutathione using the **Advanced Search**. See the [link](https://metlin.scripps.edu/landing_page.php?pgcontent=advanced_search). Note that free registration is required. Which collision energy (and polarity) gives the best (visual) match to your experimental spectrum in TOPPView? Here you can compare the fragmentation patterns in both spectra shown by the Intensity or relative Intensity, the m/z of a peak and the distance between peaks. Each distance between two peaks corresponds to a fragment of elemental composition (e.g., NH2 with the charge of one would have mass of two peaks of 16.023 Th). -
- -(Figure_41)= -|![Tandem spectrum of glutathione. Visualized in Metlin. Note that several fragment spectra from varying collision energies are available.](/images/openms-user-tutorial/metabo/glutathioneMetlin.png)| -|:--:| -|Figure 41: Tandem spectrum of glutathione. Visualized in Metlin. Note that several fragment spectra from varying collision energies are available.| - -#### De novo identification - -Another method for MS2 spectra-based metabolite identification is de novo identification. This approach can be used in addition to the other methods (accurate mass search, spectral library search) or individually if no spectral library is available. In this part of the tutorial, we discuss how metabolite spectra can be identified using de -novo tools. To this end, the tools SIRIUS and CSI:FingerID ([^18], [^19], [^20]) were integrated in the OpenMS Framework as SiriusAdapter. SIRIUS uses isotope pattern analysis to detect the molecular formula and further analyses the fragmentation pattern -of a compound using fragmentation trees. CSI:FingerID is a method for searching a -fingerprint of a small molecule (metabolite) in a molecular structure database. -The node **SiriusAdapter** is able to work in different modes depending on the provided input. - -- Input: mzML - SiriusAdapter will search all MS2 spectra in a map. -- Input: mzML, featureXML (FeatureFinderMetabo) - SiriusAdapter can use the provided feature information to reduce the search space to valid features with MS2 spectra. Additionally it can use the isotopic trace information. -- Input: mzML, featureXML (FeatureFinderMetabo / MetaboliteAdductDecharger / AccurateMassSearch) - SiriusAdapter can use the feature information as mentioned above together with feature adduct information from adduct grouping or previous identification. - -By using a mzML and featureXML, SIRIUS gains a lot of additional information by using the OpenMS tools for preprocessing. - -
-

**Task**

-Construct the workflow as shown in Fig. 42. -{path}`Example_Data,Metabolomics,datasets` -Use the [file](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/Metabolite_DeNovoID.mzML) `MetaboliteDeNovoID.mzML` as input for your workflow. -
- -Below we show an example workflow for de novo identification (Fig. 42). Here, the node `FeatureFinderMetabo` is used for feature detection to annotate analytes in mz, rt, intensity and charge. This is followed by adduct grouping, trying to asses possible adducts based on the feature space using the **MetaboliteAdductDecharger**. In addition, the **HighResPrecursorMassCorrector** can use the newly generated feature information to map MS2 spectra, which were measured on one of the isotope traces to the monoisotopic precursor. This helps with feature mapping and analyte identification in the **SiriusAdapter** due to the usage of additional MS2 spectra that belong to a specific feature. - -(Figure_42)= -|![De novo identification workflow](/images/openms-user-tutorial/metabo/denovoid.png)| -|:--:| -|Figure 42: *De novo* identification workflow| - -Run the workflow and inspect the output. - -The output consists of two mzTab files and an internal .ms file. One mzTab for SIRIUS and the other for the CSI:FingerID. These provide information about the chemical formula, adduct and the possible compound structure. The information is referenced to the spectrum used in the analysis. Additional information can be extracted from the **SiriusAdapter** by setting an ”out_workspace_directory”. Here the SIRIUS workspace will be provided after the calculation has finished. This workspace contains information about annotated fragments for each successfully explained compound. - -### Downstream data analysis and reporting - -In this part of the metabolomics session we take a look at more advanced downstream analysis and the use of the statistical programming language R. As laid out in the introduction we try to detect a set of spike-in compounds against a complex blood background. As there are many ways to perform this type of analysis we provide a complete workflow. - -
-

**Task**

-Import the workflow from WorkflowsmetaboliteID.knwf in KNIME: -**File** > **Import KNIME Workflow...** -
- -The section below will guide you in your understanding of the different parts of the workflow. Once you understood the workflow you should play around and be creative. Maybe create a novel visualization in KNIME or R? Do some more elaborate statistical analysis? Note that some basic R knowledge is required to fully understand the processing in **R Snippet** nodes. - -#### Signal processing and data preparation for identification - -The following part is analogous to what you did for the simple metabolomics pipeline. - -#### Data preparation for quantification - -The first part is identical to what you did for the simple metabolomics pipeline. Additionally, we convert zero intensities into NA values and remove all rows that contain at least one NA value from the analysis. We do this using a very simple **R Snippet** and subsequent **Missing Value filter** node. - -
-

**Task**

-Inspect the **R Snippet** by double-clicking on it. The KNIME table that is passed to an **R Snippet** node is available in R as a data.frame named knime.in. The result of this node will be read from the data.frame knime.out after the script finishes. Try to understand and evaluate parts of the script (Eval Selection). In this dialog you can also print intermediary results using for example the R command head(knime.in) or cat(knime.in) to the Console pane. -
- -#### Statistical analysis - -After we linked features across all maps, we want to identify features that are significantly deregulated between the two conditions. We will first scale and normalize the data, then perform a t-test, and finally correct the obtained p-values for multiple testing using Benjamini-Hochberg. All of these steps will be carried out in individual **R Snippet** nodes. -- Double-click on the first **R Snippet** node labeled ”log scaling” to open the **R Snippet** dialog. In the middle you will see a short R script that performs the log scaling. To perform the log scaling we use a so-called regular expression (grepl) to select all columns containing the intensities in the six maps and take the log2 logarithm. -- The output of the log scaling node is also used to draw a boxplot that can be used to examine the structure of the data. Since we only want to plot the intensities in the different maps (and not m/z or rt) we first use a `Column Filter` node to keep only the columns that contain the intensities. We connect the resulting table to a **Box Plot** node which draws one box for every column in the input table. Right-click and select **View: Box Plot** -- The median normalization is performed in a similar way to the log scaling. First we calculate the median intensity for each intensity column, then we subtract the median from every intensity. -- Open the **Box Plot** connected to the normalization node and compare it to the box plot connected to the log scaling node to examine the effect of the median normalization. -- To perform the t-test we defined the two groups we want to compare. Finally we save the p-values and fold-changes in two new columns named p-value and FC. -- The **Numeric Row Splitter** is used to filter less interesting parts of the data. In this case we only keep columns where the fold-change is ≥ 2. -- We adjust the p-values for multiple testing using Benjamini-Hochberg and keep all consensus features with a q-value ≤ 0.01 (i.e. we target a false-discovery rate of 1%). - -#### Interactive visualization - -KNIME supports multiple nodes for interactive visualization with interrelated output. The nodes used in this part of the workflow exemplify this concept. They further demonstrate how figures with data dependent customization can be easily realized using basic KNIME nodes. Several simple operations are concatenated in order to enable an interactive volcano plot. - -- We first log-transform fold changes and p-values in the **R Snippet** node. We then append columns noting interesting features (concerning fold change and p-value). -- With this information, we can use various Manager nodes (**Views** > **Property**) to emphasize interesting data points. The configuration dialogs allow us to select columns to change color, shape or size of data points dependent on the column values. -- The **Scatter Plot** node (from the **Views** repository) enables interactive visualization of the logarithmized values as a volcano plot: the log-transformed values can be chosen in the ‘Column Selection’ tab of the plot view. Data points can be selected in the plot and highlighted via the menu option. The highlighting transfers to all other interactive nodes connected to the same data table. In our case, selection and the highlighting will also occur in the **Interactive Table** node (from the **Views** repository). -- Output of the interactive table can then be filtered via the ”HiLite” menu tab. For example, we could restrict shown rows to points highlighted in the volcano plot. - -
-

**Task**

-Inspect the nodes of this section. Customize your visualization and possibly try to visualize other aspects of your data. -
- -#### Advanced visualization - -R Dependencies: This section requires that the R packages ggplot2 and ggfortify are both installed. ggplot2 is part of the KNIME R Statistics Integration (Windows Binaries) which should already be installed via the full KNIME installer, ggfortify however is not. In case that you use an R installation where one or both of them are not yet installed, add an **R Snippet** node and double-click to configure. In the R Script text editor, enter the following code: - -```r -#Include the next line if you also have to install ggplot2: -install.packages("ggplot2") - -#Include the following lines to install ggfortify: -install.packages("ggfortify") - -library(ggplot2) -library(ggfortify) -``` - -You can remove the: - -```r -install.packages -``` - -commands once it was successfully installed. - -Even though the basic capabilities for (interactive) plots in KNIME are valuable for initial data exploration, professional looking depiction of analysis results often relies on dedicated plotting libraries. The statistics language R supports the addition of a large variety of packages, including packages providing extensive plotting capabilities. This part of the workflow shows how to use R nodes in KNIME to visualize more advanced figures. Specifically, we make use of different plotting packages to realize heatmaps. -- The used `RView (Table)` nodes combine the possibility to write R snippet code with visualization capabilities inside KNIME. Resulting images can be looked at in the output RView, or saved via the **Image Writer (Port)** node. -- The heatmap nodes make use of the `gplots` libary, which is by default part of the R Windows binaries (for full KNIME version 3.1.1 or higher). We again use regular expressions to extract all measured intensity columns for plotting. For clarity, feature names are only shown in the heatmap after filtering by fold changes. - -#### Data preparation for reporting - -Following the identification, quantification and statistical analysis our data is merged and formatted for reporting. First we want to discard our normalized and logarithmized intensity values in favor of the original ones. To this end we first remove the intensity columns (`Column Filter`) and add the original intensities back (**Joiner**). For that, we use an Inner Join 2 with the **Joiner** node. In the dialog of the node, we add two entries for the Joining Columns and for the first column we pick `retention_time` from the top input (i.e. the **AccurateMassSearch** output) and `rt_cf` (the retention time of the consensus features) for the bottom input (the result from the quantification). For the second column you should choose `exp_mass_to_charge` and `mz_cf` respectively to make the joining unique. Note that the workflow needs to be executed up to the previous nodes for the possible selections of columns to appear. - -(Figure_43)= -|![Data preparation for reporting](/images/openms-user-tutorial/metabo/reporting.png)| -|:--:| -|Figure 43: Data preparation for reporting| - -
-

**Question**

-What happens if we use a *Left Outer Join*, *Right Outer Join* or *Full Outer Join* instead of the *Inner Join*? -
- -
-

**Task**

-Inspect the output of the join operation after the Molecule Type Cast and RDKit molecular structure generation. -
- -While all relevant information is now contained in our table the presentation could be improved. Currently, we have several rows corresponding to a single consensus feature (=linked feature) but with different, alternative identifications. It would be more convenient to have only one row for each consensus feature with all accurate mass identifications added as additional columns. To this end, we use the **Column to Grid** node that flattens several rows with the same consensus number into a single one. Note that we have to specify the maximum number of columns in the grid so we set this to a large value (e.g. 100). We finally export the data to an Excel file (**XLS Writer**). - -## OpenSWATH - -### Introduction - -OpenSWATH [^21] allows the analysis of LC-MS/MS DIA (data independent acquisition) data using the approach described by Gillet *et al*. [^22]. The DIA approach described there uses 32 cycles to iterate through precursor ion windows from 400-426 Da to 1175-1201 Da and at each step acquires a complete, multiplexed fragment ion spectrum of all precursors present in that window. After 32 fragmentations (or 3.2 seconds), the cycle is restarted and the first window (400-426 Da) is fragmented again, thus delivering complete “snapshots” of all fragments of a specific window every 3.2 seconds. -The analysis approach described by Gillet et al. extracts ion traces of specific fragment ions from all MS2 spectra that have the same precursor isolation window, thus generating data that is very similar to SRM traces. - -### Installation of OpenSWATH - -OpenSWATH has been fully integrated since OpenMS 1.10 [^4], [^2], [^23], [^24], [^25]. - -### Installation of mProphet - -mProphet[^26] is available as standalone script in {path}`External_Tools,mProphet`. [R](http://www.r-project.org/) and the package [MASS](http://cran.r-project.org/web/packages/MASS/) are further required to execute mProphet. Please obtain a version for either Windows, Mac or Linux directly from CRAN. -PyProphet, a much faster reimplementation of the mProphet algorithm is available from [PyPI](https://pypi.python.org/pypi/pyprophet/). The usage of pyprophet instead of mProphet is suggested for large-scale applications. - -mProphet will be used in this tutorial. - -### Generating the Assay Library - -#### Generating TraML from transition lists - -OpenSWATH requires an assay library to be supplied in the TraML format[^27]. To enable manual editing of transition lists, the TOPP tool **TargetedFileConverter** is available, which uses tab separated files as input. Example datasets are provided in {path}`ExampleData,OpenSWATH,assay`. Please note that the transition lists need to be named `.tsv`. - -The header of the transition list contains the following variables (with example values in brackets): - -**Required Columns**: -`PrecursorMz` - - The mass-to-charge (m/z) of the precursor ion. (924.539) - -`ProductMz` - - The mass-to-charge (m/z) of the product or fragment ion. (728.99) - -`LibraryIntensity` - - The relative intensity of the transition. (0.74) - -`NormalizedRetentionTime` - - The normalized retention time (or iRT)[^28] of the peptide. (26.5) - -**Targeted Proteomics Columns** -`ProteinId` - - A unique identifier for the protein. (AQUA4SWATH_HMLangeA) - -`PeptideSequence` - - The unmodified peptide sequence. (ADSTGTLVITDPTR) - -`ModifiedPeptideSequence` - - The peptide sequence with UniMod modifications. (ADSTGTLVITDPTR(UniMod:267)) - -`PrecursorCharge` - - The precursor ion charge. (2) - -`ProductCharge` - - The product ion charge. (2) - -**Grouping Columns**: -`TransitionGroupId` - - A unique identifier for the transition group. -(AQUA4SWATH_HMLangeA_ADSTGTLVITDPTR(UniMod:267)/2) - -`TransitionId` - - A unique identifier for the transition. -(AQUA4SWATH_HMLangeA_ADSTGTLVITDPTR(UniMod:267)/2_y8) - -`Decoy` - - A binary value whether the transition is target or decoy. (target: 0, decoy: 1) - -`PeptideGroupLabel` - - Which label group the peptide belongs to. - -`DetectingTransition` - - Use transition for peak group detection. (1) - -`IdentifyingTransition` - - Use transition for peptidoform inference using IPF. (0) - -`QuantifyingTransition` - - Use transition to quantify peak group. (1) - -For further instructions about generic transition list and assay library generation please see the following [link](http://openswath.org/en/latest/docs/generic.html). -To convert transitions lists to TraML, use the TargetedFileConverter: Please use the absolute path to your OpenMS installation. - -**Linux or Mac** - -On the Terminal: - -```bash - TargetedFileConverter -in OpenSWATH_SGS_AssayLibrary_woDecoy.tsv -out OpenSWATH_SGS_AssayLibrary_woDecoy.TraML -``` - -**Windows** - -On the TOPP command: - -```bash - TargetedFileConverter.exe -in OpenSWATH_SGS_AssayLibrary_woDecoy.tsv -out OpenSWATH_SGS_AssayLibrary_woDecoy.TraML -``` - -#### Appending decoys to a TraML file - -In addition to the target assays, OpenSWATH requires decoy assays in the library which are later used for classification and error rate estimation. For the decoy generation it is crucial that the decoys represent the targets in a realistic but unnatural manner without interfering with the targets. The methods for decoy generation implemented in OpenSWATH include ’shuffle’, ’pseudo-reverse’, ’reverse’ and ’shift’. To append decoys to a TraML, the TOPP tool **OpenSwathDecoyGenerator** can be used: Please use the absolute path to your OpenMS installation. - -**Linux or Mac** - -On the Terminal: - -```bash -OpenSwathDecoyGenerator -in OpenSWATH_SGS_AssayLibrary_woDecoy.TraML -out OpenSWATH_SGS_AssayLibrary.TraML -method shuffle -switchKR false -``` - -**Windows** - -On the TOPP command: - -```bash -OpenSwathDecoyGenerator.exe -in OpenSWATH_SGS_AssayLibrary_woDecoy.TraML -out OpenSWATH_SGS_AssayLibrary.TraML -method shuffle -switchKR false -``` - -### OpenSWATH KNIME - -An example KNIME workflow for OpenSWATH is supplied in `Workflows` (Fig. 44). The example dataset can be used for this workflow (filenames in brackets): - -1. Open {path}`Workflows,OpenSWATH.knwf` in KNIME: **File** > **Import KNIME Workflow...** -2. Select the normalized retention time (iRT) assay library in TraML format by double-clicking on node `File Importer` > **iRT Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHiRTAssayLibrary.TraML`). -3. Select the SWATH MS data in mzML format as input by double-clicking on node **Input File** > **SWATH-MS files**. ({path}`ExampleData,OpenSWATH,data,splitnapedroL120420x010SW-*.nf.pp.mzML`). -4. Select the target peptide assay library in TraML format as input by double-clicking on node `Input Files` > **Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHSGSAssayLibrary.TraML`). -5. Set the output destination by double-clicking on node `Output File`. -6. Run the workflow. - -The resulting output can be found at your selected path, which will be used as input for mProphet. Execute the script on the Terminal (Linux or Mac) or cmd.exe (Windows) in {path}`ExampleData,OpenSWATH,result`. Please use the absolute path to your R installation and the result file: - -```r -R --slave --args bin_dir=../../../External_Tools/mProphet/ mquest=OpenSWATH_quant.tsv workflow=LABEL_FREE num_xval=5 run_log=FALSE write_classifier=1 write_all_pg=1 < ../../../External_Tools/mProphet/mProphet.R -``` - -or for Windows: - -```r -"C:\Program Files\R\R-3.5.1\bin\x86\R.exe" --slave --args bin_dir=../../../External_Tools/mProphet/ mquest=OpenSWATH_quant.tsv workflow=LABEL_FREE num_xval=5 run_log=FALSE write_classifier=1 write_all_pg=1 < ../../../External_Tools/mProphet/mProphet.R -``` - -The main output will be called: {path}`OpenSWATH,result,mProphetxallxpeakgroups.xls` with statistical information available in {path}`OpenSWATH,result,mProphet.pdf`. - -Please note that due to the semi-supervised machine learning approach of mProphet the results differ slightly when mProphet is executed several times. - -(Figure_44)= -|![OpenSWATH KNIME Workflow.](/images/openms-user-tutorial/openswath/OpenSWATHWF.png)| -|:--:| -|Figure 44: OpenSWATH KNIME Workflow.| - -Additionally, the chromatogram output (.mzML) can be visualized for inspection with TOPPView. -For additional instructions on how to use pyProphet instead of mProphet please have a look at the [PyProphet Legacy Workflow](http://openswath.org/en/latest/docs/pyprophet_legacy.html). If you want to use the SQLite-based workflow in your lab in the future, please have a look [here](http://openswath.org/en/latest/docs/pyprophet.html). The SQLite-based workflow will not be part of the tutorial. - -### From the example dataset to real-life applications - -The sample dataset used in this tutorial is part of the larger SWATH MS Gold Standard (SGS) dataset which is described in the publication of Roest *et al.*[^21]. It contains one of 90 SWATH-MS runs with significant data reduction (peak picking of the raw, profile data) to make file transfer and working with it easier. Usually SWATH-MS datasets are huge with several gigabyte per run. Especially when complex samples in combination with large assay libraries are analyzed, the TOPP tool based workflow requires a lot of computational resources. Additional information and instruction can be found at the following [link](http://openswath.org/en/latest/). - -## OpenSWATH for Metabolomics - -### Introduction - -We would like to present an automated DIA/SWATH analysis workflow for metabolomics, which takes advantage of experiment specific target-decoy assay library generation. This allows for targeted extraction, scoring and statistical validation of metabolomics DIA data[^29], [^30]. - -### Workflow - -The workflow follows multiple steps (see Fig. 45). - -(Figure_45)= -|![DIAMetAlyzer - pipeline for assay library generation and targeted analysis with statistical validation](/images/openms-user-tutorial/openswath/pipeline_overview.png)| -|:--:| -|Figure 45: DIAMetAlyzer - pipeline for assay library generation and targeted analysis with statistical validation. DDA data is used for candidate identification containing feature detection, adduct grouping and accurate mass search. Library construction uses fragment annotation via compositional fragmentation trees and decoy generation using a fragmentation tree re-rooting method to create a target-decoy assay library. This library is used in a second step to analyse metabolomics DIA data performing targeted extraction, scoring and statistical validation (FDR estimation).| - -(Figure_46)= -|![Assay library generation](/images/openms-user-tutorial/openswath/assay_library_generation.png)| -|:--:| -|Figure 46: Assay library generation. The results of the compound identification (feature, molecular formula, adduct), with the corresponding fragment spectra for the feature, are used to perform fragment annotation via SIRIUS, using the compositional fragmentation trees. Then, the n highest intensity transitions are extracted and stored in the assay library.| - -(Figure_47)= -|![Decoy generation](/images/openms-user-tutorial/openswath/decoy_generation.png)| -|:--:| -|Figure 47: Decoy generation. The compositional fragmentations trees from the step above are used to run the fragmentation tree re-rooting method from Passatutto, generating a compound specific decoy MS2 spectrum. Here, the n highest intensity decoy transitions are extracted and stored in the target-decoy assay library.| - -- **Candidate identification** - Feature detection, adduct grouping and accurate mass search are applied on DDA data. -- **Library construction** - The knowledge determined from the DDA data, about compound identification, its potential adduct and the corresponding fragment spectra are used to perform fragment annotation via compositional fragmentation trees sugin SIRIUS 4[^31]. Afterwards transitions, which are the reference of a precursor to its fragment ions are stored in a so-called assay library (Fig. 46). Assay libraries usually contain additional metadata (i.e. retention time, peak intensities). FDR estimation is based on the target-decoy approach[^32]. For the generation of the MS2 decoys, the fragmentation tree-based rerooting method by Passatutto ensure the consistency of decoy spectra (Fig.47)[^33]. The target-decoy assay library is then used to analyse the SWATH data. -- **Targeted extraction** - Chromatogram extraction and peak-group scoring. This step is performed using an algorithm based on OpenSWATH[^29] for metabolomics data. -- **Statistical validation** - FDR estimation uses the PyProphet algorithm[^30]. To prevent overfitting we chose the simpler linear model (LDA) for target-decoy discrimination in PyProphet, using MS1 and MS2 scoring with low correlated scores. - -### Prerequisites -Apart from the usual KNIME nodes, the workflow uses python scripting nodes. One basic requirement for the installation of python packages, in particular pyOpenMS, is a package manager for python. Using conda as an environment manger allows to specify a specific environment in the KNIME settings (**File**>**Preferences**>**KNIME**>**Python**). - -#### Windows - -We suggest do use a virtual environment for the Python 3 installation on windows. Here you can install miniconda and follow the further instructions. - -1. Create new `conda` python environment. - ```bash - conda create -n py39 python=3.9 - ``` -2. Activate `py39` environment. - ```bash - conda activate py39 - ``` -3. Install pip (see above). -4. On the command line: - ```bash - python -m pip install -U pip - python -m pip install -U numpy - python -m pip install -U pandas - - python -m pip install -U pyprophet - python -m pip install -U pyopenms - ``` - -#### macOS - -We suggest do use a virtual environment for the Python 3 installation on Mac. Here you can install miniconda and follow the further instructions. - -1. Create new `conda` python environment. - ```bash - conda create -n py39 python=3.9 - ``` -2. Activate py39 environment. - ```bash - conda activate py39 - ``` -3. On the Terminal: - ```bash - python -m pip install -U pip - python -m pip install -U numpy - python -m pip install -U pandas - - python -m pip install -U pyprophet - python -m pip install -U pyopenms - ``` - -#### Linux - -Use your package manager apt-get or yum, where possible. - -1. Install Pytohn 3.9 (Debian: python-dev, RedHat: python-devel) -2. Install NumPy (Debian/RedHat: python-numpy). -3. Install setuptools (Debian/RedHat: python-setuptools). -4. On the Terminal: - ```bash - python -m pip install -U pip - python -m pip install -U numpy - python -m pip install -U pandas - - python -m pip install -U pyprophet - python -m pip install -U pyopenms - ``` - -### Benchmark data - -For the assay library construction pesticide mixes (Agilent Technologies, Waldbronn, Germany) were measured individually in solvent (DDA). Benchmark DIA samples were prepared by spiking different commercially available pesticide mixes into human plasma metabolite extracts in a 1:4 dilution series, which covers 5 orders of magnitude. - -The example data can be found [here](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Data/DIAMetAlyzer/). - -### Example workflow - -Example workflow for the usage of the DIAMetAlyzer Pipeline in KNIME (see Fig. 48). Inputs are the SWATH-MS data in profile mode (.mzML), a path for saving the new target-decoy assay library, the SIRIUS 4.9.0 executable, the DDA data (.mzML), custom libraries and adducts for **AccurateMassSearch**, the min/max fragment mass-to-charge to be able to restrict the mass of the transitions and the path to the PyProphet executable. The DDA is used for feature detection, adduct grouping, accurate mass search and forwarded to the **AssayGeneratorMetabo**. Here, feature mapping is performed to collect MS2 spectra that belong to a feature. All information collected before (feautre, adduct, putative identification, MS2 spectra) are then internally forwarded to SIRIUS. SIRIUS is used for fragment annotation and decoy generation based on the fragmentation tree re-rooting approach. This information is then used to filter spectra/decoys based on their explained intensity (min. 85%). Afterwards internal feature linking is performed which is most important for untargeted experiments using a lot of DDA data to construct the library. The constructed target-decoy assay library is processed with the SWATH-MS data in OpenSWATH. The results are used by PyProphet for scoring and output a list of metabolites with their respective q-value and quantitative information. - -(Figure_48)= -|![Example workflow for the usage of the DIAMetAlyzer Pipeline in KNIME](/images/openms-user-tutorial/openswath/oswm_example_wf.png)| -|:--:| -|Figure 48: Example workflow for the usage of the DIAMetAlyzer Pipeline in KNIME.| - -### Run the workflow - -These steps need to be followed to run the workflow successfully: -- Add DDA Input Files (.mzML). -- Specify SIRIUS 4.9.0 executable. -- Specify library files (mapping, struct) for **AccurateMassSearch**. -- Add positive/negative adducts lists for **AccurateMassSearch**. -- Supply an output path for the SIRIUS workspace in the **AssayGeneratorMetabo**. -- Specify additional paths and variables, such as an output path for the target-decoy assay library and a path to the pyprophet installation as well as decoy fragment mz filter (min/max). -- Input DIA/SWATH files (.mzML). -- Specify output path in the output folders. - -You can now run the workflow. - -### Important parameters - -Please have a look at the most important parameters, which should be tweaked to fit your data. In general, OpenMS has a lot of room for parameter optimization to best fit your chromatography and instrumental settings. - -#### FeatureFinderMetabo - -|**parameter**|**explanation**| -|:------------|:--------------| -|*noise_threshold_int*|Intensity threshold below which peaks are regarded as noise.| -|*chrom_fwhm*|Expected chromatographic peak width (in seconds).| -|*mass_error_ppm*|Allowed mass deviation (in ppm).| - -#### MetaboliteAdductDecharger - -|**parameter**|**explanation**| -|:------------|:--------------| -|*mass_max_diff*|Maximum allowed mass tolerance per feature..| -|*potential_adducts*|Adducts used to explain mass differences - These should fit to the adduct list specified for AccurateMassSearch.| - -#### AccurateMassSearch - -|**parameter**|**explanation**| -|:------------|:--------------| -|*mass_error_value*|Tolerance allowed for accurate mass search.| -|*ionization_mode*|Positive or negative ionization mode.| - -#### AssayGeneratorMetabo - -|**parameter**|**explanation**| -|:------------|:--------------| -|*min_transitions*|Minimal number of transitions (3).| -|*max_transitions*|Maximal number of transitions (3).| -|**min_fragment_mz**|Minimal m/z of a fragment ion choosen as a transition| -|**max_fragment_mz**|Maximal m/z of a fragment ion choosen as a transition| -|*transitions_threshold*|Further transitions need at least x% of the maximum intensity.| -|**fragment_annotation_score_threshold**|Filters annotations based on the explained intensity of the peaks in a spectrum (0.8).| -|SIRIUS (internal):| -|*out_workspace_directory*|Output directory for SIRIUS workspace (Fragmentation Trees).| -|*filter_by_num_masstraces*|Features have to have at least x MassTraces. To use this parameter feature_only is neccessary.| -|*precursor_mass_tolerance*|Tolerance window for precursor selection (Feature selection in regard to the precursor).| -|*precursor_rt_tolerance*|Tolerance allowed for matching MS2 spectra depending on the feature size (should be around the FWHM of the chromatograms).| -|*profile*|Specify the used analysis profile (e.g. qtof).| -|*elements*|Allowed elements for assessing the putative sumformula (e.g. CHNOP[5]S[8]Cl[1]). Elements found in the isotopic pattern are added automatically, but can be specified nonetheless.| -|Feature linking (internal):| -|**ambiguity_resolution mz_tolerance**|M/z tolerance for the resolution of identification ambiguity over multiple files - Feature linking m/z tolerance.| -|**ambiguity_resolution rt_tolerance**|RT tolerance in seconds for the resolution of identification ambiguity over multiple files - Feature linking m/z tolerance.| -|**total_occurrence_filter**|Filter compound based on total occurrence in analysed samples.| - -In case of the **total_occurrence_filter** the value to chose depends on the analysis strategy used. In the instance you are using only identified compounds (**use_known_unknowns**= false) - it will filter based on identified features. This means that even if the feature -was detected in e.g. 50% of all samples it might be only identified correctly by accurate mass search in 20% of all samples. Using a **total_occurrence_filter** this specific feature would still be filtered out due to less identifications. - -#### OpenSWATH - -|**parameter**|**explanation**| -|:------------|:--------------| -|*rt_extraction_window*|Extract x seconds around this value.| -|*rt_normalization_factor*|Please use the range of your gradient e.g. 950 seconds.| - -If you are analysing a lot of big DIA mzML files ≈ 3-20GB per File, it makes sense to change how OpenSWATH processes the spectra. - -|**parameter**|**explanation**| -|:------------|:--------------| -|*readOptions*|Set cacheWorkingInMemory - will cache the files to disk -and read SWATH-by-SWATH into memory| -|*tempDirectory*|Set a directory, where cached mzMLs are stored (be -aware that his directory can be quite huge depending on the data).| - -In the workflow pyprophet is called after OpenSWATH, it merges the result files, which allows to get enough data for the model training. - -```bash -pyprophet merge --template path_to_target-decoy_assay_library.pqp --out merged.osw,→ ./*.osw -``` -Afterwards, the results are scored using the MS1 and MS2 levels and filter for metabolomics scores, which have a low correlation. - -```bash -pyprophet score --in merged.osw --out scored.osw --level ms1ms2 --ss_main_score,→ ”var_isotope_correlation_score” --ss_score_filter metabolomics -``` -Export the non filtered results: - -```bash -pyprophet export-compound --in scored.osw --out scored + ”_pyprophet_nofilter_ms1ms2.tsv” --max_rs_peakgroup_qvalue 1000.0 -``` - -Please see the workflow for actual parameter values used for the benchmarking dataset. - -The workflow can be used without any identification (remove AccurateMassSearch). -Here, all features (**known_unknowns**) are processed. The assay library is constructed based on the chemical composition elucidated via the fragment annotation (SIRIUS 4). -It is also possible to use identified and in addition unknown (non-identified) features, by using **AccurateMassSearch** in combination with the use_known_unknowns in the **AssayGeneratorMetabo**. - -## Untargeted metabolomics preprocessing - -The universal workflow for untargeted metabolomics always consists of feature detection in the individual MS sample files and their linkage to consensus features with common m/z and retention time values. In addition, there are optional steps such as adduct detection and annotation of features with associated MS2 spectra. This workflow prepares all the file necessary to do formula and structural annotations via `SiriusAdapter`. Furthermore it prepares all required files to run `GNPSExport`, which generates all files necessary to directly run [GNPS](https://gnps.ucsd.edu) Feature Based Molecular Networking (FBMN) and Ion Identity Molecular Networking (IIMN). - -(Figure_49)= -|![metabolomics preprocessing](/images/tutorials/metabolomics-preprocessing.png)| -|:--:| -|Figure 49: Metabolomics preprocessing steps| - -If you want to use the example data, download the files [sample1.mzML](/data/sample1.mzML) and [sample2.mzML](/data/sample2.mzML). - -For each mzML file do mass trace, elution peak and feature detection. -```shell -FeatureFinderMetabo -in sample1.mzML -out sample1.featureXML -algorithm:common:noise_threshold_int 10000 -algorithm:mtd:mass_error_ppm 10 -algorithm:ffm:remove_single_traces true -FeatureFinderMetabo -in sample2.mzML -out sample2.featureXML -algorithm:common:noise_threshold_int 10000 -algorithm:mtd:mass_error_ppm 10 -algorithm:ffm:remove_single_traces true -``` - -Align feature retention times based on the feature map with the highest number of features (reference map). -```shell -MapAlignerPoseClustering -in sample1.featureXML sample2.featureXML -out aligned_sample1.featureXML aligned_sample2.featureXML -trafo_out sample1.trafoXML sample2.trafoXML -algorithm:pairfinder:distance_MZ:max_difference 10.0 -algorithm:pairfinder:distance_MZ:unit ppm -``` - -Align mzML files aligment based on FeatureMap alignment (optional, only for GNPS). -```shell -MapRTTransformer -in sample1.mzML -out aligned_sample1.mzML -trafo_in sample1.trafoXML -MapRTTransformer -in sample2.mzML -out aligned_sample2.mzML -trafo_in sample2.trafoXML -``` - -Map MS2 spectra to features as PeptideIdentification objects (optional, only for GNPS). Requires an [empty idXML](/data/empty.idXML) file. -```shell -IDMapper -id empty.idXML -in aligned_sample1.featureXML -spectra:in aligned_sample1.mzML -out IDmapped_sample1.featureXML -IDMapper -id empty.idXML -in aligned_sample2.featureXML -spectra:in aligned_sample2.mzML -out IDmapped_sample2.featureXML -``` - -Detect adducts (optional, only for SIRIUS and GNPS Ion Identity -Molecular Networking). -```shell -MetaboliteAdductDecharger -in IDmapped_sample1.featureXML -out_fm adducts_sample1.featureXML -algorithm:MetaboliteFeatureDeconvolution:potential_adducts "H:+:0.6" "Na:+:0.1" "NH4:+:0.1" "H-1O-1:+:0.1" "H-3O-2:+:0.1" -MetaboliteAdductDecharger -in IDmapped_sample2.featureXML -out_fm adducts_sample2.featureXML -algorithm:MetaboliteFeatureDeconvolution:potential_adducts "H:+:0.6" "Na:+:0.1" "NH4:+:0.1" "H-1O-1:+:0.1" "H-3O-2:+:0.1" -``` - -Link features in a ConsensusMap. -```shell -FeatureLinkerUnlabeledKD -in adducts_sample1.featureXML adducts_sample2.featureXML -out Preprocessed.consensusXML -algorithm:link:rt_tol 30.0 -algorithm:link:mz_tol 10.0 -``` - -Export table of metabolic features as tsv file including meta values (e.g. best consensus adduct ion). -```shell -TextExporter -in Preprocessed.consensusXML -out Features.tsv -consensus:add_metavalues -``` - -You can recreate this workflow in KNIME. [Download the KNIME workflow here](/workflows/UntargetedMetabolomicsPreProcessing.knwf). The workflow should look like this: - -(Figure_50)= -|![metabolomics preprocessing workflow in KNIME](/images/tutorials/metabolomics-preprocessing-knime-workflow.png)| -|:--:| -|Figure 50: Metabolomics preprocessing workflow in KNIME| - - -## An introduction to pyOpenMS - -### Introduction - -pyOpenMS provides Python bindings for a large part of the OpenMS library for mass spectrometry based proteomics and metabolomics. It thus provides access to a featurerich, open-source algorithm library for mass-spectrometry based LC-MS analysis. These Python bindings allow raw access to the data-structures and algorithms implemented -in OpenMS, specifically those for file access (mzXML, mzML, TraML, mzIdentML among others), basic signal processing (smoothing, filtering, de-isotoping and peak-picking) and complex data analysis (including label-free, SILAC, iTRAQ and SWATH analysis tools). pyOpenMS is integrated into OpenMS starting from version 1.11. This tutorial is addressed to people already familiar with Python. If you are new to Python, we suggest to start with a [Python tutorial](https://en.wikibooks.org/wiki/Non-Programmer%27s_Tutorial_for_Python_3). - -### Installation - -One basic requirement for the installation of python packages, in particular pyOpenMS, is a package manager for python. We provide a package for [pip](https://pypi.python.org/pypi/pip). - -#### Windows - -1. Install [Python 3.9](http://www.python.org/download/). -2. Install pip (see above). -3. On the command line: - ```bash - python -m pip install -U pip - python -m pip install -U numpy - python -m pip install pyopenms - ``` - -#### macOS - -We suggest do use a virtual environment for the Python 3 installation on Mac. Here you can install miniconda and follow the further instructions. - -1. Create new `conda` python environment. - ```bash - conda create -n py37 python=3.9 anaconda - ``` -2. Activate `py37` environment. - ```bash - source activate py37 - ``` -3. On the Terminal: - ```bash - pip install -U pip - pip install -U numpy - pip install pyopenms - ``` - -#### Linux - -Use your package manager apt-get or yum, where possible. - -1. Install Python 3.9 (Debian: python-dev, RedHat: python-devel). -2. Install NumPy (Debian / RedHat: python-numpy). -3. Install setuptools (Debian / RedHat: python-setuptools). -4. On the Terminal: - ```bash - pip install pyopenms - ``` - -#### IDE with Anaconda integration - -If you do not have python installed or do not want to modify your native installation, another possibility is to use an IDE (integrated development environment) with Anaconda integration. Here, we recommend [`spyder`](https://www.spyder-ide.org/). It comes with Anaconda, which is a package and environment manager. Thus the IDE should be able to run a specific environment independent of your systems python installation. -Please execute the installer for your respective platform located in the respective directory for your platform and follow the installation instructions. -After installation, the ANACONDA Navigator (Anaconda 3) should be available. Please start the application. To install pyopenms please choose the button ”Environments” and click the play symbol of the base environment and ”Open Terminal”. -Update `pip` and install `pyopenms` (MacOS, Linux): - -```bash -pip install -U pip -pip install -U numpy -pip install -U pyopenms -``` - -Update `pip` and install `pyopenms`: - -```bash -python -m pip install -U pip -python -m pip install -U numpy -python -m pip install -U pyopenms -``` - -Install a local available package: - -```bash -pip install numpy-1.20.0-cp37*.whl -pip install pyopenms-2.7.0-cp37*.whl -or (in case of windows) - -python -m pip install -U numpy-1.20.0-cp37*.whl -python -m pip install -U pyopenms-2.7.0-cp37*.whl -``` -The local available packages can be found in the directory corresponding to your operating system. Please use the absolute path to the packages for the installation. - -Now launch ”Spyder” (python IDE) in the home menu. - -### Build instructions - -Instructions on how to build pyOpenMS can be found [online](https://pyopenms.readthedocs.io/en/latest/community/build_from_source.html). - -### Scripting with pyOpenMS - -A big advantage of pyOpenMS are its scripting capabilities (beyond its application in tool development). Most of the OpenMS datastructure can be accessed using [python](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/index.html). Here we would like to give some examples on how pyOpenMS can be used for simple scripting task, such as peptide mass calculation and peptide/protein digestion as well as isotope distribution calculation. - -Calculation of the monisotopic and average mass of a peptide sequence: - -```python -from pyopenms import * - -seq = AASequence.fromString("DFPIANGER") - - -mono_mass = seq.getMonoWeight(Residue.ResidueType.Full, 0) - -average_mass = seq.getAverageWeight(Residue.ResidueType.Full, 0) - - -print("The masses of the peptide sequence " + seq.toString().decode('utf-8') + " are:") - -print("mono: " + str(mono_mass)) -print("average: "+ str(average_mass)) -``` - -Enzymatic digest of a peptide/protein sequence: - -```python -enzyme = "Trypsin" -to_digest = AASequence.fromString("MKWVTFISLLLLFSSAYSRGVFRRDTHKSEIAHRFKDLGE") - -after_digest = [] - -EnzymaticDigest = EnzymaticDigestionLogModel() - -EnzymaticDigest.setEnzyme(enzyme) -EnzymaticDigest.digest(to_digest, after_digest) - - -print("The peptide " + to_digest.toString().decode('utf-8') + " was digested using " + str(EnzymaticDigest.getEnzymeName().decode('utf-8')) + " to:") - - -for element in after_digest: - print(element.toString().decode('utf-8')) -``` - -Use empirical formula to calculate the isotope distribution: - -```python -from pyopenms import * - -methanol = EmpiricalFormula("CH3OH") -water = EmpiricalFormula("H2O") - -wm = EmpiricalFormula(water.toString().decode('utf-8') + methanol.toString().decode('utf-8')) - -print(wm.toString().decode('utf-8')) -print(wm.getElementalComposition()) - - -isotopes = wm.getIsotopeDistribution( CoarseIsotopePatternGenerator(3) ) - -for iso in isotopes.getContainer(): - print (iso.getMZ(), ":", iso.getIntensity()) -``` - -For further examples and the pyOpenMS data structures please see the following [link](https://pyopenms.readthedocs.io/en/latest/user_guide/ms_data.html). - -### Tool development with pyOpenMS - -Scripting is one side of pyOpenMS, the other is the ability to create Tools using the C++ OpenMS library in the background. In the following section we will create a ”ProteinDigestor” pyOpenMS Tool. It should be able to read in a fasta file. Digest the proteins with a specific enzyme (e.g. Trypsin) and export an idXML output file. Please see {path}`ExampleData,pyopenms` for code snippets. - -```bash -usage: ProteinDigestor.py [-h] [-in INFILE] [-out OUTFILE] [-enzyme ENZYME] - - [-min_length MIN_LENGTH] [-max_length MAX_LENGTH] - - [-missed_cleavages MISSED_CLEAVAGES] - -ProteinDigestor −− In silico digestion of proteins. - - -optional arguments: - -h, --help show this help message and exit - - -in INFILE An input file containing amino acid sequences [fasta] - - -out OUTFILE Output digested sequences in idXML format [idXML] - - -enzyme ENZYME Enzyme used for digestion - -min_length MIN_LENGTH Minimum length of peptide - - -max_length MAX_LENGTH Maximum length of peptide - -missed_cleavages MISSED_CLEAVAGES The number of allowed missed cleavages -``` - -#### Basics -First, your tool needs to be able to read parameters from the command line and provide a main routine. Here standard Python can be used (no pyOpenMS is required so far). - -```python -#!/usr/bin/env python -import sys - -def main(options): - - # test parameter handling - - print(options.infile, options.outfile, options.enzyme, options.min_length, options.max_length, options.missed_cleavages) - - -def handle_args(): - import argparse - - usage = "" - - usage += "\nProteinDigestor −− In silico digestion of proteins." - - - parser = argparse.ArgumentParser(description = usage) - - parser.add_argument('-in', dest='infile', help='An input file containing amino acid sequences [fasta]') - - parser.add_argument('-out', dest='outfile', help='Output digested sequences in idXML format [idXML]') - - parser.add_argument('-enzyme', dest='enzyme', help='Enzyme used for digestion') - - parser.add_argument('-min_length', type=int, dest='min_length', help ='Minimum length of peptide') - - parser.add_argument('-max_length', type=int, dest='max_length', help='Maximum length of peptide') - - parser.add_argument('-missed_cleavages', type=int, dest='missed_cleavages', help='The number of allowed missed cleavages') - - - args = parser.parse_args(sys.argv[1:]) - return args - -if __name__ == '__main__': - - options = handle_args() - main(options) -``` -Open the Anaconda Terminal and change into the {path}`ExampleData,pyopenms` directory. Execute the example script. - -```bash -python ProteinDigestor_argparse.py -h -python ProteinDigestor_argparse.py -in mini_example.fasta -out mini_example_out.idXML -enzyme Trypsin -min_length 6 -max_length 40 -missed_cleavages 1 -``` - -The parameters are being read from the command line by the function `handle_args()` and given to the `main(`) function of the script, which prints the different variables. - -OpenMS has a `ProteaseDB` class containing a list of enzymes which can be used for digestion of proteins. You can add this to the `argparse` code to be able to see the usable enzymes. From this point onward, pyOpenMS is required. - -```python -# from here pyopenms is needed -# get available enzymes from ProteaseDB - -all_enzymes = [] -p_db=ProteaseDB().getAllNames(all_enzymes) - - -# concatenate them to the enzyme argument. -parser.add_argument('-enzyme', dest='enzyme', help='Enzymes which can be used for digestion: '+ ', '.join(map(bytes.decode, all_enzymes))) -``` - -#### Loading data structures with pyOpenMS - -We already scripted enzymatic digestion with the `AASequence` and `EnzymaticDigest` (see above). To make this even easier, we can use an existing class in OpenMS, called `ProteaseDigestion`. - -```python - # Use the ProteaseDigestion class - # set the enzyme used for digestion and the number of missed cleavages - digestor = ProteaseDigestion() - digestor.setEnzyme(options.enzyme) - digestor.setMissedCleavages(options.missed_cleavages) - # call the ProteaseDigestion::digest function - # which will return the number of discarded digestions products - # and fill the current_digest list with digested peptide sequences - digestor.digest(aaseq.fromString(fe.sequence), current_digest, options.min_length, options.max_length) -``` - -The next step is to use FASTAFile class to read the fasta input: - -```python - # construct a FASTAFile Object and read the input file - ff = FASTAFile() - - ff.readStart(options.infile) - - # construct and FASTAEntry Object - fe = FASTAEntry() - - - # loop over the entry in the fasta while using while - while(ff.readNext(fe)): -``` - -The output idXML needs the information about protein and peptide level, which can be saved in the `ProteinIdentification` and `PeptideIdentification` classes. - -```python -idxml = IdXMLFile() -idxml.store(options.outfile, protein_identifications, peptide_identifications) -``` - -This is the part of the program which unifies the snippets provided above. Please have a closer look how the protein and peptide datastructure is incorporated in the program. - -```python -def main(options): - # read fasta file - ff = FASTAFile() - ff.readStart(options.infile) - - fe = FASTAEntry() - - # use ProteaseDigestion class - digestor = ProteaseDigestion() - - digestor.setEnzyme(options.enzyme) - digestor.setMissedCleavages(options.missed_cleavages) - - - # protein and peptide datastructure - protein_identifications = [] - - peptide_identifications = [] - protein_identification = ProteinIdentification() - - protein_identifications.append(protein_identification) - temp_pe = PeptideEvidence() - - - # number of dropped peptides due to length restriction - dropped_by_length = 0 - - while(ff.readNext(fe)): - - # construct ProteinHit and fill it with sequence information - temp_protein_hit = ProteinHit() - - temp_protein_hit.setSequence(fe.sequence) - temp_protein_hit.setAccession(fe.identifier) - - - # save the ProteinHit in a ProteinIdentification Object - - protein_identification.insertHit(temp_protein_hit) - - - # construct a PeptideHit and save the ProteinEvidence (Mapping) for the specific - # current protein - - temp_peptide_hit = PeptideHit() - temp_pe.setProteinAccession(fe.identifier); - - temp_peptide_hit.setPeptideEvidences([temp_pe]) - - # digestion - - current_digest = [] - aaseq = AASequence() - if (options.enzyme == "none"): - - current_digest.append(aaseq.fromString(fe.sequence)) - else: - - dropped_by_length += digestor.digest(aaseq.fromString(fe.sequence), current_digest, options.min_length, options.max_length) - - - for seq in current_digest: - # fill the PeptideHit and PeptideIdentification datastructure - - peptide_identification = PeptideIdentification() - temp_peptide_hit.setSequence(seq) - - peptide_identification.insertHit(temp_peptide_hit) - - peptide_identifications.append(peptide_identification) - - - print(str(dropped_by_length) + " peptides have been dropped due to the length restriction.") - - idxml = IdXMLFile() - idxml.store(options.outfile, protein_identifications, peptide_identifications) -``` -#### Putting things together - -The paramter input and the functions can be used to construct the program we are looking for. If you are struggling please have a look in the example data section `ProteinDigestor.py`. - -Now you can run your tool in the Anaconda Terminal {path}`ExampleData,pyopenms`. - -```bash -python ProteinDigestor.py -in mini_example.fasta -out mini_example_out.idXML -enzyme Trypsin -min_length 6 -max_length 40 -missed_cleavages 1 -``` - -## Quality control - -### Introduction - -In this chapter, we will build on an existing workflow with OpenMS / KNIME to add some quality control (QC). We will utilize the qcML tools in OpenMS to create a file with which we can collect different measures of quality to the mass spectrometry runs themselves and the applied analysis. The file also serves the means of visually reporting on the collected quality measures and later storage along the other analysis result files. We will, step-by-step, extend the label-free quantitation workflow from section 3 with QC functions and thereby enrich each time the report given by the qcML file. But first, to make sure you get the most of this tutorial section, a little primer on how we handle QC on the technical level. - -#### QC metrics and qcML - -To assert the quality of a measurement or analysis we use quality metrics. Metrics are describing a certain aspect of the measurement or analysis and can be anything from a single value, over a range of values to an image plot or other summary. Thus, qcML metric representation is divided into QC parameters (QP) and QC attachments (QA) to be able to represent all sorts of metrics on a technical level. -A QP may (or may not) have a value which would equal a metric describable with a single value. If the metric is more complex and needs more than just a single value, the QP does not require the single value but rather depends on an attachment of values (QA) for full meaning. Such a QA holds the plot or the range of values in a table-like form. Like this, we can describe any metric by a QP and an optional QA. -To assure a consensual meaning of the quality parameters and attachments, we created a controlled vocabulary (CV). Each entry in the CV describes a metric or part/extension thereof. We embed each parameter or attachment with one of these and by doing so, connect a meaning to the QP/QA. Like this, we later know exactly what we collected and the programs can find and connect the right dots for rendering the report or calculating new metrics automatically. You can find the constantly growing controlled vocabulary [here](https://github.com/qcML/qcML-development/blob/master/cv/qc-cv.obo). -Finally, in a qcml file, we split the metrics on a per mass-spectrometry-run base or a set of mass-spectrometry-runs respectively. Each run or set will contain its QP/QA we calculate for it, describing their quality. - -### Building a qcML file per run - -As a start, we will build a basic qcML file for each mzML file in the label-free analysis. We are already creating the two necessary analysis files to build a basic qcML file upon each mzML file, a feature file and an identification file. We use the **QCCalculator** node from **Community** > **OpenMS** > **Utilities** where also all other QC* nodes will be found. The **QCCalculator** will create a very basic qcML file in which it will store collected and calculated quality data. - -- Copy your label-fee quantitation workflow into a new lfq-qc workflow and open it. -- Place the **QCCalculator** node after the `IDMapper` node. Being inside the **ZipLoop**, it will execute for each of the three mzML files the **Input** node. -- Connect the first **QCCalculator** port to the first `ZipLoopStart` outlet port, which will carry the individual mzML files. -- Connect the last’s ID outlet port (`IDFilter` or the ID metanode) to the second **QCCalculator** port for the identification file. -- Finally, connect the `IDMapper` outlet to the third **QCCalculator** port for the feature file. - -The created qcML files will not have much to show for, basic as they are. So we will extend them with some basic plots. - -- First, we will add an 2D overview image of the given mass spectrometry run as you may know it from TOPPView. Add the **ImageCreator** node from **Community Nodes** > **OpenMS** > **Utilities**. Change the width and heigth parameters to 640x640 as we don’t want it to be too big. Connect it to the first `ZipLoopStart` outlet port, so it will create an image file of the mzML’s contained run. -- Now we have to embed this file into the qcML file, and attach it to the right **QualityParameter**. For this, place a **QCEmbedder** node behind the **ImageCreator** and connect that to its third inlet port. Connect its first inlet port to the outlet of the **QCCalculator** node to pass on the qcML file. Now change the parameter cv_acc to QC:0000055 which designates the attached image to be of type QC:0000055 - MS experiment heatmap. Finally, change the parameter qp_att_acc to QC:0000004, to attach the image to the QualityParameter QC:0000004 - MS acquisition result details. -- For a reference of which CVs are already defined for qcML, have a look at the following [link](https://github.com/qcML/qcML-development/blob/master/cv/qc-cv.obo). - -There are two other basic plots which we almost always might want to look at before judging the quality of a mass spectrometry run and its identifications: the **total ion current** (TIC) and the **PSM mass error** (Mass accuracy), which we have available as pre-packaged QC metanodes. - -
-

**Task**

-Import the workflow from {path}`Workflows,Quality Control,QC Metanodes.zip` by navigating to **File** > **Import KNIME Workflow...** -
- -- Copy the **Mass accuracy** metanode into the workflow behind the **QCEmbedder** node and connect it. The qcML will be passed on and the Mass accuracy plots added. The information needed was already collected by the **QCCalculator**. -- Do the same with the **TIC** metanode so that your qcML file will get passed on and enriched on each step. - -R Dependencies: This section requires that the R packages `ggplot2` and scales are both installed. This is the same procedure as in this section. In case that you use an R installation where one or both of them are not yet installed, open the **R Snippet** nodes inside the metanodes you just used (double-click). Edit the script in the *R Script* text editor from: - -```r -#install.packages("ggplot2") -#install.packages("scales") -``` -to -```r -install.packages("ggplot2") -install.packages("scales") -``` -Press **Eval script** to execute the script. - -(Figure_51)= -|![Basic QC setup within a LFQ workflow.](/images/openms-user-tutorial/quality-control/qc_basic.png)| -|:--:| -|Figure 51: Basic QC setup within a LFQ workflow.| - -```{note} -To have a peek into what our qcML now looks like for one of the **ZipLoop** iterations, we can add an `Output Folder` node from **Community Nodes** > **GenericKnimeNodes** > **IO** and set its destination parameter to somewhere we want to find our intermediate qcML files in, for example **tmp** > **qcxlfq**. If we now connect the last metanode with the Output Folder and restart the workflow, we can start inspecting the qcML files. -``` - -
-

**Task**

-Find your first created qcML file and open it with the browser (not IE), and the contained QC parameters will be rendered for you. -
- -### Adding brand new QC metrics - -We can also add brand new QC metrics to our qcML files. Remember the **Histogram** you added inside the **ZipLoop** during the label-free quantitation section? Let’s imagine for a moment this was a brand new and utterly important metric and plot for the assessment of your analyses quality. There is an easy way to integrate such new metrics into your qcMLs. Though the **Histogram** node cannot pass its plot to an image, we can do so with a **R View (table)**. - -- Add an **R View (table)** next to the **IDTextReader** node and connect them. -- Edit the **R View (table)** by adding the *R Script* according to this: - -```r - #install.packages("ggplot2") -library("ggplot2") -ggplot(knime.in, aes(x=peptide_charge)) + - - geom_histogram(binwidth=1, origin =-0.5) + - scale_x_discrete() + - - ggtitle("Identified peptides charge histogram") + - ylab("Count") -``` - -- This will create a plot like the **Histogram** node on *peptide_charge* and pass it on as an *image*. -- Now add and connect a **Image2FilePort** node from **Community Nodes** > **GenericKnimeNodes** > **Flow** to the **R View (table)**. -- We can now use a **QCEmbetter** node like before to add our new metric plot into the qcML. -- After looking for an appropriate target from the following [link](https://github.com/qcML/qcML-development/blob/master/cv/qc-cv.obo), we found that we can attach our plot to the MS *identification result details* by setting the parameter `qp_att_acc` to `QC:0000025`, as we are plotting the charge histogram of our identified peptides. -- To have the plot later displayed properly, we assign it the parameter `cv_acc` of `QC:0000051`, a generic plot. Also we made sure in the *R Script*, that our plot carries a caption so that we know which is which, if we had more than one new plot. -- Now we redirect the **QCEmbedders** output to the `Output Folder` from before and can have a look at how our qcML is coming along after restarting the workflow. - -(Figure_52)= -|![QC with new metric](/images/openms-user-tutorial/quality-control/qc_extra.png)| -|:--:| -|Figure 52: QC with new metric.| - -### Set QC metrics - -Besides monitoring the quality of each individual mass spectrometry run analysis, another capability of QC with OpenMS and qcML is to monitor the complete set. The easiest control is to compare mass spectrometry runs which should be similar, e.g. technical replicates, to spot any aberrations in the set. -For this, we will first collect all created qcML files, merge them together and use the qcML onboard set QC properties to detect any outliers. - -- Connect the **QCEmbedders** output from last section to the **ZipLoopEnds** second input port. -- The corresponding output port will collect all qcML files from each **ZipLoop** iteration and pass them on as a list of files. -- Now we add a **QCMerger** node after the `ZipLoopEnd` and feed it that list of qcML files. In addition, we set its parameter `setname` to give our newly created set a name - say `spikein_replicates`. -- To inspect all the QCs next to each other in that created qcML file, we have to add a new `Output Folder` to which we can connect the **QCMerger** output. - -When inspecting the set-qcML file in a browser, we will be presented another overview. After the set content listing, the basic QC parameters (like number of identifications) are each displayed in a graph. Each set member (or run) has its own section on the x-axis and each run is connected with that graph via a link in the mouseover on one of the QC parameter values. - -(Figure_53)= -|![QC set creation from ZipLoop](/images/openms-user-tutorial/quality-control/qc_set.png)| -|:--:| -|Figure 53: QC set creation from ZipLoop.| - -
-

**Task**

-For ideas on new QC metrics and parameters, as you add them in your qcML files as generic parameters, feel free to [contact us](/quick-reference/contact-us.md), so we can include them in the CV. -
- -## Advanced topic: R integration - -KNIME provides a large number of nodes for a wide range of statistical analysis, machine learning, data processing, and -visualization. Still, more recent statistical analysis methods, specialized visualizations or cutting edge algorithms -may not be covered in KNIME. In order to expand its capabilities beyond the readily available nodes, external scripting -languages can be integrated. In this tutorial, we primarily use scripts of the powerful statistical computing language R. -Note that this part is considered advanced and might be difficult to follow if you are not familiar with R. In this case -you might skip this part. - -**R View (Table)** allows to seamlessly include R scripts into KNIME. We will -demonstrate on a minimal example how such a script is integrated. - -
-

**Task**

-

-First we need some example data in KNIME, which we will generate using the **Data Generator** node (**IO** > **Other** > **Data Generator**). -You can keep the default settings and execute the node. The table contains four columns, each containing random coordinates and one column -containing a cluster number (Cluster_0 to Cluster_3). Now place a **R View (Table)** node into the workflow and connect -the upper output port of the **Data Generator** node to the input of the **R View (Table)** node. Right-click and -configure the node. If you get an error message like `Execute failed: R_HOME does not contain a folder with name ’bin’.` -or `Execution failed: R Home is invalid.`: please change the R settings in the preferences. To do so open **File** > -**Preferences** > **KNIME** > **R** and enter the path to your R installation (the folder that contains the bin -directory. e.g., {path}`C:,Program Files,R,R-3.4.3`). -

-

-If you get an error message like: ”Execute failed: Could not find Rserve package. Please install it in your R -installation by running ”install.packages(’Rserve’)”.” You may need to run your R binary as administrator (In windows -explorer: right-click ”Run as administrator”) and enter install.packages(’Rserve’) to install the package. -

-

-If R is correctly recognized we can start writing an R script. Consider that we are interested in plotting the first and -second coordinates and color them according to their cluster number. In R this can be done in a single line. In the -**R view (Table)** text editor, enter the following code: -```r -plot(x=knime.in$Universe_0_0, y=knime.in$Universe_0_1, main="Plotting column Universe_0_0 vs. Universe_0_1", col=knime.in$"Cluster Membership") -``` -

-

-**Explanation:** The table provided as input to the **R View (Table)** node is available as R **data.frame** with name -`knime.in`. Columns (also listed on the left side of the R View window) can be accessed in the usual R way by first -specifying the `data.frame` name and then the column name (e.g., `knime.in$Universe_0_0`). `plot` is the plotting function -we use to generate the image. We tell it to use the data in column `Universe_0_0` of the dataframe object **knime.in** -(denoted as `knime.in$Universe_0_0`) as x-coordinate and the other column `knime.in$Universe_0_1` as y-coordinate in the -plot. `main` is simply the main title of the plot and `col` the column that is used to determine the color (in this case -it is the `Cluster Membership` column). -

-

-Now press the Eval script and Show plot buttons. -

-
- -```{note} -Note that we needed to put some extra quotes around `Cluster Membership`. If we omit those, R would interpret the column -name only up to the first space `(knime.in$Cluster)` which is not present in the table and leads to an error. Quotes are -regularly needed if column names contain spaces, tabs or other special characters like $ itself. -``` - -## Troubleshooting guide - -This section will show you where you can turn to when you encounter any problems with this tutorial or with our nodes in general. Please see the [FAQ](/quick-reference/contributor-faq.md) first. If your problem is not listed or the proposed solution does not work, feel free to leave us a message at the means of support that you see most fit. If that is the case, please provide us with as much information as you can. In an ideal case, that would be: - -- Your operating system and its version (e.g. Windows 8, Ubuntu 14.04). -- Your KNIME version (e.g. KNIME 3.1.2 full, KNIME 3.1.1 core). -- If not full: Which update site did you use for the OpenMS plugin? Trunk (nightly-builds) or Stable? -- Your OpenMS plugin version found under **Help** > **Install New Software** > **What is already installed?** -- Other installations of OpenMS on your computer (e.g. from the independent OpenMS installer, another KNIME instance etc.) -- The log of the error in KNIME and the standard output of the tool (see FAQ: How to debug). -- Your description of what you tried to do and experienced instead. - -### FAQ - -#### How to debug KNIME and/or the OpenMS nodes? - -- **KNIME**: Start with the normal log on the bottom right of KNIME. In general all warnings and errors will be listed there. If the output is not helpful enough, try to set the logging verbosity to the highest (DEBUG) under **Preferences** > **KNIME** > **Log file log level**. -- **OpenMS nodes**: The first step should also be the log of KNIME. Additionally, you can view the output and the errors of our tools by right-clicking on the node and selecting **View: NODENAME Std Output?error**. This shows you the output of the OpenMS executable that was called by that node. For advanced users, you can try to execute the underlying executable in your `KNIME/plugins/de.openms.platform.arch.version/payload/bin` folder, to see if the error is reproducible outside of KNIME. -You can look up temporary files that are created by OpenMS nodes not connected to an Output or Viewer Node by right- clicking on a node and selecting the corresponding output view for the output you want to have a look at. The output views are located on the bottom of the menu that shows up after right-clicking. Their icon is a magnifying glass on top of a data table. The names of the output views in that menu may vary from node to node (usually a combination of ”file”,”out”,”output” and optionally its possible extensions). For example for the File Importer node you can open the information on the output files by clicking on ”loaded file”. In any case, a hierarchy of file descriptions will show up. If there are multiple files on that port they will be numbered (usually beginning from 0). Expand the information for the file you want to see and copy its URI (you might need to erase the ”file:” prefix). Now open it with an editor of your choice. Be aware that temporary files are subject to deletion and are usually only stored as long as they are actually needed. There is also a Debug mode for the GKN nodes that keeps temporary files that can be activated under **Preferences** > **KNIME** > **Generic KNIME Nodes** > **Debug mode**. For the single nodes you can also increase the debug level in the configuration dialog under the advanced parameters. You can also specify a log file there, to save the log output of a specific node on your file system. - -#### General - -**Q:** Can I add my own modifications to the Unimod.xml? - -**A:** Unfortunately not very easy. This is an open issue since the selections are hard-coded during creation of the tools. We included 10 places for dummy modifications that can be entered in our Unimod.xml and selected in KNIME. - -**Q:** I have problem XYZ but it also occurs with other nodes or generally in the KNIME environment/GUI, what should I do? - -**A:** This sounds like a general KNIME bug and we advise to search help directly at the KNIME developers. They also provide a [FAQ](https://www.knime.com/faq) and a [forum](https://forum.knime.com). - -**Q:** After exporting and reading in results into a KNIME table (e.g. with a MzTabExporter and MzTabReader combination) numeric values get rounded (e.g. from scientific notation 4.5e-10 to zero) or are in a different representation than in the underlying exported file! - -**A:** Please try a different table column renderer in KNIME. Open the table in question, right-click on the header of an affected column and select another Available Renderer by hovering and finally left-clicking. - -**Q:** I have checked all the configurations but KNIME complains that it can not find certain output Files (FileStoreObjects). - -**A:** Sometimes KNIME/GKN has hiccups with multiple nodes with a same name, executed at the same time in the same loop. We have seen that a simple save and restart of KNIME usually solves the problem. - -#### Platform-specific problems - -##### Linux - -**Q:** Whenever I try to execute an OpenMS node I get an error similar to these: - -```bash -/usr/lib/x86_64-linux-gnu/libgomp.so.1: version `GOMP_4.0' not found -/usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found -``` -**A:** We currently build the binaries shipped in the OpenMS KNIME plugin with gcc 4.8. We will try to extend our support for older compilers. Until then you either need to upgrade your gcc compiler or at least the library that the tool complained about or you need to build the binaries yourself (see OpenMS documentation) and replace them in your KNIME binary folder (`YOURKNIMEFOLDER/plugins/de.openms.platform.architecture.version/payload/bin`) - -**Q:** Why is my configuration dialog closing right away when I double-click or try to configure it? Or why is my GUI responding so slow? - -**A:** If you have any problems with the KNIME GUI or the opening of dialogues under Linux you might be affected by a GTK bug. See the KNIME forum (e.g. [here](https://forum.knime.com/t/ubuntu-16-04-slow-performance/4345) or [here](https://forum.knime.com/t/knime-3-0-0-crashes-after-splash-screen/8370)) for a discussion and a possible solution. In short: set environment variable by calling `export SWT_GTK3=0` or edit `knime.ini` to make Eclipse use GTK2 by adding the following two lines: -```xml -–launcher.GTK_version -2 -``` -##### macOS - -**Q:** I have problems installing RServe in my local R installation for the R KNIME Extension. - -**A:** If you encounter linker errors while running `install.packages(”Rserve”)` when using an R installation from homebrew, make sure gettext is installed via homebrew and you pass flags to its lib directory. - -**Q:** Although Ctrl + Left-click TOPPAS.app or TOPPView.app and accept the risk of a downloaded application, the icon only shortly blinks and nothing happens. - -**A:** It seems like your OS is not able to remove the quarantine flag. If you trust us, please remove it yourself by typing the following command in your Terminal.app: - -```bash - xattr -r -d {{ 'com.apple.quarantine /Applications/OpenMS-{0}'.format(version) }} -``` -##### Windows - -**Q:** KNIME has problems getting the requirements for some of the OpenMS nodes on Windows, what can I do? - -**A:** Get the prerequisites installer [here](https://abibuilder.cs.uni-tuebingen.de/archive/openms/OpenMSInstaller/PrerequisitesInstaller/) or install .NET3.5, .NET4 and VCRedist10.0 and 12.0 yourself. - -#### Nodes - -**Q:** Why is my XTandemAdapter printing empty or VERY few results, although I did not use an e-value cutoff? - -**A:** Due to a bug in OpenMS 2.0.1, the XTandemAdapter requires a default parameter file. Give it the default configuration in `YOURKNIMEFOLDER/plugins/de.openms.platform.architecture.version/payload/share/CHEMISTRY/XTandemdefaultinput.xml` as a third input file. This should be resolved in newer versions though, such that it automatically uses this file if the optional inputs is empty. This should be solved in newer versions. - -**Q:** Do MSGFPlusAdapter, LuciphorAdapter or SiriusAdapter generally behave different/unexpected? - -**A:** These are Java processes that are started underneath. For example they can not be killed during cancellation of the node. This should not affect its performance, however. Make sure you set the Java memory parameter in these nodes to a reasonable value. Also MSGFPlus is creating several auxiliary files and accesses them during execution. Some users therefore experienced problems when executing several instances at the same time. - -### Sources of support - -If your questions could not be answered by the FAQ, please feel free to turn to our developers via one of the following means: - -- File an issue on [GitHub](https://github.com/OpenMS/OpenMS/issues) -- Write to the [Mailing List](https://sourceforge.net/projects/open-ms/lists/open-ms-general) -- Open a thread on the KNIME Community Contributions [forum](https://forum.knime.com/) for OpenMS - -## References - -[^1]: OpenMS, OpenMS home page [online]. - -[^2]: M. Sturm, A. Bertsch, C. Gröpl, A. Hildebrandt, R. Hussong, E. Lange, N. Pfeifer, -O. Schulz-Trieglaff, A. Zerck, K. Reinert, and O. Kohlbacher, OpenMS - an opensource software framework for mass spectrometry., BMC bioinformatics 9(1) -(2008), doi:10.1186/1471-2105-9-163. 7, 83 - -[^3]: H. L. Röst, T. Sachsenberg, S. Aiche, C. Bielow, H. Weisser, F. Aicheler, S. Andreotti, -H.-C. Ehrlich, P. Gutenbrunner, E. Kenar, et al., OpenMS: a flexible open-source -software platform for mass spectrometry data analysis, Nature Methods 13(9), -741–748 (2016). 7 - -[^4]: O. Kohlbacher, K. Reinert, C. Gröpl, E. Lange, N. Pfeifer, O. Schulz-Trieglaff, and -M. Sturm, TOPP–the OpenMS proteomics pipeline., Bioinformatics 23(2) (Jan. -2007). 7, 83 - -[^5]: M. R. Berthold, N. Cebron, F. Dill, T. R. Gabriel, T. Kötter, T. Meinl, P. Ohl, C. Sieb, K. Thiel, and B. Wiswedel, KNIME: The Konstanz Information Miner, in Studies in Classification, Data Analysis, and Knowledge Organization (GfKL 2007), Springer, 2007. - -[^6]: M. Sturm and O. Kohlbacher, TOPPView: An Open-Source Viewer for Mass Spectrometry Data, Journal of proteome research 8(7), 3760–3763 (July 2009), doi:10.1021/pr900171m. 7 - -[^7]: RDKit: Open-source cheminformatics, http://www.rdkit.org, [Online; accessed -31-August-2018]. 25 - -[^8]: C. Steinbeck, Y. Han, S. Kuhn, O. Horlacher, E. Luttmann, and E. Willighagen, The -Chemistry Development Kit (CDK): An Open-Source Java Library for Chemo- and -Bioinformatics, Journal of Chemical Information and Computer Sciences 43(2), -493–500 (2003), PMID: 12653513, doi:10.1021/ci025584y. 25 - -[^9]: L. Y. Geer, S. P. Markey, J. A. Kowalak, L. Wagner, M. Xu, D. M. Maynard, X. Yang, -W. Shi, and S. H. Bryant, Open mass spectrometry search algorithm, Journal of -Proteome Research 3(5), 958–964 (2004). 30 - -[^10]: A. Chawade, M. Sandin, J. Teleman, J. Malmström, and F. Levander, Data Processing Has Major Impact on the Outcome of Quantitative Label-Free LC-MS Analysis, Journal of Proteome Research 14(2), 676–687 (2015), PMID: 25407311, -arXiv:http://dx.doi.org/10.1021/pr500665j, doi:10.1021/pr500665j. 30 - -[^11]: A. Chawade, M. Sandin, J. Teleman, J. Malmström, and F. Levander, Data Processing Has Major Impact on the Outcome of Quantitative Label-Free LC-MS Analysis, Journal of Proteome Research 14(2), 676–687 (2015), PMID: 25407311, arXiv:http://dx.doi.org/10.1021/pr500665j, doi:10.1021/pr500665j. 30 - -[^12]: M. Choi, Z. F. Eren-Dogu, C. Colangelo, J. Cottrell, M. R. Hoopmann, E. A. Kapp, -S. Kim, H. Lam, T. A. Neubert, M. Palmblad, B. S. Phinney, S. T. Weintraub, B. MacLean, and O. Vitek, ABRF Proteome Informatics Research Group (iPRG) -2015 Study: Detection of Differentially Abundant Proteins in Label-Free Quantitative LC-MS/MS Experiments, J. Proteome Res. 16(2), 945–957 (2017), doi: 10.1021/acs.jproteome.6b00881. 40 - -[^13]: T. Huang, M. Choi, S. Hao, and O. Vitek, MSstatsTMT: Protein Significance Analysis in shotgun mass spectrometry-based proteomic experiments with tandem -mass tag (TMT) labeling., (2020), doi:10.18129/B9.bioc.MSstatsTMT. 55 - -[^14]: D. S. Wishart, D. Tzur, C. Knox, et al., HMDB: the Human Metabolome Database, -Nucleic Acids Res 35(Database issue), D521–6 (Jan 2007), doi:10.1093/nar/gkl923. 69 - -[^15]: D. S. Wishart, C. Knox, A. C. Guo, et al., HMDB: a knowledgebase for the human -metabolome, Nucleic Acids Res 37(Database issue), D603–10 (Jan 2009), doi: 10.1093/nar/gkn810. 69 - -[^16]: D. S. Wishart, T. Jewison, A. C. Guo, M. Wilson, C. Knox, et al., HMDB 3.0–The -Human Metabolome Database in 2013, Nucleic Acids Res 41(Database issue),D801–7 (Jan 2013), doi:10.1093/nar/gks1065. 69 - -[^17]: J. Griss, A. R. Jones, T. Sachsenberg, M. Walzer, L. Gatto, J. Hartler, G. G. -Thallinger, R. M. Salek, C. Steinbeck, N. Neuhauser, J. Cox, S. Neumann, J. Fan, -F. Reisinger, Q.-W. Xu, N. Del Toro, Y. Perez-Riverol, F. Ghali, N. Bandeira, I. Xenarios, O. Kohlbacher, J. A. Vizcaino, and H. Hermjakob, The mzTab Data Exchange Format: communicating MS-based proteomics and metabolomics experimental results to a wider audience, Mol Cell Proteomics (Jun 2014), doi:10.1074/mcp.O113.036681. 69 - -[^18]: S. Böcker, M. C. Letzel, Z. Lipták, and A. Pervukhin, SIRIUS: Decomposing isotope -patterns for metabolite identification, Bioinformatics 25(2), 218–224 (2009), doi:10.1093/bioinformatics/btn603. 75 - -[^19]: S. Böcker and K. Dührkop, Fragmentation trees reloaded, J. Cheminform. 8(1), -1–26 (2016), doi:10.1186/s13321-016-0116-8. 75 - -[^20]: K. Dührkop, H. Shen, M. Meusel, J. Rousu, and S. Böcker, Searching molecular structure databases with tandem mass spectra using CSI:FingerID, Proc. Natl. -Acad. Sci. 112(41), 12580–12585 (oct 2015), doi:10.1073/pnas.1509788112. 75 - -[^21]: H. L. Röst, G. Rosenberger, P. Navarro, L. Gillet, S. M. Miladinovic, O. T. Schubert, W. Wolski, B. C. Collins, J. Malmstrom, L. Malmström, and R. Aebersold, -OpenSWATH enables automated, targeted analysis of data-independent acquisition MS data, Nature Biotechnology 32(3), 219–223 (Mar. 2014). 83, 87 - -[^22]: L. C. Gillet, P. Navarro, S. Tate, H. Röst, N. Selevsek, L. Reiter, R. Bonner, and -R. Aebersold, Targeted Data Extraction of the MS/MS Spectra Generated by Data-independent Acquisition: A New Concept for Consistent and Accurate Proteome Analysis, Molecular & Cellular Proteomics 11(6) (June 2012), doi:10.1074/mcp.O111.016717, 83 - -[^23]: A. Bertsch, C. Gröpl, K. Reinert, and O. Kohlbacher, OpenMS and TOPP: open source software for LC-MS data analysis., Methods in molecular biology (Clifton, -N.J.) 696, 353–367 (2011), doi:10.1007/978-1-60761-987-1_23. 83 - -[^24]: H. L. Röst, T. Sachsenberg, S. Aiche, C. Bielow, H. Weisser, F. Aicheler, S. Andreotti, H.-c. Ehrlich, P. Gutenbrunner, E. Kenar, X. Liang, S. Nahnsen, L. Nilse, -J. Pfeuffer, G. Rosenberger, M. Rurik, U. Schmitt, J. Veit, M. Walzer, D. Wojnar, -W. E. Wolski, O. Schilling, J. S. Choudhary, L. Malmström, R. Aebersold, K. Reinert, and O. Kohlbacher, OpenMS: a flexible open-source software platform -for mass spectrometry data analysis, Nat. Methods 13(9), 741–748 (sep 2016),doi:10.1038/nmeth.3959. 83 - -[^25]: J. Pfeuffer, T. Sachsenberg, O. Alka, M. Walzer, A. Fillbrunn, L. Nilse, O. Schilling, -K. Reinert, and O. Kohlbacher, OpenMS - A platform for reproducible analysis -of mass spectrometry data, J. Biotechnol. 261(February), 142–148 (2017), doi:10.1016/j.jbiotec.2017.05.016. 83 - -[^26]: L. Reiter, O. Rinner, P. Picotti, R. Huttenhain, M. Beck, M.-Y. Brusniak, M. O. Hengartner, and R. Aebersold, mProphet: automated data processing and statistical validation for large-scale SRM experiments, Nature Methods 8(5), 430–435 (May -2011), doi:10.1038/nmeth.1584. 83 - -[^27]: E. W. Deutsch, M. Chambers, S. Neumann, F. Levander, P.-A. Binz, J. Shofstahl, -D. S. Campbell, L. Mendoza, D. Ovelleiro, K. Helsens, L. Martens, R. Aebersold, -R. L. Moritz, and M.-Y. Brusniak, TraML—A Standard Format for Exchange of Selected Reaction Monitoring Transition Lists, Molecular & Cellular Proteomics -11(4) (Apr. 2012), doi:10.1074/mcp.R111.015040, 84 - -[^28]: C. Escher, L. Reiter, B. MacLean, R. Ossola, F. Herzog, J. Chilton, M. J. MacCoss, and O. Rinner, Using iRT, a normalized retention time for more targeted measurement of peptides., Proteomics 12(8), 1111–1121 (Apr. 2012), -doi:10.1002/pmic.201100463. 84 - -[^29]: H. L. Röst, G. Rosenberger, P. Navarro, L. Gillet, S. M. Miladinović, O. T. Schubert, W. Wolski, B. C. Collins, J. Malmström, L. Malmström, and R. Aebersold, -OpenSWATH enables automated, targeted analysis of data-independent acquisition MS data., Nat. Biotechnol. 32(3), 219–23 (2014), doi:10.1038/nbt.2841. -89, 90 - -[^30]: J. Teleman, H. L. Röst, G. Rosenberger, U. Schmitt, L. Malmström, J. Malmström, and F. Levander, DIANA-algorithmic improvements for analysis of dataindependent acquisition MS data, Bioinformatics 31(4), 555–562 (2015), arXiv: -9808008, doi:10.1093/bioinformatics/btu686. 89, 90 - -[^31]: K. Dührkop, M. Fleischauer, M. Ludwig, A. A. Aksenov, A. V. Melnik, M. Meusel, -P. C. Dorrestein, J. Rousu, and S. Böcker, SIRIUS 4: a rapid tool for turning tandem -mass spectra into metabolite structure information, Nat. Methods 16(4), 299– -302 (apr 2019), doi:10.1038/s41592-019-0344-8. 89 - -[^32]: J. E. Elias and S. P. Gygi, Target-decoy search strategy for increased confidence -in large-scale protein identifications by mass spectrometry, Nat. Methods 4(3), -207–214 (Mar. 2007). 89 - -[^33]: K. Scheubert, F. Hufsky, D. Petras, M. Wang, L. F. Nothias, K. Dührkop, N. Bandeira, P. C. Dorrestein, and S. Böcker, Significance estimation for large scale -metabolomics annotations by spectral matching, Nat. Commun. 8(1) (2017), -doi:10.1038/s41467-017-01318-5. 89 diff --git a/docs/run-workflows-with-openms-tools/openms-in-knime.md b/docs/run-workflows-with-openms-tools/openms-in-knime.md index e718e1d0..59b8c0e2 100644 --- a/docs/run-workflows-with-openms-tools/openms-in-knime.md +++ b/docs/run-workflows-with-openms-tools/openms-in-knime.md @@ -11,5 +11,5 @@ maxdepth: 1 knime/installation.md knime/workflows.md -knime/tutorial.md +OpenMS KNIME User Tutorial <../tutorials-and-quickstart-guides/openms-user-tutorial.md> ``` \ No newline at end of file diff --git a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md index 5fdfc870..478ce95b 100644 --- a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md +++ b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md @@ -1,5 +1,4 @@ -OpenMS User Tutorial -==================== +# OpenMS KNIME User Tutorial ## General Remarks @@ -11,67 +10,67 @@ OpenMS User Tutorial - This tutorial was designed for use in a hands-on tutorial session but can also be worked through at home using the online resources. You will become familiar with some of the basic functionalities of OpenMS/TOPP, TOPPView, as well as KNIME and learn how to use a selection of TOPP tools used in the tutorial workflows. -- If you are attending the tutorial and received a USB stick, all sample data referenced in this tutorial can be found in the {path}`C:,Example_Data` folder, on the USB stick, or released online on our [Archive](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Data/latest/). +- If you are attending the tutorial and received a USB stick, all sample data referenced in this tutorial can be found in the {path}`C:,Example_Data` folder, on the USB stick, or released online on our [Archive](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/tutorial.zip). ## Getting Started ### Installation -Before we get started, we will install OpenMS and KNIME. If you take part in a training session you will have likely received an USB stick from us that contains the required data and software. If we provide laptops with the software you may of course skip the installation process and continue reading the next section. +Before we get started, we will install OpenMS with its viewer TOPPView, KNIME and the OpenMS KNIME plugin. If you take part in a live training session you will have likely received an USB stick from us that contains the required data and software. If we provide laptops with the software you may of course skip the installation process and continue reading the next section. If you are doing this tutorial online, choose online in the following tab(s). -::::{tab-set} +:::::{tab-set} -:::{tab-item} Online +::::{tab-item} Online :sync: online If you are working through this tutorial at home/online, proceed with the following steps: -- Download and install OpenMS using the installation instructions for your operating system: - - [GNU/Linux](/openms-applications-and-tools/installation/installation-on-gnu-linux.md) - - [macOS](/openms-applications-and-tools/installation/installation-on-macos.md) - - [Windows](/openms-applications-and-tools/installation/installation-on-windows.md) +- Download and install OpenMS using the installation instructions for the [OpenMS tools](/openms-applications-and-tools/installation.md). + :::{note} + To install the graphical application, please use the downloadable installer for your platform, + not conda, nor docker. + ::: + - Download and install [KNIME](https://www.knime.org/downloads/overview) -::: +:::: -:::{tab-item} USB Stick +::::{tab-item} USB Stick :sync: usb Please choose the directory that matches your operating system and execute the installer. For Windows, you run: +```{note} +The OpenMS installer for windows now supports installing only for a single user. If you choose this option the location of the tools will be different than {{ '{path}'+'`C:,Program Files,OpenMS-{0}`'.format(version) }} specified in this document. In most cases they will install to {{ '{path}'+'`C:,Users,$YOUR_USER,AppData,Local,OpenMS-{0}`'.format(version) }} where $YOUR_USER is replaced with your username. +``` - The OpenMS installer: {{ '{path}'+'`Windows,OpenMS-{0}-Win64.exe`'.format(version) }} - The KNIME installer: {{ '{path}'+'`Windows,KNIME-{0}-Installer-64bit.exe`'.format(knime_version) }} -On macOS, you run: +On macOS(x86), you run: - The OpenMS installer: {{ '{path}'+'`Mac,OpenMS-{0}-macOS.dmg`'.format(version) }} -- The KNIME installer: {{ '{path}'+'`Mac,knime_{0}.app.macosx.cocoa.x86_64.dmg`'.format(version) }} +- The KNIME installer: {{ '{path}'+'`Mac,knime_{0}.app.macosx.cocoa.x86_64.dmg`'.format(knime_version) }} -On Linux, you can extract KNIME to a folder of your choice and for TOPPView you need to install OpenMS via your package manager or build it on your own with our -[build instructions](/openms-applications-and-tools/installation/installation-on-gnu-linux.md#build-openms-from-source). +On macOS(arm), you run: -::: -:::: -```{note} -If you have installed OpenMS on Linux or macOS via your package -manager (for instance by installing the {{ '`OpenMS-{0}-Linux.deb`'.format(version) }} package), -then you need to set the `OPENMS_DATA_PATH` variable to the directory containing the shared data (normally `/usr/share/OpenMS`). This must be done prior to running any TOPP tool. -``` -#### Installation from the internet +- The OpenMS installer: {{ '{path}'+'`Mac,OpenMS-{0}-macOS.dmg`'.format(version) }} +- The KNIME installer: {{ '{path}'+'`Mac,knime_{0}.app.macosx.cocoa.aarch64.dmg`'.format(knime_version) }} -If you are working through this tutorial at home, you can get the installers under the following links: +On Linux: +- The OpenMS package: {{ '{path}'+'`Linux,OpenMS-{0}-Debian-Linux-x86_64.deb`'.format(version) }} can be installed with your package manager +- The KNIME package can be extracted to a folder of your choice from {{ '{path}'+'`knime_{0}.linux.gtk.x86_64.tar`'.format(knime_version) }} -- [OpenMS](https://openms.readthedocs.io/en/latest/downloads.html) -- [KNIME](https://www.knime.org/downloads/overview) -- OpenMS prerequisites (Windows-only): After installation, before your first use -of the OpenMS plugin in KNIME you will be asked to download it automatically -if certain requirements are not found in your Windows registry. Alternatively, -you can get a bundled version here. + ```{note} + You can also install OpenMS via your package manager (version availability not guaranteed) or build it on your own with our + [build instructions](/openms-applications-and-tools/installation/installation-on-gnu-linux.md#build-openms-from-source). + ``` -Choose the installers for the platform you are working on. +:::: + +::::: ### Data conversion @@ -101,7 +100,7 @@ graphical user interface) or `msconvert` (a simple command line tool). Both tools are available in: {{ '{path}'+'`C:,Program Files,OpenMS-{0},share,OpenMS,THIRDPARTY,pwiz-bin`'.format(version) }}. -You can find a small RAW file on the USB stick {path}`C:,Example_Data,Introduction,datasets,raw`. +You can find a small RAW file on the USB stick {path}`Example_Data,Introduction,datasets,raw`. #### MSConvertGUI @@ -158,9 +157,9 @@ our tutorial data set. Note that conceptually, there are no differences in visua - Start TOPPView (see Windows' Start-Menu or {{ '{path}'+'`Applications,OpenMS-{0}`'.format(version) }} on macOS) - Go to **File** > **Open File**, navigate to the directory where you copied the contents -of the USB stick to, and select {path}`Example_Data,Introduction,datasets,small,velos005614.mzML`. This file contains only a reduced LC-MS map of a label-free proteomic platelet measurement recorded on an Orbitrap velos. The other two mzML files contain technical replicates of this experiment. First, we want to -obtain a global view on the whole LC-MS map - the default option Map view 2D -is the correct one and we can click the Ok button. + of the USB stick to, and [select](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Introduction/datasets/small/velos005614.mzML) {path}`Example_Data,Introduction,datasets,small,velos005614.mzML`. This file contains only a reduced LC-MS map of a label-free proteomic platelet measurement recorded on an Orbitrap velos. The other two mzML files contain technical replicates of this experiment. First, we want to + obtain a global view on the whole LC-MS map - the default option Map view 2D + is the correct one and we can click the Ok button. - Play around. @@ -172,20 +171,20 @@ is the correct one and we can click the Ok button. - Arrow keys can be used to scroll the view as well. - **Zoom mode** - Zooming into the data; either mark an area in the current view with -your mouse while holding the left mouse button plus the Ctrl key to -zoom to this area or use your mouse wheel to zoom in and out. + your mouse while holding the left mouse button plus the Ctrl key to + zoom to this area or use your mouse wheel to zoom in and out. - All previous zoom levels are stored in a zoom history. The zoom history -can be traversed using Ctrl + + or Ctrl + - or the mouse wheel (scroll up and down). + can be traversed using Ctrl + + or Ctrl + - or the mouse wheel (scroll up and down). - Pressing backspace zooms out to show the full LC-MS map (and -also resets the zoom history). + also resets the zoom history). - **Measure mode** - It is activated using the ⇧ Shift key. - Press the left mouse button down while a peak is selected and drag -the mouse to another peak to measure the distance between peaks. + the mouse to another peak to measure the distance between peaks. - This mode is implemented in the 1D and 2D mode only. - Right click on your 2D map and select **Switch to 3D mode** and examine your data in 3D mode (see Fig. 4). -- Go back to the 2D view. In 2D mode, visualize your data in different intensity normalization modes, use linear , percentage, snap and log-view (icons on -the upper left tool bar). You can hover over the icons for additional information. +- Visualize your data in different intensity normalization modes, use linear, percentage (set intensity axis scale to percentage), snap and log-view (icons on + the upper left tool bar). You can hover over the icons for additional information. ```{note} On macOS, due to a bug in one of the external libraries used by @@ -193,7 +192,7 @@ the upper left tool bar). You can hover over the icons for additional informatio to 2D. Close the 3D tab in order to get rid of it. ``` - In TOPPView you can also execute TOPP tools. Go to **Tools** > **Apply tool (whole layer)** -and choose a TOPP tool (e.g., `FileInfo`) and inspect the results. + and choose a TOPP tool (e.g., `FileInfo`) and inspect the results. Dependent on your data MS/MS spectra can be visualized as well (see Fig.5) . You can do so, by double-click on the MS/MS spectrum shown in scan view @@ -213,10 +212,18 @@ workflows. The first step is to become familiar with KNIME. Additional informati found on the KNIME [Getting Started page](https://www.knime.com/getting-started-guide). However, the most important concepts will also be reviewed in this tutorial. -#### Plugin and dependency +#### KNIME Modern and Classic UI #### + +Since version 5.0 KNIME has a new updated user interface. For the purposes of this tutorial we will continue to use the "classic user interface". +Depending on your OS KNIME may have started automatically in the Modern UI, which looks like the following: +|![ms2 spectrum](/images/openms-user-tutorial/introduction/KNIME_switch_to_classic.png)| +|:--:| +|Figure 5.5: The modern KNIME UI. To switch back to the classic UI, select "Menu" and click "Switch to classic user interface"| +#### Plugin and dependency -Before we can start with the tutorial, we need to install all the required extensions for KNIME. Since KNIME 3.2.1, the program automatically +Before we can start with the tutorial, we need to install all the required extensions for KNIME. +Since KNIME 3.2.1, the program automatically detects missing plugins when you open a workflow but to make sure that the right source for the OpenMS plugin is chosen, please follow the instructions here. @@ -226,19 +233,20 @@ First, we install some additional extensions that are required by our OpenMS nodes or used in the Tutorials for downstream processing, visualization or reporting. 1. In KNIME, click on **Help** > **Install New Software**. -2. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME 4.6 - https://update.knime.com/community-contributions/trusted/4.6' +2. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME 5.2 - https://update.knime.com/analytics-platform/5.2' 3. Now select the following KNIME core plugins from the KNIME & Extensions category - - KNIME Base Chemistry Types & Nodes - - KNIME Chemistry Add-Ons - - KNIME Interactive R Statistics Integration - - KNIME Report Designer - - KNIME SVG Support -4. Click on **Next** and follow the instructions (you may but don’t need to restart KNIME now). + - KNIME Base Chemistry Types & Nodes + - KNIME Chemistry Add-Ons + - KNIME Interactive R Statistics Integration + - KNIME Report Designer +4. Click on **Next** and follow the instructions (it's not necessary to restart KNIME now). 5. Click again on **Help** > **Install New Software** -6. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME Community Extensions (Trusted) - https://update.knime.com/community-contributions/trusted/4.6' -7. Now select the following plugin from the "KNIME Community Contributions - Cheminformatics" category - - RDKit KNIME integration -8. Click on **Next** and follow the instructions and after a restart of KNIME the dependencies will be installed. +6. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME Community Extensions (Trusted) - https://update.knime.com/community-contributions/trusted/5.2' +7. From the "KNIME Community Contributions - Cheminformatics" category select + - RDKit Nodes Feature +8. From the "KNIME Community Extensions - Other" category select + - Generic Worfkflow Nodes for KNIME +9. Click on **Next** and follow the instructions and after a restart of KNIME the dependencies will be installed. ##### R programming language and its KNIME integration @@ -246,7 +254,7 @@ In addition, we need to install `R` for the statistical downstream analysis. Cho operating system, double-click the `R` installer and follow the instructions. We recommend to use the default settings whenever possible. On macOS you also need to install `XQuartz` from the same directory. -Afterwards, open your `R` installation. If you use Windows, you will find an ”R x64 3.6.X” icon on your desktop. If you use +Afterwards open your `R` installation. If you use Windows, you will find an ”R x64 4.3.2” icon on your desktop. If you use macOS, you will find R in your Applications folder. In `R`, type the following lines (you might also copy them from the file {path}`R,install_R_packages.R` on the USB stick): @@ -264,18 +272,18 @@ if (!requireNamespace("BiocManager", quietly = TRUE)) BiocManager::install() BiocManager::install(c("MSstats")) ``` -In KNIME, click on **KNIME** > **Preferences**, select the category **KNIME** > **R** and set the ”Path to R Home” to +In KNIME, click on **File** > **Preferences**, select the category **KNIME** > **R** and set the ”Path to R Home” to your installation path. You can use the following settings, if you installed R as described above: -- Windows: `C:\Program Files\R\R-3.6.X'` (where X is the version you used to install the above libraries) -- macOS: `/Library/Frameworks/R.framework/Versions/3.6/Resources` +- Windows: `C:\Program Files\R\R-4.3.2'` +- macOS: `/Library/Frameworks/R.framework/Versions/4.3/Resources` ##### KNIME OpenMS plugin You are now ready to install the OpenMS nodes. - In KNIME, click on **Help** > **Install New Software** -You now have to choose an _update site_ to install the OpenMS plugin from. Which _update site_ to choose depends on if you received a USB stick +You now have to choose an _update site_ to install the OpenMS plugin from. Which _update site_ to choose depends on if you received an USB stick in a hands-on Tutorial or if you are doing this Tutorial online. ::::{tab-set} @@ -285,12 +293,13 @@ in a hands-on Tutorial or if you are doing this Tutorial online. To install the OpenMS KNIME plugin from the internet, do the following: -1. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME Community Extensions (Trusted) - https://update.knime.com/community-contributions/trusted/4.6' +1. From the '**Work with**:' drop-down list, select the _update site_ 'KNIME Community Extensions (Trusted) - https://update.knime.com/community-contributions/trusted/5.2' 2. Now select the following plugin from the "KNIME Community Contributions - Bioinformatics & NGS" category - - OpenMS + - OpenMS + - OpenMSThirdParty 3. Click on **Next** and follow the instructions and after a restart of KNIME the OpenMS nodes will be available in the Node repository under - "Community Nodes". - + "Community Nodes". + ```{note} If this does not work for you, report it and while waiting for a reply/fix, try to use an _update site_ of an older KNIME version by editing the KNIME version number in the URL or by using our inofficial _update site_ at https://abibuilder.cs.uni-tuebingen.de/archive/openms/knime-plugin/updateSite/release/latest @@ -318,7 +327,7 @@ From now on, you can use this repository for plugins in the **Work with**: drop- - Select the OpenMS nodes in the ”Uncategorized” category and click **Next**. - Follow the instructions and after a restart of KNIME the OpenMS nodes will be available in the Node repository under "Community Nodes”. - + ::: :::{tab-item} Online experimental @@ -339,7 +348,7 @@ From now on, you can use this repository for plugins in the **Work with:** drop- - Select the OpenMS nodes in the "Uncategorized" category and click **Next**. - Follow the instructions and after a restart of KNIME the OpenMS nodes will be available in the Node repository under "Community Nodes". - + ::: :::: @@ -350,10 +359,10 @@ A workflow is a sequence of computational steps applied to a single or multiple data. In KNIME such workflows are implemented graphically by connecting so-called nodes. A node represents a single analysis step in a workflow. Nodes have input and output ports where the data enters the node or the results are provided for other nodes after processing, respectively. KNIME distinguishes between different port types, representing different -types of data. The most common representation of data in KNIME are tables (similar to an Excel sheet). Ports that accept +types of data. The most common representation of data in KNIME are tables (similar to an excel sheet). Ports that accept tables are marked with a small triangle. For OpenMS nodes, we use a different port type, so called file ports, representing complete files. Those ports are marked by a small blue box. Filled blue boxes represent mandatory inputs and empty blue -boxes optional inputs. The same holds for output ports, despite you can deactivate them in the configuration dialog +boxes optional inputs. The same holds for output ports, except that you can deactivate them in the configuration dialog (double-click on node) under the **OutputTypes** tab. After execution, deactivated ports will be marked with a red cross and downstream nodes will be inactive (not configurable). @@ -361,7 +370,7 @@ A typical OpenMS workflow in KNIME can be divided in two conceptually different - Nodes for signal and data processing, filtering and data reduction. Here, files are passed between nodes. Execution times of the individual steps are typically longer for these types of nodes as they perform the main computations. -- Downstream statistical analysis and visualization. Here, tables are passed between nodes, and mostly internal KNIME +- Downstream statistical analysis and visualization. Here, tables are passed between nodes and mostly internal KNIME nodes or nodes from third-party statistics plugins are used. The transfer from files (produced by OpenMS) and tables usually happens with our provided Exporter and Reader nodes (e.g. MzTabExporter followed by MzTabReader). @@ -377,7 +386,7 @@ until the predecessor was executed. If nodes still remain in a red state, probab provided in the configuration dialog that can neither be guessed from the data nor filled with sensible defaults. In this case, or if you want to customize the default configuration in general, you can open the configuration dialog of a node with a double-click on the node. For all OpenMS nodes you will see a configuration dialog like the one shown in -the figure below. +below figure. |![Node configuration dialog of an OpenMS node](/images/openms-user-tutorial/knime-setup/knime_configure_dialog.png)| |:--:| @@ -387,14 +396,14 @@ the figure below. OpenMS distinguishes between normal parameters and advanced parameters. Advanced parameters are by default hidden from the users since they should only rarely be customized. In case you want to have a look at the parameters or need to customize them in one of the tutorials you can show them by clicking on the checkbox **Show advanced parameter** -in the lower part of the dialog. Afterwards, the parameters are shown in a light gray color. +in the lower part of the dialog. Afterwards the parameters are shown in a light gray color. ``` The dialog shows the individual parameters, their current value and type, and, in the lower part of the dialog, the documentation for the currently selected parameter. Please also note the tabs on the top of the configuration dialog. In the case of OpenMS nodes, there will be another tab called OutputTypes. It contains dropdown menus for every output -port that let you select the output file type that you want the node to return (if the tool supports it). For optional -output ports, you can select Inactive such that the port is crossed out after execution and the associated generation of +port that let you select the output filetype that you want the node to return (if the tool supports it). For optional +output ports you can select Inactive such that the port is crossed out after execution and the associated generation of the file and possible additional computations are not performed. Note that this will deactivate potential downstream nodes connected to this port. @@ -405,7 +414,7 @@ nodes connected to this port. |Figure 7: The KNIME workbench| The graphical user interface (GUI) of KNIME consists of different components or so-called panels that are shown in -the above image. We will briefly introduce the individual panels and their purposes below. +above image. We will briefly introduce the individual panels and their purposes below. ##### Workflow Editor @@ -424,16 +433,17 @@ Shows a list of available workflows (also called workflow projects). You can ope new workflow can be created with a right-click in the Workflow Explorer followed by choosing **New KNIME Workflow** from the appearing context menu. Remember to save your workflow often with the Ctrl + S shortcut. -##### Workflow Coach (since KNIME 3.2.1) +##### Workflow Coach Shows a list of suggested following nodes, based on the last added/clicked nodes. When you are not sure which node to -choose next, you have a reasonable suggestion based on other users' behavior there. Connect them to the last node with a -double click. +choose next, you have a reasonable suggestion based on other users behavior there. Connect them to the last node with a +double-click. ##### Node Repository Shows all nodes that are available in your KNIME installation. Every plugin you install will provide new nodes that can -be found here. The OpenMS nodes can be found in **Community Node** > **OpenMS** Nodes for managing files (e.g., Input +be found here. The OpenMS nodes can be found in **Community Node** > **OpenMS** Nodes to hook up to external search engines +and the RawFileConverter are found under **Community Node** > **OpenMSThirdParty** Nodes for managing files (e.g., Input Files or Output Folders) can be found in **Community Nodes** > **GenericKnimeNode**. You can search the node repository by typing the node name into the small text box in the upper part of the node repository. @@ -456,7 +466,7 @@ may produce or expect. For OpenMS nodes you will also find a link to the tool pa #### Creating workflows -Workflows can easily be created by a right-click in the Workflow Explorer followed by clicking on **New KNIME workflow**. +Workflows can easily be created by a right click in the Workflow Explorer followed by clicking on **New KNIME workflow**. #### Sharing workflows @@ -467,9 +477,9 @@ workflows as a _knwf_ file containing all the information on nodes, their connec Those *knwf* files can again be imported by selecting: **File** > **Import KNIME Workflow** ```{note} -For your convenience, we added all workflows discussed in this tutorial to the **Workflows** folder on the USB Stick. - Additionally, the workflow files can be found on workflow downloads. If you want to check - your own workflow by comparing it to the solution or get stuck, simply import the full workflow from the corresponding +For your convenience we added all workflows discussed in this tutorial to the **Workflows** folder on the USB Stick. + Additionally, the workflow files can be found on workflow downloads. If you want to check + your own workflow by comparing it to the solution or got stuck, simply import the full workflow from the corresponding *knwf* file and after that double-click it in your KNIME Workflow repository to open it. ``` @@ -477,16 +487,16 @@ For your convenience, we added all workflows discussed in this tutorial to the * In this tutorial, a lot of the workflows will be created based on the workflow from a previous task. To keep the intermediate workflows, we suggest you create copies of your workflows so you can see the progress. To create a copy of -your workflow, save it, close it, and follow the next steps. +your workflow, save it, close it and follow the next steps. -- Right-click on the workflow you want to create a copy of in the Workflow Explorer and select **Copy**. -- Right-click again somewhere on the workflow explorer and select **Paste**. -- This will create a workflow with the same name as the one you copied with a (2) appended. -- To distinguish them later on you can easily rename the workflows in the Workflow Explorer by right-clicking on the +- Right click on the workflow you want to create a copy of in the Workflow Explorer and select **Copy**. +- Right click again somewhere on the workflow explorer and select **Paste**. +- This will create a workflow with same name as the one you copied with a (2) appended. +- To distinguish them later on you can easily rename the workflows in the Workflow Explorer by right clicking on the workflow and selecting **Rename**. ```{note} -To rename a workflow it has to be closed, too. +To rename a workflow it has to be closed. ``` #### A minimal workflow @@ -496,110 +506,74 @@ information about the data set before starting the actual development of a data can also be used to check if all requirements are met and that your system is compatible. - Create a new workflow. -- Add an Input File node and an Output Folder node (to be found in **Community Nodes** > **GenericKnimeNodes** > **IO** - and a FileInfo node (to be found in the category **Community Node** > **OpenMS** > **File Handling**) to the workflow. -- Connect the Input File node to the FileInfo node, and the first output port of the FileInfo node to the Output Folder +- Add an `File Importer` node and an `Output Folder` node (found in **Community Nodes** > **GenericKnimeNodes** > **IO**) + and a `FileInfo` node (to be found in the category **Community Node** > **OpenMS** > **File Handling**) to the workflow. +- Connect the File Importer node to the FileInfo node, and the first output port of the FileInfo node to the Output Folder node. ```{tip} In case you are unsure about which node port to use, hovering the cursor over the port in question will display the port name and what kind of input it expects. ``` -The complete workflow is shown in the below image. `FileInfo` can produce two different kinds of output files. +The complete workflow is shown in below image. `FileInfo` can produce two different kinds of output files. -|![A minimal workflow calling FileInfo on a single file.](/images/openms-user-tutorial/knime-setup/minimal_FileInfo.svg)| +|![A minimal workflow calling FileInfo on a single file.](/images/openms-user-tutorial/knime-setup/minimal_FileInfo.png)| |:--:| |Figure 8: A minimal workflow calling `FileInfo` on a single file.| -- All nodes are still marked red since we are missing an actual input file. Double-click the Input File node and select - **Browse**. In the file system browser select {path}`Example_Data,Introduction,datasets,tiny,velos005614.mzML` - and click **Open**. Afterward, close the dialog by clicking **Ok**. +- All nodes are still marked red, since we are missing an actual input file. Double-click the File Importer node and select + **Browse**. In the file system browser [select](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Introduction/datasets/tiny/velos005614.mzML) {path}`Example_Data,Introduction,datasets,tiny,velos005614.mzML` + and click **Open**. Afterwards close the dialog by clicking **Ok**. -```{note} -Make sure to use the “tiny” version this time, not “small”, for the sake of faster workflow execution. -``` -- The **Input File** node and the `FileInfo` node should now have switched to yellow, but the **Output Folder** node is still red. - Double-click on the **Output Folder** node and click on **Browse** to select an output directory for the generated data. +- The `File Importer` node and the `FileInfo` node should now have switched to yellow, but the `Output Folder` node is still red. + Double-click on the `Output Folder` node and click on **Browse** to select an output directory for the generated data. - Great! Your first workflow is now ready to be run. Press + F7 (shift key + F7; or the - button with multiple green triangles in the KNIME Toolbar) to execute the complete workflow. You can also right-click + button with multiple green triangles in the KNIME Toolbar) to execute the complete workflow. You can also right click on any node of your workflow and select Execute from the context menu. - The traffic lights tell you about the current status of all nodes in your workflow. Currently running tools show either a progress in percent or a moving blue bar, nodes waiting for data show the small word “queued”, and successfully executed ones become green. If something goes wrong (e.g., a tool crashes), the light will become red. - In order to inspect the results, you can just right-click the Output Folder node and select **View: Open the output folder** - You can then open the text file and inspect its contents. You will find some basic information about the data contained + You can then open the text file and inspect its contents. You will find some basic information of the data contained in the mzML file, e.g., the total number of spectra and peaks, the RT and m/z range, and how many MS1 and MS2 spectra the file contains. Workflows are typically constructed to process a large number of files automatically. As a simple example, consider you -would like to convert multiple Thermo Raw files into the mzML format. We will now modify the workflow to compute the +would like to filter multiple mzML files to only include MS1 spectra. We will now modify the workflow to compute the same information on three different files and then write the output files to a folder. - We start from the previous workflow. -- First, we need to replace our single input file with multiple files. Therefore we add the Input Files node from the +- First we need to replace our single input file with multiple files. Therefore we add the `Input Files` node from the category **Community Nodes** > **GenericKnimeNodes** > **IO**. -- To select the files we double-click on the Input Files node and click on **Add**. In the filesystem browser, we select - all three files from the directory **Example_Data** > **Introduction** > **datasets** > **tiny**. And close the dialog +- To select the files we double-click on the `Input Files` node and click on **Add**. In the filesystem browser we select + all three files from the [directory](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Introduction/datasets/tiny) **Example_Data** > **Introduction** > **datasets** > **tiny**. And close the dialog with **Ok**. - We now add two more nodes: the `ZipLoopStart` and the `ZipLoopEnd` node from the category - **Community Nodes** > **GenericKnimeNodFlow** > **Flow**. + **Community Nodes** > **GenericKnimeNodes* > **Flow** and replace the `FileInfo` node with `FileFilter` from **Community Nodes** > **OpenMS** > **File Handling**. - Afterwards we connect the `Input Files` node to the first port of the `ZipLoopStart` node, the first port of the `ZipLoopStart` node to the **FileConverter** node, the first output port of the **FileConverter** node to the first input port of the - `ZipLoopEnd` node, and the first output port of the `ZipLoopEnd` node to the **Output Folder** node (NOT to the Output File). + `ZipLoopEnd` node, and the first output port of the `ZipLoopEnd` node to the `Output Folder` node. -The complete workflow is shown in the below figure. +The complete workflow is shown in the top right of the figure below. -|![A minimal workflow calling the FileConverter on multiple Thermo Raw files in a loop](/images/openms-user-tutorial/knime-setup/Minimal_RawFileConverter_Loop.png)| +|![A minimal workflow calling the FileFilter on multiple mzML files in a loop](/images/openms-user-tutorial/knime-setup/KNIME_annotated_FileFilter.png)| |:--:| -|Figure 9: A minimal workflow calling the FileConverter on multiple Thermo Raw files in a loop| +|Figure 9: The FileFilter workflow. Showing the configure dialog for `FileFilter`, and the level selector pane. + +Now we need to configure the `FileFilter` to only store MS1 data. To do this we double click on the `FileFilter` node to open the configuration dialog (see left pane above), double click "level", select 2 +from the sub-pane (see bottom right panel above), and click delete. Repeat the process for 3. Select OK to exit the sub-pane, and then OK again in the configuration dialog. Execute the workflow and inspect the output as before. +Now, if you open the resulting files in TOPPView, you can see that only the MS1 spectra remain. + In case you had trouble to understand what `ZipLoopStart` and `ZipLoopEnd` do, here is a brief explanation: -- The `Input Files` node passes a list of files to the ZipLoopStart node. -- The ZipLoopStart node takes the files as input, but passes the single files sequentially (that is: one after the other) +- The `Input Files` node passes a list of files to the `ZipLoopStart` node. +- The `ZipLoopStart` node takes the files as input, but passes the single files sequentially (that is: one after the other) to the next node. -- The ZipLoopEnd collects the single files that arrive at its input port. After all, files have been processed, the collected - files are passed again as a file list to the next node that follows. - -#### Digression: Working with chemical structures - -Metabolomics analyses often involve working with chemical structures. Popular cheminformatic toolkits such as RDKit[^7] -or CDK[^8] are available as KNIME plugins and allow us to work with chemical structures directly from within KNIME. -In particular, we will use KNIME and RDKit to visualize a list of compounds and filter them by predefined substructures. -Chemical structures are often represented as SMILES (**S**implified **m**olecular **i**nput **l**ine **e**ntry **s**pecification), a simple and compact way to describe complex chemical structures as text. For example, the chemical structure of L-alanine can be written as the SMILES string `C[C@H](N)C(O)=O`. As we will discuss later, all OpenMS tools that perform metabolite -identification will report SMILES as part of their result, which can then be further processed and visualized using RDKit -and KNIME. - -|![ Workflow to visualize a list of SMILES strings and filter them by predefined substructures](/images/openms-user-tutorial/metabo/structures_filter_workflow.png)| -|:--:| -|Figure 10: Workflow to visualize a list of SMILES strings and filter them by predefined substructures| - -Perform the following steps to build the workflow shown in the above figure. You will use this workflow to visualize a -list of SMILES strings and filter them by predefined substructures: - -- Add the node File Reader, open the node configuration dialog, and select the file `smiles.csv`. This file has been - exported from the Human Metabolome Database (HMDB) and contains the portion of the human metabolome that has been - detected and quantified. The file preview atthe bottom of the dialog shows that each compound is given by its HMDB - accession, compound name, and SMILES string. Click on the column header **SMILES** to change its properties. Change the - column type from **string** to **smiles** and close the dialog with **Ok**. Afterward, the **SMILES** column will be - visualized as chemical structures instead of text directly within all **KNIME** tables. -- Add the node `RDKit From Molecule` and connect it to the `File Reader`. This node will use the provided `SMILES` - strings to add an additional column that is required by RDKit. -- Add the node `RDKit Functional Group Filter` and open the node configuration dialog. You can use this dialog to filter - the compounds by any combination of functional groups. In this case, we want to find all compounds that contain at - least one aromatic carboxylic acid group. To do this, set this group as active and choose ’¿=’ and ’1’. -- Connect the first output port (Molecules passing the filter) to a `CSV Writer` node to save the filtered metabolites - to a file. Right-click **RDKit Functional Group Filter** and select the view ’Molecules passing the filter’ to inspect - the selected compounds in KNIME. How many compounds pass the chosen filter, see the below figure. - - -The following figure shows the resulting list of compounds that contains at least one aromatic carboxylic acid group. - -|![Resulting list of compounds that contains at least one aromatic carboxylic acid group](/images/openms-user-tutorial/metabo/structures_filter_results.png)| -|:--:| -|Figure 11: Resulting list of compounds that contains at least one aromatic carboxylic acid group.| +- The `ZipLoopEnd` collects the single files that arrive at its input port. After all files have been processed, the collected + files are passed again as file list to the next node that follows. #### Advanced topic: Metanodes @@ -610,10 +584,10 @@ improve handling and clarity of large workflows:

**Task**

- Select multiple nodes (e.g. all nodes of the ZipLoop including the start and end node). To select a set of nodes, draw a rectangle around them with the left mouse button or hold Ctrl to add/remove single nodes from the selection. + Select multiple nodes (e.g. all nodes of the **ZipLoop** including the start and end node). To select a set of nodes, draw a rectangle around them with the left mouse button or hold Ctrl to add/remove single nodes from the selection.

**Tip**

- There is a **Select Loop** option when you right-click a node in a loop, that does exactly that for you. Then, open the + There is a **Select Scope** option when you right-click a node in a loop, that does exactly that for you. Then, open the context menu (right-click on a node in the selection) and select **Create Metanode**. Enter a caption for the **Metanode**. The previously selected nodes are now contained in the **Metanode**. Double-clicking on the **Metanode** will display the contained nodes in a new tab window. @@ -622,73 +596,65 @@ improve handling and clarity of large workflows:

**Task**

-Create the Metanode to let it behave like an encapsulated single node. First, select the **Metanode**, open the context -menu (right-click), and select **Metanode** > **Wrap**. The differences between Metanodes and their wrapped counterparts -are marginal (and only apply when exposing user inputs and workflow variables). Therefore we suggest using standard +Create the Metanode to let it behave like an encapsulated single node. First select the **Metanode**, open the context +menu (right-click) and select **Metanode** > **Convert to Component**. The differences between Metanodes and components +are marginal (Metanodes allow exposing user inputs, workflow variables and contained nodes). Therefore, we suggest to use standard Metanodes to clean up your workflow and cluster common subparts until you actually notice their limits.

**Task**

-Undo the packaging. First select the (**Wrapped**) **Metanode**, open the context menu (right-click) and select **(Wrapped) Metanode** > **Expand**. +Undo the packaging. First select the **Metanode/Component**, open the context menu (right-click) and select **Metanode/Component** > **Expand**.
-#### Advanced topic: R integration + -```{note} -Note that we needed to put some extra quotes around `Cluster Membership`. If we omit those, R would interpret the column -name only up to the first space `(knime.in$Cluster)` which is not present in the table and leads to an error. Quotes are -regularly needed if column names contain spaces, tabs, or other special characters like $ itself. -``` ## Label-free quantification of peptides @@ -698,109 +664,103 @@ In the following chapter, we will build a workflow with OpenMS / KNIME to quanti quantification is a method aiming to compare the relative amounts of proteins or peptides in two or more samples. We will start from the minimal workflow of the last chapter and, step-by-step, build a label-free quantification workflow. +The complete workflow can be downloaded [here](https://hub.knime.com/openms-team/spaces/Tutorial%20Workflows%20OpenMS%203.0/Proteomics_LFQ~MvMoVSrTZKLI6H3B/current-state) as well. + ### Peptide identification -As a start, we will extend the minimal workflow so that it performs a peptide identification using the OMSSA[^9] search -engine. Since OpenMS version 1.10, OMSSA is included in the OpenMS installation, so you do not need to download and +As a start, we will extend the minimal workflow so that it performs a peptide identification using the Comet search +engine. Comet is included in the OpenMS installation, so you do not need to download and install it yourself. -Let’s start by replacing the input files in our `Input Files` node with the three mzML files in +Let’s start by replacing the input files in our `Input Files` node by the three mzML files in **Example Data** > **Labelfree** > **datasets** > **lfqxspikeinxdilutionx1-3.mzML**. This is a reduced toy dataset where -each of the three runs contains a constant background of S. `pyogenes` peptides as well as human spike-in peptides in +each of the three runs contains a constant background of `S. pyogenes` peptides as well as human spike-in peptides in different concentrations. [^10] -- Instead of FileInfo, we want to perform OMSSA identification, so we simply replace the `FileInfo` node with the - `OMSSAAdapter` node **Community Nodes** > **OpenMS** > **Identification**, and we are almost done. Just make sure you - have connected the `ZipLoopStart` node with the `in` port of the `OMSSAAdapter` node. -- OMSSA, like most mass spectrometry identification engines, relies on searching the input spectra against sequence +- Instead of `FileFilter`, we want to perform Comet identification, so we simply replace the `FileFilter` node with the + `CometAdapter` node **Community Nodes** > **OpenMSThirdParty** > **Identification**, and we are almost done. Just make sure you + have connected the `ZipLoopStart` node with the `in` (top) port of the `CometAdapter` node. +- Comet, like most mass spectrometry identification engines, relies on searching the input spectra against sequence databases. Thus, we need to introduce a search database input. As we want to use the same search database for all of - our input files, we can just add a single `Input File` node to the workflow and connect it directly with the - `OMSSAAdapter database` port. KNIME will automatically reuse this Input node each time a new ZipLoop iteration is - started. In order to specify the database, select {path}`Example_Data,Labelfree,databases,/break,s_pyo_sf370_potato_human_target_decoy_with_contaminants.fasta`, - and we have a very basic peptide identification workflow. + our input files, we can just add a single `File Importer` node to the workflow and connect it directly with the + `CometAdapter database` (middle) port. KNIME will automatically reuse this Input node each time a new ZipLoop iteration is + started. In order to specify the database, [select](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Labelfree/databases/s_pyo_sf370_potato_human_target_decoy_with_contaminants.fasta) {path}`Example_Data,Labelfree,databases,/break,s_pyo_sf370_potato_human_target_decoy_with_contaminants.fasta` +- Connect the **out** port of the `CometAdapter` to `ZipLoopEnd` and we have a very basic peptide identification workflow. ```{note} You might also want to save your new identification workflow under a different name. Have a look at duplicating workflows for information on how to create copies of workflows. ``` -- The result of a single OMSSA run is basically a number of peptide-spectrum-matches (PSM) with a score each, and these +- The result of a single Comet run is basically a number of peptide-spectrum-matches (PSM) with a score each, and these will be stored in an idXML file. Now we can run the pipeline and after execution is finished, we can have a first look - at the results: just open the input files folder with a file browser, and from there open an mzML file in **TOPPView**. + at the the results: just open the output folder with a file browser and from there open one of the three input mzML's in **TOPPView**. - Here, annotate this spectrum data file with the peptide identification results. Choose **Tools** > **Annonate with identification** - from the menu and select the idXML file that **OMSSAAdapter** generated (it is located within the output directory that + from the menu and select the idXML file that `CometAdapter` generated (it is located within the output directory that you specified when starting the pipeline). -- On the right, select the tab **Identification view**. All identified peptides can be seen using this view. Users can also +- On the right, select the tab **Identification view**. All identified peptides can be seen using this view. User can also browse the corresponding MS2 spectra. ```{note} - Opening the output file of `OMSSAAdapter` (the idXML file) directly is also possible, but the direct visusalisation of - an idXML files is less useful. + Opening the output file of `CometAdapter` (the idXML file) directly is also possible, but unless you REALLY like XML, reading + idXML files is less useful. ``` - The search results stored in the idXML file can also be read back into a KNIME table for inspection and subsequent analyses: Add a `TextExporter` node from **Community Nodes** > **OpenMS** > **File Handling** to your workflow and - connect the output port of your `OMSSAAdapter` (the same port `ZipLoopEnd` is connected to) to its input port. This + connect the output port of your `CometAdapter` (the same port `ZipLoopEnd` is connected to) to its input port. This tool will convert the idXML file to a more human-readable text file which can also be read into a KNIME table using the `IDTextReader` node. Add an `IDTextReader` node(**Community Nodes** > **OpenMS** > **Conversion**) after - **TextExporter** and execute it. Now you can right-click `IDTextReader` and select **ID Table** to browse your peptide + `TextExporter` and execute it. Now you can right click `IDTextReader` and select **ID Table** to browse your peptide identifications. - From here, you can use all the tools KNIME offers for analyzing the data in this table. As a simple example, add a - `Histogram (local)` node (from category **Views - Local (Swing)**) node after `IDTextReader`, double-click it, select - `peptide_charge` as Histogram column, hit **OK**, and execute it. Right-clicking and selecting - **Interactive View: Histogram view** will open a plot showing the charge state distribution of your identifications. + `Histogram` node (from category **Views**) node after `IDTextReader`, double-click it, select + `peptide_charge` as Dimension, click **Save and Execute** to generate a plot showing the charge state distribution + of your identifications. -In the next step, we will tweak the parameters of OMSSA to better reflect the instrument’s accuracy. Also, we will +In the next step, we will tweak the parameters of Comet to better reflect the instrument’s accuracy. Also, we will extend our pipeline with a false discovery rate (FDR) filter to retain only those identifications that will yield an FDR of < 1 %. -- Open the configuration dialog of `OMSSAAdapter`. The dataset was recorded using an LTQ Orbitrap XL mass spectrometer, - setting the precursor mass tolerance to a smaller value, say 5 ppm. Set `precursor_mass_tolerance` to 5 and - `precursor_error_units` to `ppm`. +- Open the configuration dialog of `CometAdapter`. The dataset was recorded using an LTQ Orbitrap XL mass spectrometer, + set the `precursor_mass_tolerance` to 5 and `precursor_error_units` to `ppm`. ```{note} Whenever you change the configuration of a node, the node as well as all its successors will be reset to the Configured state (all node results are discarded and need to be recalculated by executing the nodes again). ``` -- Set `max_precursor_charge` to 5, in order to also search for peptides with charges up to 5. -- Add `Carbamidomethyl (C)` as fixed modification and `Oxidation(M)` as variable modification. +- Make sure that `Carbamidomethyl (C)` is set as fixed modification and `Oxidation(M)` as variable modification. ```{note} To add a modification click on the empty value field in the configuration dialog to open the list editor dialog. In the - new dialog click **Add**. Then select the newly added modification to open the drop-down list where you can select the - correct modification. + new dialog click **Add**. Then select the newly added modification to open the drop down list where you can select the + the correct modification. ``` -- A common step in the analysis is to search not only against a regular protein database but also search against a decoy +- A common step in analysis is to search not only against a regular protein database, but to also search against a decoy database for FDR estimation. The fasta file we used before already contains such a decoy database. For OpenMS to know - which OMSSA PSM came from which part of the file (i.e. target versus decoy), we have tso index the results. To this end, + which Comet PSM came from which part of the file (i.e. target versus decoy), we have to index the results. To this end, extend the workflow with a `PeptideIndexer` node **Community Nodes** > **OpenMS** > **ID Processing**. This node needs the idXML as input as well as the database file (see below figure). ```{tip} - You can direct the files of an `Input File` node to more than just one destination port. + You can direct the files of an `File Importer` node to more than just one destination port. ``` - The decoys in the database are prefixed with “DECOY_”, so we have to set `decoy_string` to `DECOY_` and `decoy_string_position` to `prefix` in the configuration dialog of `PeptideIndexer`. - Now we can go for the FDR estimation, which the `FalseDiscoveryRate` node will calculate for us (you will find it in - **Community Nodes** > **OpenMS** > **ID Processing**). -- In order to set the FDR level to 1%, we need an `IDFilter` node from **Community Nodes** > **OpenMS** > **ID Processing**. + **Community Nodes** > **OpenMS** > **Identification Processing**). `FalseDiscoveryRate` is meant to be run on data with protein inferencences + (more on that later), in order to just use it for peptides, open the configure window, select "show advanced parameter" and toggle "force" to true. +- In order to set the FDR level to 1%, we need an `IDFilter` node from **Community Nodes** > **OpenMS** > **Identification Processing**. Configuring its parameter `score→pep` to 0.01 will do the trick. The FDR calculations (embedded in the idXML) from the `FalseDiscoveryRate` node will go into the *in* port of the `IDFilter` node. -- Execute your workflow and inspect the results using `IDTextReader` as you did before. How many peptides did you +- Execute your workflow and inspect the results using `IDTextReader` like you did before. How many peptides did you identify at this FDR threshold? - ```{note} - The finished identification workflow is now sufficiently complex that we might want to encapsulate it in a Metanode. - For this, select all nodes inside the ZipLoop (including the **Input File** node) and right-click to select - **Collapse into Metanode** and name it ID. Metanodes are useful when you construct even larger workflows and want to - keep an overview. - - ``` - The below images shows OMSSA ID pipeline including FDR filtering. +The below images shows Comet ID pipeline including FDR filtering. - |![OMSSA ID pipeline including FDR filtering](/images/openms-user-tutorial/labelfree/PepIdFDR.png)| +|![Comet ID pipeline including FDR filtering](/images/openms-user-tutorial/labelfree/PepIdFDR.png)| |:--:| - |Figure 12: OMSSA ID pipeline including FDR filtering| +|Figure 12: Comet ID pipeline including FDR filtering| #### Bonus task: Identification using several search engines @@ -814,51 +774,50 @@ It has become widely accepted that the parallel usage of different search engine rates in shotgun proteomics experiments. The ConsensusID algorithm is based on the calculation of posterior error probabilities (PEP) and a combination of the normalized scores by considering missing peptide sequences. -- Next to the `OMSSAAdapter` and a `XTandemAdapter` **Community Nodes** > **OpenMS** > **Identification** node and set - its parameters and ports analogously to the `OMSSAAdapter`. In XTandem, to get more evenly distributed scores, we +- Next to the `CometAdapter` add a `XTandemAdapter` **Community Nodes** > **OpenMSThirdParty** > **Identification of Proteins** > **Peptides(SearchEngines)** node and set + its parameters and ports analogously to the `CometAdapter`. In XTandem, to get more evenly distributed scores, we decrease the number of candidates a bit by setting the precursor mass tolerance to 5 ppm and the fragment mass tolerance to 0.1 Da. -- To calculate the PEP, introduce each a `IDPosteriorErrorProbability` **Community Nodes** > **OpenMS** > **ID Processing** +- To calculate the PEP, introduce a `IDPosteriorErrorProbability` **Community Nodes** > **OpenMS** > **Identification Processing** node to the output of each ID engine adapter node. This will calculate the PEP to each hit and output an updated idXML. - To create a consensus, we must first merge these two files with a `FileMerger` node **Community Nodes** > **GenericKnimeNode** > **Flow** so we can then merge the corresponding IDs with a `IDMerger` **Community Nodes** > **OpenMS** > **File Handling**. -- Now we can create a consensus identification with the `ConsensusID` **Community Nodes** > **OpenMS** > **ID Processing** +- Now we can create a consensus identification with the `ConsensusID` **Community Nodes** > **OpenMS** > **Identification Processing** node. We can connect this to the `PeptideIndexer` and go along with our existing FDR filtering. ```{note} - By default, X!Tandem takes additional enzyme-cutting rules into consideration (besides the specified tryptic digest). + By default, X!Tandem takes additional enzyme cutting rules into consideration (besides the specified tryptic digest). Thus for the tutorial files, you have to set PeptideIndexer’s `enzyme→specificity` parameter to `none` to accept - X!Tandems non-tryptic identifications as well. + X!Tandem's non-tryptic identifications as well. ``` -In the end, the ID processing part of the workflow can be collapsed into a Metanode to keep the structure clean (see the below figure which shows the complete consensus identification workflow). +In the end, the ID processing part of the workflow can be collapsed into a Metanode to keep the structure clean (see below figure which shows complete consensus identification workflow). |![Complete consensus identification workflow](/images/openms-user-tutorial/labelfree/PepConsensusId.png)| |:--:| |Figure 13: Complete consensus identification workflow| -### Quantification +### Feature Mapping -Now that we have successfully constructed a peptide identification pipeline, we can -add quantification capabilities to our workflow. +Now that we have successfully constructed a peptide identification pipeline, we can assign this information to the corresponding feature signals. - Add a `FeatureFinderCentroided` node from **Community Nodes** > **OpenMS** > **Quantitation** -which gets input from the first output port of the `ZipLoopStart` node. Also, add -an `IDMapper` node (from **Community Nodes** > **OpenMS** > **ID Processing** ) which receives -input from the `FeatureFinderCentroided` node (Port 1) and the ID Metanode (or **IDFilter** node (Port 0) if you haven’t used the Metanode). The output of the `IDMapper` node is then connected to an in port of the `ZipLoopEnd` node. + which gets input from the first output port of the `ZipLoopStart` node. Also, add + an `IDMapper` node (from **Community Nodes** > **OpenMS** > **Identification Processing** ) which receives + input from the `FeatureFinderCentroided` node (Port 1) and the `IDFilter` node (Port 0). The output of the `IDMapper` node is then connected to an in port of the `ZipLoopEnd` node. - `FeatureFinderCentroided` finds and quantifies peptide ion signals contained in -the MS1 data. It reduces the entire signal, i.e., all peaks explained by one and -the same peptide ion signal, to a single peak at the maximum of the chromatographic elution profile of the monoisotopic mass trace of this peptide ion and -assigns an overall intensity. + the MS1 data. It reduces the entire signal, i.e., all peaks explained by one and + the same peptide ion signal, to a single peak at the maximum of the chromatographic elution profile of the monoisotopic mass trace of this peptide ion and + assigns an overall intensity. - `FeatureFinderCentroided` produces a featureXML file as output, containing only quantitative information of so-far unidentified peptide signals. In order to annotate these with the corresponding ID information, we need the `IDMapper` node. -- Run your pipeline and inspect the results of the `IDMapper` node in TOPPView. Open the mzML file of your data to display the raw peak intensities. +- Run your pipeline and inspect the results of the `IDMapper` node in TOPPView. Open the mzML file of your data to display the raw peak intensities. - To assess how well the feature finding worked, you can project the features contained in the featureXML file on the raw data contained in the mzML file. To -this end, open the featureXML file in TOPPView by clicking on File Open file and add it to a new layer ( Open in New layer ). The features are now visualized on top of your raw data. If you zoom in on a small region, you should be able to see the individual boxes around features that have been detected (see Fig. 14). If you -hover over the feature centroid (small circle indicating the chromatographic apex of the monoisotopic trace) additional information about the feature is displayed. + this end, open the featureXML file in TOPPView by clicking on File Open file and add it to a new layer ( Open in New layer ). The features are now visualized on top of your raw data. If you zoom in on a small region, you should be able to see the individual boxes around features that have been detected (see Fig. 14). If you + hover over the the feature centroid (small circle indicating the chromatographic apex of monoisotopic trace) additional information of the feature is displayed. |![Visualization of detected features (boxes) in TOPPView](/images/openms-user-tutorial/labelfree/featureXML.png)| - |:--:| + |:--:| |Figure 14: Visualization of detected features (boxes) in TOPPView| ```{note} @@ -868,33 +827,34 @@ hover over the feature centroid (small circle indicating the chromatographic ape dragging a narrow box from the very left to the very right ``` - You can see which features were annotated with a peptide identification by first -selecting the featureXML file in the **Layers** window on the upper right side and then clicking on the icon with the letters A, B and C on the upper icon bar. Now, -click on the small triangle next to that icon and select **Peptide identification**. + selecting the featureXML file in the **Layers** window on the upper right side and then clicking on the icon with the letters A, B and C on the upper icon bar. Now, + click on the small triangle next to that icon and select **Peptide identification**. The following image shows the final constructed workflow: -|![Extended workflow featuring peptide identification and quantification](/images/openms-user-tutorial/labelfree/PepQuantIdNoAlign.png)| -|:--:| -|Figure 15: Extended workflow featuring peptide identification and quantification| +| ![Extended workflow featuring peptide identification and quantification](/images/openms-user-tutorial/labelfree/PepQuantIdNoAlign.png) | +|:--------------------------------------------------------------------------------------------------------------------------------------:| +| Figure 15: Extended workflow featuring peptide identification and feature mapping. | -### Combining quantitative information across several label-free experiments +### Combining features across several label-free experiments -So far, we successfully performed peptide identification as well as quantification on -individual LC-MS runs. For differential label-free analyses, however, we need to identify and quantify corresponding signals in different experiments and link them together to compare their intensities. Thus, we will now run our pipeline on all three +So far, we successfully performed peptide identification as well as feature mapping on +individual LC-MS runs. For differential label-free analyses, however, we need to identify and map corresponding signals in different experiments and link them together to compare their intensities. Thus, we will now run our pipeline on all three available input files and extend it a bit further, so that it is able to find and link features across several runs. -|![Complete identification and label-free quantification workflow](/images/openms-user-tutorial/labelfree/PepQuantId.png)| -|:--:| -|Figure 16: Complete identification and label-free quantification workflow| +| ![Complete identification and label-free quantification workflow](/images/openms-user-tutorial/labelfree/PepQuantId.png) | +|:-----------------------------------------------------------------------------------------------------------------------------------------:| +| Figure 16: Complete identification and label-free feature mapping workflow. The identification nodes are grouped together as ID metanode. | -- To find features across several maps, we first have to align them to correct retention time shifts between the different label-free measurements. With the **MapAlignerPoseClustering** node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can align corresponding peptide signals to each other as closely as possible by applying a transformation in the RT dimension. +- To link features across several maps, we first have to align them to correct for retention time shifts between the different label-free measurements. With the `MapAlignerPoseClustering` node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can align corresponding peptide signals to each other as closely as possible by applying a transformation in the RT dimension. ```{note} `MapAlignerPoseClustering` consumes several featureXML files and its output should still be several featureXML files containing the same features, but with the transformed RT values. In its configuration dialog, make sure that **OutputTypes** is set to **featureXML**. ``` -- With the **FeatureLinkerUnlabeledQT** node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can then perform the actual linking of corresponding features. Its output is a consensusXML file containing linked groups of corresponding features across the different experiments. -- Since the overall intensities can vary a lot between different measurements (for example, because the amount of injected analytes was different), we apply the **ConsensusMapNormalizer** node in **Community Node** > **OpenMS** > **Map Alignment** as a last processing step. Configure its parameters by setting `algorithm_type` to `median`. It will then normalize the maps in such a way that the median intensity of all input maps is equal. -- Finally, export the resulting normalized consensusXML file to a csv format using the **TextExporter** node. Connect its out port to a new **Output Folder** node. +- With the `FeatureLinkerUnlabeledQT` node in **Community Nodes** > **OpenMS** > **Map Alignment**, we can then perform the actual linking of corresponding features. Its output is a consensusXML file containing linked groups of corresponding features across the different experiments. +- Since the overall intensities can vary a lot between different measurements (for example, because the amount of injected analytes was different), we apply the **ConsensusMapNormalizer** node in **Community Node** > **OpenMS** > **Map Alignment** as a last processing step. Configure its parameters with setting `algorithm_type` to `median`. It will then normalize the maps in such a way that the median intensity of all input maps is equal. +- Export the resulting normalized consensusXML file to a csv format using the **TextExporter** node. +- Use the `ConsensusTextReader` node in **Community Nodes** > **OpenMS** > **Conversion** to convert the output into a KNIME table. After running the node you can view the KNIME table by right-clicking on the `ConsensusTextReader` node and selecting `Consensus Table`. Every row in this table corresponds to a so-called consensus feature, i.e., a peptide signal quantified across several runs. The first couple of columns describe the consensus feature as a whole (average RT and m/z across the maps, charge, etc.). The remaining columns describe the exact positions and intensities of the quantified features separately for all input samples (e.g., intensity_0 is the intensity of the feature in the first input file). The last 11 columns contain information on peptide identification. ```{note} You can specify the desired column separation character in the parameter settings (by default, it is set to “ ” (a space)). The output file of `TextExporter` can also be opened with external tools, e.g., Microsoft Excel, for downstream statistical analyses. @@ -902,13 +862,13 @@ available input files and extend it a bit further, so that it is able to find an #### Basic data analysis in KNIME -For downstream analysis of the quantification results within the KNIME environment, you can use the **ConsensusTextReader** node in **Community Nodes** > **OpenMS** > **Conversion** instead of the **Output Folder** node to convert the output into a KNIME table (indicated by a triangle as output port). After running the node you can view the KNIME table by right-clicking on the **ConsensusTextReader** node and selecting `Consensus Table`. Every row in this table corresponds to a so-called consensus feature, i.e., a peptide signal quantified across several runs. The first couple of columns describe the consensus feature as a whole (average RT and m/z across the maps, charge, etc.). The remaining columns describe the exact positions and intensities of the quantified features separately for all input samples (e.g., intensity_0 is the intensity of the feature in the first input file). The last 11 columns contain information on peptide identification. +In this section we are going to use the output of the `ConsensusTextReader` for downstream analysis of the quantification results: -- Now, let’s say we want to plot the log intensity distributions of the human spike-in peptides for all input files. In addition, we will plot the intensity distributions of the background peptides. -- As shown in Fig. 17, add a **Row Splitter** node (**Data Manipulation** > **Row** > **Filter**) after the **ConsensusTextReader** node. Double-click it to configure. The human spike-in peptides have accessions starting with “hum”. Thus, set the column to apply the test to: accessions, select pattern matching as a matching criterion, enter `hum` into the corresponding text field, and check the contains wild cards box. Press **OK** and execute the node. -- **Row Splitter** produces two output tables: the first one contains all rows from the input table matching the filter criterion, and the second table contains all other rows. You can inspect the tables by right-clicking and selecting **Filtered** and **Filtered Out**. The former table should now only contain peptides with a human accession, whereas the latter should contain all remaining peptides (including unidentified ones). -- Now, since we only want to plot intensities, we can add a **Column Filter** node by going to **Data Manipulation** > **Column Filter**. Connect its input port to the **Filtered output** port of the **Row Filter** node, and open its configuration dialog. We could either manually select the columns we want to keep, or, more elegantly, select **Wildcard/Regex Selection** and enter `intensity_?` as the pattern. KNIME will interactively show you which columns your pattern applies to while you’re typing. -- Since we want to plot log intensities, we will now compute the log of all intensity values in our table. The easiest way to do this in KNIME is a small piece of R code. Add an **R Snippet** node `R` after **Column Filter** and double-click to configure. In the R Script text editor, enter the following code: +- Let’s say we want to plot the log intensity distributions of the human spike-in peptides for all input files. In addition, we will plot the intensity distributions of the background peptides. +- As shown in Fig. 17, add a `Row Splitter` node (**Data Manipulation** > **Row** > **Filter**) after the `ConsensusTextReader` node. Double-click it to configure. The human spike-in peptides have accessions starting with “hum”. Thus, set the column to apply the test to `accessions`, select pattern matching as matching criterion, enter `hum*` into the corresponding text field, and check the contains wild cards box. Press **OK** and execute the node. +- `Row Splitter` produces two output tables: the first one contains all rows from the input table matching the filter criterion, and the second table contains all other rows. You can inspect the tables by right-clicking and selecting **Filtered** and **Filtered Out**. The former table should now only contain peptides with a human accession, whereas the latter should contain all remaining peptides (including unidentified ones). +- Now, since we only want to plot intensities, we can add a `Column Filter` node by going to **Data Manipulation** > `Column Filter`. Connect its input port to the **Filtered output** port of the **Row Filter** node, and open its configuration dialog. We could either manually select the columns we want to keep, or, more elegantly, select **Wildcard/Regex Selection** and enter `intensity_?` as the pattern. KNIME will interactively show you which columns your pattern applies to while you’re typing. +- Since we want to plot log intensities, we will now compute the log of all intensity values in our table. The easiest way to do this in KNIME is a small piece of R code. Add an **R Snippet** node `R` after `Column Filter` and double-click to configure. In the R Script text editor, enter the following code: ```r x <- knime.in # store copy of input table in x @@ -918,10 +878,10 @@ For downstream analysis of the quantification results within the KNIME environme x <- log10(x) # compute log of all values knime.out <- x # write result to output table ``` -- Now we are ready to plot! Add a **Box Plot (local)** node `Views -Swing (local)` after the **R Snippet** node, execute it, and open its view. If everything went well, you should see a significant fold change in your human peptide intensities across the three runs. -- To verify that the concentration of background peptides is constant in all three runs, copy and paste the three nodes after **Row Splitter** and connect the duplicated **Column Filter** to the second output port (Filtered Out) of **Row Splitter**, as shown in Fig. 17. Execute and open the view of your second **Box Plot**. +- Now we are ready to plot! Add a `Box Plot (JavaScript)` node `Views -JavaScript` after the **R Snippet** node, execute it, and open its view. If everything went well, you should see a significant fold change of your human peptide intensities across the three runs. +- To verify that the concentration of background peptides is constant in all three runs, copy and paste the three nodes after `Row Splitter` and connect the duplicated `Column Filter` to the second output port (Filtered Out) of `Row Splitter`, as shown in Fig. 17. Execute and open the view of your second **Box Plot**. -You have now constructed an entire identification and label-free quantification workflow including a simple data analysis using KNIME. The final workflow should be like the workflow shown in the following image: +You have now constructed an entire identification and label-free feature mapping workflow including a simple data analysis using KNIME. The final workflow should like the workflow shown in the following image: |![Simple KNIME data analysis example for LFQ](/images/openms-user-tutorial/labelfree/data_analysis.png)| |:--:| @@ -930,18 +890,18 @@ You have now constructed an entire identification and label-free quantification ### Identification and quantification of the iPRG2015 data with subsequent MSstats analysis Advanced downstream data analysis of quantitative mass spectrometry-based proteomics data can be performed using MSstats[^11]. This tool can be combined with -an OpenMS preprocessing pipeline (e.g. in KNIME). The OpenMS experimental design is used to present the data in an MSstats-conformant way for analysis. Here, -we give an example of how to utilize these resources when working with quantitative label-free data. We describe how to use OpenMS and MSstats for the analysis of the +an OpenMS preprocessing pipeline (e.g. in KNIME). The OpenMS experimental design is used to present the data in an MSstats-conformant way for the analysis. Here, +we give an example how to utilize these resources when working with quantitative label-free data. We describe how to use OpenMS and MSstats for the analysis of the ABRF iPRG2015 dataset[^12]. ```{note} -Reanalyzing the full dataset from scratch would take too long. In the following tutorial, we will focus on just the conversion process and the downstream analysis. +Reanalysing the full dataset from scratch would take too long. In the following tutorial, we will focus on just the conversion process and the downstream analysis. ``` #### Excursion MSstats -The R package `MSstats` can be used for statistical relative quantification of proteins and peptides in mass spectrometry-based proteomics. Supported are label-free as well as labeled experiments in combination with data-dependent, targeted, and data independent acquisition. Inputs can be identified and quantified entities (peptides or proteins) and the output is a list of differentially abundant entities or summaries of their relative abundance. It depends on accurate feature detection, identification -, and quantification which can be performed e.g. by an OpenMS workflow. MSstats can be used for data processing & visualization, as well as statistical modeling & inference. Please see [^11] and the [MSstats](http://msstats.org) website for further +The R package `MSstats` can be used for statistical relative quantification of proteins and peptides in mass spectrometry-based proteomics. Supported are label-free as well as labeled experiments in combination with data-dependent, targeted and data independent acquisition. Inputs can be identified and quantified entities (peptides or proteins) and the output is a list of differentially abundant entities, or summaries of their relative abundance. It depends on accurate feature detection, identification +and quantification which can be performed e.g. by an OpenMS workflow. MSstats can be used for data processing & visualization, as well as statistical modeling & inference. Please see [^11] and the [MSstats](http://msstats.org) website for further information. #### Dataset @@ -982,15 +942,15 @@ quantities [fmols] |:--:| |Figure 18: KNIME data analysis of iPRG LFQ data.| -The iPRG LFQ workflow (Fig. 18) consists of an identification and a quantification part. The identification is achieved by searching the computationally calculated MS2 spectra from a sequence database (**Input File** node, here with the given database from iPRG: +The iPRG LFQ workflow (Fig. 18) consists of an identification and a quantification part. The identification is achieved by searching the computationally calculated MS2 spectra from a sequence database (`File Importer` node, here with the given database from iPRG: {path}`ExampleData,iPRG2015,database,iPRG2015targetdecoynocontaminants.fasta` -against the MS2 from the original data (`Input Files` node with all mzMLs following {path}`ExampleData,iPRG2015,datasets,JD06232014sample*.mzML` using the `OMSSAAdapter`. +against the MS2 from the original data (`Input Files` node with all mzMLs following {path}`ExampleData,iPRG2015,datasets,JD06232014sample*.mzML` using the `CometAdapter`. ```{note} If you want to reproduce the results at home, you have to download the iPRG data in mzML format and perform peak picking on it or convert and pick the raw data with `msconvert`. ``` -Afterwards, the results are scored using the **FalseDiscoveryRate** node and filtered to obtain only unique peptides (**IDFilter**) since `MSstats` does not support shared peptides, yet. The quantification is achieved by using the `FeatureFinderCentroided` node, which performs the feature detection on the samples (maps). In the end, the quantification results are combined with the filtered identification results (`IDMapper`). In addition, a linear retention time alignment is performed (**MapAlignerPoseClustering**), followed by the feature linking process (**FeatureLinkerUnlabledQT**). The **ConsensusMapNormalizer**s is used to normalize the intensities via robust regression over a set of maps and the **IDConflictResolver** assures that only one identification (best score) is associated with a feature. The output of this workflow is a consensusXML file, which can now be converted using the **MSstatsConverter** (see Conversion and downstream analysis section). +Afterwards, the results are scored using the **FalseDiscoveryRate** node and filtered to obtain only unique peptides (`IDFilter`) since `MSstats` does not support shared peptides, yet. The quantification is achieved by using the `FeatureFinderCentroided` node, which performs the feature detection on the samples (maps). In the end the quantification results are combined with the filtered identification results (`IDMapper`). In addition, a linear retention time alignment is performed (`MapAlignerPoseClustering`), followed by the feature linking process (**FeatureLinkerUnlabledQT**). The **ConsensusMapNormalizer**s is used to normalize the intensities via robust regression over a set of maps and the `IDConflictResolver` assures that only one identification (best score) is associated with a feature. The output of this workflow is a consensusXML file, which can now be converted using the `MSStatsConverter` (see Conversion and downstream analysis section). #### Experimental design @@ -1073,7 +1033,7 @@ The conditions are highly dependent on the type of experiment and on which kind #### Conversion and downstream analysis -Conversion of the OpenMS-internal consensusXML format (which is an aggregation of quantified and possibly identified features across several MS-maps) to a table (in MSstats-conformant CSV format) is very easy. First, create a new KNIME workflow. Then, run the **MSstatsConverter** node with a consensusXML and the manually created (e.g. in Excel) experimental design as inputs (loaded via **Input File** nodes). The first input can be found in: +Conversion of the OpenMS-internal consensusXML format (which is an aggregation of quantified and possibly identified features across several MS-maps) to a table (in MSstats-conformant CSV format) is very easy. First, create a new KNIME workflow. Then, run the `MSStatsConverter` node with a consensusXML and the manually created (e.g. in Excel) experimental design as inputs (loaded via `File Importer` nodes). The first input can be found in: {path}`ExampleData,iPRG2015,openmsLFQResults,iPRGlfq.consensusXML` @@ -1090,17 +1050,17 @@ Adjust the parameters in the config dialog of the converter to match the given e |*labeled_reference_peptides*|false| |*retention_time_summarization_method (advanced)*|sum| -The downstream analysis of the peptide ions with `MSstats` is performed in several steps. These steps are reflected by several KNIME R nodes, which consume the output of **MSstatsConverter**. The outline of the workflow is shown in Figure 19. +The downstream analysis of the peptide ions with `MSstats` is performed in several steps. These steps are reflected by several KNIME R nodes, which consume the output of `MSStatsConverter`. The outline of the workflow is shown in Figure 19. |![MSstats analysis using KNIME](/images/openms-user-tutorial/labelfree/MSstats.png)| |:--:| |Figure 19: MSstats analysis using KNIME. The individual steps (Preprocessing, Group Comparisons, Result Data Renaming, and Export) are split among several consecutive nodes.| -We load the file resulting from **MSStatsConverter** either by saving it with an **Output File** node and reloading it with the **File Reader**. Alternatively, for advanced users, you can use a URI Port to Variable node and use the variable in the File Reader config dialog (**V** button - located on the right of the **Browse** button) to read from the temporary file. +We load the file resulting from `MSStatsConverter` either by saving it with an `Output File` node and reloading it with the `File Reader`. Alternatively, for advanced users, you can use a URI Port to Variable node and use the variable in the File Reader config dialog (**V** button - located on the right of the **Browse** button) to read from the temporary file. ##### Preprocessing -The first node (**Table to R**) loads `MSstats` as well as the data from the previous KNIME node and performs a preprocessing step on the input data. The following inline R script ( needs to be pasted into the config dialog of the node): +The first node (`Table to R`) loads `MSstats` as well as the data from the previous KNIME node and performs a preprocessing step on the input data. The following inline R script ( needs to be pasted into the config dialog of the node): ```r library(MSstats) @@ -1108,7 +1068,7 @@ data <- knime.in quant <- OpenMStoMSstatsFormat(data, removeProtein_with1Feature = FALSE) ``` -The inline R script allows further preparation of the data produced by **MSstatsConverter** before the actual analysis is performed. In this example, the lines with proteins, which were identified with only one feature, were retained. Alternatively, they could be removed. +The inline R script allows further preparation of the data produced by `MSStatsConverter` before the actual analysis is performed. In this example, the lines with proteins, which were identified with only one feature, were retained. Alternatively they could be removed. In the same node, most importantly, the following line transforms the data into a format that is understood by `MSstats`: ```r @@ -1132,9 +1092,9 @@ The goal of the analysis is the determination of differentially-expressed protei This matrix has the following properties: -- The number of rows equals the number of comparisons that we want to perform, the number of columns equals the number of conditions (here, column 1 refers to C1, column 2 to C2, and so forth). +- The number of rows equals the number of comparisons that we want to perform, the number of columns equals the number of conditions (here, column 1 refers to C1, column 2 to C2 and so forth). - The entries of each row consist of exactly one 1 and one -1, the others must be 0. -- The condition with the entry `1` constitutes the enumerator of the log2 fold-change. The one with entry `-1` denotes the denominator. Hence, the first row states that we want to calculate: +- The condition with the entry `1` constitutes the enumerator of the log2 fold-change. The one with entry `-1` denotes the denominator. Hence, the first row states that we want calculate: ```{math} \begin{equation} \log_2 \frac{C_{2}}{C_{1}} \end{equation} ``` @@ -1280,17 +1240,17 @@ the files in the Input Files nodes (don’t forget the one for the FASTA databas We have made the following changes compared to the original label-free quantification workflow from the last chapter: - First, we have added a **ProteinQuantifier** node and connected its input port to the output port of the **ConsensusMapNormalizer** node. -- This already enables protein quantification. **ProteinQuantifier** quantifies peptides by summarizing overall observed charge states and proteins by summarizing their quantified peptides. It stores two output files, one for the quantified peptides and one for the proteins. +- This already enables protein quantification. **ProteinQuantifier** quantifies peptides by summarizing over all observed charge states and proteins by summarizing over their quantified peptides. It stores two output files, one for the quantified peptides and one for the proteins. - In this example, we consider only the protein quantification output file, which is written to the first output port of **ProteinQuantifier**. -- Because there is no dedicated node in KNIME to read back the **ProteinQuantifier** output file format into a KNIME table, we have to use a workaround. Here, we have added an additional URI Port to the Variable node which converts the name of the output file to a so-called “flow variable” in KNIME. This variable is passed on to the next node **CSV Reader**, where it is used to specify the name of the input file to be read. If you double-click on **CSV Reader**, you will see that the text field, where you usually enter the location of the CSV file to be read, is greyed out. Instead, the flow variable is used to specify the location, as indicated by the small green button with the “v=?” label on the right. +- Because there is no dedicated node in KNIME to read back the **ProteinQuantifier** output file format into a KNIME table, we have to use a workaround. Here, we have added an additional URI Port to Variable node which converts the name of the output file to a so-called “flow variable” in KNIME. This variable is passed on to the next node **CSV Reader**, where it is used to specify the name of the input file to be read. If you double-click on **CSV Reader**, you will see that the text field, where you usually enter the location of the CSV file to be read, is greyed out. Instead, the flow variable is used to specify the location, as indicated by the small green button with the “v=?” label on the right. - The table containing the **ProteinQuantifier** results is filtered one more time in order to remove decoy proteins. You can have a look at the final list of quantified protein groups by right-clicking the **Row Filter** and selecting **Filtered**. - By default, i.e., when the second input port `protein_groups` is not used, **ProteinQuantifier** quantifies proteins using only the unique peptides, which usually results in rather low numbers of quantified proteins. - In this example, however, we have performed protein inference using Fido and -used the resulting protein grouping information to also quantify indistinguishable proteins. In fact, we also used a greedy method in **FidoAdapter** (parameter `greedy_group_resolution`) to uniquely assign the peptides of a group to the most probable protein(s) in the respective group. This boosts the number of quantifications but slightly raises the chances to yield distorted protein quantities. + used the resulting protein grouping information to also quantify indistinguishable proteins. In fact, we also used a greedy method in **FidoAdapter** (parameter `greedy_group_resolution`) to uniquely assign the peptides of a group to the most probable protein(s) in the respective group. This boosts the number of quantifications but slightly raises the chances to yield distorted protein quantities. - As a prerequisite for using **FidoAdapter**, we have added an **IDPosteriorErrorProbability** node within the ID meta node, between the **XTandemAdapter** (note the replacement of OMSSA because of ill-calibrated scores) and **PeptideIndexer**. We have -set its parameter `prob_correct` to `true`, so it computes posterior probabilities instead of posterior error probabilities (1 - PEP). These are stored in the resulting idXML file and later on, used by the Fido algorithm. Also, note that we excluded FDR filtering from the standard meta node. Harsh filtering before inference impacts the calibration of the results. Since we filter peptides before quantification though, no potentially random peptides will be included in the results anyway. -- Next, we added a third outgoing connection to our ID meta node and connected it to the second input port of `ZipLoopEnd`. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. -- Instead of the meta node **Protein inference** with **FidoAdapter**, we could have just used a **FidoAdapter** node ( **Community Nodes** > **OpenMS** > **ID Processing**). However, the meta node contains an additional subworkflow which, besides calling **FidoAdapter**, performs a statistical validation (e.g. (pseudo) receiver operating curves; ROCs) of the protein inference results using some of the more advanced KNIME and R nodes. The meta node also shows how to use **MzTabExporter** and **MzTabReader**. + set its parameter `prob_correct` to `true`, so it computes posterior probabilities instead of posterior error probabilities (1 - PEP). These are stored in the resulting idXML file and later on used by the Fido algorithm. Also note that we excluded FDR filtering from the standard meta node. Harsh filtering before inference impacts the calibration of the results. Since we filter peptides before quantification though, no potentially random peptides will be included in the results anyway. +- Next, we have added a third outgoing connection to our ID meta node and connected it to the second input port of `ZipLoopEnd`. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. +- Instead of the meta node **Protein inference** with **FidoAdapter**, we could have just used a **FidoAdapter** node ( **Community Nodes** > **OpenMS** > **Identification Processing**). However, the meta node contains an additional subworkflow which, besides calling **FidoAdapter**, performs a statistical validation (e.g. (pseudo) receiver operating curves; ROCs) of the protein inference results using some of the more advanced KNIME and R nodes. The meta node also shows how to use **MzTabExporter** and **MzTabReader**. ### Statistical validation of protein inference results @@ -1300,17 +1260,17 @@ In the following section, we will explain the subworkflow contained in the **Pro For downstream analysis on the protein ID level in KNIME, it is again necessary to convert the idXML-file-format result generated from **FidoAdapter** into a KNIME table. -- We use the **MzTabExporter** to convert the inference results from **FidoAdapter** to a human-readable, tab-separated mzTab file. mzTab contains multiple sections, -that are all exported by default, if applicable. This file, with its different sections, can again be read by the **MzTabReader** that produces one output in KNIME table -format (triangle ports) for each section. Some ports might be empty if a section did not exist. Of course, we continue by connecting the downstream nodes with the protein section output (second port). +- We use the **MzTabExporter** to convert the inference results from **FidoAdapter** to a human readable, tab-separated mzTab file. mzTab contains multiple sections, + that are all exported by default, if applicable. This file, with its different sections can again be read by the **MzTabReader** that produces one output in KNIME table + format (triangle ports) for each section. Some ports might be empty if a section did not exist. Of course, we continue by connecting the downstream nodes with the protein section output (second port). - Since the protein section contains single proteins as well as protein groups, we filter them for single proteins with the standard **Row Filter**. #### ROC curve of protein ID -ROC Curves (Receiver Operating Characteristic curves) are graphical plots that visualize sensitivity (true-positive rate) against fall-out (false positive rate). They are often used to judge the quality of a discrimination method e.g., peptide or protein identification engines. ROC Curve already provides the functionality of drawing ROC curves for binary classification problems. When configuring this node, select the `opt_global_target_decoy` column as the class (i.e. target outcome) column. We want to find out, how well our inferred protein probability discriminates between them, +ROC Curves (Receiver Operating Characteristic curves) are graphical plots that visualize sensitivity (true-positive rate) against fall-out (false positive rate). They are often used to judge the quality of a discrimination method like e.g., peptide or protein identification engines. ROC Curve already provides the functionality of drawing ROC curves for binary classification problems. When configuring this node, select the `opt_global_target_decoy` column as the class (i.e. target outcome) column. We want to find out, how good our inferred protein probability discriminates between them, therefore add `best_search_engine_score[1]` (the inference engine score is treated like a peptide search engine score) to the list of *”Columns containing positive class probabilities”*. View the plot by right-clicking and selecting **View: ROC Curves**. A perfect classifier has -an area under the curve (AUC) of 1.0 and its curve touches the upper left of the plot. However, in protein or peptide identification, the ground truth (i.e., which target -identifications are true, and which are false) is usually not known. Instead, so-called pseudoROC Curves are regularly used to plot the number of target proteins against the false +an area under the curve (AUC) of 1.0 and its curve touches the upper left of the plot. However, in protein or peptide identification, the ground-truth (i.e., which target +identifications are true, which are false) is usually not known. Instead, so called pseudoROC Curves are regularly used to plot the number of target proteins against the false discovery rate (FDR) or its protein-centric counterpart, the q-value. The FDR is approximated by using the target-decoy estimate in order to distinguish true IDs from false IDs by separating target IDs from decoy IDs. @@ -1352,15 +1312,15 @@ Let’s have a look at the workflow (see Fig 23). The full analysis workflow can be found here: {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` -The workflow has four input nodes. The first is for the experimental design to allow for MSstatsTMT compatible export (**MSstatsConverter**). The second is for the `.mzML` files with the centroided spectra from the isobaric labeling experiment and the third one is for the `.fasta` database used for identification. The last one allows to specify an output path for the plots generated by the R View, which runs MSstatsTMT (I). The quantification (A) is performed using the **IsobaricAnalzyer**. The tool is able to extract and normalize quantitative information from TMT and iTRAQ data. The values can be assessed from centroided MS2 or MS3 spectra (if available). Isotope correction is performed based on the specified correction matrix (as provided by the manufacturer). The identification (C) is applied as known from the previous chapters by using a database search and a target-decoy database. +The workflow has four input nodes. The first for the experimental design to allow for MSstatsTMT compatible export (`MSStatsConverter`). The second for the `.mzML` files with the centroided spectra from the isobaric labeling experiment and the third one for the `.fasta` database used for identification. The last one allows to specify an output path for the plots generated by the R View, which runs MSstatsTMT (I). The quantification (A) is performed using the **IsobaricAnalzyer**. The tool is able to extract and normalize quantitative information from TMT and iTRAQ data. The values can be assessed from centroided MS2 or MS3 spectra (if available). Isotope correction is performed based on the specified correction matrix (as provided by the manufacturer). The identification (C) is applied as known from the previous chapters by using database search and a target-decoy database. -To reduce the complexity of the data for later inference the q-value estimation and FDR filtering is performed on PSM level for each file individually (B). Afterwards, the identification (PSM) and quantitative information is combined using the `IDMapper`. After the processing of all available files, the intermediate results are aggregated (**FileMerger** - D). All PSM results are used for score estimation and protein inference (**Epifany**) (E). For detailed information about protein inference please see Chapter 4. Then, decoys are removed and the inference results are filtered via a protein group FDR. Peptide level results can be exported via **MzTabExporter** (F), protein level results can be obtained via the **ProteinQuantifier** (G), or the results can be exported (**MSstatsConverter** - H) and further processed with the following R pipeline to allow for downstream processing using `MSstatsTMT`. +To reduce the complexity of the data for later inference the q-value estimation and FDR filtering is performed on PSM level for each file individually (B). Afterwards the identification (PSM) and quantiative information is combined using the `IDMapper`. After the processing of all available files, the intermediate results are aggregated (**FileMerger** - D). All PSM results are used for score estimation and protein inference (**Epifany**) (E). For detailed information about protein inference please see Chaper 4. Then, decoys are removed and the inference results are filtered via a protein group FDR. Peptide level results can be exported via **MzTabExporter** (F), protein level results can be obtained via the **ProteinQuantifier** (G) or the results can exported (`MSStatsConverter` - H) and further processed with the following R pipeline to allow for downstream processing using `MSstatsTMT`. Please import the workflow from {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. Before you can execute the workflow, you have to correct the locations of the files in the `Input Files` nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. ### Excursion MSstatsTMT -The R package `MSstatsTMT` can be used for protein significance analysis in shotgun mass spectrometry-based proteomic experiments with tandem mass tag (TMT) labeling. `MSstatsTMT` provides functionality for two types of analysis & their visualization: Protein summarization based on peptide quantification and Model-based group comparison to detect significant changes in abundance. It depends on accurate feature detection, identification, and quantification which can be performed e.g. by an OpenMS workflow. +The R package `MSstatsTMT` can be used for protein significance analysis in shotgun mass spectrometry-based proteomic experiments with tandem mass tag (TMT) labeling. `MSstatsTMT` provides functionality for two types of analysis & their visualization: Protein summarization based on peptide quantification and Model-based group comparison to detect significant changes in abundance. It depends on accurate feature detection, identification and quantification which can be performed e.g. by an OpenMS workflow. In general, `MSstatsTMT` can be used for data processing & visualization, as well as statistical modeling. Please see [^13] and the [MSstats](http://msstats.org/msstatstmt/) website for further information. @@ -1375,7 +1335,7 @@ We are using the MSV000084264 ground truth dataset, which consists of TMT10plex |:--:| |Figure 24: Experimental Design| -The experimental design in a table format allows for `MSstatsTMT` compatible export. The design is represented by two tables. The first one 4 represents the overall structure of the experiment in terms of samples, fractions, labels, and fraction groups. The second one 5 adds to the first by specifying specific conditions, biological replicates as well as mixtures and labels for each channel. For additional information about the experimental design please see Table 3. +The experimental design in table format allows for `MSstatsTMT` compatible export. The design is represented by two tables. The first one 4 represents the overall structure of the experiment in terms of samples, fractions, labels and fraction groups. The second one 5 adds to the first by specifying specific conditions, biological replicates as well as mixtures and label for each channel. For additional information about the experimental design please see Table 3.
@@ -1428,8 +1388,8 @@ The experimental design in a table format allows for `MSstatsTMT` compatible exp

- - + +
Table 5: Experimental Design 2
@@ -1465,7 +1425,7 @@ The experimental design in a table format allows for `MSstatsTMT` compatible exp -After running the worklfow, the **MSstatsConverter** will convert the OpenMS output in addition with the experimental design to a file (.csv) which can be processed by using `MSstatsTMT`. +After running the worklfow, the `MSStatsConverter` will convert the OpenMS output in addition with the experimental design to a file (.csv) which can be processed by using `MSstatsTMT`. #### MSstatsTMT analysis @@ -1476,9 +1436,9 @@ Here, we depict the analysis by `MSstatsTMT` using a segment of the isobaric ana |:--:| |Figure 25: MSstatsTMT workflow segment| -There are two input nodes, the first one takes the result (.csv) from the **MSstatsConverter** and the second a path to the directory where the plots generated by `MSstatsTMT` should be saved. The **R source** node loads the required packages, such as `dplyr` for data wrangling, `MSstatsTMT` for analysis and `MSstats` for plotting. The inputs are further processed in the **R View** node. +There are two input nodes, the first one takes the result (.csv) from the `MSStatsConverter` and the second a path to the directory where the plots generated by `MSstatsTMT` should be saved. The **R source** node loads the required packages, such as `dplyr` for data wrangling, `MSstatsTMT` for analysis and `MSstats` for plotting. The inputs are further processed in the **R View** node. -Here, the data of the **Input File** is loaded into **R** using the flow variable [”URI-0”]: +Here, the data of the `File Importer` is loaded into **R** using the flow variable [”URI-0”]: ```r file <- substr(knime.flow.in[["URI-0"]], 6, nchar(knime.flow.in[["URI-0"]])) @@ -1584,11 +1544,11 @@ why we need a different feature finder for metabolites lies in the step after tr have very different isotopic distributions. To group small molecule mass traces correctly, an aggregation model tailored to small molecules is thus needed. - Create a new workflow called for instance ”Metabolomics”. -- Add an **Input File** node and configure it with one mzML file from the {path}`Example_Data,Metabolomics,datasets`. -- Add a **FeatureFinderMetabo** node (from **Community Nodes** > **OpenMS** > **Quantitation**) and -connect the first output port of the **Input File** to the **FeatureFinderMetabo**. +- Add an `File Importer` node and configure it with one mzML file [from the](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/) {path}`Example_Data,Metabolomics,datasets`. +- Add a `FeatureFinderMetabo` node (from **Community Nodes** > **OpenMS** > **Quantitation**) and + connect the first output port of the `File Importer` to the `FeatureFinderMetabo`. - For an optimal result adjust the following settings. Please note that some of these are advanced parameters. -- Connect a **Output Folder** to the output of the **FeatureFinderMetabo** (see Fig. 27). +- Connect a `Output Folder` to the output of the `FeatureFinderMetabo` (see Fig. 27). (Figure_27)= |![FeatureFinderMetabo workflow](/images/openms-user-tutorial/metabo/minimal_FFM_wf.png)| @@ -1606,19 +1566,19 @@ In the following advanced parameters will be highlighted. These parameter can be |*algorithm*→*epd*→*width_filtering*|off| |*algorithm*→*ffm*→*report_convex_hulls*|true| -The parameters change the behavior of **FeatureFinderMetabo** as follows: +The parameters change the behavior of `FeatureFinderMetabo` as follows: - **chrom_fwhm**: The expected chromatographic peak width in seconds. -- **trace_termination_criterion**: In the first stage **FeatureFinderMetabo** assembles -mass traces with a pre-defined mass accuracy. If this parameter is set to ’outlier’, the extension of a mass trace is stopped after a predefined number of consecutive outliers is found. If this parameter is set to ’sample_rate’, the extension of a mass trace is stopped once the ratio of collected peaks versus visited spectra falls below the ratio given by `min_sample_rate`. +- **trace_termination_criterion**: In the first stage `FeatureFinderMetabo` assembles + mass traces with a pre-defined mass accuracy. If this parameter is set to ’outlier’, the extension of a mass trace is stopped after a predefined number of consecutive outliers is found. If this parameter is set to ’sample_rate’, the extension of a mass trace is stopped once the ratio of collected peaks versus visited spectra falls below the ratio given by `min_sample_rate`. - **min_trace_length**: Minimal length of a mass trace in seconds. Choose a small value, if you want to identify low-intensity compounds. - **max_trace_length**: Maximal length of a mass trace in seconds. Set this parameter to -1 to disable the filtering by maximal length. -- **width_filtering**: **FeatureFinderMetabo** can remove features with unlikely peak widths from the results. If activated it will use the interval provided by the parameters `min_fwhm` and `max_fwhm`. +- **width_filtering**: `FeatureFinderMetabo` can remove features with unlikely peak widths from the results. If activated it will use the interval provided by the parameters `min_fwhm` and `max_fwhm`. - **report_convex_hulls**: If set to true, convex hulls including mass traces will be reported for all identified features. This increases the output size considerably. -The output file .featureXML can be visualized with TOPPView on top of the used `.mzML` file - in a so-called layer - to look at the identified features. +The output file .featureXML can be visualized with TOPPView on top of the used `.mzML` file - in a so called layer - to look at the identified features. -First start TOPPView and open the example `.mzML` file (see Fig. 28). Afterwards, open the `.featureXML` output as a new layer (see Fig. 29). The overlay is depicted in Figure 30. The zoom of the `.mzML` - `.featureXML` overlay shows the individual mass traces and the assembly of those in a feature (see Fig. 31). +First start TOPPView and open the example `.mzML` file (see Fig. 28). Afterwards open the `.featureXML` output as new layer (see Fig. 29). The overlay is depicted in Figure 30. The zoom of the `.mzML` - `.featureXML` overlay shows the individual mass traces and the assembly of those in a feature (see Fig. 31). (Figure_28)= |![Opened .mzML in TOPPView](/images/openms-user-tutorial/metabo/ToppView_1.png)| @@ -1640,16 +1600,16 @@ First start TOPPView and open the example `.mzML` file (see **OpenMS**>**Map Alignment**), set its Output Type to featureXML, and adjust the following settings: +- After the `ZipLoopEnd` node, add a `MapAlignerPoseClustering` node (**Community Nodes**>**OpenMS**>**Map Alignment**), set its Output Type to featureXML, and adjust the following settings: |**parameter**| **value**| |:------------|:---------| @@ -1677,22 +1637,22 @@ The next step after retention time correction is the grouping of corresponding f |:--:| |Figure 33: Features A and B correspond to the same analyte. The linking of features between runs (indicated by an arrow) allows comparing feature intensities.| -- After the **MapAlignerPoseClustering** node, add a **FeatureLinkerUnlabeledQT** node (**Community Nodes** > **OpenMS**>**Map Alignment**) and adjust the following settings: - - |**parameter**|**value**| - |:------------|:--------| - |*algorithm* → *distance_RT* → *max_difference*|40| - |*algorithm* → *distance_MZ* → *max_difference*|20| - |*algorithm* → *distance_MZ* → *unit*|ppm| - - The parameters change the behavior of **FeatureLinkerUnlabeledQT** as follows (similar to the parameters we adjusted for **MapAlignerPoseClustering**): - - - **distance_RT → max_difference**: Features that have a larger RT difference will never be paired. - - **distance_MZ → max_difference**: Features that have a larger m/z difference will never be paired. - - **distance_MZ → unit**: Unit used for the parameter distance_MZ max_difference, either Da or ppm. - -- After the **FeatureLinkerUnlabeledQT** node, add a **TextExporter** node (**Community Nodes** > **OpenMS** > **File Handling**). -- Add an **Output Folder** node and configure it with an output directory where you want to store the resulting files. +- After the `MapAlignerPoseClustering` node, add a `FeatureLinkerUnlabeledQT` node (**Community Nodes** > **OpenMS**>**Map Alignment**) and adjust the following settings: + + |**parameter**|**value**| + |:------------|:--------| + |*algorithm* → *distance_RT* → *max_difference*|40| + |*algorithm* → *distance_MZ* → *max_difference*|20| + |*algorithm* → *distance_MZ* → *unit*|ppm| + + The parameters change the behavior of `FeatureLinkerUnlabeledQT` as follows (similar to the parameters we adjusted for `MapAlignerPoseClustering`): + + - **distance_RT → max_difference**: Features that have a larger RT difference will never be paired. + - **distance_MZ → max_difference**: Features that have a larger m/z difference will never be paired. + - **distance_MZ → unit**: Unit used for the parameter distance_MZ max_difference, either Da or ppm. + +- After the `FeatureLinkerUnlabeledQT` node, add a **TextExporter** node (**Community Nodes** > **OpenMS** > **File Handling**). +- Add an `Output Folder` node and configure it with an output directory where you want to store the resulting files. - Run the pipeline and inspect the output. (Figure_34)= @@ -1700,9 +1660,9 @@ The next step after retention time correction is the grouping of corresponding f |:--:| |Figure 34: Label-free quantification workflow for metabolites.| -You should find a single, tab-separated file containing the information on where metabolites were found and with which intensities. You can also add **Output Folder** nodes at different stages of the workflow and inspect the intermediate results (e.g., identified metabolite features for each input map). The complete workflow can be seen in Figure 34. In the following section we will try to identify those metabolites. +You should find a single, tab-separated file containing the information on where metabolites were found and with which intensities. You can also add `Output Folder` nodes at different stages of the workflow and inspect the intermediate results (e.g., identified metabolite features for each input map). The complete workflow can be seen in Figure 34. In the following section we will try to identify those metabolites. -The **FeatureLinkerUnlabeledQT** output can be visualized in TOPPView on top of the input and output of the **FeatureFinderMetabo** (see Fig 35). +The `FeatureLinkerUnlabeledQT` output can be visualized in TOPPView on top of the input and output of the `FeatureFinderMetabo` (see Fig 35). (Figure_35)= |![Label-free quantification workflow for metabolites](/images/openms-user-tutorial/metabo/ToppView_5.png)| @@ -1715,7 +1675,7 @@ At the current state we found several metabolites in the individual maps but so - Add a **FileConverter** node (**Community Nodes** > **OpenMS** > **File Handling**) and connect the output of the FeatureLinkerUnlabeledQT to the incoming port. - Open the Configure dialog of the **FileConverter** node and select the tab **OutputTypes**. In the drop down list for FileConverter.1.out select **featureXML**. - Add an **AccurateMassSearch** node (**Community Nodes** > **OpenMS** > **Utilities**) and connect the output of the **FileConverter** node to the first port of the **AccurateMassSearch** node. -- Add four **Input File** nodes and configure them with the following files: +- Add four `File Importer` nodes and configure them with the following [files](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/databases/): - {path}`Example_Data,Metabolomics,databases,PositiveAdducts.tsv` This file specifies the list of adducts that are considered in the positive mode. Each line contains the formula and charge of an adduct separated by a semicolon (e.g. M+H;1+). The mass of the adduct is calculated automatically. - {path}`Example_Data,Metabolomics,databases,NegativeAdducts.tsv` @@ -1725,8 +1685,8 @@ At the current state we found several metabolites in the individual maps but so - {path}`Example_Data,Metabolomics,databases,HMDB2StructMapping.tsv` This file contains additional information about the identifiers in the mapping file. It has four tab-separated columns that contain the identifier, name, SMILES, and INCHI. These will be included in the result file. The identifiers in this file must match the identifiers in the `HMDBMappingFile.tsv`. - In the same order as they are given above connect them to the remaining input ports of the **AccurateMassSearch** node. -- Add an **Output Folder** node and connect the first output port of the -**AccurateMassSearch** node to the **Output Folder** node. +- Add an `Output Folder` node and connect the first output port of the + **AccurateMassSearch** node to the `Output Folder` node. The result of the **AccurateMassSearch** node is in the mzTab format[^17] so you can easily open it in a text editor or import it into Excel or KNIME, which we will do in the next section. The complete workflow from this section is shown in Figure 36. @@ -1737,7 +1697,7 @@ The result of the **AccurateMassSearch** node is in the mzTab format[^17] so you #### Convert your data into a KNIME table -The result from the TextExporter node as well as the result from the **AccurateMassSearch** node are files while standard KNIME nodes display and process only KNIME tables. To convert these files into KNIME tables we need two different nodes. For the **AccurateMassSearch** results, we use the **MzTabReader** node (**Community Nodes** > **OpenMS** > **Conversion** > **mzTab**) and its **Small Molecule Section** port. For the result of the **TextExporter**, we use the **ConsensusTextReader** (**Community Nodes** > **OpenMS** > **Conversion**). +The result from the TextExporter node as well as the result from the **AccurateMassSearch** node are files while standard KNIME nodes display and process only KNIME tables. To convert these files into KNIME tables we need two different nodes. For the **AccurateMassSearch** results, we use the **MzTabReader** node (**Community Nodes** > **OpenMS** > **Conversion** > **mzTab**) and its **Small Molecule Section** port. For the result of the **TextExporter**, we use the `ConsensusTextReader` (**Community Nodes** > **OpenMS** > **Conversion**). When executed, both nodes will import the OpenMS files and provide access to the data as KNIME tables. The retention time values are exported as a list using the **MzTabReader** based on the current PSI-Standard. This has to be parsed using the **SplitCollectionColumn**, which outputs a ”Split Value 1” based on the first entry in the rention time list, which has to be renamed to retention time using the **ColumnRename**. You can now combine both tables using the **Joiner** node (**Manipulation** > **Column** > **Split & Combine**) and configure it to match the m/z and retention time values of the respective tables. The full workflow is shown in Figure 37. (Figure_37)= @@ -1747,7 +1707,7 @@ When executed, both nodes will import the OpenMS files and provide access to the #### Adduct grouping -Metabolites commonly co-elute as ions with different adducts (e.g., glutathione+H, glutathione+Na) or with charge-neutral modifications (e.g., water loss). Grouping such related ions allows to leverage information across features. For example, a low-intensity, single trace feature could still be assigned a charge and adduct due to a matching high-quality feature. Several OpenMS tools, such as **AccurateMassSearch**, can use this information to, for example, narrow down candidates for identification. +Metabolites commonly co-elute as ions with different adducts (e.g., glutathione+H, glutathione+Na) or with charge-neutral modifications (e.g., water loss). Grouping such related ions allows to leverage information across features. For example, a low intensity, single trace feature could still be assigned a charge and adduct due to a matching high-quality feature. Several OpenMS tools, such as **AccurateMassSearch**, can use this information to, for example, narrow down candidates for identification. For this grouping task, we provide the **MetaboliteAdductDecharger** node. Its method explores the combinatorial space of all adduct combinations in a charge range for optimal explanations. Using defined adduct probabilities, it assigns co-eluting features having suitable mass shifts and charges those adduct combinations which maximize overall ion probabilities. @@ -1782,7 +1742,7 @@ Check out the **Molecule Type Cast** node (**Chemistry** > **Translators**) toge

**Task**

-Have a look at the **Column Filter** node to reduce the table to the interesting columns, e.g., only the Ids, chemical formula, and intensities. +Have a look at the `Column Filter` node to reduce the table to the interesting columns, e.g., only the Ids, chemical formula, and intensities.
@@ -1813,15 +1773,14 @@ Run the workflow and inspect the output. In metabolomics, matches between tandem spectra and spectral libraries are manually validated. Several commercial and free online resources exist which help in that task. Some examples are: - mzCloud contains only spectra from Thermo Orbitrap instruments. The webpage requires Microsoft Silverlight which currently does not work in modern browsers (see the following [link](https://www.mzcloud.org/DataViewer). - -- MassBank North America (MoNA) has spectra from different instruments but falls short in the number of spectra (compared to Metlin and mzCloud). See the following [link](http://mona.fiehnlab.ucdavis.edu/spectra/display/KNA00122). -- METLIN includes 961,829 molecules ranging from lipids, steroids, metabolites, small peptides, carbohydrates, exogenous drugs, and toxicants. In total over 14,000 metabolites. +- MassBank North America (MoNA) has spectra from different instruments but falls short in number of spectra (compared to Metlin and mzCloud). See the following [link](http://mona.fiehnlab.ucdavis.edu/spectra/display/KNA00122). +- METLIN includes 961,829 molecules ranging from lipids, steroids, metabolites, small peptides, carbohydrates, exogenous drugs and toxicants. In total over 14,000 metabolites. Here, we will use METLIN to manually validate metabolites.

**Task**

-Check in the .xlsx output from the Excel writer (XLS) if you can find glutathione. Use the retention time column to find the spectrum in the mzML file. Here open the file in the {path}`Example_Data,Metabolomics,datasets,MetaboliteIDSpectraDBpositive.mzML` in TOPPView. The MSMS spectrum with a retention time of 67.6 s is used as an example. The spectrum can be selected based on the retention time in the scan view window. Therefore the MS1 spectrum with a retention time of 66.9 s has to be double-clicked and the MSMS spectra recorded in this time frame will show up. Select the tandem spectrum of Glutathione, but do not close TOPPView, yet. +Check in the .xlsx output from the Excel writer (XLS) if you can find glutathione. Use the retention time column to find the spectrum in the mzML file. Here open the [file](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/Metabolite_ID_SpectraDB_positive.mzML) in the {path}`Example_Data,Metabolomics,datasets,MetaboliteIDSpectraDBpositive.mzML` in TOPPView. The MSMS spectrum with the retention time of 67.6 s is used as example. The spectrum can be selected based on the retention time in the scan view window. Therefore the MS1 spectrum with the retention time of 66.9 s has to be double clicked and the MSMS spectra recorded in this time frame will show up. Select the tandem spectrum of Glutathione, but do not close TOPPView, yet.
(Figure_40)= @@ -1831,7 +1790,7 @@ Check in the .xlsx output from the Excel writer (XLS) if you can find glutathion

**Task**

-On the METLIN homepage search for **Name** Glutathione using the **Advanced Search**. See the [link](https://metlin.scripps.edu/landing_page.php?pgcontent=advanced_search). Note that free registration is required. Which collision energy (and polarity) gives the best (visual) match to your experimental spectrum in TOPPView? Here you can compare the fragmentation patterns in both spectra shown by the Intensity or relative Intensity, the m/z of a peak, and the distance between peaks. Each distance between two peaks corresponds to a fragment of elemental composition (e.g., NH2 with the charge of one would have mass of two peaks of 16.023 Th). +On the METLIN homepage search for **Name** Glutathione using the **Advanced Search**. See the [link](https://metlin.scripps.edu/landing_page.php?pgcontent=advanced_search). Note that free registration is required. Which collision energy (and polarity) gives the best (visual) match to your experimental spectrum in TOPPView? Here you can compare the fragmentation patterns in both spectra shown by the Intensity or relative Intensity, the m/z of a peak and the distance between peaks. Each distance between two peaks corresponds to a fragment of elemental composition (e.g., NH2 with the charge of one would have mass of two peaks of 16.023 Th).
(Figure_41)= @@ -1857,10 +1816,10 @@ By using a mzML and featureXML, SIRIUS gains a lot of additional information by

**Task**

Construct the workflow as shown in Fig. 42. {path}`Example_Data,Metabolomics,datasets` -Use the file `MetaboliteDeNovoID.mzML` as input for your workflow. +Use the [file](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Metabolomics/datasets/Metabolite_DeNovoID.mzML) `MetaboliteDeNovoID.mzML` as input for your workflow.
-Below we show an example workflow for de novo identification (Fig. 42). Here, the node **FeatureFinderMetabo** is used for feature detection to annotate analytes in mz, rt, intensity, and charge. This is followed by adduct grouping, trying to asses possible adducts based on the feature space using the **MetaboliteAdductDecharger**. In addition, the **HighResPrecursorMassCorrector** can use the newly generated feature information to map MS2 spectra, which were measured on one of the isotope traces to the monoisotopic precursor. This helps with feature mapping and analyte identification in the **SiriusAdapter** due to the usage of additional MS2 spectra that belong to a specific feature. +Below we show an example workflow for de novo identification (Fig. 42). Here, the node `FeatureFinderMetabo` is used for feature detection to annotate analytes in mz, rt, intensity and charge. This is followed by adduct grouping, trying to asses possible adducts based on the feature space using the **MetaboliteAdductDecharger**. In addition, the **HighResPrecursorMassCorrector** can use the newly generated feature information to map MS2 spectra, which were measured on one of the isotope traces to the monoisotopic precursor. This helps with feature mapping and analyte identification in the **SiriusAdapter** due to the usage of additional MS2 spectra that belong to a specific feature. (Figure_42)= |![De novo identification workflow](/images/openms-user-tutorial/metabo/denovoid.png)| @@ -1869,7 +1828,7 @@ Below we show an example workflow for de novo identification (Fig. 44). The example dataset can be used for this workflow (filenames in brackets): 1. Open {path}`Workflows,OpenSWATH.knwf` in KNIME: **File** > **Import KNIME Workflow...** -2. Select the normalized retention time (iRT) assay library in TraML format by double-clicking on node **Input File** > **iRT Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHiRTAssayLibrary.TraML`). +2. Select the normalized retention time (iRT) assay library in TraML format by double-clicking on node `File Importer` > **iRT Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHiRTAssayLibrary.TraML`). 3. Select the SWATH MS data in mzML format as input by double-clicking on node **Input File** > **SWATH-MS files**. ({path}`ExampleData,OpenSWATH,data,splitnapedroL120420x010SW-*.nf.pp.mzML`). 4. Select the target peptide assay library in TraML format as input by double-clicking on node `Input Files` > **Assay Library**. ({path}`ExampleData,OpenSWATH,assay,OpenSWATHSGSAssayLibrary.TraML`). -5. Set the output destination by double-clicking on node **Output File**. +5. Set the output destination by double-clicking on node `Output File`. 6. Run the workflow. The resulting output can be found at your selected path, which will be used as input for mProphet. Execute the script on the Terminal (Linux or Mac) or cmd.exe (Windows) in {path}`ExampleData,OpenSWATH,result`. Please use the absolute path to your R installation and the result file: @@ -2126,7 +2085,7 @@ or for Windows: "C:\Program Files\R\R-3.5.1\bin\x86\R.exe" --slave --args bin_dir=../../../External_Tools/mProphet/ mquest=OpenSWATH_quant.tsv workflow=LABEL_FREE num_xval=5 run_log=FALSE write_classifier=1 write_all_pg=1 < ../../../External_Tools/mProphet/mProphet.R ``` -The main output will be called: {path}`OpenSWATH,result,mProphetxallxpeakgroups.xls` with statistical information available in {path}`OpenSWATH,result,mProphet.pdf`. +The main output will be called: {path}`OpenSWATH,result,mProphetxallxpeakgroups.xls` with statistical information available in {path}`OpenSWATH,result,mProphet.pdf`. Please note that due to the semi-supervised machine learning approach of mProphet the results differ slightly when mProphet is executed several times. @@ -2140,13 +2099,13 @@ For additional instructions on how to use pyProphet instead of mProphet please h ### From the example dataset to real-life applications -The sample dataset used in this tutorial is part of the larger SWATH MS Gold Standard (SGS) dataset which is described in the publication of Roest *et al.*[^21]. It contains one of 90 SWATH-MS runs with significant data reduction (peak picking of the raw, profile data) to make file transfer and working with it easier. Usually, SWATH-MS datasets are huge with several gigabyte per run. Especially when complex samples in combination with large assay libraries are analyzed, the TOPP tool-based workflow requires a lot of computational resources. Additional information and instruction can be found at the following [link](http://openswath.org/en/latest/). +The sample dataset used in this tutorial is part of the larger SWATH MS Gold Standard (SGS) dataset which is described in the publication of Roest *et al.*[^21]. It contains one of 90 SWATH-MS runs with significant data reduction (peak picking of the raw, profile data) to make file transfer and working with it easier. Usually SWATH-MS datasets are huge with several gigabyte per run. Especially when complex samples in combination with large assay libraries are analyzed, the TOPP tool based workflow requires a lot of computational resources. Additional information and instruction can be found at the following [link](http://openswath.org/en/latest/). ## OpenSWATH for Metabolomics ### Introduction -We would like to present an automated DIA/SWATH analysis workflow for metabolomics, which takes advantage of experiment-specific target-decoy assay library generation. This allows for targeted extraction, scoring, and statistical validation of metabolomics DIA data[^29], [^30]. +We would like to present an automated DIA/SWATH analysis workflow for metabolomics, which takes advantage of experiment specific target-decoy assay library generation. This allows for targeted extraction, scoring and statistical validation of metabolomics DIA data[^29], [^30]. ### Workflow @@ -2155,7 +2114,7 @@ The workflow follows multiple steps (see Fig. 45). (Figure_45)= |![DIAMetAlyzer - pipeline for assay library generation and targeted analysis with statistical validation](/images/openms-user-tutorial/openswath/pipeline_overview.png)| |:--:| -|Figure 45: DIAMetAlyzer - pipeline for assay library generation and targeted analysis with statistical validation. DDA data is used for candidate identification containing feature detection, adduct grouping, and accurate mass search. Library construction uses fragment annotation via compositional fragmentation trees and decoy generation using a fragmentation tree re-rooting method to create a target-decoy assay library. This library is used in a second step to analyze metabolomics DIA data by performing targeted extraction, scoring, and statistical validation (FDR estimation).| +|Figure 45: DIAMetAlyzer - pipeline for assay library generation and targeted analysis with statistical validation. DDA data is used for candidate identification containing feature detection, adduct grouping and accurate mass search. Library construction uses fragment annotation via compositional fragmentation trees and decoy generation using a fragmentation tree re-rooting method to create a target-decoy assay library. This library is used in a second step to analyse metabolomics DIA data performing targeted extraction, scoring and statistical validation (FDR estimation).| (Figure_46)= |![Assay library generation](/images/openms-user-tutorial/openswath/assay_library_generation.png)| @@ -2165,19 +2124,19 @@ The workflow follows multiple steps (see Fig. 45). (Figure_47)= |![Decoy generation](/images/openms-user-tutorial/openswath/decoy_generation.png)| |:--:| -|Figure 47: Decoy generation. The compositional fragmentations trees from the step above are used to run the fragmentation tree re-rooting method from Passatutto, generating a compound-specific decoy MS2 spectrum. Here, the n highest intensity decoy transitions are extracted and stored in the target-decoy assay library.| +|Figure 47: Decoy generation. The compositional fragmentations trees from the step above are used to run the fragmentation tree re-rooting method from Passatutto, generating a compound specific decoy MS2 spectrum. Here, the n highest intensity decoy transitions are extracted and stored in the target-decoy assay library.| - **Candidate identification** - Feature detection, adduct grouping, and accurate mass search are applied to DDA data. + Feature detection, adduct grouping and accurate mass search are applied on DDA data. - **Library construction** - The knowledge determined from the DDA data, about compound identification, its potential adduct, and the corresponding fragment spectra are used to perform fragment annotation via compositional fragmentation trees sugin SIRIUS 4[^31]. Afterwards transitions, which are the reference of a precursor to its fragment ions are stored in a so-called assay library (Fig. 46). Assay libraries usually contain additional metadata (i.e. retention time, peak intensities). FDR estimation is based on the target-decoy approach[^32]. For the generation of the MS2 decoys, the fragmentation tree-based rerooting method by Passatutto ensures the consistency of decoy spectra (Fig.47)[^33]. The target-decoy assay library is then used to analyze the SWATH data. + The knowledge determined from the DDA data, about compound identification, its potential adduct and the corresponding fragment spectra are used to perform fragment annotation via compositional fragmentation trees sugin SIRIUS 4[^31]. Afterwards transitions, which are the reference of a precursor to its fragment ions are stored in a so-called assay library (Fig. 46). Assay libraries usually contain additional metadata (i.e. retention time, peak intensities). FDR estimation is based on the target-decoy approach[^32]. For the generation of the MS2 decoys, the fragmentation tree-based rerooting method by Passatutto ensure the consistency of decoy spectra (Fig.47)[^33]. The target-decoy assay library is then used to analyse the SWATH data. - **Targeted extraction** Chromatogram extraction and peak-group scoring. This step is performed using an algorithm based on OpenSWATH[^29] for metabolomics data. - **Statistical validation** FDR estimation uses the PyProphet algorithm[^30]. To prevent overfitting we chose the simpler linear model (LDA) for target-decoy discrimination in PyProphet, using MS1 and MS2 scoring with low correlated scores. ### Prerequisites -Apart from the usual KNIME nodes, the workflow uses python scripting nodes. One basic requirement for the installation of python packages, in particular pyOpenMS, is a package manager for python. Using conda as an environment manager allows one to specify a specific environment in the KNIME settings (**File**>**Preferences**>**KNIME**>**Python**). +Apart from the usual KNIME nodes, the workflow uses python scripting nodes. One basic requirement for the installation of python packages, in particular pyOpenMS, is a package manager for python. Using conda as an environment manger allows to specify a specific environment in the KNIME settings (**File**>**Preferences**>**KNIME**>**Python**). #### Windows @@ -2249,7 +2208,7 @@ The example data can be found [here](https://abibuilder.cs.uni-tuebingen.de/arch ### Example workflow -Example workflow for the usage of the DIAMetAlyzer Pipeline in KNIME (see Fig. 48). Inputs are the SWATH-MS data in profile mode (.mzML), a path for saving the new target-decoy assay library, the SIRIUS 4.9.0 executable, the DDA data (.mzML), custom libraries and adducts for **AccurateMassSearch**, the min/max fragment mass-to-charge to be able to restrict the mass of the transitions and the path to the PyProphet executable. The DDA is used for feature detection, adduct grouping, and accurate mass search and forwarded to the **AssayGeneratorMetabo**. Here, feature mapping is performed to collect MS2 spectra that belong to a feature. All information collected before (feature, adduct, putative identification, MS2 spectra) is then internally forwarded to SIRIUS. SIRIUS is used for fragment annotation and decoy generation based on the fragmentation tree re-rooting approach. This information is then used to filter spectra/decoys based on their explained intensity (min. 85%). Afterwards, internal feature linking is performed which is most important for untargeted experiments using a lot of DDA data to construct the library. The constructed target-decoy assay library is processed with the SWATH-MS data in OpenSWATH. The results are used by PyProphet for scoring and output a list of metabolites with their respective q-value and quantitative information. +Example workflow for the usage of the DIAMetAlyzer Pipeline in KNIME (see Fig. 48). Inputs are the SWATH-MS data in profile mode (.mzML), a path for saving the new target-decoy assay library, the SIRIUS 4.9.0 executable, the DDA data (.mzML), custom libraries and adducts for **AccurateMassSearch**, the min/max fragment mass-to-charge to be able to restrict the mass of the transitions and the path to the PyProphet executable. The DDA is used for feature detection, adduct grouping, accurate mass search and forwarded to the **AssayGeneratorMetabo**. Here, feature mapping is performed to collect MS2 spectra that belong to a feature. All information collected before (feautre, adduct, putative identification, MS2 spectra) are then internally forwarded to SIRIUS. SIRIUS is used for fragment annotation and decoy generation based on the fragmentation tree re-rooting approach. This information is then used to filter spectra/decoys based on their explained intensity (min. 85%). Afterwards internal feature linking is performed which is most important for untargeted experiments using a lot of DDA data to construct the library. The constructed target-decoy assay library is processed with the SWATH-MS data in OpenSWATH. The results are used by PyProphet for scoring and output a list of metabolites with their respective q-value and quantitative information. (Figure_48)= |![Example workflow for the usage of the DIAMetAlyzer Pipeline in KNIME](/images/openms-user-tutorial/openswath/oswm_example_wf.png)| @@ -2262,7 +2221,7 @@ These steps need to be followed to run the workflow successfully: - Add DDA Input Files (.mzML). - Specify SIRIUS 4.9.0 executable. - Specify library files (mapping, struct) for **AccurateMassSearch**. -- Add positive/negative adducts lists for **AccurateMassSearch**. +- Add positive/negative adducts lists for **AccurateMassSearch**. - Supply an output path for the SIRIUS workspace in the **AssayGeneratorMetabo**. - Specify additional paths and variables, such as an output path for the target-decoy assay library and a path to the pyprophet installation as well as decoy fragment mz filter (min/max). - Input DIA/SWATH files (.mzML). @@ -2361,7 +2320,7 @@ It is also possible to use identified and in addition unknown (non-identified) f ## Untargeted metabolomics preprocessing -The universal workflow for untargeted metabolomics always consists of feature detection in the individual MS sample files and their linkage to consensus features with common m/z and retention time values. In addition, there are optional steps such as adduct detection and annotation of features with associated MS2 spectra. This workflow prepares all the file necessary to do formula and structural annotations via `SiriusAdapter`. Furthermore, it prepares all required files to run `GNPSExport`, which generates all files necessary to directly run [GNPS](https://gnps.ucsd.edu) Feature-Based Molecular Networking (FBMN) and Ion Identity Molecular Networking (IIMN). +The universal workflow for untargeted metabolomics always consists of feature detection in the individual MS sample files and their linkage to consensus features with common m/z and retention time values. In addition, there are optional steps such as adduct detection and annotation of features with associated MS2 spectra. This workflow prepares all the file necessary to do formula and structural annotations via `SiriusAdapter`. Furthermore it prepares all required files to run `GNPSExport`, which generates all files necessary to directly run [GNPS](https://gnps.ucsd.edu) Feature Based Molecular Networking (FBMN) and Ion Identity Molecular Networking (IIMN). (Figure_49)= |![metabolomics preprocessing](/images/tutorials/metabolomics-preprocessing.png)| @@ -2381,7 +2340,7 @@ Align feature retention times based on the feature map with the highest number o MapAlignerPoseClustering -in sample1.featureXML sample2.featureXML -out aligned_sample1.featureXML aligned_sample2.featureXML -trafo_out sample1.trafoXML sample2.trafoXML -algorithm:pairfinder:distance_MZ:max_difference 10.0 -algorithm:pairfinder:distance_MZ:unit ppm ``` -Align mzML file alignment based on FeatureMap alignment (optional, only for GNPS). +Align mzML files aligment based on FeatureMap alignment (optional, only for GNPS). ```shell MapRTTransformer -in sample1.mzML -out aligned_sample1.mzML -trafo_in sample1.trafoXML MapRTTransformer -in sample2.mzML -out aligned_sample2.mzML -trafo_in sample2.trafoXML @@ -2393,7 +2352,7 @@ IDMapper -id empty.idXML -in aligned_sample1.featureXML -spectra:in aligned_samp IDMapper -id empty.idXML -in aligned_sample2.featureXML -spectra:in aligned_sample2.mzML -out IDmapped_sample2.featureXML ``` -Detect adducts (optional, only for SIRIUS and GNPS Ion Identity +Detect adducts (optional, only for SIRIUS and GNPS Ion Identity Molecular Networking). ```shell MetaboliteAdductDecharger -in IDmapped_sample1.featureXML -out_fm adducts_sample1.featureXML -algorithm:MetaboliteFeatureDeconvolution:potential_adducts "H:+:0.6" "Na:+:0.1" "NH4:+:0.1" "H-1O-1:+:0.1" "H-3O-2:+:0.1" @@ -2410,7 +2369,7 @@ Export table of metabolic features as tsv file including meta values (e.g. best TextExporter -in Preprocessed.consensusXML -out Features.tsv -consensus:add_metavalues ``` -You can recreate this workflow in KNIME. [Download the KNIME workflow here](../workflows/UntargetedMetabolomicsPreProcessing.knwf). The workflow should look like this: +You can recreate this workflow in KNIME. [Download the KNIME workflow here](/workflows/UntargetedMetabolomicsPreProcessing.knwf). The workflow should look like this: (Figure_50)= |![metabolomics preprocessing workflow in KNIME](/images/tutorials/metabolomics-preprocessing-knime-workflow.png)| @@ -2422,7 +2381,7 @@ You can recreate this workflow in KNIME. [Download the KNIME workflow here](../w ### Introduction -pyOpenMS provides Python bindings for a large part of the OpenMS library for mass-spectrometry based proteomics and metabolomics. It thus provides access to a featurerich, open-source algorithm library for mass-spectrometry based LC-MS analysis. These Python bindings allow raw access to the data-structures and algorithms implemented +pyOpenMS provides Python bindings for a large part of the OpenMS library for mass spectrometry based proteomics and metabolomics. It thus provides access to a featurerich, open-source algorithm library for mass-spectrometry based LC-MS analysis. These Python bindings allow raw access to the data-structures and algorithms implemented in OpenMS, specifically those for file access (mzXML, mzML, TraML, mzIdentML among others), basic signal processing (smoothing, filtering, de-isotoping and peak-picking) and complex data analysis (including label-free, SILAC, iTRAQ and SWATH analysis tools). pyOpenMS is integrated into OpenMS starting from version 1.11. This tutorial is addressed to people already familiar with Python. If you are new to Python, we suggest to start with a [Python tutorial](https://en.wikibooks.org/wiki/Non-Programmer%27s_Tutorial_for_Python_3). ### Installation @@ -2432,7 +2391,7 @@ One basic requirement for the installation of python packages, in particular pyO #### Windows 1. Install [Python 3.9](http://www.python.org/download/). -2. Install pip (see above). +2. Install pip (see above). 3. On the command line: ```bash python -m pip install -U pip @@ -2463,9 +2422,9 @@ We suggest do use a virtual environment for the Python 3 installation on Mac. He Use your package manager apt-get or yum, where possible. -1. Install Python 3.9 (Debian: python-dev, RedHat: python-devel). +1. Install Python 3.9 (Debian: python-dev, RedHat: python-devel). 2. Install NumPy (Debian / RedHat: python-numpy). -3. Install setuptools (Debian / RedHat: python-setuptools). +3. Install setuptools (Debian / RedHat: python-setuptools). 4. On the Terminal: ```bash pip install pyopenms @@ -2496,11 +2455,11 @@ Install a local available package: ```bash pip install numpy-1.20.0-cp37*.whl -pip install pyopenms-3.0.0-cp37*.whl +pip install pyopenms-2.7.0-cp37*.whl or (in case of windows) python -m pip install -U numpy-1.20.0-cp37*.whl -python -m pip install -U pyopenms-3.0.0-cp37*.whl +python -m pip install -U pyopenms-2.7.0-cp37*.whl ``` The local available packages can be found in the directory corresponding to your operating system. Please use the absolute path to the packages for the installation. @@ -2512,7 +2471,7 @@ Instructions on how to build pyOpenMS can be found [online](https://pyopenms.rea ### Scripting with pyOpenMS -A big advantage of pyOpenMS is its scripting capabilities (beyond its application in tool development). Most of the OpenMS datastructure can be accessed using [python](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/index.html). Here we would like to give some examples on how pyOpenMS can be used for simple scripting task, such as peptide mass calculation and peptide/protein digestion as well as isotope distribution calculation. +A big advantage of pyOpenMS are its scripting capabilities (beyond its application in tool development). Most of the OpenMS datastructure can be accessed using [python](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Documentation/nightly/html/index.html). Here we would like to give some examples on how pyOpenMS can be used for simple scripting task, such as peptide mass calculation and peptide/protein digestion as well as isotope distribution calculation. Calculation of the monisotopic and average mass of a peptide sequence: @@ -2801,13 +2760,6 @@ Now you can run your tool in the Anaconda Terminal {path}`ExampleData,pyopenms`. python ProteinDigestor.py -in mini_example.fasta -out mini_example_out.idXML -enzyme Trypsin -min_length 6 -max_length 40 -missed_cleavages 1 ``` -#### Bonus task - -
-

**Task**

-Implement all other 184 TOPP tools using pyOpenMS. -
- ## Quality control ### Introduction @@ -2828,7 +2780,7 @@ As a start, we will build a basic qcML file for each mzML file in the label-free - Copy your label-fee quantitation workflow into a new lfq-qc workflow and open it. - Place the **QCCalculator** node after the `IDMapper` node. Being inside the **ZipLoop**, it will execute for each of the three mzML files the **Input** node. - Connect the first **QCCalculator** port to the first `ZipLoopStart` outlet port, which will carry the individual mzML files. -- Connect the last’s ID outlet port (**IDFilter** or the ID metanode) to the second **QCCalculator** port for the identification file. +- Connect the last’s ID outlet port (`IDFilter` or the ID metanode) to the second **QCCalculator** port for the identification file. - Finally, connect the `IDMapper` outlet to the third **QCCalculator** port for the feature file. The created qcML files will not have much to show for, basic as they are. So we will extend them with some basic plots. @@ -2866,7 +2818,7 @@ Press **Eval script** to execute the script. |Figure 51: Basic QC setup within a LFQ workflow.| ```{note} -To have a peek into what our qcML now looks like for one of the **ZipLoop** iterations, we can add an **Output Folder** node from **Community Nodes** > **GenericKnimeNodes** > **IO** and set its destination parameter to somewhere we want to find our intermediate qcML files in, for example **tmp** > **qcxlfq**. If we now connect the last metanode with the Output Folder and restart the workflow, we can start inspecting the qcML files. +To have a peek into what our qcML now looks like for one of the **ZipLoop** iterations, we can add an `Output Folder` node from **Community Nodes** > **GenericKnimeNodes** > **IO** and set its destination parameter to somewhere we want to find our intermediate qcML files in, for example **tmp** > **qcxlfq**. If we now connect the last metanode with the Output Folder and restart the workflow, we can start inspecting the qcML files. ```
@@ -2898,7 +2850,7 @@ ggplot(knime.in, aes(x=peptide_charge)) + - We can now use a **QCEmbetter** node like before to add our new metric plot into the qcML. - After looking for an appropriate target from the following [link](https://github.com/qcML/qcML-development/blob/master/cv/qc-cv.obo), we found that we can attach our plot to the MS *identification result details* by setting the parameter `qp_att_acc` to `QC:0000025`, as we are plotting the charge histogram of our identified peptides. - To have the plot later displayed properly, we assign it the parameter `cv_acc` of `QC:0000051`, a generic plot. Also we made sure in the *R Script*, that our plot carries a caption so that we know which is which, if we had more than one new plot. -- Now we redirect the **QCEmbedders** output to the **Output Folder** from before and can have a look at how our qcML is coming along after restarting the workflow. +- Now we redirect the **QCEmbedders** output to the `Output Folder` from before and can have a look at how our qcML is coming along after restarting the workflow. (Figure_52)= |![QC with new metric](/images/openms-user-tutorial/quality-control/qc_extra.png)| @@ -2913,7 +2865,7 @@ For this, we will first collect all created qcML files, merge them together and - Connect the **QCEmbedders** output from last section to the **ZipLoopEnds** second input port. - The corresponding output port will collect all qcML files from each **ZipLoop** iteration and pass them on as a list of files. - Now we add a **QCMerger** node after the `ZipLoopEnd` and feed it that list of qcML files. In addition, we set its parameter `setname` to give our newly created set a name - say `spikein_replicates`. -- To inspect all the QCs next to each other in that created qcML file, we have to add a new **Output Folder** to which we can connect the **QCMerger** output. +- To inspect all the QCs next to each other in that created qcML file, we have to add a new `Output Folder` to which we can connect the **QCMerger** output. When inspecting the set-qcML file in a browser, we will be presented another overview. After the set content listing, the basic QC parameters (like number of identifications) are each displayed in a graph. Each set member (or run) has its own section on the x-axis and each run is connected with that graph via a link in the mouseover on one of the QC parameter values. @@ -2927,12 +2879,69 @@ When inspecting the set-qcML file in a browser, we will be presented another ove For ideas on new QC metrics and parameters, as you add them in your qcML files as generic parameters, feel free to [contact us](/quick-reference/contact-us.md), so we can include them in the CV.
+## Advanced topic: R integration + +KNIME provides a large number of nodes for a wide range of statistical analysis, machine learning, data processing, and +visualization. Still, more recent statistical analysis methods, specialized visualizations or cutting edge algorithms +may not be covered in KNIME. In order to expand its capabilities beyond the readily available nodes, external scripting +languages can be integrated. In this tutorial, we primarily use scripts of the powerful statistical computing language R. +Note that this part is considered advanced and might be difficult to follow if you are not familiar with R. In this case +you might skip this part. + +**R View (Table)** allows to seamlessly include R scripts into KNIME. We will +demonstrate on a minimal example how such a script is integrated. + +
+

**Task**

+

+First we need some example data in KNIME, which we will generate using the **Data Generator** node (**IO** > **Other** > **Data Generator**). +You can keep the default settings and execute the node. The table contains four columns, each containing random coordinates and one column +containing a cluster number (Cluster_0 to Cluster_3). Now place a **R View (Table)** node into the workflow and connect +the upper output port of the **Data Generator** node to the input of the **R View (Table)** node. Right-click and +configure the node. If you get an error message like `Execute failed: R_HOME does not contain a folder with name ’bin’.` +or `Execution failed: R Home is invalid.`: please change the R settings in the preferences. To do so open **File** > +**Preferences** > **KNIME** > **R** and enter the path to your R installation (the folder that contains the bin +directory. e.g., {path}`C:,Program Files,R,R-3.4.3`). +

+

+If you get an error message like: ”Execute failed: Could not find Rserve package. Please install it in your R +installation by running ”install.packages(’Rserve’)”.” You may need to run your R binary as administrator (In windows +explorer: right-click ”Run as administrator”) and enter install.packages(’Rserve’) to install the package. +

+

+If R is correctly recognized we can start writing an R script. Consider that we are interested in plotting the first and +second coordinates and color them according to their cluster number. In R this can be done in a single line. In the +**R view (Table)** text editor, enter the following code: +```r +plot(x=knime.in$Universe_0_0, y=knime.in$Universe_0_1, main="Plotting column Universe_0_0 vs. Universe_0_1", col=knime.in$"Cluster Membership") +``` +

+

+**Explanation:** The table provided as input to the **R View (Table)** node is available as R **data.frame** with name +`knime.in`. Columns (also listed on the left side of the R View window) can be accessed in the usual R way by first +specifying the `data.frame` name and then the column name (e.g., `knime.in$Universe_0_0`). `plot` is the plotting function +we use to generate the image. We tell it to use the data in column `Universe_0_0` of the dataframe object **knime.in** +(denoted as `knime.in$Universe_0_0`) as x-coordinate and the other column `knime.in$Universe_0_1` as y-coordinate in the +plot. `main` is simply the main title of the plot and `col` the column that is used to determine the color (in this case +it is the `Cluster Membership` column). +

+

+Now press the Eval script and Show plot buttons. +

+
+ +```{note} +Note that we needed to put some extra quotes around `Cluster Membership`. If we omit those, R would interpret the column +name only up to the first space `(knime.in$Cluster)` which is not present in the table and leads to an error. Quotes are +regularly needed if column names contain spaces, tabs or other special characters like $ itself. +``` + ## Troubleshooting guide This section will show you where you can turn to when you encounter any problems with this tutorial or with our nodes in general. Please see the [FAQ](/quick-reference/contributor-faq.md) first. If your problem is not listed or the proposed solution does not work, feel free to leave us a message at the means of support that you see most fit. If that is the case, please provide us with as much information as you can. In an ideal case, that would be: - Your operating system and its version (e.g. Windows 8, Ubuntu 14.04). -- Your KNIME version (e.g. KNIME 3.1.2 full, KNIME 3.1.1 core). +- Your KNIME version (e.g. KNIME 3.1.2 full, KNIME 3.1.1 core). - If not full: Which update site did you use for the OpenMS plugin? Trunk (nightly-builds) or Stable? - Your OpenMS plugin version found under **Help** > **Install New Software** > **What is already installed?** - Other installations of OpenMS on your computer (e.g. from the independent OpenMS installer, another KNIME instance etc.) @@ -2943,9 +2952,9 @@ This section will show you where you can turn to when you encounter any problems #### How to debug KNIME and/or the OpenMS nodes? -- **KNIME**: Start with the normal log on the bottom right of KNIME. In general all warnings and errors will be listed there. If the output is not helpful enough, try to set the logging verbosity to the highest (DEBUG) under **Preferences** > **KNIME** > **Log file log level**. +- **KNIME**: Start with the normal log on the bottom right of KNIME. In general all warnings and errors will be listed there. If the output is not helpful enough, try to set the logging verbosity to the highest (DEBUG) under **Preferences** > **KNIME** > **Log file log level**. - **OpenMS nodes**: The first step should also be the log of KNIME. Additionally, you can view the output and the errors of our tools by right-clicking on the node and selecting **View: NODENAME Std Output?error**. This shows you the output of the OpenMS executable that was called by that node. For advanced users, you can try to execute the underlying executable in your `KNIME/plugins/de.openms.platform.arch.version/payload/bin` folder, to see if the error is reproducible outside of KNIME. -You can look up temporary files that are created by OpenMS nodes not connected to an Output or Viewer Node by right- clicking on a node and selecting the corresponding output view for the output you want to have a look at. The output views are located on the bottom of the menu that shows up after right-clicking. Their icon is a magnifying glass on top of a data table. The names of the output views in that menu may vary from node to node (usually a combination of ”file”,”out”,”output” and optionally its possible extensions). For example for the Input File node you can open the information on the output files by clicking on ”loaded file”. In any case, a hierarchy of file descriptions will show up. If there are multiple files on that port they will be numbered (usually beginning from 0). Expand the information for the file you want to see and copy its URI (you might need to erase the ”file:” prefix). Now open it with an editor of your choice. Be aware that temporary files are subject to deletion and are usually only stored as long as they are actually needed. There is also a Debug mode for the GKN nodes that keeps temporary files that can be activated under **Preferences** > **KNIME** > **Generic KNIME Nodes** > **Debug mode**. For the single nodes you can also increase the debug level in the configuration dialog under the advanced parameters. You can also specify a log file there, to save the log output of a specific node on your file system. + You can look up temporary files that are created by OpenMS nodes not connected to an Output or Viewer Node by right- clicking on a node and selecting the corresponding output view for the output you want to have a look at. The output views are located on the bottom of the menu that shows up after right-clicking. Their icon is a magnifying glass on top of a data table. The names of the output views in that menu may vary from node to node (usually a combination of ”file”,”out”,”output” and optionally its possible extensions). For example for the File Importer node you can open the information on the output files by clicking on ”loaded file”. In any case, a hierarchy of file descriptions will show up. If there are multiple files on that port they will be numbered (usually beginning from 0). Expand the information for the file you want to see and copy its URI (you might need to erase the ”file:” prefix). Now open it with an editor of your choice. Be aware that temporary files are subject to deletion and are usually only stored as long as they are actually needed. There is also a Debug mode for the GKN nodes that keeps temporary files that can be activated under **Preferences** > **KNIME** > **Generic KNIME Nodes** > **Debug mode**. For the single nodes you can also increase the debug level in the configuration dialog under the advanced parameters. You can also specify a log file there, to save the log output of a specific node on your file system. #### General @@ -3077,7 +3086,7 @@ Human Metabolome Database in 2013, Nucleic Acids Res 41(Database issue),D801–7 [^17]: J. Griss, A. R. Jones, T. Sachsenberg, M. Walzer, L. Gatto, J. Hartler, G. G. Thallinger, R. M. Salek, C. Steinbeck, N. Neuhauser, J. Cox, S. Neumann, J. Fan, -F. Reisinger, Q.-W. Xu, N. Del Toro, Y. Perez-Riverol, F. Ghali, N. Bandeira, I. Xenarios, O. Kohlbacher, J. A. Vizcaino, and H. Hermjakob, The mzTab Data Exchange Format: communicating MS-based proteomics and metabolomics experimental results to a wider audience, Mol Cell Proteomics (Jun 2014), doi:10.1074/mcp.O113.036681 . 69 +F. Reisinger, Q.-W. Xu, N. Del Toro, Y. Perez-Riverol, F. Ghali, N. Bandeira, I. Xenarios, O. Kohlbacher, J. A. Vizcaino, and H. Hermjakob, The mzTab Data Exchange Format: communicating MS-based proteomics and metabolomics experimental results to a wider audience, Mol Cell Proteomics (Jun 2014), doi:10.1074/mcp.O113.036681. 69 [^18]: S. Böcker, M. C. Letzel, Z. Lipták, and A. Pervukhin, SIRIUS: Decomposing isotope patterns for metabolite identification, Bioinformatics 25(2), 218–224 (2009), doi:10.1093/bioinformatics/btn603. 75 From 34656b78c3e6f5f1df118365bb66ccbe2ae81dc0 Mon Sep 17 00:00:00 2001 From: matteopilz Date: Wed, 21 Feb 2024 19:20:10 +0200 Subject: [PATCH 7/8] reordered sections --- .../openms-user-tutorial.md | 209 +++++++++++------- 1 file changed, 129 insertions(+), 80 deletions(-) diff --git a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md index 478ce95b..65b0b072 100644 --- a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md +++ b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md @@ -656,7 +656,7 @@ The following figure shows resulting list of compounds that contains at least on --> -## Label-free quantification of peptides +## Label-free quantification of peptides and proteins ### Introduction @@ -887,23 +887,139 @@ You have now constructed an entire identification and label-free feature mapping |:--:| |Figure 17: Simple KNIME data analysis example for LFQ| -### Identification and quantification of the iPRG2015 data with subsequent MSstats analysis -Advanced downstream data analysis of quantitative mass spectrometry-based proteomics data can be performed using MSstats[^11]. This tool can be combined with -an OpenMS preprocessing pipeline (e.g. in KNIME). The OpenMS experimental design is used to present the data in an MSstats-conformant way for the analysis. Here, -we give an example how to utilize these resources when working with quantitative label-free data. We describe how to use OpenMS and MSstats for the analysis of the -ABRF iPRG2015 dataset[^12]. +### Extending the LFQ workflow by protein inference and quantification + +We have made the following changes compared to the original label-free quantification workflow from the last chapter: + +- First, we have added a **ProteinQuantifier** node and connected its input port to the output port of the **ConsensusMapNormalizer** node. +- This already enables protein quantification. **ProteinQuantifier** quantifies peptides by summarizing over all observed charge states and proteins by summarizing over their quantified peptides. It stores two output files, one for the quantified peptides and one for the proteins. +- In this example, we consider only the protein quantification output file, which is written to the first output port of **ProteinQuantifier**. +- Because there is no dedicated node in KNIME to read back the **ProteinQuantifier** output file format into a KNIME table, we have to use a workaround. Here, we have added an additional URI Port to Variable node which converts the name of the output file to a so-called “flow variable” in KNIME. This variable is passed on to the next node **CSV Reader**, where it is used to specify the name of the input file to be read. If you double-click on **CSV Reader**, you will see that the text field, where you usually enter the location of the CSV file to be read, is greyed out. Instead, the flow variable is used to specify the location, as indicated by the small green button with the “v=?” label on the right. +- The table containing the **ProteinQuantifier** results is filtered one more time in order to remove decoy proteins. You can have a look at the final list of quantified protein groups by right-clicking the **Row Filter** and selecting **Filtered**. +- By default, i.e., when the second input port `protein_groups` is not used, **ProteinQuantifier** quantifies proteins using only the unique peptides, which usually results in rather low numbers of quantified proteins. +- In this example, however, we have performed protein inference using Fido and + used the resulting protein grouping information to also quantify indistinguishable proteins. In fact, we also used a greedy method in **FidoAdapter** (parameter `greedy_group_resolution`) to uniquely assign the peptides of a group to the most probable protein(s) in the respective group. This boosts the number of quantifications but slightly raises the chances to yield distorted protein quantities. +- As a prerequisite for using **FidoAdapter**, we have added an **IDPosteriorErrorProbability** node within the ID meta node, between the **XTandemAdapter** (note the replacement of OMSSA because of ill-calibrated scores) and **PeptideIndexer**. We have + set its parameter `prob_correct` to `true`, so it computes posterior probabilities instead of posterior error probabilities (1 - PEP). These are stored in the resulting idXML file and later on used by the Fido algorithm. Also note that we excluded FDR filtering from the standard meta node. Harsh filtering before inference impacts the calibration of the results. Since we filter peptides before quantification though, no potentially random peptides will be included in the results anyway. +- Next, we have added a third outgoing connection to our ID meta node and connected it to the second input port of `ZipLoopEnd`. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. +- Instead of the meta node **Protein inference** with **FidoAdapter**, we could have just used a **FidoAdapter** node ( **Community Nodes** > **OpenMS** > **Identification Processing**). However, the meta node contains an additional subworkflow which, besides calling **FidoAdapter**, performs a statistical validation (e.g. (pseudo) receiver operating curves; ROCs) of the protein inference results using some of the more advanced KNIME and R nodes. The meta node also shows how to use **MzTabExporter** and **MzTabReader**. + +### Statistical validation of protein inference results + +In the following section, we will explain the subworkflow contained in the **Protein inference with FidoAdapter** meta node. + +#### Data preparation + +For downstream analysis on the protein ID level in KNIME, it is again necessary to convert the idXML-file-format result generated from **FidoAdapter** into a KNIME table. + +- We use the **MzTabExporter** to convert the inference results from **FidoAdapter** to a human readable, tab-separated mzTab file. mzTab contains multiple sections, + that are all exported by default, if applicable. This file, with its different sections can again be read by the **MzTabReader** that produces one output in KNIME table + format (triangle ports) for each section. Some ports might be empty if a section did not exist. Of course, we continue by connecting the downstream nodes with the protein section output (second port). +- Since the protein section contains single proteins as well as protein groups, we filter them for single proteins with the standard **Row Filter**. + +#### ROC curve of protein ID + +ROC Curves (Receiver Operating Characteristic curves) are graphical plots that visualize sensitivity (true-positive rate) against fall-out (false positive rate). They are often used to judge the quality of a discrimination method like e.g., peptide or protein identification engines. ROC Curve already provides the functionality of drawing ROC curves for binary classification problems. When configuring this node, select the `opt_global_target_decoy` column as the class (i.e. target outcome) column. We want to find out, how good our inferred protein probability discriminates between them, +therefore add `best_search_engine_score[1]` (the inference engine score is treated like a peptide search engine score) to the list of *”Columns containing positive class probabilities”*. View the plot by right-clicking and selecting **View: ROC Curves**. A perfect classifier has +an area under the curve (AUC) of 1.0 and its curve touches the upper left of the plot. However, in protein or peptide identification, the ground-truth (i.e., which target +identifications are true, which are false) is usually not known. Instead, so called pseudoROC Curves are regularly used to plot the number of target proteins against the false +discovery rate (FDR) or its protein-centric counterpart, the q-value. The FDR is approximated by using the target-decoy estimate in order to distinguish true IDs from +false IDs by separating target IDs from decoy IDs. + +#### Posterior probability and FDR of protein IDs + +ROC curves illustrate the discriminative capability of the scores of IDs. In the case of protein identifications, Fido produces the posterior probability of each protein as +the output score. However, a perfect score should not only be highly discriminative (distinguishing true from false IDs), it should also be “calibrated” (for probability indicating that all IDs with reported posterior probability scores of 95% should roughly have a 5% probability of being false. This implies that the estimated number of false +positives can be computed as the sum of posterior error probabilities ( = 1 - posterior probability) in a set, divided by the number of proteins in the set. Thereby a +posterior-probability-estimated FDR is computed which can be compared to the actual target-decoy FDR. We can plot calibration curves to help us visualize the quality of +the score (when the score is interpreted as a probability as Fido does), by comparing how similar the target-decoy estimated FDR and the posterior probability estimated +FDR are. Good results should show a close correspondence between these two measurements, although a non-correspondence does not necessarily indicate wrong results. + +The calculation is done by using a simple R script in R snippet. First, the target decoy protein FDR is computed as the proportion of decoy proteins among all significant protein IDs. Then posterior probabilistic-driven FDR is estimated by the average of the posterior error probability of all significant protein IDs. Since FDR is the property for a group of protein IDs, we can also calculate a local property for each protein: the q-value of a certain protein ID is the minimum FDR of any groups of protein IDs +that contain this protein ID. We plot the protein ID results versus two different kinds of FDR estimates in R View(Table) (see Fig. 22). +(Figure_21)= +|![The workflow of statistical analysis of protein inference results](/images/openms-user-tutorial/protein-inference/inference_metanode.png)| +|:--:| +|Figure 21: The workflow of statistical analysis of protein inference results| +(Figure_22)= +|![The pseudo-ROC Curve of protein IDs](/images/openms-user-tutorial/protein-inference/proteinFDR.png)| +|:--:| +|Figure 22: The pseudo-ROC Curve of protein IDs. The accumulated number of protein IDs is plotted on two kinds of scales: target-decoy protein FDR and Fido posterior probability estimated FDR. The largest value of posterior probability estimated FDR is already smaller than 0.04, this is because the posterior probability output from Fido is generally very high| + + +## Advanced topic: R integration + +KNIME provides a large number of nodes for a wide range of statistical analysis, machine learning, data processing, and +visualization. Still, more recent statistical analysis methods, specialized visualizations or cutting edge algorithms +may not be covered in KNIME. In order to expand its capabilities beyond the readily available nodes, external scripting +languages can be integrated. In this tutorial, we primarily use scripts of the powerful statistical computing language R. +Note that this part is considered advanced and might be difficult to follow if you are not familiar with R. In this case +you might skip this part. + +**R View (Table)** allows to seamlessly include R scripts into KNIME. We will +demonstrate on a minimal example how such a script is integrated. + +
+

**Task**

+

+First we need some example data in KNIME, which we will generate using the **Data Generator** node (**IO** > **Other** > **Data Generator**). +You can keep the default settings and execute the node. The table contains four columns, each containing random coordinates and one column +containing a cluster number (Cluster_0 to Cluster_3). Now place a **R View (Table)** node into the workflow and connect +the upper output port of the **Data Generator** node to the input of the **R View (Table)** node. Right-click and +configure the node. If you get an error message like `Execute failed: R_HOME does not contain a folder with name ’bin’.` +or `Execution failed: R Home is invalid.`: please change the R settings in the preferences. To do so open **File** > +**Preferences** > **KNIME** > **R** and enter the path to your R installation (the folder that contains the bin +directory. e.g., {path}`C:,Program Files,R,R-3.4.3`). +

+

+If you get an error message like: ”Execute failed: Could not find Rserve package. Please install it in your R +installation by running ”install.packages(’Rserve’)”.” You may need to run your R binary as administrator (In windows +explorer: right-click ”Run as administrator”) and enter install.packages(’Rserve’) to install the package. +

+

+If R is correctly recognized we can start writing an R script. Consider that we are interested in plotting the first and +second coordinates and color them according to their cluster number. In R this can be done in a single line. In the +**R view (Table)** text editor, enter the following code: +```r +plot(x=knime.in$Universe_0_0, y=knime.in$Universe_0_1, main="Plotting column Universe_0_0 vs. Universe_0_1", col=knime.in$"Cluster Membership") +``` +

+

+**Explanation:** The table provided as input to the **R View (Table)** node is available as R **data.frame** with name +`knime.in`. Columns (also listed on the left side of the R View window) can be accessed in the usual R way by first +specifying the `data.frame` name and then the column name (e.g., `knime.in$Universe_0_0`). `plot` is the plotting function +we use to generate the image. We tell it to use the data in column `Universe_0_0` of the dataframe object **knime.in** +(denoted as `knime.in$Universe_0_0`) as x-coordinate and the other column `knime.in$Universe_0_1` as y-coordinate in the +plot. `main` is simply the main title of the plot and `col` the column that is used to determine the color (in this case +it is the `Cluster Membership` column). +

+

+Now press the Eval script and Show plot buttons. +

+
```{note} -Reanalysing the full dataset from scratch would take too long. In the following tutorial, we will focus on just the conversion process and the downstream analysis. +Note that we needed to put some extra quotes around `Cluster Membership`. If we omit those, R would interpret the column +name only up to the first space `(knime.in$Cluster)` which is not present in the table and leads to an error. Quotes are +regularly needed if column names contain spaces, tabs or other special characters like $ itself. ``` -#### Excursion MSstats +## Using MSstats in a KNIME workflow The R package `MSstats` can be used for statistical relative quantification of proteins and peptides in mass spectrometry-based proteomics. Supported are label-free as well as labeled experiments in combination with data-dependent, targeted and data independent acquisition. Inputs can be identified and quantified entities (peptides or proteins) and the output is a list of differentially abundant entities, or summaries of their relative abundance. It depends on accurate feature detection, identification and quantification which can be performed e.g. by an OpenMS workflow. MSstats can be used for data processing & visualization, as well as statistical modeling & inference. Please see [^11] and the [MSstats](http://msstats.org) website for further information. +### Identification and quantification of the iPRG2015 data with subsequent MSstats analysis + +Here, we describe how to use OpenMS and MSstats for the analysis of the ABRF iPRG2015 dataset[^12]. + +```{note} +Reanalysing the full dataset from scratch would take too long. In the following tutorial, we will focus on just the conversion process and the downstream analysis. +``` + + #### Dataset The iPRG (Proteome Informatics Research Group) dataset from the study in 2015, as @@ -1228,80 +1344,12 @@ The Volcano plots show differently expressed spiked-in proteins. In the left plo The full analysis workflow can be found under: {path}`Workflows,MSstatsstatPostProcessingiPRG2015.knwf` -## Protein inference - -In the last chapter, we have successfully quantified peptides in a label-free experiment. As a next step, we will further extend this label-free quantification workflow by protein inference and protein quantification capabilities. This workflow uses some of the more advanced concepts of KNIME, as well as a few more nodes containing R code. For these reasons, you will not have to build it yourself. Instead, we have already prepared and copied this workflow to the USB sticks. Just import {path}`Workflows,labelfree_with_protein_quantification.knwf` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. - -Before you can execute the workflow, you again have to correct the locations of -the files in the Input Files nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. - -### Extending the LFQ workflow by protein inference and quantification - -We have made the following changes compared to the original label-free quantification workflow from the last chapter: -- First, we have added a **ProteinQuantifier** node and connected its input port to the output port of the **ConsensusMapNormalizer** node. -- This already enables protein quantification. **ProteinQuantifier** quantifies peptides by summarizing over all observed charge states and proteins by summarizing over their quantified peptides. It stores two output files, one for the quantified peptides and one for the proteins. -- In this example, we consider only the protein quantification output file, which is written to the first output port of **ProteinQuantifier**. -- Because there is no dedicated node in KNIME to read back the **ProteinQuantifier** output file format into a KNIME table, we have to use a workaround. Here, we have added an additional URI Port to Variable node which converts the name of the output file to a so-called “flow variable” in KNIME. This variable is passed on to the next node **CSV Reader**, where it is used to specify the name of the input file to be read. If you double-click on **CSV Reader**, you will see that the text field, where you usually enter the location of the CSV file to be read, is greyed out. Instead, the flow variable is used to specify the location, as indicated by the small green button with the “v=?” label on the right. -- The table containing the **ProteinQuantifier** results is filtered one more time in order to remove decoy proteins. You can have a look at the final list of quantified protein groups by right-clicking the **Row Filter** and selecting **Filtered**. -- By default, i.e., when the second input port `protein_groups` is not used, **ProteinQuantifier** quantifies proteins using only the unique peptides, which usually results in rather low numbers of quantified proteins. -- In this example, however, we have performed protein inference using Fido and - used the resulting protein grouping information to also quantify indistinguishable proteins. In fact, we also used a greedy method in **FidoAdapter** (parameter `greedy_group_resolution`) to uniquely assign the peptides of a group to the most probable protein(s) in the respective group. This boosts the number of quantifications but slightly raises the chances to yield distorted protein quantities. -- As a prerequisite for using **FidoAdapter**, we have added an **IDPosteriorErrorProbability** node within the ID meta node, between the **XTandemAdapter** (note the replacement of OMSSA because of ill-calibrated scores) and **PeptideIndexer**. We have - set its parameter `prob_correct` to `true`, so it computes posterior probabilities instead of posterior error probabilities (1 - PEP). These are stored in the resulting idXML file and later on used by the Fido algorithm. Also note that we excluded FDR filtering from the standard meta node. Harsh filtering before inference impacts the calibration of the results. Since we filter peptides before quantification though, no potentially random peptides will be included in the results anyway. -- Next, we have added a third outgoing connection to our ID meta node and connected it to the second input port of `ZipLoopEnd`. Thus, KNIME will wait until all input files have been processed by the loop and then pass on the resulting list of idXML files to the subsequent IDMerger node, which merges all identifications from all idXML files into a single idXML file. This is done to get a unique assignment of peptides to proteins over all samples. -- Instead of the meta node **Protein inference** with **FidoAdapter**, we could have just used a **FidoAdapter** node ( **Community Nodes** > **OpenMS** > **Identification Processing**). However, the meta node contains an additional subworkflow which, besides calling **FidoAdapter**, performs a statistical validation (e.g. (pseudo) receiver operating curves; ROCs) of the protein inference results using some of the more advanced KNIME and R nodes. The meta node also shows how to use **MzTabExporter** and **MzTabReader**. - -### Statistical validation of protein inference results - -In the following section, we will explain the subworkflow contained in the **Protein inference with FidoAdapter** meta node. - -#### Data preparation - -For downstream analysis on the protein ID level in KNIME, it is again necessary to convert the idXML-file-format result generated from **FidoAdapter** into a KNIME table. - -- We use the **MzTabExporter** to convert the inference results from **FidoAdapter** to a human readable, tab-separated mzTab file. mzTab contains multiple sections, - that are all exported by default, if applicable. This file, with its different sections can again be read by the **MzTabReader** that produces one output in KNIME table - format (triangle ports) for each section. Some ports might be empty if a section did not exist. Of course, we continue by connecting the downstream nodes with the protein section output (second port). -- Since the protein section contains single proteins as well as protein groups, we filter them for single proteins with the standard **Row Filter**. - -#### ROC curve of protein ID - -ROC Curves (Receiver Operating Characteristic curves) are graphical plots that visualize sensitivity (true-positive rate) against fall-out (false positive rate). They are often used to judge the quality of a discrimination method like e.g., peptide or protein identification engines. ROC Curve already provides the functionality of drawing ROC curves for binary classification problems. When configuring this node, select the `opt_global_target_decoy` column as the class (i.e. target outcome) column. We want to find out, how good our inferred protein probability discriminates between them, -therefore add `best_search_engine_score[1]` (the inference engine score is treated like a peptide search engine score) to the list of *”Columns containing positive class probabilities”*. View the plot by right-clicking and selecting **View: ROC Curves**. A perfect classifier has -an area under the curve (AUC) of 1.0 and its curve touches the upper left of the plot. However, in protein or peptide identification, the ground-truth (i.e., which target -identifications are true, which are false) is usually not known. Instead, so called pseudoROC Curves are regularly used to plot the number of target proteins against the false -discovery rate (FDR) or its protein-centric counterpart, the q-value. The FDR is approximated by using the target-decoy estimate in order to distinguish true IDs from -false IDs by separating target IDs from decoy IDs. - -#### Posterior probability and FDR of protein IDs - -ROC curves illustrate the discriminative capability of the scores of IDs. In the case of protein identifications, Fido produces the posterior probability of each protein as -the output score. However, a perfect score should not only be highly discriminative (distinguishing true from false IDs), it should also be “calibrated” (for probability indicating that all IDs with reported posterior probability scores of 95% should roughly have a 5% probability of being false. This implies that the estimated number of false -positives can be computed as the sum of posterior error probabilities ( = 1 - posterior probability) in a set, divided by the number of proteins in the set. Thereby a -posterior-probability-estimated FDR is computed which can be compared to the actual target-decoy FDR. We can plot calibration curves to help us visualize the quality of -the score (when the score is interpreted as a probability as Fido does), by comparing how similar the target-decoy estimated FDR and the posterior probability estimated -FDR are. Good results should show a close correspondence between these two measurements, although a non-correspondence does not necessarily indicate wrong results. - -The calculation is done by using a simple R script in R snippet. First, the target decoy protein FDR is computed as the proportion of decoy proteins among all significant protein IDs. Then posterior probabilistic-driven FDR is estimated by the average of the posterior error probability of all significant protein IDs. Since FDR is the property for a group of protein IDs, we can also calculate a local property for each protein: the q-value of a certain protein ID is the minimum FDR of any groups of protein IDs -that contain this protein ID. We plot the protein ID results versus two different kinds of FDR estimates in R View(Table) (see Fig. 22). -(Figure_21)= -|![The workflow of statistical analysis of protein inference results](/images/openms-user-tutorial/protein-inference/inference_metanode.png)| -|:--:| -|Figure 21: The workflow of statistical analysis of protein inference results| -(Figure_22)= -|![The pseudo-ROC Curve of protein IDs](/images/openms-user-tutorial/protein-inference/proteinFDR.png)| -|:--:| -|Figure 22: The pseudo-ROC Curve of protein IDs. The accumulated number of protein IDs is plotted on two kinds of scales: target-decoy protein FDR and Fido posterior probability estimated FDR. The largest value of posterior probability estimated FDR is already smaller than 0.04, this is because the posterior probability output from Fido is generally very high| - -## Isobaric analysis +### Isobaric analysis workflow In the last chapters, we identified and quantified peptides in a label-free experiment. In this section, we would like to introduce a possible workflow for the analysis of isobaric data. - -### Isobaric analysis workflow - Let’s have a look at the workflow (see Fig 23). (Figure_23)= @@ -1318,7 +1366,7 @@ To reduce the complexity of the data for later inference the q-value estimation Please import the workflow from {path}`Workflows,IdentificationquantificationisobaricinferenceepifanyMSstatsTMT` into KNIME via the menu entry **File** > **Import KNIME workflow** > **Select file** and double-click the imported workflow in order to open it. Before you can execute the workflow, you have to correct the locations of the files in the `Input Files` nodes (don’t forget the one for the FASTA database inside the “ID” meta node). Try and run your workflow by executing all nodes at once. -### Excursion MSstatsTMT +#### Excursion MSstatsTMT The R package `MSstatsTMT` can be used for protein significance analysis in shotgun mass spectrometry-based proteomic experiments with tandem mass tag (TMT) labeling. `MSstatsTMT` provides functionality for two types of analysis & their visualization: Protein summarization based on peptide quantification and Model-based group comparison to detect significant changes in abundance. It depends on accurate feature detection, identification and quantification which can be performed e.g. by an OpenMS workflow. @@ -1326,7 +1374,7 @@ In general, `MSstatsTMT` can be used for data processing & visualization, as wel There is also an [online lecture](https://youtu.be/3CDnrQxGLbA) and tutorial for `MSstatsTMT` from the May Institute Workshop 2020. -### Dataset and experimental design +#### Dataset and experimental design We are using the MSV000084264 ground truth dataset, which consists of TMT10plex controlled mixes of different concentrated UPS1 peptides spiked into SILAC HeLa peptides measured in a dilution series https://www.omicsdi.org/dataset/massive/MSV000084264. Figure 24 shows the experimental design. In this experiment, 5 different TMT10plex mixtures – different labeling strategies – were analysed. These were measured in triplicates represented by the 15 MS runs (3 runs each). The example data, database and experimental design to run the workflow can be found [here](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Data/isobaric_MSV000084264/). @@ -1527,10 +1575,11 @@ Here, we have a example output of the **R View**, which depicts the significant All plots are saved to the in the beginning specified output directory in addition. -### Note +#### Note The isobaric analysis does not always has to be performed on protein level, for example for phosphoproteomics studies one is usually interested on the peptide level - in addition inference on peptides with post-translational modification is not straight forward. Here, we present and additonal workflow on peptide level, which can potentially be adapted and used for such cases. Please see {path}`Workflows,IdentificationquantificationisobaricMSstatsTMT` + ## Label-free quantification of metabolites ### Introduction From e72aefe9b1892aed6cff0e12626ecb8d62afef84 Mon Sep 17 00:00:00 2001 From: matteopilz Date: Wed, 21 Feb 2024 20:29:06 +0200 Subject: [PATCH 8/8] download fix --- docs/tutorials-and-quickstart-guides/openms-user-tutorial.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md index 65b0b072..d0a8fa48 100644 --- a/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md +++ b/docs/tutorials-and-quickstart-guides/openms-user-tutorial.md @@ -478,7 +478,7 @@ Those *knwf* files can again be imported by selecting: **File** > **Import KNIME ```{note} For your convenience we added all workflows discussed in this tutorial to the **Workflows** folder on the USB Stick. - Additionally, the workflow files can be found on workflow downloads. If you want to check + Additionally, the workflow files can be found on workflow downloads. If you want to check your own workflow by comparing it to the solution or got stuck, simply import the full workflow from the corresponding *knwf* file and after that double-click it in your KNIME Workflow repository to open it. ```
Sample MSstats_Condition MSstats_BioReplicate MSstats_Mixture LabelName
1 Norm Norm 1 126

j0Z_7at>ez3$HZ(T= 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 literal 46395 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 diff --git a/docs/openms-applications-and-tools/topp-tools/types-of-topp-tools/feature-detection-on-centroided-data.md b/docs/openms-applications-and-tools/topp-tools/types-of-topp-tools/feature-detection-on-centroided-data.md index f640786a..b3ea53b7 100644 --- a/docs/openms-applications-and-tools/topp-tools/types-of-topp-tools/feature-detection-on-centroided-data.md +++ b/docs/openms-applications-and-tools/topp-tools/types-of-topp-tools/feature-detection-on-centroided-data.md @@ -4,7 +4,7 @@ orphan: true Feature Detection on Centroided Data ==================================== -To quantify peptide features, TOPP offers the **FeatureFinder** tools. In this section the **FeatureFinderCentroided** +To quantify peptide features, TOPP offers the **FeatureFinder** tools. In this section the `FeatureFinderCentroided` is used, which works only on centroided data. There are other FeatureFinders available that also work on profile data. For this example the file `LCMS-centroided.mzML` from the examples data is used (**File** > **Open example data**). In order diff --git a/docs/openms-applications-and-tools/topp-tools/types-of-topp-tools/file-handling.md b/docs/openms-applications-and-tools/topp-tools/types-of-topp-tools/file-handling.md index 91452c55..b53b28d5 100644 --- a/docs/openms-applications-and-tools/topp-tools/types-of-topp-tools/file-handling.md +++ b/docs/openms-applications-and-tools/topp-tools/types-of-topp-tools/file-handling.md @@ -6,7 +6,7 @@ File Handling ## General information about peak and feature maps -For general information about a peak or feature map, use the **FileInfo** tool. +For general information about a peak or feature map, use the `FileInfo` tool. - It can print RT, m/z and intensity ranges, the overall number of peaks, and the distribution of MS levels. - It can print a statistical summary of intensities. diff --git a/docs/run-workflows-with-openms-tools/knime/tutorial.md b/docs/run-workflows-with-openms-tools/knime/tutorial.md index 8d459552..1bc8f8d0 100644 --- a/docs/run-workflows-with-openms-tools/knime/tutorial.md +++ b/docs/run-workflows-with-openms-tools/knime/tutorial.md @@ -506,8 +506,8 @@ information about the data set before starting the actual development of a data can also be used to check if all requirements are met and that your system is compatible. - Create a new workflow. -- Add an **File Importer** node and an **Output Folder** node (found in **Community Nodes** > **GenericKnimeNodes** > **IO**) - and a **FileInfo** node (to be found in the category **Community Node** > **OpenMS** > **File Handling**) to the workflow. +- Add an `File Importer` node and an `Output Folder` node (found in **Community Nodes** > **GenericKnimeNodes** > **IO**) + and a `FileInfo` node (to be found in the category **Community Node** > **OpenMS** > **File Handling**) to the workflow. - Connect the File Importer node to the FileInfo node, and the first output port of the FileInfo node to the Output Folder node. @@ -525,8 +525,8 @@ The complete workflow is shown in below image. `FileInfo` can produce two differ **Browse**. In the file system browser [select](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Introduction/datasets/tiny/velos005614.mzML) {path}`Example_Data,Introduction,datasets,tiny,velos005614.mzML` and click **Open**. Afterwards close the dialog by clicking **Ok**. -- The **File Importer** node and the **FileInfo** node should now have switched to yellow, but the **Output Folder** node is still red. - Double-click on the **Output Folder** node and click on **Browse** to select an output directory for the generated data. +- The `File Importer` node and the `FileInfo` node should now have switched to yellow, but the `Output Folder` node is still red. + Double-click on the `Output Folder` node and click on **Browse** to select an output directory for the generated data. - Great! Your first workflow is now ready to be run. Press + F7 (shift key + F7; or the button with multiple green triangles in the KNIME Toolbar) to execute the complete workflow. You can also right click on any node of your workflow and select Execute from the context menu. @@ -543,36 +543,36 @@ would like to filter multiple mzML files to only include MS1 spectra. We will no same information on three different files and then write the output files to a folder. - We start from the previous workflow. -- First we need to replace our single input file with multiple files. Therefore we add the Input Files node from the +- First we need to replace our single input file with multiple files. Therefore we add the `Input Files` node from the category **Community Nodes** > **GenericKnimeNodes** > **IO**. -- To select the files we double-click on the Input Files node and click on **Add**. In the filesystem browser we select +- To select the files we double-click on the `Input Files` node and click on **Add**. In the filesystem browser we select all three files from the [directory](https://abibuilder.cs.uni-tuebingen.de/archive/openms/Tutorials/Example_Data/Introduction/datasets/tiny) **Example_Data** > **Introduction** > **datasets** > **tiny**. And close the dialog with **Ok**. -- We now add two more nodes: the **ZipLoopStart** and the **ZipLoopEnd** node from the category - **Community Nodes** > **GenericKnimeNodes* > **Flow** and replace the **FileInfo** node with **FileFilter** from **Community Nodes** > **OpenMS** > **File Handling**. -- Afterwards we connect the **Input Files** node to the first port of the **ZipLoopStart** node, the first port of the **ZipLoopStart** +- We now add two more nodes: the `ZipLoopStart` and the `ZipLoopEnd` node from the category + **Community Nodes** > **GenericKnimeNodes* > **Flow** and replace the `FileInfo` node with `FileFilter` from **Community Nodes** > **OpenMS** > **File Handling**. +- Afterwards we connect the `Input Files` node to the first port of the `ZipLoopStart` node, the first port of the `ZipLoopStart` node to the **FileConverter** node, the first output port of the **FileConverter** node to the first input port of the - **ZipLoopEnd** node, and the first output port of the **ZipLoopEnd** node to the **Output Folder** node. + `ZipLoopEnd` node, and the first output port of the `ZipLoopEnd` node to the `Output Folder` node. The complete workflow is shown in the top right of the figure below. |![A minimal workflow calling the FileFilter on multiple mzML files in a loop](/images/openms-user-tutorial/knime-setup/KNIME_annotated_FileFilter.png)| |:--:| -|Figure 9: The fileFilter workflow. Showing the configure dialog for FileFilter, and the level selector pane. +|Figure 9: The FileFilter workflow. Showing the configure dialog for `FileFilter`, and the level selector pane. -Now we need to configure the FileFilter to only store MS1 data. To do this we double click on the FileFilter node to open the configuration dialog (see left pane above), double click "level", select 2 +Now we need to configure the `FileFilter` to only store MS1 data. To do this we double click on the `FileFilter` node to open the configuration dialog (see left pane above), double click "level", select 2 from the sub-pane (see bottom right panel above), and click delete. Repeat the process for 3. Select OK to exit the sub-pane, and then OK again in the configuration dialog. Execute the workflow and inspect the output as before. Now, if you open the resulting files in TOPPView, you can see that only the MS1 spectra remain. -In case you had trouble to understand what **ZipLoopStart** and **ZipLoopEnd** do, here is a brief explanation: +In case you had trouble to understand what `ZipLoopStart` and `ZipLoopEnd` do, here is a brief explanation: -- The **Input Files** node passes a list of files to the ZipLoopStart node. -- The ZipLoopStart node takes the files as input, but passes the single files sequentially (that is: one after the other) +- The `Input Files` node passes a list of files to the `ZipLoopStart` node. +- The `ZipLoopStart` node takes the files as input, but passes the single files sequentially (that is: one after the other) to the next node. -- The ZipLoopEnd collects the single files that arrive at its input port. After all files have been processed, the collected +- The `ZipLoopEnd` collects the single files that arrive at its input port. After all files have been processed, the collected files are passed again as file list to the next node that follows. #### Advanced topic: Metanodes @@ -584,7 +584,7 @@ improve handling and clarity of large workflows: