Post code-cleanup.
This commit is contained in:
@@ -11,6 +11,12 @@ month = date.today().month
|
|||||||
day = date.today().day
|
day = date.today().day
|
||||||
|
|
||||||
def get_week_of_month() -> int:
|
def get_week_of_month() -> int:
|
||||||
|
"""
|
||||||
|
Gets the current week number of the month.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int:
|
||||||
|
"""
|
||||||
for ii, week in enumerate(calendar.monthcalendar(date.today().year, date.today().month)):
|
for ii, week in enumerate(calendar.monthcalendar(date.today().year, date.today().month)):
|
||||||
if day in week:
|
if day in week:
|
||||||
return ii + 1
|
return ii + 1
|
||||||
|
|||||||
@@ -503,7 +503,7 @@ class IridaControl(Control):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
super().make_parent_buttons(parent=parent)
|
super().make_parent_buttons(parent=parent)
|
||||||
rows = parent.layout.rowCount()
|
rows = parent.layout.rowCount() - 2
|
||||||
# logger.debug(f"Parent rows: {rows}")
|
# logger.debug(f"Parent rows: {rows}")
|
||||||
checker = QCheckBox(parent)
|
checker = QCheckBox(parent)
|
||||||
checker.setChecked(True)
|
checker.setChecked(True)
|
||||||
|
|||||||
@@ -17,6 +17,25 @@ logger = logging.getLogger(f"submissions.{__name__}")
|
|||||||
env = jinja_template_loading()
|
env = jinja_template_loading()
|
||||||
|
|
||||||
|
|
||||||
|
class ReportArchetype(object):
|
||||||
|
|
||||||
|
def write_report(self, filename: Path | str, obj: QWidget | None = None):
|
||||||
|
"""
|
||||||
|
Writes info to files.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filename (Path | str): Basename of output file
|
||||||
|
obj (QWidget | None, optional): Parent object. Defaults to None.
|
||||||
|
"""
|
||||||
|
if isinstance(filename, str):
|
||||||
|
filename = Path(filename)
|
||||||
|
filename = filename.absolute()
|
||||||
|
self.writer = ExcelWriter(filename.with_suffix(".xlsx"), engine='openpyxl')
|
||||||
|
self.df.to_excel(self.writer, sheet_name=self.sheet_name)
|
||||||
|
# logger.debug(f"Writing report to: {filename}")
|
||||||
|
self.writer.close()
|
||||||
|
|
||||||
|
|
||||||
class ReportMaker(object):
|
class ReportMaker(object):
|
||||||
|
|
||||||
def __init__(self, start_date: date, end_date: date, organizations: list | None = None):
|
def __init__(self, start_date: date, end_date: date, organizations: list | None = None):
|
||||||
@@ -138,7 +157,7 @@ class ReportMaker(object):
|
|||||||
if cell.row > 1:
|
if cell.row > 1:
|
||||||
cell.style = 'Currency'
|
cell.style = 'Currency'
|
||||||
|
|
||||||
class TurnaroundMaker(object):
|
class TurnaroundMaker(ReportArchetype):
|
||||||
|
|
||||||
def __init__(self, start_date: date, end_date: date, submission_type:str):
|
def __init__(self, start_date: date, end_date: date, submission_type:str):
|
||||||
self.start_date = start_date
|
self.start_date = start_date
|
||||||
@@ -147,6 +166,7 @@ class TurnaroundMaker(object):
|
|||||||
self.subs = BasicSubmission.query(start_date=start_date, end_date=end_date, submission_type_name=submission_type, page_size=0)
|
self.subs = BasicSubmission.query(start_date=start_date, end_date=end_date, submission_type_name=submission_type, page_size=0)
|
||||||
records = [self.build_record(sub) for sub in self.subs]
|
records = [self.build_record(sub) for sub in self.subs]
|
||||||
self.df = DataFrame.from_records(records)
|
self.df = DataFrame.from_records(records)
|
||||||
|
self.sheet_name = "Turnaround"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def build_record(cls, sub: BasicSubmission) -> dict:
|
def build_record(cls, sub: BasicSubmission) -> dict:
|
||||||
@@ -163,18 +183,12 @@ class TurnaroundMaker(object):
|
|||||||
return dict(name=str(sub.rsl_plate_num), days=days, submitted_date=sub.submitted_date,
|
return dict(name=str(sub.rsl_plate_num), days=days, submitted_date=sub.submitted_date,
|
||||||
completed_date=sub.completed_date, acceptable=tat_ok)
|
completed_date=sub.completed_date, acceptable=tat_ok)
|
||||||
|
|
||||||
def write_report(self, filename: Path | str, obj: QWidget | None = None):
|
|
||||||
"""
|
|
||||||
Writes info to files.
|
|
||||||
|
|
||||||
Args:
|
class ChartReportMaker(ReportArchetype):
|
||||||
filename (Path | str): Basename of output file
|
|
||||||
obj (QWidget | None, optional): Parent object. Defaults to None.
|
def __init__(self, df: DataFrame, sheet_name):
|
||||||
"""
|
self.df = df
|
||||||
if isinstance(filename, str):
|
self.sheet_name = sheet_name
|
||||||
filename = Path(filename)
|
|
||||||
filename = filename.absolute()
|
|
||||||
self.writer = ExcelWriter(filename.with_suffix(".xlsx"), engine='openpyxl')
|
|
||||||
self.df.to_excel(self.writer, sheet_name="Turnaround")
|
|
||||||
# logger.debug(f"Writing report to: {filename}")
|
|
||||||
self.writer.close()
|
|
||||||
|
|||||||
@@ -2,4 +2,4 @@
|
|||||||
Constructs main application.
|
Constructs main application.
|
||||||
'''
|
'''
|
||||||
from .widgets import *
|
from .widgets import *
|
||||||
from .visualizations import *
|
from .visualizations import *
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
'''
|
'''
|
||||||
Contains all operations for creating charts, graphs and visual effects.
|
Contains all operations for creating charts, graphs and visual effects.
|
||||||
'''
|
'''
|
||||||
from datetime import timedelta
|
from datetime import timedelta, date
|
||||||
|
from typing import Generator
|
||||||
from PyQt6.QtWidgets import QWidget
|
from PyQt6.QtWidgets import QWidget
|
||||||
import plotly, logging
|
import plotly, logging
|
||||||
from plotly.graph_objects import Figure
|
from plotly.graph_objects import Figure
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
from frontend.widgets.functions import select_save_file
|
from frontend.widgets.functions import select_save_file
|
||||||
|
from tools import divide_chunks
|
||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
|
|
||||||
@@ -18,31 +19,121 @@ class CustomFigure(Figure):
|
|||||||
|
|
||||||
def __init__(self, df: pd.DataFrame, settings: dict, modes: list, ytitle: str | None = None, parent: QWidget | None = None):
|
def __init__(self, df: pd.DataFrame, settings: dict, modes: list, ytitle: str | None = None, parent: QWidget | None = None):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
# self.settings = settings
|
|
||||||
try:
|
try:
|
||||||
months = int(settings['months'])
|
months = int(settings['months'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
months = 6
|
months = 6
|
||||||
self.df = df
|
self.df = df
|
||||||
self.update_xaxes(range=[settings['start_date'] - timedelta(days=1), settings['end_date']])
|
self.update_xaxes(range=[settings['start_date'] - timedelta(days=1), settings['end_date']])
|
||||||
|
self.generic_figure_markers(modes=modes, ytitle=ytitle, months=months)
|
||||||
|
|
||||||
def save_figure(self, group_name: str = "plotly_output", parent: QWidget | None = None):
|
def generic_figure_markers(self, modes: list = [], ytitle: str | None = None, months: int = 6):
|
||||||
"""
|
"""
|
||||||
Writes plotly figure to html file.
|
Adds standard layout to figure.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
figs ():
|
fig (Figure): Input figure.
|
||||||
settings (dict): settings passed down from click
|
modes (list, optional): List of modes included in figure. Defaults to [].
|
||||||
fig (Figure): input figure object
|
ytitle (str, optional): Title for the y-axis. Defaults to None.
|
||||||
group_name (str): controltype
|
|
||||||
|
Returns:
|
||||||
|
Figure: Output figure with updated titles, rangeslider, buttons.
|
||||||
"""
|
"""
|
||||||
|
if modes:
|
||||||
|
ytitle = modes[0]
|
||||||
|
# logger.debug("Creating visibles list for each mode.")
|
||||||
|
self.update_layout(
|
||||||
|
xaxis_title="Submitted Date (* - Date parsed from fastq file creation date)",
|
||||||
|
yaxis_title=ytitle,
|
||||||
|
showlegend=True,
|
||||||
|
barmode='stack',
|
||||||
|
updatemenus=[
|
||||||
|
dict(
|
||||||
|
type="buttons",
|
||||||
|
direction="right",
|
||||||
|
x=0.7,
|
||||||
|
y=1.2,
|
||||||
|
showactive=True,
|
||||||
|
buttons=[button for button in self.make_pyqt_buttons(modes=modes)],
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
self.update_xaxes(
|
||||||
|
rangeslider_visible=True,
|
||||||
|
rangeselector=dict(
|
||||||
|
buttons=[button for button in self.make_plotly_buttons(months=months)]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assert isinstance(self, CustomFigure)
|
||||||
|
|
||||||
output = select_save_file(obj=parent, default_name=group_name, extension="png")
|
def make_plotly_buttons(self, months: int = 6) -> Generator[dict, None, None]:
|
||||||
self.write_image(output.absolute().__str__(), engine="kaleido")
|
"""
|
||||||
|
Creates html buttons to zoom in on date areas
|
||||||
|
|
||||||
def save_data(self, group_name: str = "plotly_export", parent:QWidget|None=None):
|
Args:
|
||||||
output = select_save_file(obj=parent, default_name=group_name, extension="xlsx")
|
months (int, optional): Number of months of data given. Defaults to 6.
|
||||||
self.df.to_excel(output.absolute().__str__(), engine="openpyxl", index=False)
|
|
||||||
|
Yields:
|
||||||
|
Generator[dict, None, None]: Button details.
|
||||||
|
"""
|
||||||
|
rng = [1]
|
||||||
|
if months > 2:
|
||||||
|
rng += [iii for iii in range(3, months, 3)]
|
||||||
|
# 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")]
|
||||||
|
buttons += [dict(step="all")]
|
||||||
|
for button in buttons:
|
||||||
|
yield button
|
||||||
|
|
||||||
|
def make_pyqt_buttons(self, modes: list) -> Generator[dict, None, None]:
|
||||||
|
"""
|
||||||
|
Creates list of buttons with one for each mode to be used in showing/hiding mode traces.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
modes (list): list of modes used by main parser.
|
||||||
|
fig_len (int): number of traces in the figure
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Generator[dict, None, None]: list of buttons.
|
||||||
|
"""
|
||||||
|
fig_len = len(self.data)
|
||||||
|
if len(modes) > 1:
|
||||||
|
for ii, mode in enumerate(modes):
|
||||||
|
# NOTE: What I need to do is create a list of bools with the same length as the fig.data
|
||||||
|
mode_vis = [True] * fig_len
|
||||||
|
# NOTE: And break it into {len(modes)} chunks
|
||||||
|
mode_vis = list(divide_chunks(mode_vis, len(modes)))
|
||||||
|
# NOTE: Then, for each chunk, if the chunk index isn't equal to the index of the current mode, set to false
|
||||||
|
for jj, sublist in enumerate(mode_vis):
|
||||||
|
if jj != ii:
|
||||||
|
mode_vis[jj] = [not elem for elem in mode_vis[jj]]
|
||||||
|
# NOTE: Finally, flatten list.
|
||||||
|
mode_vis = [item for sublist in mode_vis for item in sublist]
|
||||||
|
# NOTE: Now, yield button to add to list
|
||||||
|
yield dict(label=mode, method="update", args=[
|
||||||
|
{"visible": mode_vis},
|
||||||
|
{"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 save_data(self, group_name: str = "plotly_export", parent:QWidget|None=None):
|
||||||
|
# output = select_save_file(obj=parent, default_name=group_name, extension="xlsx")
|
||||||
|
# self.df.to_excel(output.absolute().__str__(), engine="openpyxl", index=False)
|
||||||
|
|
||||||
def to_html(self) -> str:
|
def to_html(self) -> str:
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -19,12 +19,13 @@ class IridaFigure(CustomFigure):
|
|||||||
def __init__(self, df: pd.DataFrame, modes: list, settings: dict, ytitle: str | None = None, parent: QWidget | None = None):
|
def __init__(self, df: pd.DataFrame, modes: list, settings: dict, ytitle: str | None = None, parent: QWidget | None = None):
|
||||||
|
|
||||||
super().__init__(df=df, modes=modes, settings=settings)
|
super().__init__(df=df, modes=modes, settings=settings)
|
||||||
|
self.df = df
|
||||||
try:
|
try:
|
||||||
months = int(settings['months'])
|
months = int(settings['months'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
months = 6
|
months = 6
|
||||||
self.construct_chart(df=df, modes=modes, start_date=settings['start_date'], end_date=settings['end_date'])
|
self.construct_chart(df=df, modes=modes, start_date=settings['start_date'], end_date=settings['end_date'])
|
||||||
self.generic_figure_markers(modes=modes, ytitle=ytitle, months=months)
|
|
||||||
|
|
||||||
def construct_chart(self, df: pd.DataFrame, modes: list, start_date: date, end_date:date):
|
def construct_chart(self, df: pd.DataFrame, modes: list, start_date: date, end_date:date):
|
||||||
"""
|
"""
|
||||||
@@ -69,94 +70,3 @@ class IridaFigure(CustomFigure):
|
|||||||
)
|
)
|
||||||
bar.update_traces(visible=ii == 0)
|
bar.update_traces(visible=ii == 0)
|
||||||
self.add_traces(bar.data)
|
self.add_traces(bar.data)
|
||||||
|
|
||||||
def generic_figure_markers(self, modes: list = [], ytitle: str | None = None, months: int = 6):
|
|
||||||
"""
|
|
||||||
Adds standard layout to figure.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
fig (Figure): Input figure.
|
|
||||||
modes (list, optional): List of modes included in figure. Defaults to [].
|
|
||||||
ytitle (str, optional): Title for the y-axis. Defaults to None.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Figure: Output figure with updated titles, rangeslider, buttons.
|
|
||||||
"""
|
|
||||||
if modes:
|
|
||||||
ytitle = modes[0]
|
|
||||||
# logger.debug("Creating visibles list for each mode.")
|
|
||||||
self.update_layout(
|
|
||||||
xaxis_title="Submitted Date (* - Date parsed from fastq file creation date)",
|
|
||||||
yaxis_title=ytitle,
|
|
||||||
showlegend=True,
|
|
||||||
barmode='stack',
|
|
||||||
updatemenus=[
|
|
||||||
dict(
|
|
||||||
type="buttons",
|
|
||||||
direction="right",
|
|
||||||
x=0.7,
|
|
||||||
y=1.2,
|
|
||||||
showactive=True,
|
|
||||||
buttons=[button for button in self.make_pyqt_buttons(modes=modes)],
|
|
||||||
)
|
|
||||||
]
|
|
||||||
)
|
|
||||||
self.update_xaxes(
|
|
||||||
rangeslider_visible=True,
|
|
||||||
rangeselector=dict(
|
|
||||||
buttons=[button for button in self.make_plotly_buttons(months=months)]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
assert isinstance(self, CustomFigure)
|
|
||||||
|
|
||||||
def make_plotly_buttons(self, months: int = 6) -> Generator[dict, None, None]:
|
|
||||||
"""
|
|
||||||
Creates html buttons to zoom in on date areas
|
|
||||||
|
|
||||||
Args:
|
|
||||||
months (int, optional): Number of months of data given. Defaults to 6.
|
|
||||||
|
|
||||||
Yields:
|
|
||||||
Generator[dict, None, None]: Button details.
|
|
||||||
"""
|
|
||||||
rng = [1]
|
|
||||||
if months > 2:
|
|
||||||
rng += [iii for iii in range(3, months, 3)]
|
|
||||||
# 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")]
|
|
||||||
buttons += [dict(step="all")]
|
|
||||||
for button in buttons:
|
|
||||||
yield button
|
|
||||||
|
|
||||||
def make_pyqt_buttons(self, modes: list) -> Generator[dict, None, None]:
|
|
||||||
"""
|
|
||||||
Creates list of buttons with one for each mode to be used in showing/hiding mode traces.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
modes (list): list of modes used by main parser.
|
|
||||||
fig_len (int): number of traces in the figure
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Generator[dict, None, None]: list of buttons.
|
|
||||||
"""
|
|
||||||
fig_len = len(self.data)
|
|
||||||
if len(modes) > 1:
|
|
||||||
for ii, mode in enumerate(modes):
|
|
||||||
# NOTE: What I need to do is create a list of bools with the same length as the fig.data
|
|
||||||
mode_vis = [True] * fig_len
|
|
||||||
# NOTE: And break it into {len(modes)} chunks
|
|
||||||
mode_vis = list(divide_chunks(mode_vis, len(modes)))
|
|
||||||
# NOTE: Then, for each chunk, if the chunk index isn't equal to the index of the current mode, set to false
|
|
||||||
for jj, sublist in enumerate(mode_vis):
|
|
||||||
if jj != ii:
|
|
||||||
mode_vis[jj] = [not elem for elem in mode_vis[jj]]
|
|
||||||
# NOTE: Finally, flatten list.
|
|
||||||
mode_vis = [item for sublist in mode_vis for item in sublist]
|
|
||||||
# NOTE: Now, yield button to add to list
|
|
||||||
yield dict(label=mode, method="update", args=[
|
|
||||||
{"visible": mode_vis},
|
|
||||||
{"yaxis.title.text": mode},
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class PCRFigure(CustomFigure):
|
|||||||
def __init__(self, df: pd.DataFrame, modes: list, settings: dict, ytitle: str | None = None, parent: QWidget | None = None,
|
def __init__(self, df: pd.DataFrame, modes: list, settings: dict, ytitle: str | None = None, parent: QWidget | None = None,
|
||||||
months: int = 6):
|
months: int = 6):
|
||||||
super().__init__(df=df, modes=modes, settings=settings)
|
super().__init__(df=df, modes=modes, settings=settings)
|
||||||
|
self.df = df
|
||||||
try:
|
try:
|
||||||
months = int(settings['months'])
|
months = int(settings['months'])
|
||||||
except KeyError:
|
except KeyError:
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
"""
|
"""
|
||||||
Handles display of control charts
|
Handles display of control charts
|
||||||
"""
|
"""
|
||||||
from datetime import date
|
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
|
||||||
from PyQt6.QtWidgets import (
|
from PyQt6.QtWidgets import (
|
||||||
QWidget, QComboBox, QPushButton, QGridLayout
|
QWidget, QComboBox, QPushButton
|
||||||
)
|
)
|
||||||
from PyQt6.QtCore import QSignalBlocker
|
from PyQt6.QtCore import QSignalBlocker
|
||||||
|
|
||||||
|
from backend import ChartReportMaker
|
||||||
from backend.db import ControlType, IridaControl
|
from backend.db import ControlType, IridaControl
|
||||||
import logging
|
import logging
|
||||||
from tools import Report, report_result, Result
|
from tools import Report, report_result
|
||||||
from frontend.visualizations import CustomFigure
|
from frontend.visualizations import CustomFigure
|
||||||
from .misc import StartEndDatePicker
|
|
||||||
from .info_tab import InfoPane
|
from .info_tab import InfoPane
|
||||||
|
|
||||||
logger = logging.getLogger(f"submissions.{__name__}")
|
logger = logging.getLogger(f"submissions.{__name__}")
|
||||||
@@ -27,13 +26,8 @@ class ControlsViewer(InfoPane):
|
|||||||
if not self.archetype:
|
if not self.archetype:
|
||||||
return
|
return
|
||||||
logger.debug(f"Archetype set as: {self.archetype}")
|
logger.debug(f"Archetype set as: {self.archetype}")
|
||||||
# self.app = self.parent().parent()
|
|
||||||
# logger.debug(f"\n\n{self.app}\n\n")
|
# logger.debug(f"\n\n{self.app}\n\n")
|
||||||
# self.report = Report()
|
|
||||||
# self.datepicker = StartEndDatePicker(default_start=-180)
|
|
||||||
# self.webengineview = QWebEngineView()
|
|
||||||
# NOTE: set tab2 layout
|
# NOTE: set tab2 layout
|
||||||
# self.layout = QGridLayout(self)
|
|
||||||
self.control_sub_typer = QComboBox()
|
self.control_sub_typer = QComboBox()
|
||||||
# NOTE: fetch types of controls
|
# NOTE: fetch types of controls
|
||||||
con_sub_types = [item for item in self.archetype.targets.keys()]
|
con_sub_types = [item for item in self.archetype.targets.keys()]
|
||||||
@@ -46,7 +40,6 @@ class ControlsViewer(InfoPane):
|
|||||||
self.mode_sub_typer = QComboBox()
|
self.mode_sub_typer = QComboBox()
|
||||||
self.mode_sub_typer.setEnabled(False)
|
self.mode_sub_typer.setEnabled(False)
|
||||||
# NOTE: add widgets to tab2 layout
|
# NOTE: add widgets to tab2 layout
|
||||||
# self.layout.addWidget(self.datepicker, 0, 0, 1, 2)
|
|
||||||
self.save_button = QPushButton("Save Chart", parent=self)
|
self.save_button = QPushButton("Save Chart", parent=self)
|
||||||
self.layout.addWidget(self.save_button, 0, 2, 1, 1)
|
self.layout.addWidget(self.save_button, 0, 2, 1, 1)
|
||||||
self.export_button = QPushButton("Save Data", parent=self)
|
self.export_button = QPushButton("Save Data", parent=self)
|
||||||
@@ -55,21 +48,17 @@ class ControlsViewer(InfoPane):
|
|||||||
self.layout.addWidget(self.mode_typer, 2, 0, 1, 4)
|
self.layout.addWidget(self.mode_typer, 2, 0, 1, 4)
|
||||||
self.layout.addWidget(self.mode_sub_typer, 3, 0, 1, 4)
|
self.layout.addWidget(self.mode_sub_typer, 3, 0, 1, 4)
|
||||||
self.archetype.get_instance_class().make_parent_buttons(parent=self)
|
self.archetype.get_instance_class().make_parent_buttons(parent=self)
|
||||||
# self.layout.addWidget(self.webengineview, self.layout.rowCount(), 0, 1, 4)
|
|
||||||
# self.setLayout(self.layout)
|
|
||||||
self.update_data()
|
self.update_data()
|
||||||
self.control_sub_typer.currentIndexChanged.connect(self.update_data)
|
self.control_sub_typer.currentIndexChanged.connect(self.update_data)
|
||||||
self.mode_typer.currentIndexChanged.connect(self.update_data)
|
self.mode_typer.currentIndexChanged.connect(self.update_data)
|
||||||
# self.datepicker.start_date.dateChanged.connect(self.update_data)
|
self.save_button.pressed.connect(self.save_png)
|
||||||
# self.datepicker.end_date.dateChanged.connect(self.update_data)
|
self.export_button.pressed.connect(self.save_excel)
|
||||||
self.save_button.pressed.connect(self.save_chart_function)
|
|
||||||
self.export_button.pressed.connect(self.save_data_function)
|
|
||||||
|
|
||||||
def save_chart_function(self):
|
# def save_chart_function(self):
|
||||||
self.fig.save_figure(parent=self)
|
# self.fig.save_figure(parent=self)
|
||||||
|
#
|
||||||
def save_data_function(self):
|
# def save_data_function(self):
|
||||||
self.fig.save_data(parent=self)
|
# self.fig.save_data(parent=self)
|
||||||
|
|
||||||
@report_result
|
@report_result
|
||||||
def update_data(self, *args, **kwargs):
|
def update_data(self, *args, **kwargs):
|
||||||
@@ -117,20 +106,6 @@ class ControlsViewer(InfoPane):
|
|||||||
self.chart_maker_function()
|
self.chart_maker_function()
|
||||||
# return report
|
# return report
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def diff_month(self, d1: date, d2: date) -> float:
|
|
||||||
"""
|
|
||||||
Gets the number of months difference between two different dates
|
|
||||||
|
|
||||||
Args:
|
|
||||||
d1 (date): Start date.
|
|
||||||
d2 (date): End date.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
float: Number of months difference
|
|
||||||
"""
|
|
||||||
return abs((d1.year - d2.year) * 12 + d1.month - d2.month)
|
|
||||||
|
|
||||||
@report_result
|
@report_result
|
||||||
def chart_maker_function(self, *args, **kwargs):
|
def chart_maker_function(self, *args, **kwargs):
|
||||||
# TODO: Generalize this by moving as much code as possible to IridaControl
|
# TODO: Generalize this by moving as much code as possible to IridaControl
|
||||||
@@ -158,6 +133,7 @@ class ControlsViewer(InfoPane):
|
|||||||
mode=self.mode,
|
mode=self.mode,
|
||||||
sub_mode=self.mode_sub_type, parent=self, months=months)
|
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)
|
||||||
|
self.report_obj = ChartReportMaker(df=self.fig.df, sheet_name=self.archetype.name)
|
||||||
if issubclass(self.fig.__class__, CustomFigure):
|
if issubclass(self.fig.__class__, CustomFigure):
|
||||||
self.save_button.setEnabled(True)
|
self.save_button.setEnabled(True)
|
||||||
# logger.debug(f"Updating figure...")
|
# logger.debug(f"Updating figure...")
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
"""
|
"""
|
||||||
A pane to show info e.g. cost reports and turnaround times.
|
A pane to show info e.g. cost reports and turnaround times.
|
||||||
"""
|
"""
|
||||||
|
from datetime import date
|
||||||
from PyQt6.QtCore import QSignalBlocker
|
from PyQt6.QtCore import QSignalBlocker
|
||||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||||
from PyQt6.QtWidgets import QWidget, QGridLayout
|
from PyQt6.QtWidgets import QWidget, QGridLayout
|
||||||
@@ -25,7 +26,8 @@ class InfoPane(QWidget):
|
|||||||
self.datepicker.end_date.dateChanged.connect(self.update_data)
|
self.datepicker.end_date.dateChanged.connect(self.update_data)
|
||||||
self.layout = QGridLayout(self)
|
self.layout = QGridLayout(self)
|
||||||
self.layout.addWidget(self.datepicker, 0, 0, 1, 2)
|
self.layout.addWidget(self.datepicker, 0, 0, 1, 2)
|
||||||
self.layout.addWidget(self.webview, 4, 0, 1, 4)
|
# NOTE: Placed in lower row to allow for addition of custom rows.
|
||||||
|
self.layout.addWidget(self.webview, 5, 0, 1, 4)
|
||||||
self.setLayout(self.layout)
|
self.setLayout(self.layout)
|
||||||
|
|
||||||
@report_result
|
@report_result
|
||||||
@@ -45,6 +47,20 @@ class InfoPane(QWidget):
|
|||||||
report.add_result(Result(owner=self.__str__(), msg=msg, status="Warning"))
|
report.add_result(Result(owner=self.__str__(), msg=msg, status="Warning"))
|
||||||
return report
|
return report
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def diff_month(self, d1: date, d2: date) -> float:
|
||||||
|
"""
|
||||||
|
Gets the number of months difference between two different dates
|
||||||
|
|
||||||
|
Args:
|
||||||
|
d1 (date): Start date.
|
||||||
|
d2 (date): End date.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
float: Number of months difference
|
||||||
|
"""
|
||||||
|
return abs((d1.year - d2.year) * 12 + d1.month - d2.month)
|
||||||
|
|
||||||
def save_excel(self):
|
def save_excel(self):
|
||||||
fname = select_save_file(self, default_name=f"Report {self.start_date.strftime('%Y%m%d')} - {self.end_date.strftime('%Y%m%d')}", extension="xlsx")
|
fname = select_save_file(self, default_name=f"Report {self.start_date.strftime('%Y%m%d')} - {self.end_date.strftime('%Y%m%d')}", extension="xlsx")
|
||||||
self.report_obj.write_report(fname, obj=self)
|
self.report_obj.write_report(fname, obj=self)
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
from PyQt6.QtCore import QSignalBlocker
|
"""
|
||||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
Pane showing turnaround time summary.
|
||||||
from PyQt6.QtWidgets import QWidget, QGridLayout, QPushButton, QLabel, QComboBox
|
"""
|
||||||
|
from PyQt6.QtWidgets import QWidget, QPushButton, QComboBox, QLabel
|
||||||
from .info_tab import InfoPane
|
from .info_tab import InfoPane
|
||||||
from backend.excel.reports import TurnaroundMaker
|
from backend.excel.reports import TurnaroundMaker
|
||||||
from pandas import DataFrame
|
from backend.db import SubmissionType
|
||||||
from backend.db import BasicSubmission, SubmissionType
|
|
||||||
from frontend.visualizations.turnaround_chart import TurnaroundChart
|
from frontend.visualizations.turnaround_chart import TurnaroundChart
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
@@ -26,12 +26,14 @@ class TurnaroundTime(InfoPane):
|
|||||||
self.submission_typer = QComboBox(self)
|
self.submission_typer = QComboBox(self)
|
||||||
subs = ["All"] + [item.name for item in SubmissionType.query()]
|
subs = ["All"] + [item.name for item in SubmissionType.query()]
|
||||||
self.submission_typer.addItems(subs)
|
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.layout.addWidget(self.submission_typer, 1, 1, 1, 3)
|
||||||
self.submission_typer.currentTextChanged.connect(self.update_data)
|
self.submission_typer.currentTextChanged.connect(self.update_data)
|
||||||
self.update_data()
|
self.update_data()
|
||||||
|
|
||||||
def update_data(self):
|
def update_data(self):
|
||||||
super().update_data()
|
super().update_data()
|
||||||
|
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":
|
if self.submission_typer.currentText() == "All":
|
||||||
submission_type = None
|
submission_type = None
|
||||||
@@ -44,5 +46,5 @@ class TurnaroundTime(InfoPane):
|
|||||||
threshold = subtype_obj.defaults['turnaround_time'] + 0.5
|
threshold = subtype_obj.defaults['turnaround_time'] + 0.5
|
||||||
else:
|
else:
|
||||||
threshold = None
|
threshold = None
|
||||||
self.fig = TurnaroundChart(df=self.report_obj.df, settings=chart_settings, modes=[], threshold=threshold)
|
self.fig = TurnaroundChart(df=self.report_obj.df, settings=chart_settings, modes=[], threshold=threshold, months=months)
|
||||||
self.webview.setHtml(self.fig.to_html())
|
self.webview.setHtml(self.fig.to_html())
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
Contains miscellaenous functions used by both frontend and backend.
|
Contains miscellaenous functions used by both frontend and backend.
|
||||||
'''
|
'''
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from datetime import date, datetime, timedelta
|
from datetime import date, datetime, timedelta
|
||||||
from json import JSONDecodeError
|
from json import JSONDecodeError
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
@@ -13,7 +12,6 @@ from jinja2 import Environment, FileSystemLoader
|
|||||||
from logging import handlers
|
from logging import handlers
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from sqlalchemy.orm.state import InstanceState
|
|
||||||
from sqlalchemy import create_engine, text, MetaData
|
from sqlalchemy import create_engine, text, MetaData
|
||||||
from pydantic import field_validator, BaseModel, Field
|
from pydantic import field_validator, BaseModel, Field
|
||||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
@@ -893,11 +891,21 @@ def yaml_regex_creator(loader, node):
|
|||||||
return f"(?P<{name}>RSL(?:-|_)?{abbr}(?:-|_)?20\d{2}-?\d{2}-?\d{2}(?:(_|-)?\d?([^_0123456789\sA-QS-Z]|$)?R?\d?)?)"
|
return f"(?P<{name}>RSL(?:-|_)?{abbr}(?:-|_)?20\d{2}-?\d{2}-?\d{2}(?:(_|-)?\d?([^_0123456789\sA-QS-Z]|$)?R?\d?)?)"
|
||||||
|
|
||||||
|
|
||||||
def super_splitter(input:str, ioi:str, idx:int) -> str:
|
def super_splitter(ins_str:str, substring:str, idx:int) -> str:
|
||||||
|
"""
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ins_str (str): input string
|
||||||
|
substring (str): substring to split on
|
||||||
|
idx (int): the occurrence of the substring to return
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
|
||||||
|
"""
|
||||||
try:
|
try:
|
||||||
return input.split(ioi)[idx]
|
return ins_str.split(substring)[idx]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
return input
|
return ins_str
|
||||||
|
|
||||||
|
|
||||||
ctx = get_config(None)
|
ctx = get_config(None)
|
||||||
@@ -1021,7 +1029,3 @@ def create_holidays_for_year(year: int|None=None) -> List[date]:
|
|||||||
holidays.append(easter(year) - timedelta(days=2))
|
holidays.append(easter(year) - timedelta(days=2))
|
||||||
holidays.append(easter(year) + timedelta(days=1))
|
holidays.append(easter(year) + timedelta(days=1))
|
||||||
return sorted(holidays)
|
return sorted(holidays)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user