From eabff43f9c9d68ba6115112c1d1a0ada1195603a Mon Sep 17 00:00:00 2001 From: joXemMx Date: Wed, 5 Nov 2025 18:08:22 +0100 Subject: [PATCH 1/6] first draft example workflow in R --- client-api_r/README.md | 147 +++++++++++++++++++++++++++++++++++------ 1 file changed, 127 insertions(+), 20 deletions(-) diff --git a/client-api_r/README.md b/client-api_r/README.md index 67b3e1db..9a8960f5 100644 --- a/client-api_r/README.md +++ b/client-api_r/README.md @@ -1,41 +1,53 @@ > [!WARNING] -> `Rsirius` is now `RSirius`! Starting with `v3.1+sirius6.3.3`, `Rsirius` is renamed to `RSirius` to fit the naming convention of `PySirius`. Please make sure you update your library imports accordingly! +> `Rsirius` is now `RSirius`! Starting with `v3.1+sirius6.3.3`, `Rsirius` is renamed to `RSirius` to fit the naming +> convention of `PySirius`. Please make sure you update your library imports accordingly! # RSirius -REST API that provides the full functionality of SIRIUS and its web services as background service. It is intended as entry-point for scripting languages and software integration SDKs. + +REST API that provides the full functionality of SIRIUS and its web services as background service. It is intended as +entry-point for scripting languages and software integration SDKs. ## Installation & Usage ### conda install (preferred) Install the `r-sirius-ms` package from conda-forge using + ```shell conda install -c conda-forge r-sirius-ms ``` + or + ```shell conda install conda-forge::r-sirius-ms ``` -This will automatically install all dependencies, including the `sirius-ms` package including SIRIUS itself and set an environment variable for SIRIUS when activating the respective conda environment. -The conda-forge install is the preferred method due to quality-of-life features (see [Getting Started](#getting-started)). +This will automatically install all dependencies, including the `sirius-ms` package including SIRIUS itself and set an +environment variable for SIRIUS when activating the respective conda environment. +The conda-forge install is the preferred method due to quality-of-life features ( +see [Getting Started](#getting-started)). ### install using remotes library #### Specific Version + Replace v0.0.0 with your api version + ```R library(remotes) install_github(repo = "sirius-ms/sirius-client-openAPI@v0.0.0", subdir = "client-api_r/generated", ref = "master", build = TRUE) ``` #### Latest (unstable) Version + ```R library(remotes) install_github(repo = "sirius-ms/sirius-client-openAPI", subdir = "client-api_r/generated", ref = "master", build = TRUE) ``` Then import the package: + ```R library(RSirius) ``` @@ -43,15 +55,18 @@ library(RSirius) ## Getting Started ### Local Endpoint -Please follow the [installation procedure](#installation--usage) and then run the following (while replacing the Strings for project_space and sirius_executable). -NOTE: the SIRIUS REST service automatically allocates a random available port on your machine. +Please follow the [installation procedure](#installation--usage) and then run the following (while replacing the Strings +for project_space and sirius_executable). + +NOTE: the SIRIUS REST service automatically allocates a random available port on your machine. `SiriusSDK` will always try to get this information **automatically**, but you can set a port manually to make sure. -If you installed via conda-forge **or** have SIRIUS in your path, you should be able to activate your environment and simply use: +If you installed via conda-forge **or** have SIRIUS in your path, you should be able to activate your environment and +simply use: ```R -library(RSirius) +library(RSirius) sdk <- SiriusSDK$new() # SIRIUS must be in the path or the SIRIUS_EXE environment variable must be specified. # Is automatically configured when installing via conda or windows ms installer @@ -67,25 +82,26 @@ sdk$shutdown_sirius() If you installed from GitHub or a local folder manually and do **not** have SIRIUS in path, you can go the manual way: ```R -library(RSirius) +library(RSirius) sdk <- SiriusSDK$new() -api <- sdk$start_sirius(sirius_path="your/path/to/sirius", port=8080) +api <- sdk$start_sirius(sirius_path = "your/path/to/sirius", port = 8080) ``` You can also attach to a running SIRIUS instance: ```R -library(RSirius) +library(RSirius) sdk <- SiriusSDK$new() -api <- sdk$attach_to_sirius(sirius_major_version=6, port=8080) +api <- sdk$attach_to_sirius(sirius_major_version = 6, port = 8080) ``` ### Remote Endpoint -Please follow the [installation procedure](#installation--usage) and then run the following (while replacing address and port with the Remote address specifications): +Please follow the [installation procedure](#installation--usage) and then run the following (while replacing address and +port with the Remote address specifications): ```R -library(RSirius) +library(RSirius) sdk <- SiriusSDK$new() api <- sdk$connect("http://localhost:8080") ``` @@ -94,13 +110,104 @@ api <- sdk$connect("http://localhost:8080") For more niche functionality and insights, find the SiriusSDK class [here](rsirius_sdk.R). -### Example code -Our feedstocks for the conda-forge packages are running an automated minimal test. -We included the scripts [here](../.updater/clientTests/CondaFeedstockMinimalTests). -Feel free to take them as example usages of the packages. +### Documentation for API Endpoints -## Documentation for API Endpoints Please click [here](generated/README.md#documentation-for-api-endpoints) -## Documentation For Models +### Documentation For Models + Please click [here](generated/README.md#documentation-for-models) + +# Example usage of RSirius + +First, import `RSirius` and start the SIRIUS REST service using the [`SiriusSDK`](./generated/R/rsirius_sdk.R) class to retrieve a [central API client](./generated/R/rsirius_api.R) for accessing all API models. + +```R +library(RSirius) +sdk <- SiriusSDK$new() +api <- sdk$attach_or_start_sirius() +``` + +Verify the service is running using the [**Actuator API**](./generated/docs/ActuatorApi.md): + +```R +if (!(api$actuator_api$Health()$status == "UP")) { + message("There seems to be a problem reaching the REST service!") + quit(status = 1) +} +``` + +Log in with the [**Login and Account API**](./generated/docs/LoginAndAccountApi.md) to access SIRIUS functionalities: + +```R +var_accept_terms <- TRUE # ensure you accept the terms +var_account_credentials <- AccountCredentials$new('SIRIUS_USER', 'SIRIUS_PW') +api$login_and_account_api$Login(var_accept_terms, var_account_credentials) +``` + +Create a project space using the [**Projects API**](./generated/docs/ProjectsApi.md). This `.sirius` file (default location: `/home//sirius-projects/.sirius`) contains all input data and annotation results. Access the path via [project info](./generated/docs/ProjectInfo.md). + +```R +project_info <- api$projects_api$CreateProject("ExampleProject") +``` + +[Import preprocessed data](./generated/docs/ProjectsApi.md#ImportPreprocessedData) from [`Kaempferol.ms`](../.updater/clientTests/Data/Kaempferol.ms). Import [as a job](./generated/docs/ProjectsApi.md#ImportPreprocessedDataAsJob) to enable waiting for completion. Both mzML run data [import](./generated/docs/ProjectsApi.md#ImportMsRunData) and [import as job](./generated/docs/ProjectsApi.md#ImportMsRunDataAsJob) are supported. + +```R +input_file <- "/sirius-client-openAPI/.updater/clientTests/Data/Kaempferol.ms" +import_job <- api$projects_api$ImportPreprocessedDataAsJob(project_info$project_id, input_file) +api$wait_for_job_completion(project_info$project_id, import_job$id) +``` + +This imports an [aligned feature](./generated/docs/AlignedFeature.md). The [**Features API**](./generated/docs/FeaturesApi.md) extracts feature information, primarily useful after computation. + +Run molecular formula identification and CSI:FingerID structure database search by modifying a standard [job submission](./generated/docs/JobSubmission.md). Formula identification and CSI:FingerID are enabled by default. Here, CANOPUS is disabled. Jobs are managed by the [**Jobs API**](./generated/docs/JobsApi.md) and run on all features by default, or on specified features via `alignedFeatureIds`. + +```R +kaempferol_feature <- api$features_api$GetAlignedFeatures(project_info$project_id)[[1]] + +job_submission <- api$jobs_api$GetDefaultJobConfig() +job_submission$canopusParams$enabled <- FALSE +job_submission$alignedFeatureIds <- list(kaempferol_feature$alignedFeatureId) # optional; defaults to all + +job <- api$jobs_api$StartJob(project_info$project_id, job_submission) +api$wait_for_job_completion(project_info$project_id, job$id) +``` + +Extract results from aligned features. [Compounds](./generated/docs/Compound.md), managed by the [**Compounds API**](./generated/docs/CompoundsApi.md), differ from features as one compound can produce multiple features and multiple features can belong to one compound. Retrieve [structure candidates](./generated/docs/StructureCandidateFormula.md) from the aligned feature and the [consensus annotation](./generated/docs/ConsensusAnnotationsCSI.md) from its top annotated compound: + +```R +feature_structure_annotations <- api$features_api$GetStructureCandidates(project_info$project_id, kaempferol_feature$alignedFeatureId) +compound <- api$compounds_api$GetCompound(project_info$project_id, kaempferol_feature$compoundId) +compound_structure_annotations <- compound$consensusAnnotations$csiFingerIdStructure + +# directly extract the top structure annotation of a feature +top_structure_annotation <- api$features_api$GetAlignedFeature(project_info$project_id, kaempferol_feature$alignedFeatureId, opt_fields = list("topAnnotations"))$topAnnotations$structureAnnotation +``` + +Create custom databases using the [**Searchable Databases API**](./generated/docs/SearchableDatabasesApi.md) if you are not satisfied with the results. Import the Kaempferol file (containing three annotated spectra with SMILES) to enable spectral library matching and structure database search. Rerun identification using only this database: + +```R +db_name <- "KaempferolDB" +db_params <- SearchableDatabaseParameters$new(display_name = db_name, location = "/my/path/KaempferolDB.siriusdb") +api$searchable_databases_api$CreateDatabase(db_name, db_params) +api$searchable_databases_api$ImportIntoDatabase(db_name, input_files = c(input_file)) + +job_submission$recompute <- TRUE +job_submission$structureDbSearchParams$structureSearchDBs <- list(db_name) + +job_submission$spectraSearchParams$enables <- TRUE +job_submission$spectraSearchParams$spectraSearchDBs <- list(db_name) + +job_2 <- api$jobs_api$StartJob(project_info$project_id, job_submission) +api$wait_for_job_completion(project_info$project_id, job_2$id) +``` + +Close the project and shut down SIRIUS: + +```R +api$projects_api$CloseProject(project_info$project_id) +sdk$shutdown_sirius() +``` + +This demonstrates a simplified `RSirius` workflow to provide a rough idea of order of operation. Prior data processing and additional downstream analyses (e.g., comparing CANOPUS compound class cluster sizes) are not covered here. \ No newline at end of file From 1ba9c549aaf48c187e23cbb085a6ba857958accc Mon Sep 17 00:00:00 2001 From: joXemMx Date: Wed, 5 Nov 2025 23:08:31 +0100 Subject: [PATCH 2/6] rephrasing and CANOPUS class grouping example --- client-api_r/README.md | 73 +++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/client-api_r/README.md b/client-api_r/README.md index 9a8960f5..1db998b7 100644 --- a/client-api_r/README.md +++ b/client-api_r/README.md @@ -7,6 +7,9 @@ REST API that provides the full functionality of SIRIUS and its web services as background service. It is intended as entry-point for scripting languages and software integration SDKs. +- to [fine-grained documentation](#documentation-for-api-endpoints) +- to our [example workflow](#example-usage-of-rsirius) + ## Installation & Usage ### conda install (preferred) @@ -120,7 +123,9 @@ Please click [here](generated/README.md#documentation-for-models) # Example usage of RSirius -First, import `RSirius` and start the SIRIUS REST service using the [`SiriusSDK`](./generated/R/rsirius_sdk.R) class to retrieve a [central API client](./generated/R/rsirius_api.R) for accessing all API models. +This example replicates a typical SIRIUS GUI workflow using the client library. We'll load spectra, run formula identification, fingerprint prediction (CSI:FingerID), structural library search (CSI:FingerID), and compound class prediction (CANOPUS). Downstream analysis of annotations depends on your specific use case and is not covered here. We are unable to showcase every method here, please refer to the [above](#documentation-for-api-endpoints) links for in-depth documentation. + +First, import `RSirius` and start the SIRIUS REST service using the [`SiriusSDK`](rsirius_sdk.R) class to retrieve a [central API client](./generated/R/rsirius_api.R) for accessing all API models. ```R library(RSirius) @@ -128,7 +133,7 @@ sdk <- SiriusSDK$new() api <- sdk$attach_or_start_sirius() ``` -Verify the service is running using the [**Actuator API**](./generated/docs/ActuatorApi.md): +Optionally, verify the service is running using the [**Actuator API**](./generated/docs/ActuatorApi.md) (should succeed if startup completed): ```R if (!(api$actuator_api$Health()$status == "UP")) { @@ -151,41 +156,70 @@ Create a project space using the [**Projects API**](./generated/docs/ProjectsApi project_info <- api$projects_api$CreateProject("ExampleProject") ``` -[Import preprocessed data](./generated/docs/ProjectsApi.md#ImportPreprocessedData) from [`Kaempferol.ms`](../.updater/clientTests/Data/Kaempferol.ms). Import [as a job](./generated/docs/ProjectsApi.md#ImportPreprocessedDataAsJob) to enable waiting for completion. Both mzML run data [import](./generated/docs/ProjectsApi.md#ImportMsRunData) and [import as job](./generated/docs/ProjectsApi.md#ImportMsRunDataAsJob) are supported. +Import [preprocessed](./generated/docs/ProjectsApi.md#ImportPreprocessedData) data or [mzML](./generated/docs/ProjectsApi.md#ImportMsRunData) runs. Here we use preprocessed data from [`Kaempferol.ms`](../.updater/clientTests/Data/Kaempferol.ms), which contains three MS2 and one MS1 spectra forming one feature. Import as a [job](./generated/docs/Job.md) to enable waiting for completion (available for both [preprocessed](./generated/docs/ProjectsApi.md#ImportPreprocessedDataAsJob) and [mzML](./generated/docs/ProjectsApi.md#ImportMsRunDataAsJob) data). ```R -input_file <- "/sirius-client-openAPI/.updater/clientTests/Data/Kaempferol.ms" +input_file <- "/sirius-client-openAPI/.updater/clientTests/Data/Kaempferol.mgf" import_job <- api$projects_api$ImportPreprocessedDataAsJob(project_info$project_id, input_file) api$wait_for_job_completion(project_info$project_id, import_job$id) ``` -This imports an [aligned feature](./generated/docs/AlignedFeature.md). The [**Features API**](./generated/docs/FeaturesApi.md) extracts feature information, primarily useful after computation. +We've now imported our [aligned feature](./generated/docs/AlignedFeature.md). The [**Features API**](./generated/docs/FeaturesApi.md) lets you select and extract feature information, primarily useful after computation. -Run molecular formula identification and CSI:FingerID structure database search by modifying a standard [job submission](./generated/docs/JobSubmission.md). Formula identification and CSI:FingerID are enabled by default. Here, CANOPUS is disabled. Jobs are managed by the [**Jobs API**](./generated/docs/JobsApi.md) and run on all features by default, or on specified features via `alignedFeatureIds`. +Run your desired methods using a [job submission](./generated/docs/JobSubmission.md). **Formula identification, CSI:FingerID, and CANOPUS are enabled by default**. Jobs are managed by the [**Jobs API**](./generated/docs/JobsApi.md) and run on all features by default, or on specified features via `alignedFeatureIds`. ```R -kaempferol_feature <- api$features_api$GetAlignedFeatures(project_info$project_id)[[1]] - job_submission <- api$jobs_api$GetDefaultJobConfig() -job_submission$canopusParams$enabled <- FALSE -job_submission$alignedFeatureIds <- list(kaempferol_feature$alignedFeatureId) # optional; defaults to all + +# to disable individual tools, set parameters as shown below for CANOPUS +# job_submission$canopusParams$enabled <- FALSE + +# you can also enable additional tools like MSNovelist +# job_submission$msNovelistParams$enabled <- TRUE + +# (optional) specify which features to analyze; default: all features +# we know we only have one feature -> Kaempferol +kaempferol_feature <- api$features_api$GetAlignedFeatures(project_info$project_id)[[1]] +job_submission$alignedFeatureIds <- list(kaempferol_feature$alignedFeatureId) job <- api$jobs_api$StartJob(project_info$project_id, job_submission) api$wait_for_job_completion(project_info$project_id, job$id) ``` -Extract results from aligned features. [Compounds](./generated/docs/Compound.md), managed by the [**Compounds API**](./generated/docs/CompoundsApi.md), differ from features as one compound can produce multiple features and multiple features can belong to one compound. Retrieve [structure candidates](./generated/docs/StructureCandidateFormula.md) from the aligned feature and the [consensus annotation](./generated/docs/ConsensusAnnotationsCSI.md) from its top annotated compound: +Now you can extract results from your aligned features. [Compounds](./generated/docs/Compound.md), managed by the [**Compounds API**](./generated/docs/CompoundsApi.md), differ from features: one compound can produce multiple features and multiple features can belong to one compound. Retrieve [structure candidates](./generated/docs/StructureCandidateFormula.md) from the aligned feature and the [consensus annotation](./generated/docs/ConsensusAnnotationsCSI.md) from its top annotated compound: ```R +# all structure annotations for our feature feature_structure_annotations <- api$features_api$GetStructureCandidates(project_info$project_id, kaempferol_feature$alignedFeatureId) + +# get the compound and its consensus annotation compound <- api$compounds_api$GetCompound(project_info$project_id, kaempferol_feature$compoundId) compound_structure_annotations <- compound$consensusAnnotations$csiFingerIdStructure +``` + +You might also want to examine all predicted CANOPUS compound classes across your dataset: + +```R +# use "topAnnotations" to get only the best scoring annotation per feature +features <- api$features_api$GetAlignedFeatures(var_project_id, opt_fields = list("topAnnotations")) -# directly extract the top structure annotation of a feature -top_structure_annotation <- api$features_api$GetAlignedFeature(project_info$project_id, kaempferol_feature$alignedFeatureId, opt_fields = list("topAnnotations"))$topAnnotations$structureAnnotation +# filter NULL annotations +features_filtered <- Filter(function(f) !is.null(f$topAnnotations$compoundClassAnnotation), features) + +# example: group classes and sort by count +df <- do.call(rbind, lapply(features_filtered, function(f) { + lineage <- f$topAnnotations$compoundClassAnnotation$classyFireLineage + row <- list(number = f$alignedFeatureId) + for (cls in lineage) { + row[[cls$level]] <- cls$name + } + as.data.frame(row, stringsAsFactors = FALSE) +})) +grouped <- aggregate(number ~ ., data = df, FUN = length, na.action = na.pass) +grouped <- grouped[order(grouped$number), ] ``` -Create custom databases using the [**Searchable Databases API**](./generated/docs/SearchableDatabasesApi.md) if you are not satisfied with the results. Import the Kaempferol file (containing three annotated spectra with SMILES) to enable spectral library matching and structure database search. Rerun identification using only this database: +Not satisfied with your results? Create custom databases using the [**Searchable Databases API**](./generated/docs/SearchableDatabasesApi.md)! Import the example Kaempferol file (containing three annotated spectra and a SMILES) to enable spectral library matching and structure database search, then re-run identification using your custom database. ```R db_name <- "KaempferolDB" @@ -193,21 +227,22 @@ db_params <- SearchableDatabaseParameters$new(display_name = db_name, location = api$searchable_databases_api$CreateDatabase(db_name, db_params) api$searchable_databases_api$ImportIntoDatabase(db_name, input_files = c(input_file)) +# allow SIRIUS to overwrite existing results job_submission$recompute <- TRUE + +# note: this disables all other DBs; you can alternatively add it to the pre-defined list job_submission$structureDbSearchParams$structureSearchDBs <- list(db_name) -job_submission$spectraSearchParams$enables <- TRUE +job_submission$spectraSearchParams$enabled <- TRUE job_submission$spectraSearchParams$spectraSearchDBs <- list(db_name) job_2 <- api$jobs_api$StartJob(project_info$project_id, job_submission) api$wait_for_job_completion(project_info$project_id, job_2$id) ``` -Close the project and shut down SIRIUS: +Hopefully you've found something valuable! After completing your analysis, close the project and shut down SIRIUS: ```R api$projects_api$CloseProject(project_info$project_id) sdk$shutdown_sirius() -``` - -This demonstrates a simplified `RSirius` workflow to provide a rough idea of order of operation. Prior data processing and additional downstream analyses (e.g., comparing CANOPUS compound class cluster sizes) are not covered here. \ No newline at end of file +``` \ No newline at end of file From 709104b441a3888fcb02bd4221b165204367712f Mon Sep 17 00:00:00 2001 From: joXemMx Date: Thu, 6 Nov 2025 17:10:54 +0100 Subject: [PATCH 3/6] R tutorial completely tested --- client-api_r/README.md | 64 ++++++++++++++++++++++-------------------- 1 file changed, 34 insertions(+), 30 deletions(-) diff --git a/client-api_r/README.md b/client-api_r/README.md index 1db998b7..c3bc0037 100644 --- a/client-api_r/README.md +++ b/client-api_r/README.md @@ -150,7 +150,7 @@ var_account_credentials <- AccountCredentials$new('SIRIUS_USER', 'SIRIUS_PW') api$login_and_account_api$Login(var_accept_terms, var_account_credentials) ``` -Create a project space using the [**Projects API**](./generated/docs/ProjectsApi.md). This `.sirius` file (default location: `/home//sirius-projects/.sirius`) contains all input data and annotation results. Access the path via [project info](./generated/docs/ProjectInfo.md). +Create a project space using the [**Projects API**](./generated/docs/ProjectsApi.md). This `.sirius` file (default location: `/home//sirius-projects/.sirius`) contains all input data and annotation results. Access the path via [project info](./generated/docs/ProjectInfo.md). ```R project_info <- api$projects_api$CreateProject("ExampleProject") @@ -159,9 +159,9 @@ project_info <- api$projects_api$CreateProject("ExampleProject") Import [preprocessed](./generated/docs/ProjectsApi.md#ImportPreprocessedData) data or [mzML](./generated/docs/ProjectsApi.md#ImportMsRunData) runs. Here we use preprocessed data from [`Kaempferol.ms`](../.updater/clientTests/Data/Kaempferol.ms), which contains three MS2 and one MS1 spectra forming one feature. Import as a [job](./generated/docs/Job.md) to enable waiting for completion (available for both [preprocessed](./generated/docs/ProjectsApi.md#ImportPreprocessedDataAsJob) and [mzML](./generated/docs/ProjectsApi.md#ImportMsRunDataAsJob) data). ```R -input_file <- "/sirius-client-openAPI/.updater/clientTests/Data/Kaempferol.mgf" -import_job <- api$projects_api$ImportPreprocessedDataAsJob(project_info$project_id, input_file) -api$wait_for_job_completion(project_info$project_id, import_job$id) +input_file <- "/sirius-client-openAPI/.updater/clientTests/Data/Kaempferol.ms" +import_job <- api$projects_api$ImportPreprocessedDataAsJob(project_info$projectId, input_file) +api$wait_for_job_completion(project_info$projectId, import_job$id) ``` We've now imported our [aligned feature](./generated/docs/AlignedFeature.md). The [**Features API**](./generated/docs/FeaturesApi.md) lets you select and extract feature information, primarily useful after computation. @@ -179,44 +179,42 @@ job_submission <- api$jobs_api$GetDefaultJobConfig() # (optional) specify which features to analyze; default: all features # we know we only have one feature -> Kaempferol -kaempferol_feature <- api$features_api$GetAlignedFeatures(project_info$project_id)[[1]] +kaempferol_feature <- api$features_api$GetAlignedFeatures(project_info$projectId)[[1]] job_submission$alignedFeatureIds <- list(kaempferol_feature$alignedFeatureId) -job <- api$jobs_api$StartJob(project_info$project_id, job_submission) -api$wait_for_job_completion(project_info$project_id, job$id) +job <- api$jobs_api$StartJob(project_info$projectId, job_submission) +api$wait_for_job_completion(project_info$projectId, job$id) ``` Now you can extract results from your aligned features. [Compounds](./generated/docs/Compound.md), managed by the [**Compounds API**](./generated/docs/CompoundsApi.md), differ from features: one compound can produce multiple features and multiple features can belong to one compound. Retrieve [structure candidates](./generated/docs/StructureCandidateFormula.md) from the aligned feature and the [consensus annotation](./generated/docs/ConsensusAnnotationsCSI.md) from its top annotated compound: ```R # all structure annotations for our feature -feature_structure_annotations <- api$features_api$GetStructureCandidates(project_info$project_id, kaempferol_feature$alignedFeatureId) +feature_structure_annotations <- api$features_api$GetStructureCandidates(project_info$projectId, kaempferol_feature$alignedFeatureId) +# best ranking structure SMILES +print(feature_structure_annotations[[1]]$smiles) # get the compound and its consensus annotation -compound <- api$compounds_api$GetCompound(project_info$project_id, kaempferol_feature$compoundId) -compound_structure_annotations <- compound$consensusAnnotations$csiFingerIdStructure +compound <- api$compounds_api$GetCompound(project_info$projectId, kaempferol_feature$compoundId, opt_fields = list("consensusAnnotations")) +compound_structure_annotation <- compound$consensusAnnotations$csiFingerIdStructure +# consensus structure SMILES; if compound has one feature, they are equal +print(compound_structure_annotation$smiles) ``` You might also want to examine all predicted CANOPUS compound classes across your dataset: ```R # use "topAnnotations" to get only the best scoring annotation per feature -features <- api$features_api$GetAlignedFeatures(var_project_id, opt_fields = list("topAnnotations")) +features <- api$features_api$GetAlignedFeatures(project_info$projectId, opt_fields = list("topAnnotations")) # filter NULL annotations features_filtered <- Filter(function(f) !is.null(f$topAnnotations$compoundClassAnnotation), features) -# example: group classes and sort by count -df <- do.call(rbind, lapply(features_filtered, function(f) { - lineage <- f$topAnnotations$compoundClassAnnotation$classyFireLineage - row <- list(number = f$alignedFeatureId) - for (cls in lineage) { - row[[cls$level]] <- cls$name - } - as.data.frame(row, stringsAsFactors = FALSE) -})) -grouped <- aggregate(number ~ ., data = df, FUN = length, na.action = na.pass) -grouped <- grouped[order(grouped$number), ] +# example: get NPC classes +for (f in features_filtered) { + class <- f$topAnnotations$compoundClassAnnotation$npcClass + print(paste("Feature with ID", f$alignedFeatureId, "is of class", class$name)) +} ``` Not satisfied with your results? Create custom databases using the [**Searchable Databases API**](./generated/docs/SearchableDatabasesApi.md)! Import the example Kaempferol file (containing three annotated spectra and a SMILES) to enable spectral library matching and structure database search, then re-run identification using your custom database. @@ -227,22 +225,28 @@ db_params <- SearchableDatabaseParameters$new(display_name = db_name, location = api$searchable_databases_api$CreateDatabase(db_name, db_params) api$searchable_databases_api$ImportIntoDatabase(db_name, input_files = c(input_file)) +# we can add our database manually or get a new default submission form that includes it +job_submission_customdb <- api$jobs_api$GetDefaultJobConfig(include_custom_dbs_for_structure_search = TRUE) +job_submission_customdb$spectraSearchParams$enabled <- TRUE + # allow SIRIUS to overwrite existing results -job_submission$recompute <- TRUE +job_submission_customdb$recompute <- TRUE -# note: this disables all other DBs; you can alternatively add it to the pre-defined list -job_submission$structureDbSearchParams$structureSearchDBs <- list(db_name) +job_customdb <- api$jobs_api$StartJob(project_info$projectId, job_submission_customdb) +api$wait_for_job_completion(project_info$projectId, job_customdb$id) +``` -job_submission$spectraSearchParams$enabled <- TRUE -job_submission$spectraSearchParams$spectraSearchDBs <- list(db_name) +Now we can look into the results again just as we did before. There is one new thing we enabled just now, that is the spectral library search. Let's look at our spectral library matches: -job_2 <- api$jobs_api$StartJob(project_info$project_id, job_submission) -api$wait_for_job_completion(project_info$project_id, job_2$id) +```R +library_matches <- api$features_api$GetSpectralLibraryMatches(project_info$projectId, kaempferol_feature$alignedFeatureId) +# SMILES of best spectral library match +library_matches[[1]]$smiles ``` Hopefully you've found something valuable! After completing your analysis, close the project and shut down SIRIUS: ```R -api$projects_api$CloseProject(project_info$project_id) +api$projects_api$CloseProject(project_info$projectId) sdk$shutdown_sirius() ``` \ No newline at end of file From 92e97b79887415e9fb187db7e277c05f15582edb Mon Sep 17 00:00:00 2001 From: joXemMx Date: Thu, 6 Nov 2025 17:12:40 +0100 Subject: [PATCH 4/6] library search comment --- client-api_r/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client-api_r/README.md b/client-api_r/README.md index c3bc0037..382d0f10 100644 --- a/client-api_r/README.md +++ b/client-api_r/README.md @@ -227,6 +227,8 @@ api$searchable_databases_api$ImportIntoDatabase(db_name, input_files = c(input_f # we can add our database manually or get a new default submission form that includes it job_submission_customdb <- api$jobs_api$GetDefaultJobConfig(include_custom_dbs_for_structure_search = TRUE) + +# enable spectral library search job_submission_customdb$spectraSearchParams$enabled <- TRUE # allow SIRIUS to overwrite existing results From 829989940ac0bf71dbccf774e57a4e4daadd54d9 Mon Sep 17 00:00:00 2001 From: joXemMx Date: Fri, 7 Nov 2025 16:10:53 +0100 Subject: [PATCH 5/6] same example workflow for python + try to homogenize workflows --- client-api_python/README.md | 150 ++++++++++++++++++++++++++++++++++++ client-api_r/README.md | 40 ++++++++-- 2 files changed, 182 insertions(+), 8 deletions(-) diff --git a/client-api_python/README.md b/client-api_python/README.md index 6dfcf4db..57e11674 100644 --- a/client-api_python/README.md +++ b/client-api_python/README.md @@ -118,3 +118,153 @@ Please click [here](generated/README.md#documentation-for-api-endpoints) ## Documentation For Models Please click [here](generated/README.md#documentation-for-models) + +# Example usage of PySirius + +This example replicates a typical SIRIUS GUI workflow using the client library. We'll load spectra, run formula identification, fingerprint prediction (CSI:FingerID), structural library search (CSI:FingerID), and compound class prediction (CANOPUS). Downstream analysis of annotations depends on your specific use case and is not covered here. We are unable to showcase every method here, please refer to the [above](#documentation-for-api-endpoints) links for in-depth documentation. + +First, import `PySirius` and start the SIRIUS REST service using the [`SiriusSDK`](pysirius_sdk.py) class to retrieve a [central API client](pysirius_api.py) for accessing all API models. +```python +from PySirius import SiriusSDK + +sdk = SiriusSDK() +api = sdk.attach_or_start_sirius() +``` + +Optionally, verify the service is running using the [**Actuator API**](./generated/docs/ActuatorApi.md) (should succeed if startup completed): +```python +if api.actuator().health().get('status') != "UP": + print("There seems to be a problem reaching the REST service!") + exit(1) +``` + +Log in with the [**Login and Account API**](./generated/docs/LoginAndAccountApi.md) to access SIRIUS functionalities: +```python +from PySirius import AccountCredentials + +accept_terms = True # ensure you accept the terms +account_credentials = AccountCredentials(username='SIRIUS_USER', password='SIRIUS_PW') +api.account().login(accept_terms, account_credentials) +``` + +Create a project space using the [**Projects API**](./generated/docs/ProjectsApi.md). This `.sirius` file (default location: `/home//sirius-projects/.sirius`) contains all input data and annotation results. Access the path via [project info](./generated/docs/ProjectInfo.md). +```python +project_info = api.projects().create_project("ExampleProject") +``` + +Import [preprocessed](./generated/docs/ProjectsApi.md#import_preprocessed_data) data or [mzML](./generated/docs/ProjectsApi.md#import_ms_run_data) runs. Here we use preprocessed data from [`Kaempferol.ms`](../.updater/clientTests/Data/Kaempferol.ms), which contains three MS2 and one MS1 spectra forming one feature. Import as a [job](./generated/docs/Job.md) to enable waiting for completion (available for both [preprocessed](./generated/docs/ProjectsApi.md#import_preprocessed_data_as_job) and [mzML](./generated/docs/ProjectsApi.md#import_ms_run_data_as_job) data). +```python +input_file = "/sirius-client-openAPI/.updater/clientTests/Data/Kaempferol.ms" +import_job = api.projects().import_preprocessed_data_as_job(project_info.project_id, input_files=[input_file]) +api.wait_for_job_completion(project_info, import_job) +``` + +We've now imported our [aligned feature](./generated/docs/AlignedFeature.md). The [**Features API**](./generated/docs/FeaturesApi.md) lets you select and extract feature information, primarily useful after computation. + +Run your desired methods using a [job submission](./generated/docs/JobSubmission.md). **Formula identification, CSI:FingerID, and CANOPUS are enabled by default**. Jobs are managed by the [**Jobs API**](./generated/docs/JobsApi.md) and run on all features by default, or on specified features via `aligned_feature_ids`. +```python +job_submission = api.jobs().get_default_job_config() + +# to disable individual tools, set parameters as shown below for CANOPUS +# job_submission.canopus_params.enabled = False + +# you can also enable additional tools like MSNovelist +# job_submission.ms_novelist_params.enabled = True + +# (optional) specify which features to analyze; default: all features +# we know we only have one feature -> Kaempferol +kaempferol_feature = api.features().get_aligned_features(project_info.project_id)[0] +job_submission.aligned_feature_ids = [kaempferol_feature.aligned_feature_id] + +job = api.jobs().start_job(project_info.project_id, job_submission) +api.wait_for_job_completion(project_info, job) +``` + +Now you can extract results from your aligned features. [Compounds](./generated/docs/Compound.md), managed by the [**Compounds API**](./generated/docs/CompoundsApi.md), differ from features: one compound can produce multiple features and multiple features can belong to one compound. Retrieve [structure candidates](./generated/docs/StructureCandidateFormula.md) from the aligned feature and the [consensus annotation](./generated/docs/ConsensusAnnotationsCSI.md) from its top annotated compound: +```python +# all structure annotations for our feature +feature_structure_annotations = api.features().get_structure_candidates( + project_info.project_id, + kaempferol_feature.aligned_feature_id +) +# best ranking structure SMILES +print(feature_structure_annotations[0].smiles) + +# get the compound and its consensus annotation +from PySirius import CompoundOptField +compound = api.compounds().get_compound( + project_info.project_id, + kaempferol_feature.compound_id, + opt_fields=[CompoundOptField.CONSENSUSANNOTATIONS] +) +compound_structure_annotation = compound.consensus_annotations.csi_finger_id_structure +# consensus structure SMILES; if compound has one feature, they are equal +print(compound_structure_annotation.smiles) +``` + +You might also want to examine all predicted CANOPUS compound classes across your dataset: +```python +# use "topAnnotations" to get only the best scoring annotation per feature +from PySirius import AlignedFeatureOptField +features = api.features().get_aligned_features( + project_info.project_id, + opt_fields=[AlignedFeatureOptField.TOPANNOTATIONS] +) + +# filter None annotations +features_filtered = [f for f in features if f.top_annotations and f.top_annotations.compound_class_annotation] + +# example: get NPC classes +for f in features_filtered: + class_annotation = f.top_annotations.compound_class_annotation.npc_class + print(f"Feature with ID {f.aligned_feature_id} is of class {class_annotation.name}") +``` + +Not satisfied with your results? Create custom databases using the [**Searchable Databases API**](./generated/docs/SearchableDatabasesApi.md)! Import the example Kaempferol file (containing three annotated spectra and a SMILES) to enable spectral library matching and structure database search, then re-run identification using your custom database. +```python +from PySirius import SearchableDatabaseParameters + +db_name = "KaempferolDB" +db_params = SearchableDatabaseParameters( + display_name=db_name, + location="/my/path/KaempferolDB.siriusdb" +) +api.databases().create_database(db_name, db_params) +api.databases().import_into_database( + db_name, + input_files=[input_file] +) + +# we can add our database manually or get a new default submission form that includes it +job_submission_customdb = api.jobs().get_default_job_config( + include_custom_dbs_for_structure_search=True +) + +# enable spectral library search +job_submission_customdb.spectra_search_params.enabled = True + +# allow SIRIUS to overwrite existing results +job_submission_customdb.recompute = True + +job_customdb = api.jobs().start_job( + project_info.project_id, + job_submission_customdb +) +api.wait_for_job_completion(project_info, job_customdb) +``` + +Now we can look into the results again just as we did before. There is one new thing we enabled just now, that is the spectral library search. Let's look at our spectral library matches: +```python +library_matches = api.features().get_spectral_library_matches( + project_info.project_id, + kaempferol_feature.aligned_feature_id +) +# SMILES of best spectral library match +print(library_matches[0].smiles) +``` + +Hopefully you've found something valuable! After completing your analysis, close the project and shut down SIRIUS: +```python +api.projects().close_project(project_info.project_id) +sdk.shutdown_sirius() +``` \ No newline at end of file diff --git a/client-api_r/README.md b/client-api_r/README.md index 382d0f10..3ee5d33a 100644 --- a/client-api_r/README.md +++ b/client-api_r/README.md @@ -190,12 +190,19 @@ Now you can extract results from your aligned features. [Compounds](./generated/ ```R # all structure annotations for our feature -feature_structure_annotations <- api$features_api$GetStructureCandidates(project_info$projectId, kaempferol_feature$alignedFeatureId) +feature_structure_annotations <- api$features_api$GetStructureCandidates( + project_info$projectId, + kaempferol_feature$alignedFeatureId +) # best ranking structure SMILES print(feature_structure_annotations[[1]]$smiles) # get the compound and its consensus annotation -compound <- api$compounds_api$GetCompound(project_info$projectId, kaempferol_feature$compoundId, opt_fields = list("consensusAnnotations")) +compound <- api$compounds_api$GetCompound( + project_info$projectId, + kaempferol_feature$compoundId, + opt_fields = list("consensusAnnotations") +) compound_structure_annotation <- compound$consensusAnnotations$csiFingerIdStructure # consensus structure SMILES; if compound has one feature, they are equal print(compound_structure_annotation$smiles) @@ -205,7 +212,10 @@ You might also want to examine all predicted CANOPUS compound classes across you ```R # use "topAnnotations" to get only the best scoring annotation per feature -features <- api$features_api$GetAlignedFeatures(project_info$projectId, opt_fields = list("topAnnotations")) +features <- api$features_api$GetAlignedFeatures( + project_info$projectId, + opt_fields = list("topAnnotations") +) # filter NULL annotations features_filtered <- Filter(function(f) !is.null(f$topAnnotations$compoundClassAnnotation), features) @@ -221,12 +231,20 @@ Not satisfied with your results? Create custom databases using the [**Searchable ```R db_name <- "KaempferolDB" -db_params <- SearchableDatabaseParameters$new(display_name = db_name, location = "/my/path/KaempferolDB.siriusdb") +db_params <- SearchableDatabaseParameters$new( + display_name = db_name, + location = "/my/path/KaempferolDB.siriusdb" +) api$searchable_databases_api$CreateDatabase(db_name, db_params) -api$searchable_databases_api$ImportIntoDatabase(db_name, input_files = c(input_file)) +api$searchable_databases_api$ImportIntoDatabase( + db_name, + input_files = c(input_file) +) # we can add our database manually or get a new default submission form that includes it -job_submission_customdb <- api$jobs_api$GetDefaultJobConfig(include_custom_dbs_for_structure_search = TRUE) +job_submission_customdb <- api$jobs_api$GetDefaultJobConfig( + include_custom_dbs_for_structure_search = TRUE +) # enable spectral library search job_submission_customdb$spectraSearchParams$enabled <- TRUE @@ -234,14 +252,20 @@ job_submission_customdb$spectraSearchParams$enabled <- TRUE # allow SIRIUS to overwrite existing results job_submission_customdb$recompute <- TRUE -job_customdb <- api$jobs_api$StartJob(project_info$projectId, job_submission_customdb) +job_customdb <- api$jobs_api$StartJob( + project_info$projectId, + job_submission_customdb +) api$wait_for_job_completion(project_info$projectId, job_customdb$id) ``` Now we can look into the results again just as we did before. There is one new thing we enabled just now, that is the spectral library search. Let's look at our spectral library matches: ```R -library_matches <- api$features_api$GetSpectralLibraryMatches(project_info$projectId, kaempferol_feature$alignedFeatureId) +library_matches <- api$features_api$GetSpectralLibraryMatches( + project_info$projectId, + kaempferol_feature$alignedFeatureId +) # SMILES of best spectral library match library_matches[[1]]$smiles ``` From 76d3f6bb6c83902fed3e2000c4a44703ccf0e96e Mon Sep 17 00:00:00 2001 From: joXemMx Date: Fri, 7 Nov 2025 16:13:52 +0100 Subject: [PATCH 6/6] homogenize --- client-api_python/README.md | 8 +++----- client-api_r/README.md | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/client-api_python/README.md b/client-api_python/README.md index 57e11674..1ed09fb1 100644 --- a/client-api_python/README.md +++ b/client-api_python/README.md @@ -1,6 +1,9 @@ # PySirius REST API that provides the full functionality of SIRIUS and its web services as background service. It is intended as entry-point for scripting languages and software integration SDKs. +- to [fine-grained documentation](#documentation-for-api-endpoints) +- to our [example workflow](#example-usage-of-pysirius) + ## Installation & Usage ### conda install (preferred) @@ -108,11 +111,6 @@ api = sdk.connect("http://localhost:8080") For more niche functionality and insights, find the SiriusSDK class [here](pysirius_sdk.py). -### Example code -Our feedstocks for the conda-forge packages are running an automated minimal test. -We included the scripts [here](../.updater/clientTests/CondaFeedstockMinimalTests). -Feel free to take them as example usages of the packages. - ## Documentation for API Endpoints Please click [here](generated/README.md#documentation-for-api-endpoints) diff --git a/client-api_r/README.md b/client-api_r/README.md index 3ee5d33a..89ed5c22 100644 --- a/client-api_r/README.md +++ b/client-api_r/README.md @@ -113,11 +113,11 @@ api <- sdk$connect("http://localhost:8080") For more niche functionality and insights, find the SiriusSDK class [here](rsirius_sdk.R). -### Documentation for API Endpoints +## Documentation for API Endpoints Please click [here](generated/README.md#documentation-for-api-endpoints) -### Documentation For Models +## Documentation For Models Please click [here](generated/README.md#documentation-for-models)