Updated controls to both Irida and PCR.
This commit is contained in:
@@ -1,4 +1,52 @@
|
||||
'''
|
||||
Contains all operations for creating charts, graphs and visual effects.
|
||||
'''
|
||||
from .control_charts import *
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
import plotly
|
||||
from plotly.graph_objects import Figure
|
||||
import pandas as pd
|
||||
from frontend.widgets.functions import select_save_file
|
||||
|
||||
|
||||
class CustomFigure(Figure):
|
||||
|
||||
def __init__(self, df: pd.DataFrame, modes: list, ytitle: str | None = None, parent: QWidget | None = None,
|
||||
months: int = 6):
|
||||
super().__init__()
|
||||
|
||||
def save_figure(self, group_name: str = "plotly_output", parent: QWidget | None = None):
|
||||
"""
|
||||
Writes plotly figure to html file.
|
||||
|
||||
Args:
|
||||
figs ():
|
||||
settings (dict): settings passed down from click
|
||||
fig (Figure): input figure object
|
||||
group_name (str): controltype
|
||||
"""
|
||||
|
||||
output = select_save_file(obj=parent, default_name=group_name, extension="png")
|
||||
self.write_image(output.absolute().__str__(), engine="kaleido")
|
||||
|
||||
def to_html(self) -> str:
|
||||
"""
|
||||
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')
|
||||
else:
|
||||
html += "<h1>No data was retrieved for the given parameters.</h1>"
|
||||
html += '</body></html>'
|
||||
return html
|
||||
|
||||
|
||||
from .irida_charts import IridaFigure
|
||||
from .pcr_charts import PCRFigure
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
"""
|
||||
Functions for constructing controls graphs using plotly.
|
||||
Functions for constructing irida controls graphs using plotly.
|
||||
"""
|
||||
from copy import deepcopy
|
||||
from datetime import date
|
||||
from pprint import pformat
|
||||
|
||||
import plotly
|
||||
import plotly.express as px
|
||||
import pandas as pd
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
from plotly.graph_objects import Figure
|
||||
from . import CustomFigure
|
||||
import logging
|
||||
from tools import get_unique_values_in_df_column, divide_chunks
|
||||
from frontend.widgets.functions import select_save_file
|
||||
@@ -17,11 +15,12 @@ from frontend.widgets.functions import select_save_file
|
||||
logger = logging.getLogger(f"submissions.{__name__}")
|
||||
|
||||
|
||||
class CustomFigure(Figure):
|
||||
class IridaFigure(CustomFigure):
|
||||
|
||||
def __init__(self, df: pd.DataFrame, modes: list, ytitle: str | None = None, parent: QWidget | None = None,
|
||||
months: int = 6):
|
||||
super().__init__()
|
||||
|
||||
super().__init__(df=df, modes=modes)
|
||||
|
||||
self.construct_chart(df=df, modes=modes)
|
||||
self.generic_figure_markers(modes=modes, ytitle=ytitle, months=months)
|
||||
@@ -105,25 +104,16 @@ class CustomFigure(Figure):
|
||||
self.update_xaxes(
|
||||
rangeslider_visible=True,
|
||||
rangeselector=dict(
|
||||
# buttons=list([
|
||||
# dict(count=1, label="1m", step="month", stepmode="backward"),
|
||||
# dict(count=3, label="3m", step="month", stepmode="backward"),
|
||||
# dict(count=6, label="6m", step="month", stepmode="backward"),
|
||||
# dict(count=1, label="YTD", step="year", stepmode="todate"),
|
||||
# dict(count=12, label="1y", step="month", stepmode="backward"),
|
||||
# dict(step="all")
|
||||
# ])
|
||||
buttons=[button for button in self.make_plotly_buttons(months=months)]
|
||||
)
|
||||
)
|
||||
assert isinstance(self, Figure)
|
||||
# return fig
|
||||
assert isinstance(self, CustomFigure)
|
||||
|
||||
def make_plotly_buttons(self, months:int=6):
|
||||
def make_plotly_buttons(self, months: int = 6):
|
||||
rng = [1]
|
||||
if months > 2:
|
||||
rng += [iii for iii in range(3, months, 3)]
|
||||
logger.debug(f"Making buttons for months: {rng}")
|
||||
# logger.debug(f"Making buttons for months: {rng}")
|
||||
buttons = [dict(count=iii, label=f"{iii}m", step="month", stepmode="backward") for iii in rng]
|
||||
if months > date.today().month:
|
||||
buttons += [dict(count=1, label="YTD", step="year", stepmode="todate")]
|
||||
@@ -161,35 +151,3 @@ class CustomFigure(Figure):
|
||||
{"yaxis.title.text": mode},
|
||||
])
|
||||
|
||||
def save_figure(self, group_name: str = "plotly_output", parent: QWidget | None = None):
|
||||
"""
|
||||
Writes plotly figure to html file.
|
||||
|
||||
Args:
|
||||
figs ():
|
||||
settings (dict): settings passed down from click
|
||||
fig (Figure): input figure object
|
||||
group_name (str): controltype
|
||||
"""
|
||||
|
||||
output = select_save_file(obj=parent, default_name=group_name, extension="png")
|
||||
self.write_image(output.absolute().__str__(), engine="kaleido")
|
||||
|
||||
def to_html(self) -> str:
|
||||
"""
|
||||
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')
|
||||
else:
|
||||
html += "<h1>No data was retrieved for the given parameters.</h1>"
|
||||
html += '</body></html>'
|
||||
return html
|
||||
34
src/submissions/frontend/visualizations/pcr_charts.py
Normal file
34
src/submissions/frontend/visualizations/pcr_charts.py
Normal file
@@ -0,0 +1,34 @@
|
||||
"""
|
||||
Functions for constructing irida controls graphs using plotly.
|
||||
"""
|
||||
from datetime import date
|
||||
from pprint import pformat
|
||||
import plotly
|
||||
from . import CustomFigure
|
||||
import plotly.express as px
|
||||
import pandas as pd
|
||||
from PyQt6.QtWidgets import QWidget
|
||||
from plotly.graph_objects import Figure
|
||||
import logging
|
||||
from tools import get_unique_values_in_df_column, divide_chunks
|
||||
from frontend.widgets.functions import select_save_file
|
||||
|
||||
logger = logging.getLogger(f"submissions.{__name__}")
|
||||
|
||||
|
||||
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)
|
||||
self.construct_chart(df=df)
|
||||
# self.generic_figure_markers(modes=modes, ytitle=ytitle, months=months)
|
||||
|
||||
def construct_chart(self, df: pd.DataFrame):
|
||||
logger.debug(f"PCR df: {df}")
|
||||
try:
|
||||
scatter = px.scatter(data_frame=df, x='submitted_date', y="ct", hover_data=["name", "target", "ct", "reagent_lot"], color='target')
|
||||
except ValueError:
|
||||
scatter = px.scatter()
|
||||
self.add_traces(scatter.data)
|
||||
|
||||
@@ -4,7 +4,7 @@ Constructs main application.
|
||||
from pprint import pformat
|
||||
from PyQt6.QtWidgets import (
|
||||
QTabWidget, QWidget, QVBoxLayout,
|
||||
QHBoxLayout, QScrollArea, QMainWindow,
|
||||
QHBoxLayout, QScrollArea, QMainWindow,
|
||||
QToolBar
|
||||
)
|
||||
from PyQt6.QtGui import QAction
|
||||
@@ -13,7 +13,7 @@ from pathlib import Path
|
||||
from markdown import markdown
|
||||
from __init__ import project_path
|
||||
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 .functions import select_save_file, select_open_file
|
||||
from datetime import date
|
||||
from .pop_ups import HTMLPop, AlertPop
|
||||
from .misc import LogParser, Pagifier
|
||||
@@ -29,6 +29,7 @@ from .summary import Summary
|
||||
logger = logging.getLogger(f'submissions.{__name__}')
|
||||
logger.info("Hello, I am a logger")
|
||||
|
||||
|
||||
class App(QMainWindow):
|
||||
|
||||
def __init__(self, ctx: Settings = None):
|
||||
@@ -61,11 +62,11 @@ class App(QMainWindow):
|
||||
self.show()
|
||||
self.statusBar().showMessage('Ready', 5000)
|
||||
self.backup_database()
|
||||
|
||||
|
||||
def _createMenuBar(self):
|
||||
"""
|
||||
adds items to menu bar
|
||||
"""
|
||||
"""
|
||||
# logger.debug(f"Creating menu bar...")
|
||||
menuBar = self.menuBar()
|
||||
fileMenu = menuBar.addMenu("&File")
|
||||
@@ -85,11 +86,11 @@ class App(QMainWindow):
|
||||
# reportMenu.addAction(self.generateReportAction)
|
||||
maintenanceMenu.addAction(self.joinExtractionAction)
|
||||
maintenanceMenu.addAction(self.joinPCRAction)
|
||||
|
||||
|
||||
def _createToolBar(self):
|
||||
"""
|
||||
adds items to toolbar
|
||||
"""
|
||||
"""
|
||||
# logger.debug(f"Creating toolbar...")
|
||||
toolbar = QToolBar("My main toolbar")
|
||||
self.addToolBar(toolbar)
|
||||
@@ -100,7 +101,7 @@ class App(QMainWindow):
|
||||
def _createActions(self):
|
||||
"""
|
||||
creates actions
|
||||
"""
|
||||
"""
|
||||
# logger.debug(f"Creating actions...")
|
||||
self.importAction = QAction("&Import Submission", self)
|
||||
self.addReagentAction = QAction("Add Reagent", self)
|
||||
@@ -139,7 +140,7 @@ class App(QMainWindow):
|
||||
def showAbout(self):
|
||||
"""
|
||||
Show the 'about' message
|
||||
"""
|
||||
"""
|
||||
j_env = jinja_template_loading()
|
||||
template = j_env.get_template("project.html")
|
||||
html = template.render(info=self.ctx.package.__dict__)
|
||||
@@ -150,7 +151,7 @@ class App(QMainWindow):
|
||||
def openDocs(self):
|
||||
"""
|
||||
Open the documentation html pages
|
||||
"""
|
||||
"""
|
||||
if check_if_app():
|
||||
url = Path(sys._MEIPASS).joinpath("files", "docs", "index.html")
|
||||
else:
|
||||
@@ -182,14 +183,14 @@ class App(QMainWindow):
|
||||
def runSampleSearch(self):
|
||||
"""
|
||||
Create a search for samples.
|
||||
"""
|
||||
"""
|
||||
dlg = SearchBox(self)
|
||||
dlg.exec()
|
||||
|
||||
def backup_database(self):
|
||||
"""
|
||||
Copies the database into the backup directory the first time it is opened every month.
|
||||
"""
|
||||
"""
|
||||
month = date.today().strftime("%Y-%m")
|
||||
current_month_bak = Path(self.ctx.backup_path).joinpath(f"submissions_backup-{month}").resolve()
|
||||
logger.info(f"Here is the db directory: {self.ctx.database_path}")
|
||||
@@ -244,8 +245,8 @@ class App(QMainWindow):
|
||||
|
||||
|
||||
class AddSubForm(QWidget):
|
||||
|
||||
def __init__(self, parent:QWidget):
|
||||
|
||||
def __init__(self, parent: QWidget):
|
||||
# logger.debug(f"Initializating subform...")
|
||||
super(QWidget, self).__init__(parent)
|
||||
self.layout = QVBoxLayout(self)
|
||||
@@ -255,11 +256,12 @@ class AddSubForm(QWidget):
|
||||
self.tab2 = QWidget()
|
||||
self.tab3 = QWidget()
|
||||
self.tab4 = QWidget()
|
||||
self.tabs.resize(300,200)
|
||||
self.tabs.resize(300, 200)
|
||||
# NOTE: Add tabs
|
||||
self.tabs.addTab(self.tab1,"Submissions")
|
||||
self.tabs.addTab(self.tab2,"Controls")
|
||||
self.tabs.addTab(self.tab3, "Summary Report")
|
||||
self.tabs.addTab(self.tab1, "Submissions")
|
||||
self.tabs.addTab(self.tab2, "Irida Controls")
|
||||
self.tabs.addTab(self.tab3, "PCR Controls")
|
||||
self.tabs.addTab(self.tab4, "Cost Report")
|
||||
# self.tabs.addTab(self.tab4, "Add Kit")
|
||||
# NOTE: Create submission adder form
|
||||
self.formwidget = SubmissionFormContainer(self)
|
||||
@@ -276,7 +278,7 @@ class AddSubForm(QWidget):
|
||||
self.sheetlayout = QVBoxLayout(self)
|
||||
self.sheetwidget.setLayout(self.sheetlayout)
|
||||
self.sub_wid = SubmissionsSheet(parent=parent)
|
||||
self.pager = Pagifier(page_max=self.sub_wid.total_count/page_size)
|
||||
self.pager = Pagifier(page_max=self.sub_wid.total_count / page_size)
|
||||
self.sheetlayout.addWidget(self.sub_wid)
|
||||
self.sheetlayout.addWidget(self.pager)
|
||||
# NOTE: Create layout of first tab to hold form and sheet
|
||||
@@ -285,15 +287,19 @@ class AddSubForm(QWidget):
|
||||
self.tab1.layout.addWidget(self.interior)
|
||||
self.tab1.layout.addWidget(self.sheetwidget)
|
||||
self.tab2.layout = QVBoxLayout(self)
|
||||
self.controls_viewer = ControlsViewer(self)
|
||||
self.tab2.layout.addWidget(self.controls_viewer)
|
||||
self.irida_viewer = ControlsViewer(self, archetype="Irida Control")
|
||||
self.tab2.layout.addWidget(self.irida_viewer)
|
||||
self.tab2.setLayout(self.tab2.layout)
|
||||
self.tab3.layout = QVBoxLayout(self)
|
||||
self.pcr_viewer = ControlsViewer(self, archetype="PCR Control")
|
||||
self.tab3.layout.addWidget(self.pcr_viewer)
|
||||
self.tab3.setLayout(self.tab3.layout)
|
||||
# NOTE: create custom widget to add new tabs
|
||||
# ST_adder = SubmissionTypeAdder(self)
|
||||
summary_report = Summary(self)
|
||||
self.tab3.layout = QVBoxLayout(self)
|
||||
self.tab3.layout.addWidget(summary_report)
|
||||
self.tab3.setLayout(self.tab3.layout)
|
||||
self.tab4.layout = QVBoxLayout(self)
|
||||
self.tab4.layout.addWidget(summary_report)
|
||||
self.tab4.setLayout(self.tab4.layout)
|
||||
# kit_adder = KitAdder(self)
|
||||
# self.tab4.layout = QVBoxLayout(self)
|
||||
# self.tab4.layout.addWidget(kit_adder)
|
||||
|
||||
@@ -4,6 +4,7 @@ Handles display of control charts
|
||||
import re
|
||||
import sys
|
||||
from datetime import timedelta, date
|
||||
from pprint import pformat
|
||||
from typing import Tuple
|
||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||
from PyQt6.QtWidgets import (
|
||||
@@ -11,20 +12,26 @@ from PyQt6.QtWidgets import (
|
||||
QDateEdit, QLabel, QSizePolicy, QPushButton, QGridLayout
|
||||
)
|
||||
from PyQt6.QtCore import QSignalBlocker
|
||||
from backend.db import ControlType, Control
|
||||
from backend.db import ControlType, IridaControl
|
||||
from PyQt6.QtCore import QDate, QSize
|
||||
import logging
|
||||
from pandas import DataFrame
|
||||
from tools import Report, Result, get_unique_values_in_df_column, Settings, report_result
|
||||
from frontend.visualizations.control_charts import CustomFigure
|
||||
from frontend.visualizations import IridaFigure, PCRFigure
|
||||
from .misc import StartEndDatePicker
|
||||
|
||||
logger = logging.getLogger(f"submissions.{__name__}")
|
||||
|
||||
|
||||
class ControlsViewer(QWidget):
|
||||
|
||||
def __init__(self, parent: QWidget) -> None:
|
||||
def __init__(self, parent: QWidget, archetype: str) -> None:
|
||||
super().__init__(parent)
|
||||
logger.debug(f"Incoming Archetype: {archetype}")
|
||||
self.archetype = ControlType.query(name=archetype)
|
||||
if not self.archetype:
|
||||
return
|
||||
logger.debug(f"Archetype set as: {self.archetype}")
|
||||
self.app = self.parent().parent()
|
||||
# logger.debug(f"\n\n{self.app}\n\n")
|
||||
self.report = Report()
|
||||
@@ -32,51 +39,53 @@ class ControlsViewer(QWidget):
|
||||
self.webengineview = QWebEngineView()
|
||||
# NOTE: set tab2 layout
|
||||
self.layout = QGridLayout(self)
|
||||
self.control_typer = QComboBox()
|
||||
self.control_sub_typer = QComboBox()
|
||||
# NOTE: fetch types of controls
|
||||
con_types = [item.name for item in ControlType.query()]
|
||||
self.control_typer.addItems(con_types)
|
||||
con_sub_types = [item for item in self.archetype.targets.keys()]
|
||||
self.control_sub_typer.addItems(con_sub_types)
|
||||
# NOTE: create custom widget to get types of analysis
|
||||
self.mode_typer = QComboBox()
|
||||
mode_types = Control.get_modes()
|
||||
mode_types = IridaControl.get_modes()
|
||||
self.mode_typer.addItems(mode_types)
|
||||
# NOTE: create custom widget to get subtypes of analysis
|
||||
self.sub_typer = QComboBox()
|
||||
self.sub_typer.setEnabled(False)
|
||||
self.mode_sub_typer = QComboBox()
|
||||
self.mode_sub_typer.setEnabled(False)
|
||||
# NOTE: add widgets to tab2 layout
|
||||
self.layout.addWidget(self.datepicker, 0,0,1,2)
|
||||
self.layout.addWidget(self.datepicker, 0, 0, 1, 2)
|
||||
self.save_button = QPushButton("Save Chart", parent=self)
|
||||
self.layout.addWidget(self.save_button, 0,2,1,1)
|
||||
self.layout.addWidget(self.control_typer, 1,0,1,3)
|
||||
self.layout.addWidget(self.mode_typer, 2,0,1,3)
|
||||
self.layout.addWidget(self.sub_typer, 3,0,1,3)
|
||||
self.layout.addWidget(self.webengineview, 4,0,1,3)
|
||||
self.layout.addWidget(self.save_button, 0, 2, 1, 1)
|
||||
self.layout.addWidget(self.control_sub_typer, 1, 0, 1, 3)
|
||||
self.layout.addWidget(self.mode_typer, 2, 0, 1, 3)
|
||||
self.layout.addWidget(self.mode_sub_typer, 3, 0, 1, 3)
|
||||
self.archetype.get_instance_class().make_parent_buttons(parent=self)
|
||||
self.layout.addWidget(self.webengineview, self.layout.rowCount(), 0, 1, 3)
|
||||
self.setLayout(self.layout)
|
||||
self.controls_getter()
|
||||
self.control_typer.currentIndexChanged.connect(self.controls_getter)
|
||||
self.mode_typer.currentIndexChanged.connect(self.controls_getter)
|
||||
self.datepicker.start_date.dateChanged.connect(self.controls_getter)
|
||||
self.datepicker.end_date.dateChanged.connect(self.controls_getter)
|
||||
self.controls_getter_function()
|
||||
self.control_sub_typer.currentIndexChanged.connect(self.controls_getter_function)
|
||||
self.mode_typer.currentIndexChanged.connect(self.controls_getter_function)
|
||||
self.datepicker.start_date.dateChanged.connect(self.controls_getter_function)
|
||||
self.datepicker.end_date.dateChanged.connect(self.controls_getter_function)
|
||||
self.save_button.pressed.connect(self.save_chart_function)
|
||||
|
||||
|
||||
def save_chart_function(self):
|
||||
self.fig.save_figure(parent=self)
|
||||
|
||||
def controls_getter(self):
|
||||
"""
|
||||
Lookup controls from database and send to chartmaker
|
||||
"""
|
||||
self.controls_getter_function()
|
||||
# def controls_getter(self):
|
||||
# """
|
||||
# Lookup controls from database and send to chartmaker
|
||||
# """
|
||||
# self.controls_getter_function()
|
||||
|
||||
@report_result
|
||||
def controls_getter_function(self):
|
||||
def controls_getter_function(self, *args, **kwargs):
|
||||
"""
|
||||
Get controls based on start/end dates
|
||||
"""
|
||||
report = Report()
|
||||
# NOTE: subtype defaults to disabled
|
||||
# NOTE: mode_sub_type defaults to disabled
|
||||
try:
|
||||
self.sub_typer.disconnect()
|
||||
self.mode_sub_typer.disconnect()
|
||||
except TypeError:
|
||||
pass
|
||||
# NOTE: correct start date being more recent than end date and rerun
|
||||
@@ -93,37 +102,32 @@ class ControlsViewer(QWidget):
|
||||
# NOTE: convert to python useable date objects
|
||||
self.start_date = self.datepicker.start_date.date().toPyDate()
|
||||
self.end_date = self.datepicker.end_date.date().toPyDate()
|
||||
self.con_type = self.control_typer.currentText()
|
||||
self.con_sub_type = self.control_sub_typer.currentText()
|
||||
self.mode = self.mode_typer.currentText()
|
||||
self.sub_typer.clear()
|
||||
self.mode_sub_typer.clear()
|
||||
# NOTE: lookup subtypes
|
||||
try:
|
||||
sub_types = ControlType.query(name=self.con_type).get_subtypes(mode=self.mode)
|
||||
sub_types = self.archetype.get_modes(mode=self.mode)
|
||||
except AttributeError:
|
||||
sub_types = []
|
||||
if sub_types != []:
|
||||
# NOTE: block signal that will rerun controls getter and update sub_typer
|
||||
with QSignalBlocker(self.sub_typer) as blocker:
|
||||
self.sub_typer.addItems(sub_types)
|
||||
self.sub_typer.setEnabled(True)
|
||||
self.sub_typer.currentTextChanged.connect(self.chart_maker)
|
||||
if sub_types:
|
||||
# NOTE: block signal that will rerun controls getter and update mode_sub_typer
|
||||
with QSignalBlocker(self.mode_sub_typer) as blocker:
|
||||
self.mode_sub_typer.addItems(sub_types)
|
||||
self.mode_sub_typer.setEnabled(True)
|
||||
self.mode_sub_typer.currentTextChanged.connect(self.chart_maker_function)
|
||||
else:
|
||||
self.sub_typer.clear()
|
||||
self.sub_typer.setEnabled(False)
|
||||
self.chart_maker()
|
||||
self.mode_sub_typer.clear()
|
||||
self.mode_sub_typer.setEnabled(False)
|
||||
self.chart_maker_function()
|
||||
return report
|
||||
|
||||
def diff_month(self, d1:date, d2:date):
|
||||
def diff_month(self, d1: date, d2: date):
|
||||
return abs((d1.year - d2.year) * 12 + d1.month - d2.month)
|
||||
|
||||
def chart_maker(self):
|
||||
"""
|
||||
Creates plotly charts for webview
|
||||
"""
|
||||
self.chart_maker_function()
|
||||
|
||||
@report_result
|
||||
def chart_maker_function(self):
|
||||
def chart_maker_function(self, *args, **kwargs):
|
||||
# TODO: Generalize this by moving as much code as possible to IridaControl
|
||||
"""
|
||||
Create html chart for controls reporting
|
||||
|
||||
@@ -134,44 +138,26 @@ class ControlsViewer(QWidget):
|
||||
Tuple[QMainWindow, dict]: Collection of new main app window and result dict
|
||||
"""
|
||||
report = Report()
|
||||
# logger.debug(f"Control getter context: \n\tControl type: {self.con_type}\n\tMode: {self.mode}\n\tStart
|
||||
# Date: {self.start_date}\n\tEnd Date: {self.end_date}")
|
||||
# NOTE: set the subtype for kraken
|
||||
if self.sub_typer.currentText() == "":
|
||||
self.subtype = None
|
||||
# logger.debug(f"Control getter context: \n\tControl type: {self.con_sub_type}\n\tMode: {self.mode}\n\tStart \
|
||||
# Date: {self.start_date}\n\tEnd Date: {self.end_date}")
|
||||
# NOTE: set the mode_sub_type for kraken
|
||||
if self.mode_sub_typer.currentText() == "":
|
||||
self.mode_sub_type = None
|
||||
else:
|
||||
self.subtype = self.sub_typer.currentText()
|
||||
# logger.debug(f"Subtype: {self.subtype}")
|
||||
self.mode_sub_type = self.mode_sub_typer.currentText()
|
||||
logger.debug(f"Subtype: {self.mode_sub_type}")
|
||||
months = self.diff_month(self.start_date, self.end_date)
|
||||
# NOTE: query all controls using the type/start and end dates from the gui
|
||||
controls = Control.query(control_type=self.con_type, start_date=self.start_date, end_date=self.end_date)
|
||||
# NOTE: if no data found from query set fig to none for reporting in webview
|
||||
if controls is None:
|
||||
fig = None
|
||||
self.save_button.setEnabled(False)
|
||||
else:
|
||||
# NOTE: change each control to list of dictionaries
|
||||
data = [control.convert_by_mode(mode=self.mode) for control in controls]
|
||||
# NOTE: flatten data to one dimensional list
|
||||
data = [item for sublist in data for item in sublist]
|
||||
# logger.debug(f"Control objects going into df conversion: {type(data)}")
|
||||
if not data:
|
||||
report.add_result(Result(status="Critical", msg="No data found for controls in given date range."))
|
||||
return
|
||||
# NOTE send to dataframe creator
|
||||
df = self.convert_data_list_to_df(input_df=data)
|
||||
if self.subtype is None:
|
||||
title = self.mode
|
||||
else:
|
||||
title = f"{self.mode} - {self.subtype}"
|
||||
# NOTE: send dataframe to chart maker
|
||||
df, modes = self.prep_df(ctx=self.app.ctx, df=df)
|
||||
months = self.diff_month(self.start_date, self.end_date)
|
||||
fig = CustomFigure(df=df, ytitle=title, modes=modes, parent=self, months=months)
|
||||
self.save_button.setEnabled(True)
|
||||
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)
|
||||
# if isinstance(self.fig, IridaFigure):
|
||||
# self.save_button.setEnabled(True)
|
||||
# logger.debug(f"Updating figure...")
|
||||
self.fig = fig
|
||||
# self.fig = fig
|
||||
# NOTE: construct html for webview
|
||||
html = fig.to_html()
|
||||
html = self.fig.to_html()
|
||||
# logger.debug(f"The length of html code is: {len(html)}")
|
||||
self.webengineview.setHtml(html)
|
||||
self.webengineview.update()
|
||||
@@ -185,7 +171,7 @@ class ControlsViewer(QWidget):
|
||||
Args:
|
||||
ctx (dict): settings passed from gui
|
||||
input_df (list[dict]): list of dictionaries containing records
|
||||
subtype (str | None, optional): sub_type of submission type. Defaults to None.
|
||||
mode_sub_type (str | None, optional): sub_type of submission type. Defaults to None.
|
||||
|
||||
Returns:
|
||||
DataFrame: dataframe of controls
|
||||
@@ -195,7 +181,7 @@ class ControlsViewer(QWidget):
|
||||
safe = ['name', 'submitted_date', 'genus', 'target']
|
||||
for column in df.columns:
|
||||
if column not in safe:
|
||||
if self.subtype is not None and column != self.subtype:
|
||||
if self.mode_sub_type is not None and column != self.mode_sub_type:
|
||||
continue
|
||||
else:
|
||||
safe.append(column)
|
||||
@@ -338,34 +324,4 @@ class ControlsViewer(QWidget):
|
||||
rerun_regex = re.compile(fr"{ctx.rerun_regex}")
|
||||
exclude = [re.sub(rerun_regex, "", sample) for sample in sample_names if rerun_regex.search(sample)]
|
||||
df = df[df.name not in exclude]
|
||||
# for sample in sample_names:
|
||||
# if rerun_regex.search(sample):
|
||||
# first_run = re.sub(rerun_regex, "", sample)
|
||||
# df = df.drop(df[df.name == first_run].index)
|
||||
return df
|
||||
|
||||
|
||||
# class ControlsDatePicker(QWidget):
|
||||
# """
|
||||
# custom widget to pick start and end dates for controls graphs
|
||||
# """
|
||||
#
|
||||
# def __init__(self) -> None:
|
||||
# super().__init__()
|
||||
# self.start_date = QDateEdit(calendarPopup=True)
|
||||
# # NOTE: start date is two months prior to end date by default
|
||||
# sixmonthsago = QDate.currentDate().addDays(-180)
|
||||
# self.start_date.setDate(sixmonthsago)
|
||||
# self.end_date = QDateEdit(calendarPopup=True)
|
||||
# self.end_date.setDate(QDate.currentDate())
|
||||
# self.layout = QHBoxLayout()
|
||||
# self.layout.addWidget(QLabel("Start Date"))
|
||||
# self.layout.addWidget(self.start_date)
|
||||
# self.layout.addWidget(QLabel("End Date"))
|
||||
# self.layout.addWidget(self.end_date)
|
||||
# self.setLayout(self.layout)
|
||||
# self.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed)
|
||||
#
|
||||
#
|
||||
# def sizeHint(self) -> QSize:
|
||||
# return QSize(80, 20)
|
||||
|
||||
@@ -7,7 +7,7 @@ from PyQt6.QtWidgets import (QDialog, QPushButton, QVBoxLayout,
|
||||
QDialogButtonBox, QTextEdit, QGridLayout)
|
||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||
from PyQt6.QtWebChannel import QWebChannel
|
||||
from PyQt6.QtCore import Qt, pyqtSlot, QMarginsF
|
||||
from PyQt6.QtCore import Qt, pyqtSlot, QMarginsF, QSize
|
||||
from jinja2 import TemplateNotFound
|
||||
from backend.db.models import BasicSubmission, BasicSample, Reagent, KitType
|
||||
from tools import is_power_user, jinja_template_loading
|
||||
@@ -38,7 +38,7 @@ class SubmissionDetails(QDialog):
|
||||
self.app = None
|
||||
self.webview = QWebEngineView(parent=self)
|
||||
self.webview.setMinimumSize(900, 500)
|
||||
self.webview.setMaximumSize(900, 700)
|
||||
self.webview.setMaximumWidth(900)
|
||||
self.webview.loadFinished.connect(self.activate_export)
|
||||
self.layout = QGridLayout()
|
||||
# self.setFixedSize(900, 500)
|
||||
@@ -98,9 +98,6 @@ class SubmissionDetails(QDialog):
|
||||
sample = BasicSample.query(submitter_id=sample)
|
||||
base_dict = sample.to_sub_dict(full_data=True)
|
||||
exclude = ['submissions', 'excluded', 'colour', 'tooltip']
|
||||
# try:
|
||||
# base_dict['excluded'] += exclude
|
||||
# except KeyError:
|
||||
base_dict['excluded'] = exclude
|
||||
template = sample.get_details_template()
|
||||
template_path = Path(self.template.environment.loader.__getattribute__("searchpath")[0])
|
||||
@@ -131,7 +128,6 @@ class SubmissionDetails(QDialog):
|
||||
html = template.render(reagent=base_dict, css=css)
|
||||
self.webview.setHtml(html)
|
||||
self.setWindowTitle(f"Reagent Details - {reagent.name} - {reagent.lot}")
|
||||
# self.btn.setEnabled(False)
|
||||
|
||||
@pyqtSlot(str)
|
||||
def submission_details(self, submission: str | BasicSubmission):
|
||||
@@ -160,8 +156,6 @@ class SubmissionDetails(QDialog):
|
||||
# logger.debug(f"Submission_details: {pformat(self.base_dict)}")
|
||||
# logger.debug(f"User is power user: {is_power_user()}")
|
||||
self.html = self.template.render(sub=self.base_dict, signing_permission=is_power_user(), css=css)
|
||||
# with open("test.html", "w") as f:
|
||||
# f.write(self.html)
|
||||
self.webview.setHtml(self.html)
|
||||
|
||||
@pyqtSlot(str)
|
||||
@@ -178,11 +172,6 @@ class SubmissionDetails(QDialog):
|
||||
Renders submission to html, then creates and saves .pdf file to user selected file.
|
||||
"""
|
||||
fname = select_save_file(obj=self, default_name=self.export_plate, extension="pdf")
|
||||
# page_layout = QPageLayout()
|
||||
# page_layout.setPageSize(QPageSize(QPageSize.PageSizeId.A4))
|
||||
# page_layout.setOrientation(QPageLayout.Orientation.Portrait)
|
||||
# page_layout.setMargins(QMarginsF(25, 25, 25, 25))
|
||||
# self.webview.page().printToPdf(fname.with_suffix(".pdf").__str__(), page_layout)
|
||||
save_pdf(obj=self, filename=fname)
|
||||
|
||||
class SubmissionComment(QDialog):
|
||||
|
||||
Reference in New Issue
Block a user