Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tmap support #12

Merged
merged 10 commits into from
Nov 19, 2024
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ This can be achieved through the following steps:
- [Running ENACT from Notebook](#running-enact-from-notebook)
- [Running ENACT from Terminal](#running-enact-from-terminal)
- [Running Instructions](#running-instructions)
- [Visualizing Results on TissUUmaps](#visualizing-results-on-tissuumaps)
- [Reproducing Paper Results](#reproducing-paper-results)
- [Creating Synthetic VisiumHD Datasets](#creating-synthetic-visiumhd-datasets)
- [Citing ENACT](#citing-enact)
Expand Down Expand Up @@ -232,7 +233,7 @@ ENACT outputs all its results under the `cache` directory which gets automatical
.
└── cache/
└── <anaylsis_name> /
├── chunks/
├── chunks/ # ENACT results at a chunck level
│ ├── bins_gdf/
│ │ └── patch_<patch_id>.csv
│ ├── cells_gdf/
Expand All @@ -245,7 +246,11 @@ ENACT outputs all its results under the `cache` directory which gets automatical
│ └── <cell_annotation_method>_results/
│ ├── cells_adata.csv
│ └── merged_results.csv
└── cells_df.csv
├── tmap/ # Directory storing files to visualize results on TissUUmaps
│ ├── <run_name>_adata.h5
│ ├── <run_name>_tmap.tmap
│ └── wsi.tif
└── cells_df.csv # cells dataframe, each row is a cell with its coordinates
```
ENACT breaks down the whole resolution image into "chunks" (or patches) of size `patch_size`. Results are provided per-chunk under the `chunks` directory.
* `bins_gdf`:Folder containing GeoPandas dataframes representing the 2um Visium HD bins within a given patch
Expand Down Expand Up @@ -378,6 +383,20 @@ Define the cell gene markers in `config/configs.yaml` file. Those can be expert
make run_enact
```

## Visualizing Results on TissUUmaps
To view results on [TissUUmaps](https://tissuumaps.github.io), begin by installing TissUUmaps by following the instructions at:
https://tissuumaps.github.io/TissUUmaps-docs/docs/intro/installation.html#.

Once installed, follow the instructions at: https://tissuumaps.github.io/TissUUmaps-docs/docs/starting/projects.html#loading-projects

For convenience, ENACT creates a TissUUmaps project file (.tmap extension) located at under the `<cache_dir>/tmap/` folder.
<!--
<div style="text-align: center;">
<img src="figs/tissuumaps.png" alt="tissuumaps"/>
</div> -->
![plot](figs/tissuumaps.png)


## Reproducing Paper Results
This section provides a guide on how to reproduce the ENACT paper results on the [10X Genomics Human Colorectal Cancer VisumHD sample](https://www.10xgenomics.com/datasets/visium-hd-cytassist-gene-expression-libraries-of-human-crc).
Here, ENACT is run on various combinations of bin-to-cell assignment methods and cell annotation algorithms.
Expand Down
14 changes: 7 additions & 7 deletions config/configs.yaml
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
analysis_name: "colon-demo"
run_synthetic: False # True if you want to run bin to cell assignment on synthetic dataset, False otherwise.
cache_dir: "/<path-to-repo>/enact-pipeline/ENACT_supporting_files/output_files"
cache_dir: "/home/oneai/enact-pipeline/ENACT_supporting_files/output_files"
paths:
wsi_path: "/<path-to-repo>/enact-pipeline/ENACT_supporting_files/public_data/human_colorectal/input_files/Visium_HD_Human_Colon_Cancer_tissue_image.btf"
visiumhd_h5_path: "/<path-to-repo>/enact-pipeline/ENACT_supporting_files/public_data/human_colorectal/input_files/filtered_feature_bc_matrix.h5"
tissue_positions_path: "/<path-to-repo>/enact-pipeline/ENACT_supporting_files/public_data/human_colorectal/input_files/tissue_positions.parquet"
wsi_path: "/home/oneai/enact-pipeline/ENACT_supporting_files/public_data/human_colorectal/input_files/Visium_HD_Human_Colon_Cancer_tissue_image.btf"
visiumhd_h5_path: "/home/oneai/enact-pipeline/ENACT_supporting_files/public_data/human_colorectal/input_files/filtered_feature_bc_matrix.h5"
tissue_positions_path: "/home/oneai/enact-pipeline/ENACT_supporting_files/public_data/human_colorectal/input_files/tissue_positions.parquet"
steps:
segmentation: True # True if you want to run segmentation
bin_to_geodataframes: True # True to convert bin to geodataframes
bin_to_cell_assignment: True # True to assign cells to bins
segmentation: False # True if you want to run segmentation
bin_to_geodataframes: False # True to convert bin to geodataframes
bin_to_cell_assignment: False # True to assign cells to bins
cell_type_annotation: True # True to run cell type annotation
params:
seg_method: "stardist" # Stardist is the only option for now
Expand Down
Binary file added figs/tissuumaps.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 63 additions & 1 deletion src/enact/package_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
"""

import os

import yaml
import json
import shutil
import anndata
import pandas as pd
from PIL import Image

# import squidpy as sq

Expand Down Expand Up @@ -112,6 +115,65 @@ def df_to_adata(self, results_df, cell_by_gene_df):
adata.obs["patch_id"] = results_df[["chunk_name"]]
return adata

def create_tmap_file(self):
"""Creates a tmap file for the sample being run on ENACT
"""
# The following three files need to be in the same directory:
# cells_adata.h5, wsi file, experiment_tmap.tmap
tmap_template_path = "./templates/tmap_template.tmap"
with open(tmap_template_path, "r") as stream:
tmap_template = yaml.safe_load(stream)
tmap_template["filename"] = self.configs["analysis_name"]
bin_to_cell_method = self.configs["params"]["bin_to_cell_method"]
cell_annotation_method = self.configs["params"]["cell_annotation_method"]
wsi_src_path = self.configs["paths"]["wsi_path"]
wsi_fname = "wsi.tif"
run_name = f"{bin_to_cell_method}|{cell_annotation_method}"
tmap_template["markerFiles"][0]["title"] = f"ENACT Results: {run_name.replace('|', ' | ')}"
tmap_template["markerFiles"][0]["expectedHeader"].update(
{
"X": "/obsm/spatial/cell_x",
"Y": "/obsm/spatial/cell_y",
"gb_col": "/obs/cell_type/",
}
)
tmap_template["layers"][0].update(
{"name": wsi_fname, "tileSource": f"{wsi_fname}.dzi"}
)
tmap_template["markerFiles"][0]["path"] = f"{run_name}_cells_adata.h5"

# save tmap file at a separate directory "tmap"
tmap_output_dir = os.path.join(self.cache_dir, "tmap")
os.makedirs(tmap_output_dir, exist_ok=True)
tmap_file_path = os.path.join(tmap_output_dir, f"{run_name}_tmap.tmap")
with open(tmap_file_path, "w") as outfile:
outfile.write(json.dumps(tmap_template, indent=4))

# Copy the anndata file to the "tmap" directory
adata_src_path = os.path.join(
self.cellannotation_results_dir, "cells_adata.h5"
)
adata_dst_path = os.path.join(tmap_output_dir, f"{run_name}_cells_adata.h5")
shutil.copy(adata_src_path, adata_dst_path)

# Saving a cropped version (lite version) of the image file to the "tmap" directory
wsi_dst_path = os.path.join(tmap_output_dir, wsi_fname)
cropped_image, _ = self.load_image()
cropped_image = Image.fromarray(cropped_image)
cropped_image.save(wsi_dst_path)

message = f"""
Sample ready to visualize on TissUUmaps. To install TissUUmaps, follow the instructions at:\n
https://tissuumaps.github.io/TissUUmaps-docs/docs/intro/installation.html#.

To view the the sample, follow the instructions at:\n
https://tissuumaps.github.io/TissUUmaps-docs/docs/starting/projects.html#loading-projects

TissUUmaps project file is located here:\n
{tmap_file_path}
"""
print (message)

# def run_neighborhood_enrichment(self, adata):
# """Sample function to run Squidpy operations on AnnData object

Expand Down
5 changes: 4 additions & 1 deletion src/enact/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,7 @@ def assign_bins_to_cells(self, adata):
cell_gdf_chunk[["num_shared_bins", "num_unique_bins"]] = cell_gdf_chunk[
["num_shared_bins", "num_unique_bins"]
].fillna(0)

# Save index lookup to store x and y values and cell index
index_lookup_df = cell_by_gene_adata.obs.merge(
cell_gdf_chunk, how="left", left_index=True, right_on="id"
Expand Down Expand Up @@ -955,13 +956,13 @@ def run_cell_type_annotation(self):
def package_results(self):
"""Packages the results of the pipeline"""
from .package_results import PackageResults

pack_obj = PackageResults(**self.kwargs)
ann_method = self.configs["params"]["cell_annotation_method"]
if ann_method == "sargent":
results_df, cell_by_gene_df = pack_obj.merge_sargent_output_files()
adata = pack_obj.df_to_adata(results_df, cell_by_gene_df)
pack_obj.save_adata(adata)
pack_obj.create_tmap_file()
self.logger.info("<package_results> Packaged Sargent results")
elif ann_method == "cellassign":
cell_by_gene_df = pack_obj.merge_cellassign_output_files()
Expand All @@ -970,6 +971,7 @@ def package_results(self):
)
adata = pack_obj.df_to_adata(results_df, cell_by_gene_df)
pack_obj.save_adata(adata)
pack_obj.create_tmap_file()
self.logger.info("<package_results> Packaged CellAssign results")
elif ann_method == "celltypist":
cell_by_gene_df = pack_obj.merge_cellassign_output_files()
Expand All @@ -978,6 +980,7 @@ def package_results(self):
)
adata = pack_obj.df_to_adata(results_df, cell_by_gene_df)
pack_obj.save_adata(adata)
pack_obj.create_tmap_file()
self.logger.info("<package_results> Packaged CellTypist results")
else:
self.logger.info(
Expand Down
103 changes: 103 additions & 0 deletions templates/tmap_template.tmap
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
{
"compositeMode": "source-over",
"filename": "<sample_name>",
"filters": [
"Saturation",
"Brightness",
"Contrast"
],
"layerFilters": {
"0": [
{
"name": "Saturation",
"value": "0"
},
{
"name": "Brightness",
"value": "0"
},
{
"name": "Contrast",
"value": "1"
}
]
},
"layerOpacities": {
"0": "1"
},
"layerVisibilities": {
"0": true
},
"layers": [
{
"name": "../wsi.tif",
"tileSource": "../wsi.tif.dzi"
}
],
"markerFiles": [
{
"autoLoad": false,
"comment": "Displays the cell centroids color-coded by their cell type as predicted by Sargent.",
"expectedHeader": {
"X": "cell_x",
"Y": "cell_y",
"cb_cmap": "",
"cb_col": "",
"cb_gr_dict": "",
"collectionItem_col": "",
"collectionItem_fixed": "0",
"coord_factor": "1",
"gb_col": "cell_type",
"gb_name": "",
"opacity": "0.7",
"opacity_col": "",
"pie_col": "",
"pie_dict": "",
"scale_col": "",
"scale_factor": "0.2",
"shape_col": "",
"shape_fixed": "disc",
"shape_gr_dict": "",
"tooltip_fmt": ""
},
"expectedRadios": {
"_no_outline": true,
"cb_col": false,
"cb_gr": true,
"cb_gr_dict": false,
"cb_gr_key": false,
"cb_gr_rand": true,
"collectionItem_col": false,
"collectionItem_fixed": false,
"opacity_check": false,
"pie_check": false,
"scale_check": false,
"shape_col": false,
"shape_fixed": true,
"shape_gr": false,
"shape_gr_dict": false,
"shape_gr_rand": true
},
"fromButton": 0,
"hideSettings": true,
"name": "Cell centroids",
"path": "<cell_assignment_fname>",
"title": "Sargent results",
"uid": "U48505"
}
],
"plugins": [
"Experiment_Data_Export",
"Feature_Space",
"Plot_Histogram",
"Live_Region_Analysis"
],
"regionFiles": [
{
"path": "<geojson_fname>",
"title": "Load Pathologist Annotation"
}
],
"regions": {},
"schemaVersion": "1.3"
}