@@ -18,14 +18,38 @@ def _filter_genes(df: pl.DataFrame, remove_features: Collection[str]) -> pl.Data
1818 return df
1919
2020
21- # 10x Xenium
22- _XENIUM_COLUMNS = {
21+ ## 10x Genomics platforms
22+ _10X_GENOMICS_COLUMNS = {
2323 "feature_name" : "gene" ,
2424 "x_location" : "x" ,
2525 "y_location" : "y" ,
2626 "z_location" : "z" ,
2727}
2828
29+
30+ def _read_10x_parquet (
31+ filepath : Path , * , min_qv : float | None = None , columns : Collection [str ] = []
32+ ) -> pl .DataFrame :
33+ transcripts = pl .scan_parquet (filepath )
34+
35+ # 'is_gene' column exists for Xenium OA v3 and v4 / Atera
36+ # but not Xenium OA v2 parquet (Xenium OA v1 does not have parquet)
37+ if "is_gene" in transcripts .collect_schema ().names ():
38+ transcripts = transcripts .filter (pl .col ("is_gene" ))
39+
40+ if min_qv is not None :
41+ transcripts = transcripts .filter (pl .col ("qv" ) >= min_qv )
42+
43+ with pl .StringCache ():
44+ transcripts = (
45+ transcripts .select (columns )
46+ .with_columns (pl .col ("feature_name" ).cast (pl .String ).cast (pl .Categorical ))
47+ .collect ()
48+ )
49+ return transcripts
50+
51+
52+ # 10x Xenium
2953XENIUM_CTRLS = [
3054 "^BLANK" ,
3155 "^DeprecatedCodeword" ,
@@ -68,28 +92,13 @@ def read_Xenium(
6892 polars.DataFrame
6993 """
7094 filepath = Path (filepath )
71- columns = list (set (_XENIUM_COLUMNS .keys ()) | set (additional_columns ))
95+ columns = list (set (_10X_GENOMICS_COLUMNS .keys ()) | set (additional_columns ))
7296
7397 if filepath .suffix == ".parquet" :
74- transcripts = pl .scan_parquet (filepath )
75-
76- # 'is_gene' column only exists for Xenium v3 which only has .parquet
77- if "is_gene" in transcripts .collect_schema ().names ():
78- transcripts = transcripts .filter (pl .col ("is_gene" ))
79-
80- if min_qv is not None :
81- transcripts = transcripts .filter (pl .col ("qv" ) >= min_qv )
82-
83- with pl .StringCache ():
84- transcripts = (
85- transcripts .select (columns )
86- .with_columns (
87- pl .col ("feature_name" ).cast (pl .String ).cast (pl .Categorical )
88- )
89- .collect ()
90- )
98+ transcripts = _read_10x_parquet (filepath , min_qv = min_qv , columns = columns )
9199
92100 else :
101+ # read Xenium csv i.e. Xenium Onboard Analysis v1 output
93102 if min_qv is not None and "qv" not in additional_columns :
94103 columns .append ("qv" )
95104 transcripts = pl .read_csv (
@@ -104,7 +113,50 @@ def read_Xenium(
104113 if "qv" not in additional_columns :
105114 transcripts = transcripts .drop ("qv" )
106115
107- transcripts = transcripts .rename (_XENIUM_COLUMNS )
116+ transcripts = transcripts .rename (_10X_GENOMICS_COLUMNS )
117+ transcripts = _filter_genes (transcripts , remove_features )
118+
119+ return transcripts
120+
121+
122+ # 10x Atera
123+
124+ # technically they are all dropped due to is_gene filter anyways
125+ ATERA_CTRLS = ["^Intergenic" , "^NegControl" , "^UnassignedCodeword" ]
126+
127+
128+ def read_Atera (
129+ filepath : str | os .PathLike ,
130+ * ,
131+ min_qv : float | None = None ,
132+ remove_features : Collection [str ] = ATERA_CTRLS ,
133+ additional_columns : Collection [str ] = [],
134+ ) -> pl .DataFrame :
135+ """
136+ Read a Xenium transcripts file.
137+
138+ Parameters
139+ ----------
140+ filepath : os.PathLike or str
141+ Path to the Atera transcripts file (.parquet). The Zarr-store is currently not supported.
142+ min_qv : float | None, optional
143+ Minimum Phred-scaled quality value (Q-Score) of a transcript to be included.
144+ If `None` no filtering is performed.
145+ remove_features : collections.abc.Collection[str], optional
146+ List of regex patterns to filter the 'feature_name' column,
147+ :py:attr:`ovrlpy.io.ATERA_CTRLS` by default.
148+ additional_columns : collections.abc.Collection[str], optional
149+ Additional columns to load from the transcripts file.
150+
151+ Returns
152+ -------
153+ polars.DataFrame
154+ """
155+ filepath = Path (filepath )
156+ columns = list (set (_10X_GENOMICS_COLUMNS .keys ()) | set (additional_columns ))
157+
158+ transcripts = _read_10x_parquet (filepath , min_qv = min_qv , columns = columns )
159+ transcripts = transcripts .rename (_10X_GENOMICS_COLUMNS )
108160 transcripts = _filter_genes (transcripts , remove_features )
109161
110162 return transcripts
0 commit comments