Second round of code cleanup.

This commit is contained in:
lwark
2024-10-30 07:34:39 -05:00
parent 1f83b61c81
commit ba1b3e5cf3
19 changed files with 176 additions and 110 deletions

View File

@@ -2,12 +2,13 @@
Contains all operations for creating charts, graphs and visual effects.
'''
from PyQt6.QtWidgets import QWidget
import plotly
import plotly, logging
from plotly.graph_objects import Figure
from plotly.graph_objs import FigureWidget
import pandas as pd
from frontend.widgets.functions import select_save_file
logger = logging.getLogger(f"submissions.{__name__}")
class CustomFigure(Figure):
@@ -40,16 +41,12 @@ class CustomFigure(Figure):
"""
Creates final html code from plotly
Args:
figure (Figure): input figure
Returns:
str: html string
"""
html = '<html><body>'
if self is not None:
html += plotly.offline.plot(self, output_type='div',
include_plotlyjs='cdn') #, image = 'png', auto_open=True, image_filename='plot_image')
html += plotly.offline.plot(self, output_type='div', include_plotlyjs='cdn')
else:
html += "<h1>No data was retrieved for the given parameters.</h1>"
html += '</body></html>'

View File

@@ -2,9 +2,6 @@
Functions for constructing irida controls graphs using plotly.
"""
from pprint import pformat
from plotly.graph_objs import FigureWidget, Scatter
from . import CustomFigure
import plotly.express as px
import pandas as pd
@@ -13,30 +10,23 @@ import logging
logger = logging.getLogger(f"submissions.{__name__}")
# NOTE: For click events try (haven't got working yet) ipywidgets >=7.0.0 required for figurewidgets:
# https://plotly.com/python/click-events/
class PCRFigure(CustomFigure):
def __init__(self, df: pd.DataFrame, modes: list, ytitle: str | None = None, parent: QWidget | None = None,
months: int = 6):
super().__init__(df=df, modes=modes)
logger.debug(f"DF: {self.df}")
# logger.debug(f"DF: {self.df}")
self.construct_chart(df=df)
def hello(self):
print("hello")
def construct_chart(self, df: pd.DataFrame):
logger.debug(f"PCR df:\n {df}")
# logger.debug(f"PCR df:\n {df}")
try:
express = px.scatter(data_frame=df, x='submitted_date', y="ct",
scatter = px.scatter(data_frame=df, x='submitted_date', y="ct",
hover_data=["name", "target", "ct", "reagent_lot"],
color="target")
except ValueError:
express = px.scatter()
scatter = FigureWidget([datum for datum in express.data])
scatter = px.scatter()
self.add_traces(scatter.data)
self.update_traces(marker={'size': 15})

View File

@@ -2,6 +2,7 @@
Constructs main application.
"""
from pprint import pformat
from PyQt6.QtCore import qInstallMessageHandler
from PyQt6.QtWidgets import (
QTabWidget, QWidget, QVBoxLayout,
QHBoxLayout, QScrollArea, QMainWindow,
@@ -11,6 +12,7 @@ from PyQt6.QtGui import QAction
from pathlib import Path
from markdown import markdown
from __init__ import project_path
from backend import SubmissionType
from tools import check_if_app, Settings, Report, jinja_template_loading, check_authorization, page_size
from .functions import select_save_file, select_open_file
from datetime import date
@@ -32,12 +34,13 @@ class App(QMainWindow):
def __init__(self, ctx: Settings = None):
# logger.debug(f"Initializing main window...")
super().__init__()
qInstallMessageHandler(lambda x, y, z: None)
self.ctx = ctx
self.last_dir = ctx.directory_path
self.report = Report()
# NOTE: indicate version and connected database in title bar
try:
self.title = f"Submissions App (v{ctx.package.__version__}) - {ctx.database_session.get_bind().url}"
self.title = f"Submissions App (v{ctx.package.__version__}) - {ctx.database_path}/{ctx.database_name}"
except (AttributeError, KeyError):
self.title = f"Submissions App"
# NOTE: set initial app position and size

View File

@@ -155,7 +155,7 @@ class ControlsViewer(QWidget):
chart_settings = dict(sub_type=self.con_sub_type, start_date=self.start_date, end_date=self.end_date,
mode=self.mode,
sub_mode=self.mode_sub_type, parent=self, months=months)
_, self.fig = self.archetype.get_instance_class().make_chart(chart_settings=chart_settings, parent=self, ctx=self.app.ctx)
self.fig = self.archetype.get_instance_class().make_chart(chart_settings=chart_settings, parent=self, ctx=self.app.ctx)
if issubclass(self.fig.__class__, CustomFigure):
self.save_button.setEnabled(True)
# logger.debug(f"Updating figure...")

View File

@@ -1,8 +1,9 @@
'''
Creates forms that the user can enter equipment info into.
'''
import time
from pprint import pformat
from PyQt6.QtCore import Qt
from PyQt6.QtCore import Qt, QSignalBlocker
from PyQt6.QtWidgets import (QDialog, QComboBox, QCheckBox,
QLabel, QWidget, QVBoxLayout, QDialogButtonBox, QGridLayout)
from backend.db.models import Equipment, BasicSubmission, Process
@@ -127,13 +128,14 @@ class RoleComboBox(QWidget):
# logger.debug(f"Updating equipment: {equip}")
equip2 = next((item for item in self.role.equipment if item.name == equip), self.role.equipment[0])
# logger.debug(f"Using: {equip2}")
self.process.clear()
with QSignalBlocker(self.process) as blocker:
self.process.clear()
self.process.addItems([item for item in equip2.processes if item in self.role.processes])
def update_tips(self):
"""
Changes what tips are available when process is changed
"""
"""
process = self.process.currentText().strip()
# logger.debug(f"Checking process: {process} for equipment {self.role.name}")
process = Process.query(name=process)

View File

@@ -1,6 +1,7 @@
"""
Gel box for artic quality control
"""
from operator import itemgetter
from PyQt6.QtWidgets import (QWidget, QDialog, QGridLayout,
QLabel, QLineEdit, QDialogButtonBox,
QTextEdit, QComboBox
@@ -65,7 +66,8 @@ class GelBox(QDialog):
layout.addWidget(self.imv, 0, 1, 20, 20)
# NOTE: setting this widget as central widget of the main window
try:
control_info = sorted(self.submission.gel_controls, key=lambda d: d['location'])
# control_info = sorted(self.submission.gel_controls, key=lambda d: d['location'])
control_info = sorted(self.submission.gel_controls, key=itemgetter('location'))
except KeyError:
control_info = None
self.form = ControlsForm(parent=self, control_info=control_info)

View File

@@ -99,19 +99,21 @@ class SubmissionsSheet(QTableView):
proxyModel.setSourceModel(pandasModel(self.data))
self.setModel(proxyModel)
def contextMenuEvent(self):
def contextMenuEvent(self, event):
"""
Creates actions for right click menu events.
Args:
event (_type_): the item of interest
"""
# logger.debug(event().__dict__)
# logger.debug(event.__dict__)
id = self.selectionModel().currentIndex()
id = id.sibling(id.row(), 0).data()
submission = BasicSubmission.query(id=id)
# logger.debug(f"Event submission: {submission}")
self.menu = QMenu(self)
self.con_actions = submission.custom_context_events()
# logger.debug(f"Menu options: {self.con_actions}")
for k in self.con_actions.keys():
# logger.debug(f"Adding {k}")
action = QAction(k, self)

View File

@@ -1,6 +1,8 @@
'''
Contains all submission related frontend functions
'''
import sys
from PyQt6.QtWidgets import (
QWidget, QPushButton, QVBoxLayout,
QComboBox, QDateEdit, QLineEdit, QLabel
@@ -190,7 +192,8 @@ class SubmissionFormWidget(QWidget):
self.app = parent.app
self.pyd = submission
self.missing_info = []
st = SubmissionType.query(name=self.pyd.submission_type['value']).get_submission_class()
self.submission_type = SubmissionType.query(name=self.pyd.submission_type['value'])
st = self.submission_type.get_submission_class()
defaults = st.get_default_info("form_recover", "form_ignore", submission_type=self.pyd.submission_type['value'])
self.recover = defaults['form_recover']
self.ignore = defaults['form_ignore']
@@ -215,7 +218,7 @@ class SubmissionFormWidget(QWidget):
value = self.pyd.model_extra[k]
except KeyError:
value = dict(value=None, missing=True)
add_widget = self.create_widget(key=k, value=value, submission_type=self.pyd.submission_type['value'],
add_widget = self.create_widget(key=k, value=value, submission_type=self.submission_type,
sub_obj=st, disable=check)
if add_widget is not None:
self.layout.addWidget(add_widget)
@@ -224,7 +227,7 @@ class SubmissionFormWidget(QWidget):
self.setStyleSheet(main_form_style)
self.scrape_reagents(self.pyd.extraction_kit)
def create_widget(self, key: str, value: dict | PydReagent, submission_type: str | None = None,
def create_widget(self, key: str, value: dict | PydReagent, submission_type: str | SubmissionType| None = None,
extraction_kit: str | None = None, sub_obj: BasicSubmission | None = None,
disable: bool = False) -> "self.InfoItem":
"""
@@ -240,6 +243,8 @@ class SubmissionFormWidget(QWidget):
self.InfoItem: Form widget to hold name:value
"""
# logger.debug(f"Key: {key}, Disable: {disable}")
if isinstance(submission_type, str):
submission_type = SubmissionType.query(name=submission_type)
if key not in self.ignore:
match value:
case PydReagent():
@@ -272,7 +277,7 @@ class SubmissionFormWidget(QWidget):
"""
extraction_kit = args[0]
report = Report()
# logger.debug(f"Extraction kit: {extraction_kit}")
logger.debug(f"Extraction kit: {extraction_kit}")
# NOTE: Remove previous reagent widgets
try:
old_reagents = self.find_widgets()
@@ -284,7 +289,7 @@ class SubmissionFormWidget(QWidget):
if isinstance(reagent, self.ReagentFormWidget) or isinstance(reagent, QPushButton):
reagent.setParent(None)
reagents, integrity_report = self.pyd.check_kit_integrity(extraction_kit=extraction_kit)
# logger.debug(f"Missing reagents: {obj.missing_reagents}")
logger.debug(f"Got reagents: {pformat(reagents)}")
for reagent in reagents:
add_widget = self.ReagentFormWidget(parent=self, reagent=reagent, extraction_kit=self.pyd.extraction_kit)
self.layout.addWidget(add_widget)
@@ -454,9 +459,11 @@ class SubmissionFormWidget(QWidget):
class InfoItem(QWidget):
def __init__(self, parent: QWidget, key: str, value: dict, submission_type: str | None = None,
def __init__(self, parent: QWidget, key: str, value: dict, submission_type: str | SubmissionType | None = None,
sub_obj: BasicSubmission | None = None) -> None:
super().__init__(parent)
if isinstance(submission_type, str):
submission_type = SubmissionType.query(name=submission_type)
layout = QVBoxLayout()
self.label = self.ParsedQLabel(key=key, value=value)
self.input: QWidget = self.set_widget(parent=parent, key=key, value=value, submission_type=submission_type,
@@ -497,7 +504,7 @@ class SubmissionFormWidget(QWidget):
return None, None
return self.input.objectName(), dict(value=value, missing=self.missing)
def set_widget(self, parent: QWidget, key: str, value: dict, submission_type: str | None = None,
def set_widget(self, parent: QWidget, key: str, value: dict, submission_type: str | SubmissionType | None = None,
sub_obj: BasicSubmission | None = None) -> QWidget:
"""
Creates form widget
@@ -511,8 +518,10 @@ class SubmissionFormWidget(QWidget):
Returns:
QWidget: Form object
"""
if isinstance(submission_type, str):
submission_type = SubmissionType.query(name=submission_type)
if sub_obj is None:
sub_obj = SubmissionType.query(name=submission_type).get_submission_class()
sub_obj = submission_type.get_submission_class()
try:
value = value['value']
except (TypeError, KeyError):
@@ -544,7 +553,8 @@ class SubmissionFormWidget(QWidget):
add_widget = MyQComboBox(scrollWidget=parent)
# NOTE: lookup existing kits by 'submission_type' decided on by sheetparser
# logger.debug(f"Looking up kits used for {submission_type}")
uses = [item.name for item in KitType.query(used_for=submission_type)]
# uses = [item.name for item in KitType.query(used_for=submission_type)]
uses = [item.name for item in submission_type.kit_types]
obj.uses = uses
# logger.debug(f"Kits received for {submission_type}: {uses}")
if check_not_nan(value):
@@ -668,7 +678,7 @@ class SubmissionFormWidget(QWidget):
dlg = QuestionAsker(title=f"Add {lot}?",
message=f"Couldn't find reagent type {self.reagent.role}: {lot} in the database.\n\nWould you like to add it?")
if dlg.exec():
wanted_reagent, _ = self.parent().parent().add_reagent(reagent_lot=lot,
wanted_reagent = self.parent().parent().add_reagent(reagent_lot=lot,
reagent_role=self.reagent.role,
expiry=self.reagent.expiry,
name=self.reagent.name)

View File

@@ -42,7 +42,6 @@ class Summary(QWidget):
self.setLayout(self.layout)
self.get_report()
def get_report(self):
orgs = [self.org_select.itemText(i) for i in range(self.org_select.count()) if self.org_select.itemChecked(i)]
if self.datepicker.start_date.date() > self.datepicker.end_date.date():