Post code-cleanup.
This commit is contained in:
@@ -2,4 +2,4 @@
|
||||
Constructs main application.
|
||||
'''
|
||||
from .widgets import *
|
||||
from .visualizations import *
|
||||
from .visualizations import *
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
'''
|
||||
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
|
||||
import plotly, logging
|
||||
from plotly.graph_objects import Figure
|
||||
import pandas as pd
|
||||
from frontend.widgets.functions import select_save_file
|
||||
from tools import divide_chunks
|
||||
|
||||
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):
|
||||
super().__init__()
|
||||
# self.settings = settings
|
||||
try:
|
||||
months = int(settings['months'])
|
||||
except KeyError:
|
||||
months = 6
|
||||
self.df = df
|
||||
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:
|
||||
figs ():
|
||||
settings (dict): settings passed down from click
|
||||
fig (Figure): input figure object
|
||||
group_name (str): controltype
|
||||
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)
|
||||
|
||||
output = select_save_file(obj=parent, default_name=group_name, extension="png")
|
||||
self.write_image(output.absolute().__str__(), engine="kaleido")
|
||||
def make_plotly_buttons(self, months: int = 6) -> Generator[dict, None, None]:
|
||||
"""
|
||||
Creates html buttons to zoom in on date areas
|
||||
|
||||
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)
|
||||
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},
|
||||
])
|
||||
|
||||
# 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:
|
||||
"""
|
||||
|
||||
@@ -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):
|
||||
|
||||
super().__init__(df=df, modes=modes, settings=settings)
|
||||
self.df = df
|
||||
try:
|
||||
months = int(settings['months'])
|
||||
except KeyError:
|
||||
months = 6
|
||||
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):
|
||||
"""
|
||||
@@ -69,94 +70,3 @@ class IridaFigure(CustomFigure):
|
||||
)
|
||||
bar.update_traces(visible=ii == 0)
|
||||
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,
|
||||
months: int = 6):
|
||||
super().__init__(df=df, modes=modes, settings=settings)
|
||||
self.df = df
|
||||
try:
|
||||
months = int(settings['months'])
|
||||
except KeyError:
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
"""
|
||||
Handles display of control charts
|
||||
"""
|
||||
from datetime import date
|
||||
from pprint import pformat
|
||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||
from PyQt6.QtWidgets import (
|
||||
QWidget, QComboBox, QPushButton, QGridLayout
|
||||
QWidget, QComboBox, QPushButton
|
||||
)
|
||||
from PyQt6.QtCore import QSignalBlocker
|
||||
|
||||
from backend import ChartReportMaker
|
||||
from backend.db import ControlType, IridaControl
|
||||
import logging
|
||||
from tools import Report, report_result, Result
|
||||
from tools import Report, report_result
|
||||
from frontend.visualizations import CustomFigure
|
||||
from .misc import StartEndDatePicker
|
||||
from .info_tab import InfoPane
|
||||
|
||||
logger = logging.getLogger(f"submissions.{__name__}")
|
||||
@@ -27,13 +26,8 @@ class ControlsViewer(InfoPane):
|
||||
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()
|
||||
# self.datepicker = StartEndDatePicker(default_start=-180)
|
||||
# self.webengineview = QWebEngineView()
|
||||
# NOTE: set tab2 layout
|
||||
# self.layout = QGridLayout(self)
|
||||
self.control_sub_typer = QComboBox()
|
||||
# NOTE: fetch types of controls
|
||||
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.setEnabled(False)
|
||||
# NOTE: add widgets to tab2 layout
|
||||
# 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.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_sub_typer, 3, 0, 1, 4)
|
||||
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.control_sub_typer.currentIndexChanged.connect(self.update_data)
|
||||
self.mode_typer.currentIndexChanged.connect(self.update_data)
|
||||
# self.datepicker.start_date.dateChanged.connect(self.update_data)
|
||||
# self.datepicker.end_date.dateChanged.connect(self.update_data)
|
||||
self.save_button.pressed.connect(self.save_chart_function)
|
||||
self.export_button.pressed.connect(self.save_data_function)
|
||||
self.save_button.pressed.connect(self.save_png)
|
||||
self.export_button.pressed.connect(self.save_excel)
|
||||
|
||||
def save_chart_function(self):
|
||||
self.fig.save_figure(parent=self)
|
||||
|
||||
def save_data_function(self):
|
||||
self.fig.save_data(parent=self)
|
||||
# def save_chart_function(self):
|
||||
# self.fig.save_figure(parent=self)
|
||||
#
|
||||
# def save_data_function(self):
|
||||
# self.fig.save_data(parent=self)
|
||||
|
||||
@report_result
|
||||
def update_data(self, *args, **kwargs):
|
||||
@@ -117,20 +106,6 @@ class ControlsViewer(InfoPane):
|
||||
self.chart_maker_function()
|
||||
# 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
|
||||
def chart_maker_function(self, *args, **kwargs):
|
||||
# TODO: Generalize this by moving as much code as possible to IridaControl
|
||||
@@ -158,6 +133,7 @@ class ControlsViewer(InfoPane):
|
||||
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.report_obj = ChartReportMaker(df=self.fig.df, sheet_name=self.archetype.name)
|
||||
if issubclass(self.fig.__class__, CustomFigure):
|
||||
self.save_button.setEnabled(True)
|
||||
# logger.debug(f"Updating figure...")
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
"""
|
||||
A pane to show info e.g. cost reports and turnaround times.
|
||||
"""
|
||||
from datetime import date
|
||||
from PyQt6.QtCore import QSignalBlocker
|
||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||
from PyQt6.QtWidgets import QWidget, QGridLayout
|
||||
@@ -25,7 +26,8 @@ class InfoPane(QWidget):
|
||||
self.datepicker.end_date.dateChanged.connect(self.update_data)
|
||||
self.layout = QGridLayout(self)
|
||||
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)
|
||||
|
||||
@report_result
|
||||
@@ -45,6 +47,20 @@ class InfoPane(QWidget):
|
||||
report.add_result(Result(owner=self.__str__(), msg=msg, status="Warning"))
|
||||
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):
|
||||
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)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
from PyQt6.QtCore import QSignalBlocker
|
||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||
from PyQt6.QtWidgets import QWidget, QGridLayout, QPushButton, QLabel, QComboBox
|
||||
"""
|
||||
Pane showing turnaround time summary.
|
||||
"""
|
||||
from PyQt6.QtWidgets import QWidget, QPushButton, QComboBox, QLabel
|
||||
from .info_tab import InfoPane
|
||||
from backend.excel.reports import TurnaroundMaker
|
||||
from pandas import DataFrame
|
||||
from backend.db import BasicSubmission, SubmissionType
|
||||
from backend.db import SubmissionType
|
||||
from frontend.visualizations.turnaround_chart import TurnaroundChart
|
||||
import logging
|
||||
|
||||
@@ -26,12 +26,14 @@ class TurnaroundTime(InfoPane):
|
||||
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()
|
||||
|
||||
def update_data(self):
|
||||
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)
|
||||
if self.submission_typer.currentText() == "All":
|
||||
submission_type = None
|
||||
@@ -44,5 +46,5 @@ class TurnaroundTime(InfoPane):
|
||||
threshold = subtype_obj.defaults['turnaround_time'] + 0.5
|
||||
else:
|
||||
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())
|
||||
|
||||
Reference in New Issue
Block a user