From 0187f1086d1e9e78e1ed239bbe2a5d44b66bce31 Mon Sep 17 00:00:00 2001 From: seohyonkim Date: Thu, 6 Aug 2026 12:05:49 +0200 Subject: [PATCH 1/5] design API for spatial TI --- src/api/comp_control_method.yaml | 10 ++--- src/api/comp_data_processor.yaml | 12 ++--- src/api/comp_method.yaml | 10 ++--- src/api/comp_metric.yaml | 4 +- .../{file_train.yaml => file_dataset.yaml} | 6 +-- src/api/file_test.yaml | 45 ------------------- 6 files changed, 15 insertions(+), 72 deletions(-) rename src/api/{file_train.yaml => file_dataset.yaml} (91%) delete mode 100644 src/api/file_test.yaml diff --git a/src/api/comp_control_method.yaml b/src/api/comp_control_method.yaml index f637aed..b556ab6 100644 --- a/src/api/comp_control_method.yaml +++ b/src/api/comp_control_method.yaml @@ -3,7 +3,7 @@ info: type: control_method type_info: label: Control Method - summary: Quality control methods for verifying the pipeline. + summary: Quality control methods for verifying the pipeline of the spatial TI task. description: | This folder contains control components for the task. These components have the same interface as the regular methods @@ -12,12 +12,8 @@ info: the task, and also as a quality control for the metrics defined in the task. arguments: - - name: --input_train - __merge__: file_train.yaml - required: true - direction: input - - name: --input_test - __merge__: file_test.yaml + - name: --dataset + __merge__: file_dataset.yaml required: true direction: input - name: "--input_solution" diff --git a/src/api/comp_data_processor.yaml b/src/api/comp_data_processor.yaml index 1ed53bd..8581557 100644 --- a/src/api/comp_data_processor.yaml +++ b/src/api/comp_data_processor.yaml @@ -3,20 +3,16 @@ info: type: data_processor type_info: label: Data processor - summary: A data processor. - description: | + summary: A data processor for the spatial TI task. + description: | # better description TODO A component for processing a Common Dataset into a task-specific dataset. arguments: - name: "--input" __merge__: file_common_dataset.yaml direction: input required: true - - name: "--output_train" - __merge__: file_train.yaml - direction: output - required: true - - name: "--output_test" - __merge__: file_test.yaml + - name: "--output" + __merge__: file_dataset.yaml direction: output required: true - name: "--output_solution" diff --git a/src/api/comp_method.yaml b/src/api/comp_method.yaml index 3a93846..11194bb 100644 --- a/src/api/comp_method.yaml +++ b/src/api/comp_method.yaml @@ -5,16 +5,12 @@ info: label: Method summary: A method. description: | - A method to predict the task effects. + A method for the spatial TI task. arguments: - - name: --input_train - __merge__: file_train.yaml + - name: --input + __merge__: file_dataset.yaml required: true direction: input - - name: "--input_test" - __merge__: file_test.yaml - direction: input - required: true - name: --output __merge__: file_prediction.yaml required: true diff --git a/src/api/comp_metric.yaml b/src/api/comp_metric.yaml index 1c76a3d..c49b68c 100644 --- a/src/api/comp_metric.yaml +++ b/src/api/comp_metric.yaml @@ -3,9 +3,9 @@ info: type: metric type_info: label: Metric - summary: A task template metric. + summary: A metric for spatial TI task. description: | - A metric for evaluating method predictions. + A metric for evaluating spatial TI method predictions. arguments: - name: "--input_solution" __merge__: file_solution.yaml diff --git a/src/api/file_train.yaml b/src/api/file_dataset.yaml similarity index 91% rename from src/api/file_train.yaml rename to src/api/file_dataset.yaml index c01eda5..53e37d1 100644 --- a/src/api/file_train.yaml +++ b/src/api/file_dataset.yaml @@ -1,8 +1,8 @@ #TODO: Change to the required and/or optional fields of the anndata type: file -example: "resources_test/task_template/cxg_mouse_pancreas_atlas/train.h5ad" -label: "Training data" -summary: "The training data in h5ad format" +example: "resources_test/task_template/cxg_mouse_pancreas_atlas/train.h5ad" # maybe adjust this after syncing resources +label: "Input data" +summary: "The input data for the spatial TI task" info: format: type: h5ad diff --git a/src/api/file_test.yaml b/src/api/file_test.yaml deleted file mode 100644 index cb9d9a6..0000000 --- a/src/api/file_test.yaml +++ /dev/null @@ -1,45 +0,0 @@ -#TODO: Change to the required and/or optional fields of the anndata -type: file -example: "resources_test/task_template/cxg_mouse_pancreas_atlas/test.h5ad" -label: "Test data" -summary: The subset of molecules used for the test dataset -info: - format: - type: h5ad - layers: - - type: integer - name: counts - description: Raw counts - required: true - - type: double - name: normalized - description: Normalized counts - required: true - obs: - - type: string - name: batch - description: Batch information - required: true - var: - - type: boolean - name: hvg - description: Whether or not the feature is considered to be a 'highly variable gene' - required: true - - type: double - name: hvg_score - description: A ranking of the features by hvg. - required: true - obsm: - - type: double - name: X_pca - description: The resulting PCA embedding. - required: true - uns: - - type: string - name: dataset_id - description: "A unique identifier for the dataset" - required: true - - type: string - name: normalization_id - description: "Which normalization was used" - required: true \ No newline at end of file From 687668d1e7d9bb44d27fad29c622541c117bb1c8 Mon Sep 17 00:00:00 2001 From: seohyonkim Date: Fri, 7 Aug 2026 12:49:26 +0200 Subject: [PATCH 2/5] data processor builds --- src/api/comp_control_method.yaml | 4 +- src/api/comp_data_processor.yaml | 2 +- src/api/comp_method.yaml | 4 +- src/api/comp_metric.yaml | 4 +- src/api/file_dataset.yaml | 30 +++------ src/api/file_solution.yaml | 28 +++------ .../process_dataset/config.vsh.yaml | 62 +++++++++++++------ src/data_processors/process_dataset/script.py | 62 ++++++++----------- 8 files changed, 93 insertions(+), 103 deletions(-) diff --git a/src/api/comp_control_method.yaml b/src/api/comp_control_method.yaml index b556ab6..36819ed 100644 --- a/src/api/comp_control_method.yaml +++ b/src/api/comp_control_method.yaml @@ -29,5 +29,5 @@ test_resources: path: /common/component_tests/run_and_check_output.py - type: python_script path: /common/component_tests/check_config.py - - path: /resources_test/task_template/cxg_mouse_pancreas_atlas - dest: resources_test/task_template/cxg_mouse_pancreas_atlas \ No newline at end of file + - path: /resources_test/common/cxg_mouse_pancreas_atlas + dest: resources_test/common/cxg_mouse_pancreas_atlas \ No newline at end of file diff --git a/src/api/comp_data_processor.yaml b/src/api/comp_data_processor.yaml index 8581557..3447884 100644 --- a/src/api/comp_data_processor.yaml +++ b/src/api/comp_data_processor.yaml @@ -11,7 +11,7 @@ arguments: __merge__: file_common_dataset.yaml direction: input required: true - - name: "--output" + - name: "--output_dataset" __merge__: file_dataset.yaml direction: output required: true diff --git a/src/api/comp_method.yaml b/src/api/comp_method.yaml index 11194bb..e94c264 100644 --- a/src/api/comp_method.yaml +++ b/src/api/comp_method.yaml @@ -20,5 +20,5 @@ test_resources: path: /common/component_tests/run_and_check_output.py - type: python_script path: /common/component_tests/check_config.py - - path: /resources_test/task_template/cxg_mouse_pancreas_atlas - dest: resources_test/task_template/cxg_mouse_pancreas_atlas \ No newline at end of file + - path: /resources_test/common/cxg_mouse_pancreas_atlas + dest: resources_test/common/cxg_mouse_pancreas_atlas \ No newline at end of file diff --git a/src/api/comp_metric.yaml b/src/api/comp_metric.yaml index c49b68c..a3ac1d8 100644 --- a/src/api/comp_metric.yaml +++ b/src/api/comp_metric.yaml @@ -24,5 +24,5 @@ test_resources: path: /common/component_tests/run_and_check_output.py - type: python_script path: /common/component_tests/check_config.py - - path: /resources_test/task_template/cxg_mouse_pancreas_atlas - dest: resources_test/task_template/cxg_mouse_pancreas_atlas + - path: /resources_test/common/cxg_mouse_pancreas_atlas + dest: resources_test/common/cxg_mouse_pancreas_atlas diff --git a/src/api/file_dataset.yaml b/src/api/file_dataset.yaml index 53e37d1..c2944d6 100644 --- a/src/api/file_dataset.yaml +++ b/src/api/file_dataset.yaml @@ -1,42 +1,28 @@ -#TODO: Change to the required and/or optional fields of the anndata type: file -example: "resources_test/task_template/cxg_mouse_pancreas_atlas/train.h5ad" # maybe adjust this after syncing resources +example: "resources_test/task_spatial_trajectory_inference/cxg_mouse_pancreas_atlas/dataset.h5ad" label: "Input data" -summary: "The input data for the spatial TI task" +summary: "The input data for the spatial TI methods" info: format: type: h5ad - layers: + layers: - type: integer name: counts description: Raw counts required: true - - type: double - name: normalized - description: Normalized counts - required: true obs: - type: string - name: label - description: Ground truth cell type labels + name: cell_type + description: Cell type information required: true - type: string name: batch description: Batch information required: true - var: - - type: boolean - name: hvg - description: Whether or not the feature is considered to be a 'highly variable gene' - required: true - - type: double - name: hvg_score - description: A ranking of the features by hvg. - required: true obsm: - type: double - name: X_pca - description: The resulting PCA embedding. + name: X_spatial + description: Spatial coordinates of each cell/spot. required: true uns: - type: string @@ -46,4 +32,4 @@ info: - type: string name: normalization_id description: "Which normalization was used" - required: true \ No newline at end of file + required: true diff --git a/src/api/file_solution.yaml b/src/api/file_solution.yaml index d2f6200..46f9e94 100644 --- a/src/api/file_solution.yaml +++ b/src/api/file_solution.yaml @@ -1,42 +1,32 @@ -#TODO: Change to the required and/or optional fields of the anndata type: file -example: "resources_test/task_template/cxg_mouse_pancreas_atlas/solution.h5ad" +example: "resources_test/task_spatial_trajectory_inference/cxg_mouse_pancreas_atlas/solution.h5ad" label: "Solution" -summary: "The solution for the test data" +summary: "The solution (ground truth) for the test data" info: format: type: h5ad - layers: + layers: - type: integer name: counts description: Raw counts required: true - - type: double - name: normalized - description: Normalized counts - required: true obs: - type: string - name: label - description: Ground truth cell type labels + name: cell_type + description: Cell type information required: true - type: string name: batch description: Batch information required: true - var: - - type: boolean - name: hvg - description: Whether or not the feature is considered to be a 'highly variable gene' - required: true - type: double - name: hvg_score - description: A ranking of the features by hvg. + name: pseudotime_true + description: Ground truth pseudotime for each cell/spot. required: true obsm: - type: double - name: X_pca - description: The resulting PCA embedding. + name: X_spatial + description: Spatial coordinates of each cell/spot. required: true uns: - type: string diff --git a/src/data_processors/process_dataset/config.vsh.yaml b/src/data_processors/process_dataset/config.vsh.yaml index 0047ae1..23d4571 100644 --- a/src/data_processors/process_dataset/config.vsh.yaml +++ b/src/data_processors/process_dataset/config.vsh.yaml @@ -1,23 +1,43 @@ __merge__: ../../api/comp_data_processor.yaml name: process_dataset -arguments: - - name: "--method" - type: "string" - description: "The process method to assign train/test." - choices: ["batch", "random"] - default: "batch" - - name: "--obs_label" - type: "string" - description: "Which .obs slot to use as label." - default: "cell_type" - - name: "--obs_batch" - type: "string" - description: "Which .obs slot to use as batch covariate." - default: "batch" - - name: "--seed" - type: "integer" - description: "A seed for the subsampling." - example: 123 +namespace: data_processors + +info: + label: Process dataset + summary: "Filter and split a common dataset into task-specific data and solution files." + +argument_groups: + - name: Parameters + arguments: + - name: "--dataset_id" + type: "string" + description: "New dataset ID" + required: false + - name: "--obs_label" + type: "string" + description: "Which .obs slot to use as label." + default: "cell_type" + - name: "--obs_batch" + type: "string" + description: "Which .obs slot to use as batch covariate." + default: "batch" + - name: "--obs_ptime" + type: "string" + description: "Which .obs slot to use as pseudotime covariate." + default: "pseudotime_true" + - name: "--obsm_spatial" + type: "string" + description: "Which .obsm slot to use as spatial metadata." + default: "X_spatial" + - name: "--layer_counts" + type: "string" + description: "Which .layers slot to use as counts." + default: "counts" + - name: "--seed" + type: "integer" + description: "The seed for." # TODO for what..? + default: 1 + resources: - type: python_script path: script.py @@ -31,4 +51,8 @@ runners: - type: executable - type: nextflow directives: - label: [highmem, midcpu, midtime] \ No newline at end of file + label: [highmem, midcpu, midtime] + +test_resources: + - path: /resources_test/common/cxg_mouse_pancreas_atlas + dest: resources_test/common/cxg_mouse_pancreas_atlas \ No newline at end of file diff --git a/src/data_processors/process_dataset/script.py b/src/data_processors/process_dataset/script.py index 3eb56c2..fd32ad4 100644 --- a/src/data_processors/process_dataset/script.py +++ b/src/data_processors/process_dataset/script.py @@ -7,12 +7,13 @@ ## VIASH START par = { 'input': 'resources_test/common/cxg_mouse_pancreas_atlas/dataset.h5ad', - 'method': 'batch', 'seed': None, 'obs_batch': 'batch', 'obs_label': 'cell_type', - 'output_train': 'train.h5ad', - 'output_test': 'test.h5ad', + 'obs_ptime': 'pseudotime_true', + 'obsm_spatial': 'X_spatial', + 'layer_counts': 'counts', + 'output_dataset': 'dataset.h5ad', 'output_solution': 'solution.h5ad' } meta = { @@ -25,62 +26,51 @@ sys.path.append(meta['resources_dir']) from subset_h5ad_by_format import subset_h5ad_by_format +# read viash config config = op.project.read_viash_config(meta["config"]) # set seed if need be if par["seed"]: - print(f">> Setting seed to {par['seed']}") + print(f">> Setting seed to {par['seed']}", flush=True) random.seed(par["seed"]) +# read the dataset print(">> Load data", flush=True) -adata = ad.read_h5ad(par["input"]) -print("input:", adata) +input = ad.read_h5ad(par['input']) +print("input:", input, flush=True) -print(f">> Process data using {par['method']} method") -if par["method"] == "batch": - batch_info = adata.obs[par["obs_batch"]] - batch_categories = batch_info.dtype.categories - test_batches = random.sample(list(batch_categories), 1) - is_test = [ x in test_batches for x in batch_info ] -elif par["method"] == "random": - train_ix = np.random.choice(adata.n_obs, round(adata.n_obs * 0.8), replace=False) - is_test = [ not x in train_ix for x in range(0, adata.n_obs) ] - -# subset the different adatas -print(">> Figuring which data needs to be copied to which output file", flush=True) -# use par arguments to look for label and batch value in different slots +# map the source slots of the common dataset onto the dest slots expected by the +# task-specific file formats (file_dataset.yaml / file_solution.yaml) slot_mapping = { + "layers": { + "counts": par["layer_counts"], + }, "obs": { - "label": par["obs_label"], + "cell_type": par["obs_label"], "batch": par["obs_batch"], - } + "pseudotime_true": par["obs_ptime"], + }, + "obsm": { + "X_spatial": par["obsm_spatial"], + }, } -print(">> Creating train data", flush=True) -output_train = subset_h5ad_by_format( - adata[[not x for x in is_test]], - config, - "output_train", - slot_mapping -) - -print(">> Creating test data", flush=True) -output_test = subset_h5ad_by_format( - adata[is_test], +print(">> Creating input data for the methods", flush=True) +output_dataset = subset_h5ad_by_format( + input, config, - "output_test", + "output_dataset", slot_mapping ) print(">> Creating solution data", flush=True) output_solution = subset_h5ad_by_format( - adata[is_test], + input, config, "output_solution", slot_mapping ) print(">> Writing data", flush=True) -output_train.write_h5ad(par["output_train"]) -output_test.write_h5ad(par["output_test"]) +output_dataset.write_h5ad(par["output_dataset"]) output_solution.write_h5ad(par["output_solution"]) From a2d3f2c0ae2ae28db0e6014bad768422d7859cbe Mon Sep 17 00:00:00 2001 From: seohyonkim Date: Mon, 10 Aug 2026 14:58:27 +0200 Subject: [PATCH 3/5] dataset processor seems to work --- src/api/file_dataset.yaml | 17 +++++++++++++++++ src/api/file_solution.yaml | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/src/api/file_dataset.yaml b/src/api/file_dataset.yaml index c2944d6..7bac9af 100644 --- a/src/api/file_dataset.yaml +++ b/src/api/file_dataset.yaml @@ -10,6 +10,10 @@ info: name: counts description: Raw counts required: true + - type: double + name: normalized + description: Normalized expression values + required: true obs: - type: string name: cell_type @@ -19,11 +23,24 @@ info: name: batch description: Batch information required: true + var: + - type: boolean + name: hvg + description: Whether or not the feature is considered to be a 'highly variable gene' + required: true + - type: double + name: hvg_score + description: A ranking of the features by hvg. + required: true obsm: - type: double name: X_spatial description: Spatial coordinates of each cell/spot. required: true + - type: double + name: X_pca + description: The resulting PCA embedding. + required: true uns: - type: string name: dataset_id diff --git a/src/api/file_solution.yaml b/src/api/file_solution.yaml index 46f9e94..3a3e7d6 100644 --- a/src/api/file_solution.yaml +++ b/src/api/file_solution.yaml @@ -61,3 +61,7 @@ info: name: normalization_id description: "Which normalization was used" required: true + - type: dataframe + name: marker_genes + description: "Marker genes per biological state, with expected ordering along the trajectory (columns: gene_name, biological_state, expected_order). Used by marker-based metrics when provided." + required: false From b88125def7de4cc00f5fa52cf0a518b819103e21 Mon Sep 17 00:00:00 2001 From: seohyonkim Date: Mon, 10 Aug 2026 14:59:37 +0200 Subject: [PATCH 4/5] task config file good for now --- _viash.yaml | 87 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 50 insertions(+), 37 deletions(-) diff --git a/_viash.yaml b/_viash.yaml index c171bca..62aeb7a 100644 --- a/_viash.yaml +++ b/_viash.yaml @@ -1,34 +1,28 @@ viash_version: 0.9.4 -# Step 1: Change the name of the task. -# example: task_name_of_this_task -name: task_template +name: task_spatial_trajectory_inference organization: openproblems-bio version: dev license: MIT -# Step 2: Add keywords to describe the task. -keywords: [single-cell, openproblems, benchmark] -# Step 3: Update the `task_template` to the name of the task from step 1. +keywords: [single-cell, openproblems, benchmark, spatial, trajectory inference] links: - issue_tracker: https://github.com/openproblems-bio/task_template/issues - repository: https://github.com/openproblems-bio/task_template + issue_tracker: https://github.com/openproblems-bio/task_spatial_trajectory_inference/issues + repository: https://github.com/openproblems-bio/task_spatial_trajectory_inference docker_registry: ghcr.io -# Step 4: Update the label, summary and description. -# A unique, human-readable, short label. Used for creating summary tables and visualisations. -label: Template -summary: A one sentence summary of purpose and methodology. Used for creating an overview tables. -description: | - Provide a clear and concise description of your task, detailing the specific problem it aims - to solve. Outline the input data types, the expected output, and any assumptions or constraints. - Be sure to explain any terminology or concepts that are essential for understanding the task. +label: Spatial Trajectory Inference +summary: Predicting the spatial trajectory of cells in a tissue based on spatial transcriptomics data. +description: - Explain the motivation behind your proposed task. Describe the biological or computational - problem you aim to address and why it's important. Discuss the current state of research in - this area and any gaps or challenges that your task could help address. This section - should convince readers of the significance and relevance of your task. + Spatial transcriptomics preserves each cell's physical position alongside its expression profile, enabling pseudotime prediction using 2D spatial context. + Different methods make different assumptions about resolution, input format, and output, and are further complicated by spatial batch effects not present in dissociated single-cell data. + While dynbenchmark resolved this comparison problem for non-spatial trajectory inference methods, no equivalent standardized benchmark exists for spatial pseudotime prediction, and existing method papers are validated only against each other or qualitative marker trends rather than tissues with independently known trajectories. + + This task benchmarks pseudotime prediction methods on 2D tissue datasets with well-characterized ground-truth spatial axes. + Input data consists of AnnData objects containing 2D spatial transcriptomics data with spatial coordinates. + The output is a set of quantitative metric scores comparing each method's predicted pseudotime against ground truth, capturing both trajectory accuracy and preservation of relevant biological information. # A list of references to relevant literature. Each reference should be a DOI or a bibtex entry references: @@ -47,32 +41,51 @@ references: info: image: The name of the image file to use for the component on the website. - # Step 5: Replace the task_template to the name of the task. test_resources: - type: s3 path: s3://openproblems-data/resources_test/common/ dest: resources_test/common - type: s3 - path: s3://openproblems-data/resources_test/task_template/ - dest: resources_test/task_template + path: s3://openproblems-data/resources_test/task_spatial_trajectory_inference/ + dest: resources_test/task_spatial_trajectory_inference -# Step 6: Update the authors of the task. authors: - # Full name of the author, usually in the name of FirstName MiddleName LastName. - - name: John Doe - # Role of the author. Possible values: - # - # * `"author"`: Authors who have made substantial contributions to the component. - # * `"maintainer"`: The maintainer of the component. - # * `"contributor"`: Authors who have made smaller contributions (such as code patches etc.). + - name: Chit Tong Lio + roles: [ "author", "maintainer" ] + info: + github: yollct + orcid: 0000-0003-2297-831X + email: chit-tong.lio@tum.de + - name: Seo Hyon Kim + roles: [ "author", "maintainer" ] + info: + github: seohyonkim + orcid: 0009-0007-3062-4681 + email: seohyon.l.kim@gmail.com + - name: Wenjia Zhong + roles: [ "author", "maintainer" ] + info: + github: Wenjia218 + orcid: 0009-0009-1594-8009 + email: wenjia.zhong@tum.de + - name: Luisa Katharina Bender + roles: [ "author", "maintainer" ] + info: + github: luisabender + orcid: 0009-0001-8753-7307 + email: luisa.bender@tum.de + - name: Florian Röckl + roles: [ "author", "maintainer" ] + info: + github: floro5 + orcid: 0009-0009-6050-890X + email: florian.roeckl@tum.de + - name: Jonathan Unger roles: [ "author", "maintainer" ] - # Additional information on the author info: - github: johndoe - orcid: 0000-0000-0000-0000 - email: john@doe.me - twitter: johndoe - linkedin: johndoe + github: Jonique02 + orcid: 0009-0009-5022-2975 + email: jonathan.unger@tum.de # Step 7: Remove all of the comments of the steps you completed From a3da64ae60c3440e75cd2ccf2fb1b21d3cfcd609 Mon Sep 17 00:00:00 2001 From: seohyonkim Date: Mon, 10 Aug 2026 15:07:50 +0200 Subject: [PATCH 5/5] changelog --- CHANGELOG.md | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 483ad29..4fa9831 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -# task_template x.y.z +# task_spatial_trajectory_inference 1.0.0 ## BREAKING CHANGES @@ -6,28 +6,13 @@ ## NEW FUNCTIONALITY -* Added `control_methods/true_labels` component (PR #5). - -* Added `methods/logistic_regression` component (PR #5). - -* Added `metrics/accuracy` component (PR #5). ## MAJOR CHANGES -* Updated `api` files (PR #5). - -* Updated configs, components and CI to the latest Viash version (PR #8). - -* Updated to Viash 0.9.4 (PR #12). - -* Use dependencies in `openproblems-bio/openproblems` (PR #12). +* Updated `api` files and set the data processor (PR #1). ## MINOR CHANGES -* Updated `README.md` (PR #5). - -* `run_benchmark`: write the commit the workflow ran from and the launch time into - `task_info.yaml`, instead of publishing `_viash.yaml` verbatim (PR #18). ## BUGFIXES