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
9 changes: 5 additions & 4 deletions ulc_mm_package/image_processing/data_storage.py
Original file line number Diff line number Diff line change
Expand Up @@ -331,15 +331,15 @@ def close(

# Get cell counts
raw_cell_counts = np.asarray(get_class_counts(pred_tensors))
(
comp_parasitemia,
comp_parasitemia_err,
) = self.compensator.get_res_from_counts(raw_cell_counts, units_ul_out=True)
# Associate class with counts
class_name_to_cell_count = {
x.capitalize(): y for (x, y) in zip(YOGO_CLASS_LIST, raw_cell_counts)
}
# 'parasites per ul' is # of rings / total rbcs * scaling factor (RBCS_PER_UL)
(
comp_parasitemia,
comp_parasitemia_err,
) = self.compensator.get_res_from_counts(raw_cell_counts, units_ul_out=True)

# Create parasitemia plot
parasitemia_plot_loc = str(self.get_parasitemia_vis_filename())
Expand All @@ -355,6 +355,7 @@ def close(
# HTML w/ absolute path
abs_css_file_path = str((summary_report_dir / CSS_FILE_NAME).resolve())
html_report_with_abs_path = make_html_report(
self.compensator,
self.time_str,
self.experiment_level_metadata,
per_image_metadata_plot_save_loc,
Expand Down
6 changes: 6 additions & 0 deletions ulc_mm_package/neural_nets/neural_network_constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ class MODELS(Enum):
YOGO_CLASS_IDX_MAP["trophozoite"],
YOGO_CLASS_IDX_MAP["schizont"],
]
ALL_PARASITE_CLASS_IDS: List[int] = [
YOGO_CLASS_IDX_MAP["ring"],
YOGO_CLASS_IDX_MAP["trophozoite"],
YOGO_CLASS_IDX_MAP["schizont"],
YOGO_CLASS_IDX_MAP["gametocyte"],
]
CLASS_IDS_FOR_TABLE_COUNTS: List[int] = [
YOGO_CLASS_IDX_MAP["healthy"],
YOGO_CLASS_IDX_MAP["ring"],
Expand Down
69 changes: 50 additions & 19 deletions ulc_mm_package/summary_report/make_summary_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@
YOGO_PRED_THRESHOLD,
YOGO_CLASS_LIST,
CLASS_IDS_FOR_TABLE_COUNTS,
CLASS_IDS_FOR_THUMBNAILS,
ASEXUAL_PARASITE_CLASS_IDS,
ALL_PARASITE_CLASS_IDS,
)
from ulc_mm_package.summary_report.parasitemia_visualization import (
make_parasitemia_plot,
Expand All @@ -37,32 +36,60 @@
matplotlib.use("agg")


def format_cell_counts(cell_counts: npt.NDArray) -> Dict[str, str]:
def format_cell_counts(
compensator: CountCompensator, raw_cell_counts: npt.NDArray
) -> Dict[str, List[str]]:
"""Format raw cell counts for display in summary report"""
# Express parasite classes as percent of total parasites
total_parasites = np.sum(cell_counts[ASEXUAL_PARASITE_CLASS_IDS])
total_parasites = np.sum(raw_cell_counts[ALL_PARASITE_CLASS_IDS])
total_cells = raw_cell_counts[0] + total_parasites

if total_parasites > 0:
str_cell_counts = [
f"{ct} ({ct / total_parasites * 100.0:.0f}% of parasites)"
if i in ASEXUAL_PARASITE_CLASS_IDS
else f"{ct}"
[
f"{ct}",
f"{int(compensator._get_res_from_counts(np.array([total_cells - raw_cell_counts[i], raw_cell_counts[i]]), units_ul_out=True)[0])} p/uL",
f"{compensator._get_res_from_counts(np.array([total_cells - raw_cell_counts[i], raw_cell_counts[i]]), units_ul_out=False)[0]:.2f} %",
]
# f"{ct} ({ct / total_parasites * 100.0:.0f}% of parasites)"
if i in ALL_PARASITE_CLASS_IDS
else [
f"{ct}",
"--",
"--",
]
for i, ct in enumerate(
[
ct if i in CLASS_IDS_FOR_TABLE_COUNTS else 0
for i, ct in enumerate(cell_counts)
for i, ct in enumerate(raw_cell_counts)
]
)
]
else:
str_cell_counts = [
f"{ct}" if i in CLASS_IDS_FOR_THUMBNAILS else 0 # type:ignore
for i, ct in enumerate(cell_counts)
[
f"{ct}",
"0 p/uL",
"0.00 %",
]
# f"{ct} ({ct / total_parasites * 100.0:.0f}% of parasites)"
if i in ALL_PARASITE_CLASS_IDS
else [
f"{ct}",
"--",
"--",
]
for i, ct in enumerate(
[
ct if i in CLASS_IDS_FOR_TABLE_COUNTS else 0
for i, ct in enumerate(raw_cell_counts)
]
)
]

# Add class name
class_name_to_cell_count = {
YOGO_CLASS_LIST[i].capitalize(): ct for (i, ct) in enumerate(str_cell_counts)
YOGO_CLASS_LIST[i].capitalize(): cts for (i, cts) in enumerate(str_cell_counts)
}

return class_name_to_cell_count
Expand Down Expand Up @@ -303,10 +330,11 @@ def make_yogo_objectness_plots(preds: npt.NDArray, save_loc: str) -> None:


def make_html_report(
compensator: CountCompensator,
dataset_name: str,
experiment_metadata: Dict[str, str],
per_image_metadata_plot_path: str,
cell_counts: npt.NDArray,
cell_counts: List,
thumbnails: Dict[str, List[str]],
parasitemia_plot_loc: str,
counts_plot_loc: str,
Expand Down Expand Up @@ -376,7 +404,7 @@ def make_html_report(
"participant_id": participant,
"notes": notes,
"flowcell_id": fc_id,
"class_name_to_cell_count": format_cell_counts(cell_counts),
"class_name_to_cell_count": format_cell_counts(compensator, cell_counts),
"parasites_per_ul_scaling_factor": f"{RBCS_PER_UL:.0E}",
"all_thumbnails": thumbnails,
"DEBUG_SUMMARY_REPORT": DEBUG_REPORT,
Expand Down Expand Up @@ -441,26 +469,29 @@ def create_pdf_from_html(path_to_html: Path, save_path: Path) -> None:
"notes": "sample only",
"flowcell_id": "A5",
}
cell_counts = np.array([1000, 0, 0, 0, 0, 0, 0])
raw_cell_counts = np.array([1000, 1, 0, 0, 0, 0, 0])

# Compensator
compensator = CountCompensator(
"elated-smoke-4492",
clinical=True,
skip=True,
conf_thresh=0.9,
clinical=False,
skip=False,
conf_thresh=0.7,
)
(
comp_parasitemia,
comp_parasitemia_err,
) = compensator.get_res_from_counts(cell_counts, units_ul_out=True)
) = compensator.get_res_from_counts(raw_cell_counts, units_ul_out=True)
make_parasitemia_plot(comp_parasitemia, comp_parasitemia_err, parasitemia_file)

print(compensator.inv_cmatrix)

content = make_html_report(
compensator,
"Dummy test",
exp_metadata,
"",
cell_counts,
raw_cell_counts,
{},
str(parasitemia_file),
"",
Expand Down
18 changes: 14 additions & 4 deletions ulc_mm_package/summary_report/summary_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,24 +67,34 @@ <h1 style="text-align: center; color: red">RESEARCH USE ONLY - <strong>NOT FOR C
<td>Flowcell ID</td>
<td>{{ flowcell_id }}</td>
</tr>
</table>

<table style="table-layout: fixed;">
{# Estimated sample composition #}
<thead>
<tr>
<th colspan="2">Estimated sample composition</th>
<th colspan="4">Estimated sample composition</th>
</tr>
</thead>
{% for key in class_name_to_cell_count %}
<tr>
<td><b>Class</b></td>
<td><b>Raw count</b></td>
<td><b>Parasitemia (p/uL)</b></td>
<td><b>Parasitemia (%)</b></td>
</tr>
{% for key, vals in class_name_to_cell_count.items() %}
<tr>
<td>{{key}}</td>
<td>{{class_name_to_cell_count[key]}}</td>
<td>{{vals[0]}}</td>
<td>{{vals[1]}}</td>
<td>{{vals[2]}}</td>
</tr>
{% endfor %}
</table>
<font size="-1">
<i>Parasitemia includes asexual stages only.</i>
</font>

{# Thumbnails #}
<div>
<pdf:nextpage />
Expand Down