Skip to content

Commit b917ac1

Browse files
committed
refactor: more robust data handling when creating the gene info file
Signed-off-by: Josh Loecker <joshloecker@icloud.com>
1 parent 4de5421 commit b917ac1

1 file changed

Lines changed: 42 additions & 28 deletions

File tree

main/como/rnaseq_preprocess.py

Lines changed: 42 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -664,15 +664,13 @@ async def _create_gene_info_file(
664664
The gene information file will be created by reading each matrix filepath in the provided list
665665
"""
666666

667-
async def read_counts(file: Path) -> list[str]:
667+
async def read_ensembl_gene_ids(file: Path) -> list[str]:
668668
data = await _read_file(file, h5ad_as_df=False)
669-
669+
if isinstance(data, pd.DataFrame):
670+
data: pd.DataFrame
671+
return data["ensembl_gene_id"].tolist()
670672
try:
671-
conversion = await (
672-
ensembl_to_gene_id_and_symbol(ids=data["ensembl_gene_id"].tolist(), taxon=taxon)
673-
if isinstance(data, pd.DataFrame)
674-
else gene_symbol_to_ensembl_and_gene_id(symbols=data.var_names.tolist(), taxon=taxon)
675-
)
673+
conversion = await gene_symbol_to_ensembl_and_gene_id(symbols=data.var_names.tolist(), taxon=taxon)
676674
except json.JSONDecodeError:
677675
_log_and_raise_error(
678676
f"Got a JSON decode error for file '{counts_matrix_filepaths}'",
@@ -681,32 +679,48 @@ async def read_counts(file: Path) -> list[str]:
681679
)
682680

683681
# Remove NA values from entrez_gene_id dataframe column
684-
return conversion["entrez_gene_id"].tolist()
682+
return conversion["ensembl_gene_id"].tolist()
685683

686684
logger.info("Fetching gene info - this can take up to 5 minutes depending on the number of genes and your internet connection")
687-
genes = set(chain.from_iterable(await asyncio.gather(*[read_counts(f) for f in counts_matrix_filepaths])))
688-
gene_data = await MyGene(cache=cache).query(items=list(genes), taxon=taxon, scopes="entrezgene")
685+
686+
ensembl_ids: set[str] = set(chain.from_iterable(await asyncio.gather(*[read_ensembl_gene_ids(f) for f in counts_matrix_filepaths])))
687+
gene_data: list[dict[str, str | int | list[str] | list[int] | None]] = await MyGene(cache=cache).query(
688+
items=list(ensembl_ids),
689+
taxon=taxon,
690+
scopes="ensemblgene",
691+
)
689692
gene_info: pd.DataFrame = pd.DataFrame(
690693
data=None,
691-
columns=["ensembl_gene_id", "gene_symbol", "entrez_gene_id", "size"],
692-
index=list(range(len(gene_data))),
694+
columns=pd.Index(data=["ensembl_gene_id", "gene_symbol", "entrez_gene_id", "size"]),
695+
index=pd.Index(data=list(range(len(ensembl_ids)))),
693696
)
694-
for i, data in enumerate(gene_data):
695-
ensembl_ids = data.get("genomic_pos.ensemblgene", pd.NA)
696-
if isinstance(ensembl_ids, list):
697-
ensembl_ids = ensembl_ids[0]
698-
699-
start_pos = data.get("genomic_pos.start", 0)
700-
start_pos: int = int(sum(start_pos) / len(start_pos)) if isinstance(start_pos, list) else int(start_pos)
701-
end_pos = data.get("genomic_pos.end", 0)
702-
end_pos: int = int(sum(end_pos) / len(end_pos)) if isinstance(end_pos, list) else int(end_pos)
703-
704-
gene_info.at[i, "gene_symbol"] = data.get("symbol", pd.NA)
705-
gene_info.at[i, "entrez_gene_id"] = data.get("entrezgene", pd.NA)
706-
gene_info.at[i, "ensembl_gene_id"] = ensembl_ids
707-
gene_info.at[i, "size"] = end_pos - start_pos
708-
gene_info.sort_values(by="ensembl_gene_id", inplace=True)
709697

698+
for i, data in enumerate(gene_data):
699+
data: dict[str, str | int | list[str] | list[int] | None]
700+
ensembl_genes: str | list[str] = cast(str | list[str], data.get("ensembl.gene", "-"))
701+
start_pos: int | list[int] = cast(int | list[int], data.get("genomic_pos.start", 0))
702+
end_pos: int | list[int] = cast(int | list[int], data.get("genomic_pos.end", 0))
703+
704+
avg_start: int | float = sum(start_pos) / len(start_pos) if isinstance(start_pos, list) else start_pos
705+
avg_end: int | float = sum(end_pos) / len(end_pos) if isinstance(end_pos, list) else end_pos
706+
size: int = int(avg_end - avg_start)
707+
708+
gene_info.at[i, "gene_symbol"] = data.get("symbol", "-")
709+
gene_info.at[i, "entrez_gene_id"] = data.get("entrezgene", "-")
710+
gene_info.at[i, "ensembl_gene_id"] = ",".join(ensembl_genes) if isinstance(ensembl_genes, list) else ensembl_genes
711+
gene_info.at[i, "size"] = size if size > 0 else -1
712+
713+
gene_info["size"] = gene_info["size"].astype(str) # replace no-length values with "-" to match rows where every value is "-"
714+
gene_info["size"] = gene_info["size"].replace("-1", "-")
715+
gene_info = cast(pd.DataFrame, gene_info[~(gene_info == "-").all(axis=1)]) # remove rows where every value is "-"
716+
717+
gene_info["ensembl_gene_id"] = gene_info["ensembl_gene_id"].str.split(",") # extend lists into multiple rows
718+
gene_info = gene_info.explode(column=["ensembl_gene_id"])
719+
gene_info["size"] = gene_info["size"].astype(int)
720+
# we would set `entrez_gene_id` to int here as well, but not all ensembl ids are mapped to entrez ids,
721+
# and as a result, there are still "-" values in the entrez id column that cannot be converted to an integer
722+
723+
gene_info: pd.DataFrame = cast(pd.DataFrame, gene_info.sort_values(by="ensembl_gene_id"))
710724
output_filepath.parent.mkdir(parents=True, exist_ok=True)
711725
gene_info.to_csv(output_filepath, index=False)
712726
logger.success(f"Gene Info file written at '{output_filepath}'")
@@ -728,7 +742,7 @@ async def _process_como_input(
728742
rna=rna,
729743
)
730744
with pd.ExcelWriter(output_config_filepath) as writer:
731-
subset_config = config_df[config_df["library_prep"] == rna.value]
745+
subset_config = config_df[config_df["library_prep"].str.lower() == rna.value.lower()]
732746
subset_config.to_excel(writer, sheet_name=context_name, header=True, index=False)
733747

734748

0 commit comments

Comments
 (0)