Skip to content

Commit 23ce92f

Browse files
committed
Update file xenium_ROI_extracet.py
1 parent 5e2172f commit 23ce92f

1 file changed

Lines changed: 102 additions & 0 deletions

File tree

‎xenium_ROI_extracet.py‎

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import pandas as pd
2+
import json
3+
import os
4+
import re
5+
import tiffile
6+
import argparse
7+
import h5py
8+
9+
def get_arguments():
10+
"""
11+
Parses and checks command line arguments, and provides an help text.
12+
Assumes 3 and returns 3 positional command line arguments:
13+
"""
14+
parser = argparse.ArgumentParser(description = "Split transcripts and images according to the given ROIs")
15+
parser.add_argument("xenium_folder", help = "path to the xenium folder")
16+
parser.add_argument("roi_folder", help = "path to the folder with the ROI images")
17+
parser.add_argument("output_folder", help = "path to the output folder")
18+
args = parser.parse_args()
19+
return args.xenium_folder, args.roi_folder, args.output_folder
20+
21+
if __name__ == "__main__":
22+
xenium_folder, roi_folder, ouptut_folder = get_arguments()
23+
24+
# Expects standard xenium filenames: https://www.10xgenomics.com/support/in-situ-gene-expression/documentation/steps/onboard-analysis/at-a-glance-xenium-output-files
25+
xenium_file_path = os.path.join(xenium_folder, "experiment.xenium")
26+
transcript_file_path = os.path.join(xenium_folder, "transcripts.parquet")
27+
cells_file_path = os.path.join(xenium_folder, "cells.parquet")
28+
cell_boundaries_file_path = os.path.join(xenium_folder, "cell_boundaries.parquet")
29+
mip_tiff_file_path = os.path.join(xenium_folder, "morphology_mip.ome.tif")
30+
print(f"Xenium file: {xenium_file_path}")
31+
print(f"Transcript file: {transcript_file_path}")
32+
print(f"Cell file: {cells_file_path}")
33+
print(f"Cell Boundary file: {cell_boundaries_file_path}")
34+
print(f"Maximum Projection Image File: {mip_tiff_file_path}")
35+
36+
# Reads the pixel size in um
37+
with open(xenium_file_path) as metadata_file:
38+
d = json.load(metadata_file)
39+
pixel_size = d["pixel_size"]
40+
41+
# Reads the transcripts and add locations in pixels
42+
print(f"Reading Transcript file: {transcript_file_path}")
43+
transcripts = pd.read_parquet(transcript_file_path)
44+
transcripts["x_location_px"] = transcripts["x_location"] / pixel_size
45+
transcripts["y_location_px"] = transcripts["y_location"] / pixel_size
46+
transcripts["z_location_px"] = transcripts["z_location"] / pixel_size
47+
48+
# Reads the cells and add locations in pixels
49+
print(f"Reading Cell file: {cells_file_path}")
50+
cells = pd.read_parquet(cells_file_path)
51+
cells["x_centroid_px"] = cells["x_centroid"] / pixel_size
52+
cells["y_centroid_px"] = cells["y_centroid"] / pixel_size
53+
54+
# Reads the cells and add locations in pixels
55+
print(f"Reading Cell Boundary file: {cell_boundaries_file_path}")
56+
cell_boundaries = pd.read_parquet(cell_boundaries_file_path)
57+
cell_boundaries["vertex_x_px"] = cell_boundaries["vertex_x"] / pixel_size
58+
cell_boundaries["vertex_y_px"] = cell_boundaries["vertex_y"] / pixel_size
59+
60+
# Reads ROIS, expects _Xnnn_Ynnnn_Wnnn_Hnnnn_ with n = 0-9
61+
# makes a lists of lists [x, y, w, h]
62+
print(f"Looking for ROIs in: {roi_folder}")
63+
ROIs = os.listdir(roi_folder)
64+
ROIs = filter(lambda filename: re.match(".*_X[0-9]+_Y[0-9]+_W[0-9]+_H[0-9]+.*", filename), ROIs)
65+
ROIs = [ re.match(".*_X([0-9]+)_Y([0-9]+)_W([0-9]+)_H([0-9]+).*", filename).groups() for filename in ROIs]
66+
ROIs = [list(int(n) for n in i) for i in ROIs]
67+
print(f"Found ROIs: {ROIs}")
68+
69+
# Read image
70+
print(f"Reading Maximum Projection Image File: {mip_tiff_file_path}")
71+
image = tiffile.imread(mip_tiff_file_path)
72+
73+
os.makedirs(ouptut_folder, exist_ok = True)
74+
75+
for r in ROIs:
76+
roi_string = "X_" + str(r[0]) + "_Y_" + str(r[0]) + "_W_" + str(r[2]) + "_H_"+ str(r[2])
77+
print(f"Processing: {roi_string}")
78+
79+
sub_transcripts = transcripts.loc[(transcripts['x_location_px'] >= r[0]) & (transcripts['x_location_px'] <= (r[0] + r[2])) & (transcripts['y_location_px'] >= r[1]) & (transcripts['y_location_px'] <= (r[1] + r[3]))]
80+
sub_image = image[r[1] : r[1] + r[3], r[0] : r[0] + r[2]]
81+
82+
# We exlude all cells not fully contained in the ROI!
83+
cell_boundaries["out"] = (cell_boundaries['vertex_x_px'] >= r[0]) & (cell_boundaries['vertex_x_px'] <= (r[0] + r[2])) & (cell_boundaries['vertex_y_px'] >= r[1]) & (cell_boundaries['vertex_y_px'] <= (r[1] + r[3]))
84+
filter_df = cell_boundaries[["cell_id", "out"]].groupby("cell_id").filter(lambda x: all(x["out"])).drop_duplicates()
85+
86+
sub_cell_boundaries = pd.merge(cell_boundaries, filter_df["cell_id"], on = "cell_id", how = "inner")
87+
sub_cell_boundaries = sub_cell_boundaries.drop('out', axis=1)
88+
sub_cells = pd.merge(cells, filter_df["cell_id"], on = "cell_id", how = "inner")
89+
90+
91+
print(f"Writing {roi_string}")
92+
subfolder= os.path.join(ouptut_folder, roi_string)
93+
os.makedirs(subfolder, exist_ok = True)
94+
95+
tiffile.imwrite(os.path.join(subfolder, roi_string + "-morphology_mip.ome.tif"),data = sub_image, ome = True)
96+
sub_transcripts.to_parquet(os.path.join(subfolder, roi_string + "-transcritps.parquet"))
97+
sub_transcripts.to_csv(os.path.join(subfolder, roi_string + "-transcritps.csv"))
98+
sub_cells.to_parquet(os.path.join(subfolder, roi_string + "-cells.parquet"))
99+
sub_cells.to_csv(os.path.join(subfolder, roi_string + "-cells.csv"))
100+
sub_cell_boundaries.to_parquet(os.path.join(subfolder, roi_string + "-cell_boundaries.parquet"))
101+
sub_cell_boundaries.to_csv(os.path.join(subfolder, roi_string + "-cell_boundaries.csv"))
102+

0 commit comments

Comments
 (0)