Skip to content

Commit 480a771

Browse files
committed
Change participant ID to sample ID. Also sneak in small changes to remove saving heatmaps to disk and adding try/catch around summary report
1 parent 7791a62 commit 480a771

File tree

8 files changed

+126
-119
lines changed

8 files changed

+126
-119
lines changed

ulc_mm_package/QtGUI/form_gui.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ def _load_ui(self):
8585

8686
# Labels
8787
self.operator_lbl = QLabel("Operator ID")
88-
self.participant_lbl = QLabel("Non-identifying participant ID")
88+
self.sample_id_lbl = QLabel("Non-identifying sample ID")
8989
self.study_select_lbl = QLabel("Select study")
9090
self.flowcell_lbl = QLabel("Flowcell ID")
9191
self.notes_lbl = QLabel("Other notes")
@@ -94,7 +94,7 @@ def _load_ui(self):
9494

9595
# Text boxes
9696
self.operator_val = QLineEdit()
97-
self.participant_val = QLineEdit()
97+
self.sample_id_val = QLineEdit()
9898

9999
self.flowcell_val = QLineEdit()
100100
self.notes_val = QPlainTextEdit()
@@ -124,7 +124,7 @@ def _load_ui(self):
124124

125125
# Place widgets
126126
self.main_layout.addWidget(self.operator_lbl, 0, 0)
127-
self.main_layout.addWidget(self.participant_lbl, 1, 0)
127+
self.main_layout.addWidget(self.sample_id_lbl, 1, 0)
128128
self.main_layout.addWidget(self.study_select_lbl, 2, 0)
129129
self.main_layout.addWidget(self.flowcell_lbl, 5, 0)
130130
self.main_layout.addWidget(self.site_lbl, 6, 0)
@@ -133,7 +133,7 @@ def _load_ui(self):
133133
self.main_layout.addWidget(self.exit_btn, 9, 0)
134134

135135
self.main_layout.addWidget(self.operator_val, 0, 1)
136-
self.main_layout.addWidget(self.participant_val, 1, 1)
136+
self.main_layout.addWidget(self.sample_id_val, 1, 1)
137137
self.main_layout.addWidget(self.study_select_val, 2, 1)
138138
self.main_layout.addWidget(self.flowcell_val, 5, 1)
139139
self.main_layout.addWidget(self.site_val, 6, 1)
@@ -154,7 +154,7 @@ def get_form_input(self) -> dict:
154154

155155
form_metadata = {
156156
"operator_id": self.operator_val.text(),
157-
"participant_id": self.participant_val.text(),
157+
"sample_id": self.sample_id_val.text(),
158158
"flowcell_id": self.flowcell_val.text(),
159159
"target_flowrate": (
160160
TARGET_FLOWRATE.name.capitalize(),
@@ -173,7 +173,7 @@ def get_form_input(self) -> dict:
173173

174174
def reset_parameters(self) -> None:
175175
"""Clear specific inputs which are expected to be unique for the next run."""
176-
self.participant_val.setText("")
176+
self.sample_id_val.setText("")
177177
self.flowcell_val.setText("")
178178
self.notes_val.setPlainText("")
179179

ulc_mm_package/QtGUI/liveview_gui.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ def closeEvent(self, event):
9191
def update_experiment(self, metadata: dict):
9292
# TODO standardize dict input
9393
self.operator_val.setText(f"{metadata['operator_id']}")
94-
self.participant_val.setText(f"{metadata['participant_id']}")
94+
self.sample_val.setText(f"{metadata['sample_id']}")
9595
self.flowcell_val.setText(f"{metadata['flowcell_id']}")
9696
self.target_flowrate_val.setText(f"{metadata['target_flowrate'][0]}")
9797
self.site_val.setText(f"{metadata['site']}")
@@ -560,35 +560,35 @@ def _load_metadata_ui(self):
560560

561561
# Populate metadata tab
562562
self.operator_lbl = QLabel("Operator ID")
563-
self.participant_lbl = QLabel("Participant ID")
563+
self.sample_lbl = QLabel("Sample ID")
564564
self.flowcell_lbl = QLabel("Flowcell ID")
565565
self.target_flowrate_lbl = QLabel("Flowrate")
566566
self.site_lbl = QLabel("Site")
567567
self.notes_lbl = QLabel("Other notes")
568568

569569
self.operator_val = QLineEdit()
570-
self.participant_val = QLineEdit()
570+
self.sample_val = QLineEdit()
571571
self.flowcell_val = QLineEdit()
572572
self.target_flowrate_val = QLineEdit()
573573
self.site_val = QLineEdit()
574574
self.notes_val = QPlainTextEdit()
575575

576576
self.operator_val.setReadOnly(True)
577-
self.participant_val.setReadOnly(True)
577+
self.sample_val.setReadOnly(True)
578578
self.flowcell_val.setReadOnly(True)
579579
self.target_flowrate_val.setReadOnly(True)
580580
self.site_val.setReadOnly(True)
581581
self.notes_val.setReadOnly(True)
582582

583583
self.metadata_layout.addWidget(self.operator_lbl, 1, 1)
584-
self.metadata_layout.addWidget(self.participant_lbl, 2, 1)
584+
self.metadata_layout.addWidget(self.sample_lbl, 2, 1)
585585
self.metadata_layout.addWidget(self.flowcell_lbl, 3, 1)
586586
self.metadata_layout.addWidget(self.target_flowrate_lbl, 4, 1)
587587
self.metadata_layout.addWidget(self.site_lbl, 5, 1)
588588
self.metadata_layout.addWidget(self.notes_lbl, 6, 1)
589589

590590
self.metadata_layout.addWidget(self.operator_val, 1, 2)
591-
self.metadata_layout.addWidget(self.participant_val, 2, 2)
591+
self.metadata_layout.addWidget(self.sample_val, 2, 2)
592592
self.metadata_layout.addWidget(self.flowcell_val, 3, 2)
593593
self.metadata_layout.addWidget(self.target_flowrate_val, 4, 2)
594594
self.metadata_layout.addWidget(self.site_val, 5, 2)
@@ -601,7 +601,7 @@ def _load_metadata_ui(self):
601601

602602
experiment_metadata = {
603603
"operator_id": "1234",
604-
"participant_id": "567",
604+
"sample_id": "567",
605605
"flowcell_id": "A2",
606606
"target_flowrate": ("Fast", 15),
607607
"site": "Uganda",

ulc_mm_package/QtGUI/oracle.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ def general_pause_handler(
430430
(
431431
"The CAP module can now be removed."
432432
"\n\nPlease empty both reservoirs and reload 12 uL of fresh "
433-
"diluted blood (from the same participant) into the sample reservoir. Make sure to close the lid after."
433+
"diluted blood (from the same sample) into the sample reservoir. Make sure to close the lid after."
434434
'\n\nAfter reloading the reservoir and closing the lid, click "OK" to resume this run.'
435435
),
436436
buttons=Buttons.OK,

ulc_mm_package/hardware/scope.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ def reset_for_end_experiment(self) -> None:
140140
# Close data storage
141141
closing_file_future = self.data_storage.close(
142142
self.predictions_handler.get_prediction_tensors(),
143-
self.predictions_handler.heatmaps,
144143
)
145144
if closing_file_future is not None:
146145
while not closing_file_future.done():

ulc_mm_package/image_processing/data_storage.py

Lines changed: 105 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -297,112 +297,122 @@ def close(
297297

298298
### Create summary report
299299
self.logger.info("> Creating summary report...")
300-
summary_report_dir = self.get_experiment_path() / "summary_report"
301-
Path.mkdir(summary_report_dir, exist_ok=True)
302-
303-
### NOTE: xhtml2pdf fails if you provide relative image file paths, e.g ("../thumbnails/ring/1.png")
304-
### so provide absolute filepaths only. Note this means that the html file will be broken if viewed from anywhere other than the Pi.
305-
306-
class_to_all_thumbnails_abs_path: Dict[str, List[str]] = {
307-
x: [
308-
str(y.resolve())
309-
for y in list(class_to_thumbnails_path[x].rglob("*.png"))
310-
]
311-
for x in class_to_thumbnails_path.keys()
312-
}
313-
314-
html_abs_path_temp_loc = (
315-
summary_report_dir / f"{self.time_str}_temp_summary.html"
316-
)
317-
pdf_save_loc = summary_report_dir / f"{self.time_str}_summary.pdf"
318-
319-
# Create per-image metadata plot
320-
per_image_metadata_plot_save_loc = str(
321-
summary_report_dir / f"{self.time_str}_per_image_metadata_plot.jpg"
322-
)
323-
324-
counts_plot_loc = str(summary_report_dir / "counts.jpg")
325-
conf_plot_loc = str(summary_report_dir / "confs.jpg")
326-
objectness_plot_loc = str(summary_report_dir / "objectness.jpg")
300+
try:
301+
summary_report_dir = self.get_experiment_path() / "summary_report"
302+
Path.mkdir(summary_report_dir, exist_ok=True)
303+
304+
### NOTE: xhtml2pdf fails if you provide relative image file paths, e.g ("../thumbnails/ring/1.png")
305+
### so provide absolute filepaths only. Note this means that the html file will be broken if viewed from anywhere other than the Pi.
306+
307+
class_to_all_thumbnails_abs_path: Dict[str, List[str]] = {
308+
x: [
309+
str(y.resolve())
310+
for y in list(class_to_thumbnails_path[x].rglob("*.png"))
311+
]
312+
for x in class_to_thumbnails_path.keys()
313+
}
314+
315+
html_abs_path_temp_loc = (
316+
summary_report_dir / f"{self.time_str}_temp_summary.html"
317+
)
318+
pdf_save_loc = summary_report_dir / f"{self.time_str}_summary.pdf"
327319

328-
# Only generate additional plots if DEBUG_REPORT environment variable is set to True
329-
if DEBUG_REPORT:
330-
with open(self.per_img_metadata_filename, "r") as per_img_metadata_file:
331-
make_per_image_metadata_plots(
332-
per_img_metadata_file, per_image_metadata_plot_save_loc
333-
)
320+
# Create per-image metadata plot
321+
per_image_metadata_plot_save_loc = str(
322+
summary_report_dir / f"{self.time_str}_per_image_metadata_plot.jpg"
323+
)
334324

335-
try:
336-
make_cell_count_plot(pred_tensors, counts_plot_loc)
337-
except Exception as e:
338-
self.logger.error(f"Failed to make cell count plot - {e}")
339-
try:
340-
make_yogo_conf_plots(pred_tensors, conf_plot_loc)
341-
except Exception as e:
342-
self.logger.error(f"Failed to make yogo confidence plots - {e}")
343-
try:
344-
make_yogo_objectness_plots(pred_tensors, objectness_plot_loc)
345-
except Exception as e:
346-
self.logger.error(f"Failed to make yogo objectness plots - {e}")
347-
348-
# Get cell counts
349-
raw_cell_counts = np.asarray(get_class_counts(pred_tensors))
350-
(
351-
comp_parasitemia,
352-
comp_parasitemia_err,
353-
) = self.compensator.get_res_from_counts(raw_cell_counts, units_ul_out=True)
354-
# Associate class with counts
355-
class_name_to_cell_count = {
356-
x.capitalize(): y for (x, y) in zip(YOGO_CLASS_LIST, raw_cell_counts)
357-
}
358-
# 'parasites per ul' is # of rings / total rbcs * scaling factor (RBCS_PER_UL)
359-
360-
# Create parasitemia plot
361-
parasitemia_plot_loc = str(self.get_parasitemia_vis_filename())
362-
try:
363-
make_parasitemia_plot(
325+
counts_plot_loc = str(summary_report_dir / "counts.jpg")
326+
conf_plot_loc = str(summary_report_dir / "confs.jpg")
327+
objectness_plot_loc = str(summary_report_dir / "objectness.jpg")
328+
329+
# Only generate additional plots if DEBUG_REPORT environment variable is set to True
330+
if DEBUG_REPORT:
331+
with open(
332+
self.per_img_metadata_filename, "r"
333+
) as per_img_metadata_file:
334+
make_per_image_metadata_plots(
335+
per_img_metadata_file, per_image_metadata_plot_save_loc
336+
)
337+
338+
try:
339+
make_cell_count_plot(pred_tensors, counts_plot_loc)
340+
except Exception as e:
341+
self.logger.error(f"Failed to make cell count plot - {e}")
342+
try:
343+
make_yogo_conf_plots(pred_tensors, conf_plot_loc)
344+
except Exception as e:
345+
self.logger.error(f"Failed to make yogo confidence plots - {e}")
346+
try:
347+
make_yogo_objectness_plots(pred_tensors, objectness_plot_loc)
348+
except Exception as e:
349+
self.logger.error(f"Failed to make yogo objectness plots - {e}")
350+
351+
# Get cell counts
352+
raw_cell_counts = np.asarray(get_class_counts(pred_tensors))
353+
(
364354
comp_parasitemia,
365355
comp_parasitemia_err,
356+
) = self.compensator.get_res_from_counts(
357+
raw_cell_counts, units_ul_out=True
358+
)
359+
# Associate class with counts
360+
class_name_to_cell_count = {
361+
x.capitalize(): y
362+
for (x, y) in zip(YOGO_CLASS_LIST, raw_cell_counts)
363+
}
364+
# 'parasites per ul' is # of rings / total rbcs * scaling factor (RBCS_PER_UL)
365+
366+
# Create parasitemia plot
367+
parasitemia_plot_loc = str(self.get_parasitemia_vis_filename())
368+
try:
369+
make_parasitemia_plot(
370+
comp_parasitemia,
371+
comp_parasitemia_err,
372+
parasitemia_plot_loc,
373+
)
374+
except Exception as e:
375+
self.logger.error(f"Failed to make parasitemia plot - {e}")
376+
377+
# HTML w/ absolute path
378+
abs_css_file_path = str((summary_report_dir / CSS_FILE_NAME).resolve())
379+
html_report_with_abs_path = make_html_report(
380+
self.compensator,
381+
self.time_str,
382+
self.experiment_level_metadata,
383+
per_image_metadata_plot_save_loc,
384+
raw_cell_counts,
385+
class_to_all_thumbnails_abs_path,
366386
parasitemia_plot_loc,
387+
counts_plot_loc,
388+
conf_plot_loc,
389+
objectness_plot_loc,
390+
css_path=abs_css_file_path,
367391
)
368-
except Exception as e:
369-
self.logger.error(f"Failed to make parasitemia plot - {e}")
370-
371-
# HTML w/ absolute path
372-
abs_css_file_path = str((summary_report_dir / CSS_FILE_NAME).resolve())
373-
html_report_with_abs_path = make_html_report(
374-
self.compensator,
375-
self.time_str,
376-
self.experiment_level_metadata,
377-
per_image_metadata_plot_save_loc,
378-
raw_cell_counts,
379-
class_to_all_thumbnails_abs_path,
380-
parasitemia_plot_loc,
381-
counts_plot_loc,
382-
conf_plot_loc,
383-
objectness_plot_loc,
384-
css_path=abs_css_file_path,
385-
)
386392

387-
# Copy the CSS file to the summary directory
388-
shutil.copy(SUMMARY_REPORT_CSS_FILE, summary_report_dir)
393+
# Copy the CSS file to the summary directory
394+
shutil.copy(SUMMARY_REPORT_CSS_FILE, summary_report_dir)
389395

390-
# Save the temporary HTML file w/ absolute path so we can properly generate the PDF
391-
save_html_report(html_report_with_abs_path, html_abs_path_temp_loc)
392-
create_pdf_from_html(html_abs_path_temp_loc, pdf_save_loc)
396+
# Save the temporary HTML file w/ absolute path so we can properly generate the PDF
397+
save_html_report(html_report_with_abs_path, html_abs_path_temp_loc)
398+
create_pdf_from_html(html_abs_path_temp_loc, pdf_save_loc)
393399

394-
# Make a copy of the summary PDF to the Desktop
395-
shutil.copy(pdf_save_loc, DESKTOP_SUMMARY_DIR)
400+
# Make a copy of the summary PDF to the Desktop
401+
shutil.copy(pdf_save_loc, DESKTOP_SUMMARY_DIR)
396402

397-
# Remove intermediate files
398-
remove(html_abs_path_temp_loc)
399-
remove(summary_report_dir / CSS_FILE_NAME)
403+
# Remove intermediate files
404+
remove(html_abs_path_temp_loc)
405+
remove(summary_report_dir / CSS_FILE_NAME)
400406

401-
if DEBUG_REPORT:
402-
remove(counts_plot_loc)
403-
remove(per_image_metadata_plot_save_loc)
404-
remove(conf_plot_loc)
405-
remove(objectness_plot_loc)
407+
if DEBUG_REPORT:
408+
remove(counts_plot_loc)
409+
remove(per_image_metadata_plot_save_loc)
410+
remove(conf_plot_loc)
411+
remove(objectness_plot_loc)
412+
except Exception as e:
413+
self.logger.error(
414+
f"Unexpected exception when saving summary report: {e}. Skipping report and continuing..."
415+
)
406416

407417
# Write to a separate csv with just cell counts for each class
408418
self.logger.info("Writing cell counts to csv...")

ulc_mm_package/scope_constants.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ def IMG_HEIGHT(self) -> int:
144144
# ================ Data storage metadata ================ #
145145
EXPERIMENT_METADATA_KEYS = [
146146
"operator_id",
147-
"participant_id",
147+
"sample_id",
148148
"sample_collection_date",
149149
"sample_collection_time",
150150
"sample_age_hours",

ulc_mm_package/summary_report/make_summary_report.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,8 @@ def make_html_report(
385385
if experiment_metadata["operator_id"]
386386
else "-"
387387
)
388-
participant = (
389-
experiment_metadata["participant_id"]
390-
if experiment_metadata["participant_id"]
391-
else "-"
388+
sample = (
389+
experiment_metadata["sample_id"] if experiment_metadata["sample_id"] else "-"
392390
)
393391
notes = experiment_metadata["notes"] if experiment_metadata["notes"] else "-"
394392
fc_id = (
@@ -401,7 +399,7 @@ def make_html_report(
401399
"css_file": css_path,
402400
"dataset_name": dataset_name,
403401
"operator_id": operator,
404-
"participant_id": participant,
402+
"sample_id": sample,
405403
"notes": notes,
406404
"flowcell_id": fc_id,
407405
"class_name_to_cell_count": format_cell_counts(compensator, cell_counts),
@@ -465,7 +463,7 @@ def create_pdf_from_html(path_to_html: Path, save_path: Path) -> None:
465463
# Dummy data
466464
exp_metadata = {
467465
"operator_id": "MK",
468-
"participant_id": "1034",
466+
"sample_id": "1034",
469467
"notes": "sample only",
470468
"flowcell_id": "A5",
471469
}

ulc_mm_package/summary_report/summary_template.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,8 @@ <h1 style="text-align: center; color: red">RESEARCH USE ONLY - <strong>NOT FOR C
5656
<td>{{ operator_id }}</td>
5757
</tr>
5858
<tr>
59-
<td>Non-identifying participant ID</td>
60-
<td>{{ participant_id }}</td>
59+
<td>Non-identifying sample ID</td>
60+
<td>{{ sample_id }}</td>
6161
</tr>
6262
<tr>
6363
<td>Notes</td>

0 commit comments

Comments
 (0)