Better xlsx reports

This commit is contained in:
Landon Wark
2023-02-03 14:18:29 -06:00
parent d2c820f03a
commit 7fb5bb12f3
5 changed files with 44 additions and 14 deletions

Binary file not shown.

View File

@@ -1,4 +1,4 @@
# __init__.py # __init__.py
# Version of the realpython-reader package # Version of the realpython-reader package
__version__ = "1.1.2" __version__ = "1.2.1"

View File

@@ -2,16 +2,14 @@ from . import models
import pandas as pd import pandas as pd
import sqlalchemy.exc import sqlalchemy.exc
import sqlite3 import sqlite3
# from sqlalchemy.exc import IntegrityError, OperationalError
# from sqlite3 import IntegrityError, OperationalError
import logging import logging
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from sqlalchemy import and_ from sqlalchemy import and_
import uuid import uuid
import base64 # import base64
from sqlalchemy import JSON from sqlalchemy import JSON
import json import json
from dateutil.relativedelta import relativedelta # from dateutil.relativedelta import relativedelta
from getpass import getuser from getpass import getuser
logger = logging.getLogger(f"submissions.{__name__}") logger = logging.getLogger(f"submissions.{__name__}")
@@ -94,11 +92,14 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
instance = ctx['database_session'].query(models.BasicSubmission).filter(models.BasicSubmission.rsl_plate_num==info_dict['rsl_plate_num']).first() instance = ctx['database_session'].query(models.BasicSubmission).filter(models.BasicSubmission.rsl_plate_num==info_dict['rsl_plate_num']).first()
msg = "This submission already exists.\nWould you like to overwrite?" msg = "This submission already exists.\nWould you like to overwrite?"
# get model based on submission type converted above # get model based on submission type converted above
logger.debug(f"Looking at models for submission type: {query}")
model = getattr(models, query) model = getattr(models, query)
logger.debug(f"We've got the model: {type(model)}")
info_dict['submission_type'] = info_dict['submission_type'].replace(" ", "_").lower() info_dict['submission_type'] = info_dict['submission_type'].replace(" ", "_").lower()
# if query return nothing, ie doesn't already exist in db # if query return nothing, ie doesn't already exist in db
if instance == None: if instance == None:
instance = model() instance = model()
logger.debug(f"Submission doesn't exist yet, creating new instance: {instance}")
msg = None msg = None
for item in info_dict: for item in info_dict:
logger.debug(f"Setting {item} to {info_dict[item]}") logger.debug(f"Setting {item} to {info_dict[item]}")
@@ -133,11 +134,11 @@ def construct_submission_info(ctx:dict, info_dict:dict) -> models.BasicSubmissio
logger.debug(f"Could not set attribute: {item} to {info_dict[item]}") logger.debug(f"Could not set attribute: {item} to {info_dict[item]}")
continue continue
# calculate cost of the run: immutable cost + mutable times number of columns # calculate cost of the run: immutable cost + mutable times number of columns
try: try:
instance.run_cost = instance.extraction_kit.immutable_cost + (instance.extraction_kit.mutable_cost * ((instance.sample_count / 8)/12)) instance.run_cost = instance.extraction_kit.immutable_cost + (instance.extraction_kit.mutable_cost * ((instance.sample_count / 8)/12))
except TypeError: except (TypeError, AttributeError):
logger.debug(f"Looks like that kit doesn't have cost breakdown yet, using full plate cost.") logger.debug(f"Looks like that kit doesn't have cost breakdown yet, using full plate cost.")
instance.run_cost = instance.extraction_kit.cost_per_run instance.run_cost = instance.extraction_kit.cost_per_run
logger.debug(f"Constructed instance: {instance.to_string()}") logger.debug(f"Constructed instance: {instance.to_string()}")
logger.debug(msg) logger.debug(msg)
return instance, {'message':msg} return instance, {'message':msg}

View File

@@ -15,9 +15,12 @@ from PyQt6.QtWebEngineWidgets import QWebEngineView
from pathlib import Path from pathlib import Path
import plotly import plotly
import pandas as pd import pandas as pd
from openpyxl.utils import get_column_letter
from openpyxl.styles import NamedStyle
from xhtml2pdf import pisa from xhtml2pdf import pisa
# import plotly.express as px # import plotly.express as px
import yaml import yaml
import pprint
from backend.excel.parser import SheetParser from backend.excel.parser import SheetParser
from backend.excel.reports import convert_control_by_mode, convert_data_list_to_df from backend.excel.reports import convert_control_by_mode, convert_data_list_to_df
@@ -35,7 +38,7 @@ import difflib
from datetime import date from datetime import date
from frontend.visualizations.charts import create_charts from frontend.visualizations.charts import create_charts
logger = logging.getLogger(__name__) logger = logging.getLogger(f'submissions.{__name__}')
logger.info("Hello, I am a logger") logger.info("Hello, I am a logger")
class App(QMainWindow): class App(QMainWindow):
@@ -65,6 +68,7 @@ class App(QMainWindow):
self.controls_getter() self.controls_getter()
self.show() self.show()
def _createMenuBar(self): def _createMenuBar(self):
""" """
adds items to menu bar adds items to menu bar
@@ -261,10 +265,11 @@ class App(QMainWindow):
logger.debug("Will not add reagent.") logger.debug("Will not add reagent.")
if wanted_reagent != None: if wanted_reagent != None:
parsed_reagents.append(wanted_reagent) parsed_reagents.append(wanted_reagent)
logger.debug(info) # logger.debug(info)
# move samples into preliminary submission dict # move samples into preliminary submission dict
info['samples'] = self.samples info['samples'] = self.samples
# construct submission object # construct submission object
logger.debug(f"Here is the info_dict: {pprint.pformat(info)}")
base_submission, output = construct_submission_info(ctx=self.ctx, info_dict=info) base_submission, output = construct_submission_info(ctx=self.ctx, info_dict=info)
# check output message for issues # check output message for issues
if output['message'] != None: if output['message'] != None:
@@ -376,7 +381,31 @@ class App(QMainWindow):
# df.to_excel(fname, engine='openpyxl') # df.to_excel(fname, engine='openpyxl')
with open(fname, "w+b") as f: with open(fname, "w+b") as f:
pisa.CreatePDF(html, dest=f) pisa.CreatePDF(html, dest=f)
df.to_excel(fname.with_suffix(".xlsx"), engine='openpyxl') writer = pd.ExcelWriter(fname.with_suffix(".xlsx"), engine='openpyxl')
df.to_excel(writer, sheet_name="Report")
worksheet = writer.sheets['Report']
for idx, col in enumerate(df): # loop through all columns
series = df[col]
max_len = max((
series.astype(str).map(len).max(), # len of largest item
len(str(series.name)) # len of column name/header
)) + 20 # adding a little extra space
try:
worksheet.column_dimensions[get_column_letter(idx)].width = max_len
except ValueError:
pass
# set_column(idx, idx, max_len) # set column width
# colu = worksheet.column_dimensions["C"]
# style = NamedStyle(name="custom_currency", number_format='Currency')
for cell in worksheet['C']:
# try:
# check = int(cell.row)
# except TypeError:
# continue
if cell.row > 3:
cell.style = 'Currency'
writer.close()

View File

@@ -1,7 +1,7 @@
{# template for constructing submission details #} {# template for constructing submission details #}
{% for key, value in sub.items() if key != 'reagents' and key != 'samples' %} {% for key, value in sub.items() if key != 'reagents' and key != 'samples' %}
{{ key }}: {{ value }} {% if key=='Cost' %} {{ key }}: {{ "${:,.2f}".format(value) }} {% else %} {{ key }}: {{ value }} {% endif %}
{% endfor %} {% endfor %}
Reagents: Reagents:
{% for item in sub['reagents'] %} {% for item in sub['reagents'] %}