Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,035 changes: 1,035 additions & 0 deletions assets/manuscript.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
copyright = '2026, Barry Digby'
author = 'Barry Digby'

release = '0.1'
version = '0.1.5'
release = '1.0'
version = '1.0.1'

# -- General configuration

Expand Down
26 changes: 15 additions & 11 deletions docs/outputs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -527,19 +527,21 @@ miRNA output are a combination of CircNET and CSCD - for this reason, not all Ta

.. code-block:: text

circRNA miRNA MSA_start MSA_end Site_type Score Energy Algorithm
chr15:100048856-100054054|+ miR-1208 30.0 37.0 8mer-1a 144.0 -13.62 miRanda,TargetScan
chr15:100048856-100054054|+ miR-1237-5p/4488-5p 140.0 -20.01 miRanda
chr15:100048856-100054054|+ miR-1289 141.0 -22.95 miRanda
chr15:100048856-100054054|+ miR-141-5p 39.0 45.0 7mer-m8 178.0 -26.76 miRanda,TargetScan
hg19 hg38 miRNA MSA_start MSA_end Site_type Score Energy Algorithm
chr15:100048856-100054054|+ chr15:100048856-100054054|+ miR-1208 30.0 37.0 8mer-1a 144.0 -13.62 miRanda,TargetScan
chr15:100048856-100054054|+ chr15:100048856-100054054|+ miR-1237-5p/4488-5p 140.0 -20.01 miRanda
chr15:100048856-100054054|+ chr15:100048856-100054054|+ miR-1289 141.0 -22.95 miRanda
chr15:100048856-100054054|+ chr15:100048856-100054054|+ miR-141-5p 39.0 45.0 7mer-m8 178.0 -26.76 miRanda,TargetScan

.. list-table::
:header-rows: 1
:widths: 50 50

* - Column Name
- Description
* - circRNA
* - hg19
- The circRNA coordinates in the hg19 reference genome.
* - hg38
- The circRNA coordinates in the hg38 reference genome.
* - miRNA
- The miRNA ID.
Expand All @@ -561,18 +563,20 @@ RBP

.. code-block:: text

circRNA Chr Start End RBP_symbol Information RBP_numbers source
chr18:12493071-12546904|+ chr18 12503834 12546883 AGO2 SBDH105-59581 24 common
chr18:12493071-12546904|+ chr18 12498779 12546872 FBL SBDH120-145469 10 common
chr18:12493071-12546904|+ chr18 12493071 12546757 U2AF2 SBDH19-189369 100 common
hg19 hg38 Chr Start End RBP_symbol Information RBP_numbers source
chr18:12493071-12546904|+ chr18:12493071-12546904|+ chr18 12503834 12546883 AGO2 SBDH105-59581 24 common
chr18:12493071-12546904|+ chr18:12493071-12546904|+ chr18 12498779 12546872 FBL SBDH120-145469 10 common
chr18:12493071-12546904|+ chr18:12493071-12546904|+ chr18 12493071 12546757 U2AF2 SBDH19-189369 100 common

.. list-table::
:header-rows: 1
:widths: 50 50

* - Column Name
- Description
* - circRNA
* - hg19
- The circRNA coordinates in the hg19 reference genome.
* - hg38
- The circRNA coordinates in the hg38 reference genome.
* - Chr
- Chromosome of the RBP binding site.
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "pycircdb"
version = "1.0.0"
version = "1.0.1"
description = "pycircdb: integrated circRNA database annotation for computational workflows."
readme = "README.md"
authors = [{ name = "Barry Digby", email = "b.digby237@gmail.com" }]
Expand Down
24 changes: 15 additions & 9 deletions utils/mirna/mirna_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,18 @@ def broadcast_mirna(
for sample_name, lookup_hits in lookup_dict.items():
# Combine all hg38 IDs for this sample across all databases
hg38_series = []
# Map strand-stripped hg38 key -> full (stranded) hg38 coordinate,
# so strand can be restored on the output after the strand-less match.
# Map strand-stripped hg38 key -> stranded hg38/hg19 coordinates,
# so both can be restored on the output after the strand-less match.
strand_frames = []
for db_name, pl_hits in lookup_hits.items():
if pl_hits.is_empty() or "hg38" not in pl_hits.columns:
continue
hg38_series.append(pl_hits["hg38"].str.split("|").list.first())
hg19_col = pl.col("hg19") if "hg19" in pl_hits.columns else pl.lit(None, dtype=pl.Utf8).alias("hg19")
strand_frames.append(pl_hits.select(
pl.col("hg38").str.split("|").list.first().alias("_hg38_key"),
pl.col("hg38").alias("circRNA"),
pl.col("hg38"),
hg19_col,
))

if not hg38_series:
Expand All @@ -50,7 +52,7 @@ def broadcast_mirna(
# Prefer stranded coordinates when de-duplicating the strand-less key.
strand_map = (
pl.concat(strand_frames)
.sort("circRNA")
.sort("hg38")
.unique(subset="_hg38_key", keep="last")
)

Expand Down Expand Up @@ -96,16 +98,20 @@ def mirna_hits(broadcast_mirna: miRNABroadcast) -> None:

if not df.is_empty():
# The miRNA table's circRNA column is the strand-stripped hg38 key.
# Join back to restore the strand onto the circRNA coordinate.
# Join back to restore stranded hg38/hg19 coordinates onto the output.
if strand_map is not None and strand_map.height > 0:
df = (
df.rename({"circRNA": "_hg38_key"})
.join(strand_map, on="_hg38_key", how="left")
# Fall back to the strand-less key if a coordinate is unmapped.
.with_columns(pl.col("circRNA").fill_null(pl.col("_hg38_key")))
# Fall back to the strand-less key if hg38 is unmapped.
.with_columns(pl.col("hg38").fill_null(pl.col("_hg38_key")))
)
ordered = ["circRNA"] + [c for c in df.columns if c not in ("circRNA", "_hg38_key")]
df = df.select(ordered)
else:
# No strand info available: fall back to the strand-less key for hg38.
df = df.rename({"circRNA": "hg38"}).with_columns(pl.lit(None, dtype=pl.Utf8).alias("hg19"))

ordered = ["hg19", "hg38"] + [c for c in df.columns if c not in ("hg19", "hg38", "_hg38_key")]
df = df.select(ordered)

p = Path(output_dir)
if p.is_absolute():
Expand Down
23 changes: 15 additions & 8 deletions utils/rbp/rbp_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,18 @@ def broadcast_rbp(
for sample_name, lookup_hits in lookup_dict.items():
# Combine all hg38 IDs for this sample across all databases
hg38_series = []
# Same code as mirna_driver below
# Map strand-stripped hg38 key -> stranded hg38/hg19 coordinates,
# so both can be restored on the output after the strand-less match.
strand_frames = []
for db_name, pl_hits in lookup_hits.items():
if pl_hits.is_empty() or "hg38" not in pl_hits.columns:
continue
hg38_series.append(pl_hits["hg38"].str.split("|").list.first())
hg19_col = pl.col("hg19") if "hg19" in pl_hits.columns else pl.lit(None, dtype=pl.Utf8).alias("hg19")
strand_frames.append(pl_hits.select(
pl.col("hg38").str.split("|").list.first().alias("_hg38_key"),
pl.col("hg38").alias("circRNA"),
pl.col("hg38"),
hg19_col,
))

if not hg38_series:
Expand All @@ -48,7 +51,7 @@ def broadcast_rbp(
# Prefer stranded coordinates when de-duplicating the strand-less key.
strand_map = (
pl.concat(strand_frames)
.sort("circRNA")
.sort("hg38")
.unique(subset="_hg38_key", keep="last")
)

Expand Down Expand Up @@ -88,16 +91,20 @@ def rbp_hits(broadcast_rbp: RBPBroadcast) -> None:

if not df.is_empty():
# The RBP table's circRNA column is the strand-stripped hg38 key.
# Join back to restore the strand onto the circRNA coordinate.
# Join back to restore stranded hg38/hg19 coordinates onto the output.
if strand_map is not None and strand_map.height > 0:
df = (
df.rename({"circRNA": "_hg38_key"})
.join(strand_map, on="_hg38_key", how="left")
# Fall back to the strand-less key if a coordinate is unmapped.
.with_columns(pl.col("circRNA").fill_null(pl.col("_hg38_key")))
# Fall back to the strand-less key if hg38 is unmapped.
.with_columns(pl.col("hg38").fill_null(pl.col("_hg38_key")))
)
ordered = ["circRNA"] + [c for c in df.columns if c not in ("circRNA", "_hg38_key")]
df = df.select(ordered)
else:
# No strand info available: fall back to the strand-less key for hg38.
df = df.rename({"circRNA": "hg38"}).with_columns(pl.lit(None, dtype=pl.Utf8).alias("hg19"))

ordered = ["hg19", "hg38"] + [c for c in df.columns if c not in ("hg19", "hg38", "_hg38_key")]
df = df.select(ordered)

p = Path(output_dir)
if p.is_absolute():
Expand Down
26 changes: 13 additions & 13 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading