Debugged reports.

This commit is contained in:
lwark
2025-03-24 13:42:39 -05:00
parent d796dc4b8d
commit 6404bc499b
5 changed files with 23 additions and 110 deletions

View File

@@ -1,3 +1,7 @@
# 202503.05
- Added concentrations chart tab.
# 202503.04 # 202503.04
- Kit editor debugging. - Kit editor debugging.

View File

@@ -1,6 +1,6 @@
''' """
Contains functions for generating summary reports Contains functions for generating summary reports
''' """
import itertools import itertools
import sys import sys
from pprint import pformat from pprint import pformat
@@ -10,7 +10,7 @@ from pathlib import Path
from datetime import date from datetime import date
from typing import Tuple from typing import Tuple
from backend.db.models import BasicSubmission, IridaControl from backend.db.models import BasicSubmission, IridaControl
from tools import jinja_template_loading, get_first_blank_df_row, row_map, ctx from tools import jinja_template_loading, get_first_blank_df_row, row_map
from PyQt6.QtWidgets import QWidget from PyQt6.QtWidgets import QWidget
from openpyxl.worksheet.worksheet import Worksheet from openpyxl.worksheet.worksheet import Worksheet
@@ -36,6 +36,7 @@ class ReportArchetype(object):
filename = Path(filename) filename = Path(filename)
filename = filename.absolute() filename = filename.absolute()
self.writer = ExcelWriter(filename.with_suffix(".xlsx"), engine='openpyxl') self.writer = ExcelWriter(filename.with_suffix(".xlsx"), engine='openpyxl')
self.df.index += 1
self.df.to_excel(self.writer, sheet_name=self.sheet_name) self.df.to_excel(self.writer, sheet_name=self.sheet_name)
self.writer.close() self.writer.close()

View File

@@ -22,86 +22,6 @@ class BaseOmni(BaseModel):
def aliases(cls): def aliases(cls):
return cls.class_object.aliases return cls.class_object.aliases
# NOTE: Okay, this will not work for editing, since by definition not all attributes will line up.
# def check_all_attributes(self, attributes: dict) -> bool:
# """
# Checks this instance against a dictionary of attributes to determine if they are a match.
#
# Args:
# attributes (dict): A dictionary of attributes to be check for equivalence
#
# Returns:
# bool: If a single unequivocal value is found will be false, else true.
# """
# logger.debug(f"Incoming attributes: {attributes}")
# for key, value in attributes.items():
# logger.debug(f"Comparing value class: {value.__class__} to omni class")
# if isinstance(value, str):
# try:
# check = value.lower() == "none"
# except AttributeError:
# continue
# if check:
# value = None
# logger.debug(f"Attempting to grab attribute: {key}")
# try:
# self_value = getattr(self, key)
# class_attr = getattr(self.class_object, key)
# except AttributeError:
# continue
# try:
# logger.debug(f"Check if {self_value.__class__} is subclass of {BaseOmni}")
# check = issubclass(self_value.__class__, BaseOmni)
# except TypeError as e:
# logger.error(f"Couldn't check if {self_value.__class__} is subclass of {BaseOmni} due to {e}")
# check = False
# if check:
# logger.debug(f"Checking for subclass name.")
# self_value = self_value.name
# try:
# logger.debug(f"Check if {value.__class__} is subclass of {BaseOmni}")
# check = issubclass(value.__class__, BaseOmni)
# except TypeError as e:
# logger.error(f"Couldn't check if {value.__class__} is subclass of {BaseOmni} due to {e}")
# check = False
# if check:
# logger.debug(f"Checking for subclass name.")
# value = value.name
# logger.debug(f"Self value: {self_value}, class attr: {class_attr} of type: {type(class_attr)}")
# if isinstance(class_attr, property):
# filter = "property"
# else:
# filter = class_attr.property
# match filter:
# case ColumnProperty():
# match class_attr.type:
# case INTEGER():
# if value.lower() == "true":
# value = 1
# elif value.lower() == "false":
# value = 0
# else:
# value = int(value)
# case FLOAT():
# value = float(value)
# case "property":
# pass
# case _RelationshipDeclared():
# logger.debug(f"Checking relationship value: {self_value}")
# try:
# self_value = self_value.name
# except AttributeError:
# pass
# if class_attr.property.uselist:
# self_value = self_value.__str__()
# logger.debug(
# f"Checking self_value {self_value} of type {type(self_value)} against attribute {value} of type {type(value)}")
# if self_value != value:
# output = False
# logger.debug(f"Value {key} is False, returning.")
# return output
# return True
def check_all_attributes(self, attributes: dict) -> bool: def check_all_attributes(self, attributes: dict) -> bool:
logger.debug(f"Incoming attributes: {attributes}") logger.debug(f"Incoming attributes: {attributes}")
attributes = {k : v for k, v in attributes.items() if k in self.list_searchables.keys()} attributes = {k : v for k, v in attributes.items() if k in self.list_searchables.keys()}
@@ -122,7 +42,6 @@ class BaseOmni(BaseModel):
logger.debug("Everything checks out, these are the same object.") logger.debug("Everything checks out, these are the same object.")
return True return True
def __setattr__(self, key, value): def __setattr__(self, key, value):
try: try:
class_value = getattr(self.class_object, key) class_value = getattr(self.class_object, key)
@@ -395,6 +314,13 @@ class OmniKitTypeReagentRoleAssociation(BaseOmni):
return {} return {}
return value return value
@field_validator("required", mode="before")
@classmethod
def rescue_required_none(cls, value):
if not value:
value = 1
return value
def __init__(self, instance_object: Any, **data): def __init__(self, instance_object: Any, **data):
super().__init__(**data) super().__init__(**data)
self.instance_object = instance_object self.instance_object = instance_object

View File

@@ -1,5 +1,5 @@
""" """
Construct turnaround time charts Construct BC control concentration charts
""" """
from pprint import pformat from pprint import pformat
from . import CustomFigure from . import CustomFigure
@@ -21,17 +21,15 @@ class ConcentrationsChart(CustomFigure):
super().__init__(df=df, modes=modes, settings=settings) super().__init__(df=df, modes=modes, settings=settings)
self.df = df self.df = df
self.construct_chart() self.construct_chart()
# if threshold:
# self.add_hline(y=threshold)
self.update_layout(showlegend=False) self.update_layout(showlegend=False)
def construct_chart(self, df: pd.DataFrame | None = None): def construct_chart(self, df: pd.DataFrame | None = None):
if df: if df:
self.df = df self.df = df
# logger.debug(f"Constructing concentration chart with df:\n{self.df}")
try: try:
self.df = self.df[self.df.concentration.notnull()] self.df = self.df[self.df.concentration.notnull()]
self.df = self.df.sort_values(['submitted_date', 'submission'], ascending=[True, True]).reset_index(drop=True) self.df = self.df.sort_values(['submitted_date', 'submission'], ascending=[True, True]).reset_index(
drop=True)
self.df = self.df.reset_index().rename(columns={"index": "idx"}) self.df = self.df.reset_index().rename(columns={"index": "idx"})
# logger.debug(f"DF after changes:\n{self.df}") # logger.debug(f"DF after changes:\n{self.df}")
scatter = px.scatter(data_frame=self.df, x='submission', y="concentration", scatter = px.scatter(data_frame=self.df, x='submission', y="concentration",
@@ -41,8 +39,6 @@ class ConcentrationsChart(CustomFigure):
except (ValueError, AttributeError) as e: except (ValueError, AttributeError) as e:
logger.error(f"Error constructing chart: {e}") logger.error(f"Error constructing chart: {e}")
scatter = px.scatter() scatter = px.scatter()
# logger.debug(f"Scatter data: {scatter.data}")
# self.add_traces(scatter.data)
# NOTE: For some reason if data is allowed to sort itself it leads to wrong ordering of x axis. # NOTE: For some reason if data is allowed to sort itself it leads to wrong ordering of x axis.
traces = sorted(scatter.data, key=itemgetter("name")) traces = sorted(scatter.data, key=itemgetter("name"))
for trace in traces: for trace in traces:
@@ -60,6 +56,9 @@ class ConcentrationsChart(CustomFigure):
tickmode='array', tickmode='array',
tickvals=tickvals, tickvals=tickvals,
ticktext=ticklabels, ticktext=ticklabels,
),
yaxis=dict(
rangemode="nonnegative"
) )
) )
self.update_traces(marker={'size': 15}) self.update_traces(marker={'size': 15})

View File

@@ -1,7 +1,7 @@
""" """
Pane showing turnaround time summary. Pane showing BC control concentrations summary.
""" """
from PyQt6.QtWidgets import QWidget, QPushButton, QComboBox, QLabel from PyQt6.QtWidgets import QWidget, QPushButton
from .info_tab import InfoPane from .info_tab import InfoPane
from backend.excel.reports import ConcentrationMaker from backend.excel.reports import ConcentrationMaker
from frontend.visualizations.concentrations_chart import ConcentrationsChart from frontend.visualizations.concentrations_chart import ConcentrationsChart
@@ -22,12 +22,6 @@ class Concentrations(InfoPane):
self.layout.addWidget(self.export_button, 0, 3, 1, 1) self.layout.addWidget(self.export_button, 0, 3, 1, 1)
self.fig = None self.fig = None
self.report_object = None self.report_object = None
# self.submission_typer = QComboBox(self)
# subs = ["All"] + [item.name for item in SubmissionType.query()]
# self.submission_typer.addItems(subs)
# self.layout.addWidget(QLabel("Submission Type"), 1, 0, 1, 1)
# self.layout.addWidget(self.submission_typer, 1, 1, 1, 3)
# self.submission_typer.currentTextChanged.connect(self.update_data)
self.update_data() self.update_data()
def update_data(self) -> None: def update_data(self) -> None:
@@ -40,17 +34,6 @@ class Concentrations(InfoPane):
super().update_data() super().update_data()
months = self.diff_month(self.start_date, self.end_date) months = self.diff_month(self.start_date, self.end_date)
chart_settings = dict(start_date=self.start_date, end_date=self.end_date) chart_settings = dict(start_date=self.start_date, end_date=self.end_date)
# if self.submission_typer.currentText() == "All":
# submission_type = None
# subtype_obj = None
# else:
# submission_type = self.submission_typer.currentText()
# subtype_obj = SubmissionType.query(name = submission_type)
# self.report_obj = ConcentrationMaker(start_date=self.start_date, end_date=self.end_date)#, submission_type=submission_type)
self.report_obj = ConcentrationMaker(**chart_settings) self.report_obj = ConcentrationMaker(**chart_settings)
# if subtype_obj:
# threshold = subtype_obj.defaults['turnaround_time'] + 0.5
# else:
# threshold = None
self.fig = ConcentrationsChart(df=self.report_obj.df, settings=chart_settings, modes=[], months=months) self.fig = ConcentrationsChart(df=self.report_obj.df, settings=chart_settings, modes=[], months=months)
self.webview.setHtml(self.fig.html) self.webview.setHtml(self.fig.html)