Skip to content

Commit f770aae

Browse files
authored
Merge pull request #123 from formbio/bc_req4
Add Base - Level Reporting - Requirement 4
2 parents 7c8a381 + 411247a commit f770aae

2 files changed

Lines changed: 59 additions & 21 deletions

File tree

src/aggregate_tables.py

Lines changed: 55 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ def analyze_alignments(path_prefix):
3434
dict: Dictionary containing analysis results and raw data
3535
"""
3636
read_df = pd.read_csv(f"{path_prefix}.per_read.tsv.gz", sep="\t")
37+
alignments_df = pd.read_csv(f"{path_prefix}.alignments.tsv.gz", sep="\t")
38+
39+
# Pre-aggregate the alignment data by read_id (sum map_len)
40+
map_len_df = alignments_df[alignments_df["is_mapped"] == "Y"].groupby("read_id")["map_len"].sum().reset_index()
41+
3742
# Filter to vector-only reads
3843
read_vector = read_df[read_df["reference_label"] == "vector"]
3944

@@ -46,10 +51,10 @@ def analyze_alignments(path_prefix):
4651

4752
result = {
4853
"agg_ref_type": get_ref_type_agg(
49-
read_df, total_read_count_all, total_read_count_vector, total_read_count_lambda
54+
read_df, map_len_df, total_read_count_all, total_read_count_vector, total_read_count_lambda
5055
),
5156
"agg_subtype": get_subtype_agg(
52-
read_vector, total_read_count_all, total_read_count_vector, total_read_count_lambda
57+
read_vector, map_len_df, total_read_count_all, total_read_count_vector, total_read_count_lambda
5358
),
5459
}
5560

@@ -62,15 +67,26 @@ def analyze_alignments(path_prefix):
6267
return result
6368

6469

65-
def get_ref_type_agg(read_df, total_read_count_all, total_read_count_vector, total_read_count_lambda):
70+
def get_ref_type_agg(read_df, map_len_df, total_read_count_all, total_read_count_vector, total_read_count_lambda):
6671
"""Counts and percentages of reference labels and types."""
67-
df = (
68-
read_df.groupby(["reference_label", "assigned_type"], dropna=False)[
69-
"effective_count"
70-
]
71-
.sum()
72-
.reset_index(name="effective_count")
72+
# Merge read_df with pre-aggregated map_len data
73+
merged_df = pd.merge(
74+
read_df[["read_id", "reference_label", "assigned_type", "effective_count"]],
75+
map_len_df,
76+
on="read_id",
77+
how="left" # Keep all reads, even if they don't have alignments
7378
)
79+
merged_df["map_len"] = merged_df["map_len"].fillna(0)
80+
81+
# Do a single groupby to get both effective_count and base
82+
df = merged_df.groupby(["reference_label", "assigned_type"], dropna=False).agg({
83+
"effective_count": "sum",
84+
"map_len": "sum"
85+
}).reset_index()
86+
87+
# Rename map_len to base
88+
df = df.rename(columns={"map_len": "base"})
89+
7490
df = df.sort_values(
7591
["reference_label", "effective_count"], ascending=[False, False]
7692
)
@@ -86,7 +102,7 @@ def get_ref_type_agg(read_df, total_read_count_all, total_read_count_vector, tot
86102
return df
87103

88104

89-
def get_subtype_agg(read_vector, total_read_count_all, total_read_count_vector, total_read_count_lambda):
105+
def get_subtype_agg(read_vector, map_len_df, total_read_count_all, total_read_count_vector, total_read_count_lambda):
90106
"""Counts and percentages of assigned types and subtypes."""
91107
# Handle case where there are no vector reads
92108
if read_vector.empty:
@@ -96,16 +112,30 @@ def get_subtype_agg(read_vector, total_read_count_all, total_read_count_vector,
96112
"assigned_type": [pd.NA],
97113
"assigned_subtype": [pd.NA],
98114
"effective_count": [0], # Use 0 so R sum() works correctly
115+
"base": [0],
99116
"pct_vector": [0.0],
100117
"pct_total": [0.0],
101118
"pct_wo_lambda": [0.0]
102119
})
103120

104-
df = (
105-
read_vector.groupby(["assigned_type", "assigned_subtype"])["effective_count"]
106-
.sum()
107-
.reset_index(name="effective_count")
121+
# Merge read_vector with pre-aggregated map_len data
122+
merged_df = pd.merge(
123+
read_vector[["read_id", "assigned_type", "assigned_subtype", "effective_count"]],
124+
map_len_df,
125+
on="read_id",
126+
how="left"
108127
)
128+
merged_df["map_len"] = merged_df["map_len"].fillna(0)
129+
130+
# Group by to get both effective_count and base
131+
df = merged_df.groupby(["assigned_type", "assigned_subtype"]).agg({
132+
"effective_count": "sum",
133+
"map_len": "sum"
134+
}).reset_index()
135+
136+
# Rename map_len to base
137+
df = df.rename(columns={"map_len": "base"})
138+
109139
df = df.sort_values(["assigned_type", "effective_count"], ascending=[False, False])
110140
df["pct_vector"] = round(df["effective_count"] * 100 / total_read_count_vector, 2)
111141
df["pct_total"] = round(df["effective_count"] * 100 / total_read_count_all, 2)
@@ -115,11 +145,17 @@ def get_subtype_agg(read_vector, total_read_count_all, total_read_count_vector,
115145

116146
def get_flipflop_agg(ff_df):
117147
"""Counts of flip-flop configurations."""
118-
df = (
119-
ff_df.groupby(["type", "subtype", "leftITR", "rightITR"])
120-
.size()
121-
.reset_index(name="count")
122-
)
148+
# Calculate length for each record
149+
ff_df["length"] = ff_df["end"] - ff_df["start"]
150+
151+
# Group by required columns and calculate count and sum of lengths
152+
df = ff_df.groupby(["type", "subtype", "leftITR", "rightITR"]).agg({
153+
"name": "count", # This gives us the count
154+
"length": "sum" # This gives us the base (sum of all lengths)
155+
}).reset_index()
156+
157+
# Rename columns
158+
df = df.rename(columns={"name": "count", "length": "base"})
123159
return df
124160

125161

src/report.Rmd

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
12
---
23
output:
34
html_document:
@@ -214,7 +215,7 @@ total_row <- agg_ref_type %>%
214215
agg_ref_type_with_total <- bind_rows(agg_ref_type, total_row)
215216
216217
# Create the flextable
217-
flextable(agg_ref_type_with_total %>% select(! c(pct_vector, pct_total))) %>%
218+
flextable(agg_ref_type_with_total %>% select(! c(pct_vector, pct_total, "base"))) %>%
218219
set_header_labels(values = c(
219220
"Mapped Reference",
220221
"Assigned Type",
@@ -634,11 +635,12 @@ if (exists("df.flipflop") && (nrow(df.flipflop) > 1)) {
634635

635636
```{r fftable, message=FALSE, warning=FALSE, results='asis'}
636637
if (exists("df.flipflop") && (nrow(df.flipflop) > 1)) {
637-
flextable(df.flipflop) %>%
638+
flextable(df.flipflop %>% select(! c("base"))) %>%
638639
set_header_labels(values = c("type", "subtype", "leftITR", "rightITR", "count"))
639640
}
640641
```
641642

643+
642644
```{r saverdata, message=FALSE, warning=FALSE}
643645
# Enable for troubleshooting -- takes some time to generate
644646
# save.image(file=paste0(params$path_prefix, '.Rdata'))

0 commit comments

Comments
 (0)