Skip to content

Commit

Permalink
Merge pull request #1 from igicerovsky/input-files
Browse files Browse the repository at this point in the history
Input files UI
  • Loading branch information
igicerovsky authored Feb 21, 2024
2 parents 963b61d + a4fa572 commit 2fa284c
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 67 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Hamiltom report changelog

## v0.1.8

21.0.2.2024

- UI to browse prameters, worklist, manual dilution files

## v0.1.6

- unit tests
Expand Down
212 changes: 161 additions & 51 deletions elisa_report.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,20 @@
Generates ELISA report from photometer output; analysis performed on Hamilton robot.
"""

from dataclasses import dataclass
from os import path, getcwd
import argparse
import warnings

from zlib import crc32

from tkinter import StringVar, Button, Entry, DISABLED, Tk
from tkinter import filedialog
from tkinter import StringVar, Button, Entry, NORMAL, DISABLED, Tk
from tkinter import filedialog, messagebox

from scipy.optimize import OptimizeWarning

from elisarep.readdata import read_params
from elisarep.mkinout import make_input_paths
from elisarep.mkinout import make_mdil_path, make_params_path, make_worklist_path
from elisarep.worklist import predil_worklist
from elisarep.sample import make_concentration
from elisarep.readdata import read_layouts
Expand All @@ -37,33 +38,41 @@
warnings.filterwarnings('ignore', category=UserWarning, module='openpyxl')


def main_report(analysis_dir: PathLike, config_dir: PathLike,
@dataclass
class InputFiles:
""" Input files
"""
analysis_dir: PathLike
config_dir: PathLike
params_file_path: PathLike
worklist_file_path: PathLike
mdil_file_path: PathLikeOrNone


def main_report(fl: InputFiles,
docxa: bool = True, docxr: bool = False, pdf: bool = True) -> None:
""" Generate main report
"""
print(f'Analysis diretory {analysis_dir}')
print(f'Configuration directory {config_dir}')
print(f'Analysis diretory {fl.analysis_dir}')
print(f'Configuration directory {fl.config_dir}')

init_config(analysis_dir, config_dir)

input_files = make_input_paths(analysis_dir)
worklist_file_path = input_files['worklist']
params_file_path = input_files['params']
init_config(fl.analysis_dir, fl.config_dir)

report_params = {
'worklist': predil_worklist(worklist_file_path),
'params': read_params(params_file_path),
'layouts': read_layouts(path.join(config_dir, cfg['plate_layout_id']),
path.join(config_dir, cfg['plate_layout_num']),
path.join(config_dir, cfg['plate_layout_dil_id'])),
'worklist': predil_worklist(fl.worklist_file_path, fl.mdil_file_path),
'params': read_params(fl.params_file_path),
'layouts': read_layouts(path.join(fl.config_dir, cfg['plate_layout_id']),
path.join(fl.config_dir,
cfg['plate_layout_num']),
path.join(fl.config_dir, cfg['plate_layout_dil_id'])),
'refconc': make_concentration(
cfg[REFVAL_NAME], cfg[DIL_NAME])
}
reports = rg.gen_report_raw(report_params, analysis_dir)
reports = rg.gen_report_raw(report_params, fl.analysis_dir)

if docxa:
export_main_report(reports, analysis_dir, cfg['pandoc_bin'],
path.join(config_dir, cfg['reference_docx']))
export_main_report(reports, fl.analysis_dir, cfg['pandoc_bin'],
path.join(fl.config_dir, cfg['reference_docx']))

for report in reports:
print(f"Report for plate {report['plate']} saved as {report['path']}")
Expand All @@ -83,44 +92,115 @@ def main_report(analysis_dir: PathLike, config_dir: PathLike,
print('Done.')


def add_msg(msg, add: str) -> None:
""" Add message
"""
if msg:
return msg + '\n' + add
return add


class Gui:
""" GUI class
"""
class BrowsePath:
""" Browse path
"""

def __init__(self, window, config_dir: PathLikeOrNone, init_folder: PathLikeOrNone) -> None:
def __init__(self, wnd, text: str, command, # pylint: disable=too-many-arguments
col, row,
var: str = None,
bstate=NORMAL) -> None:
self.button = Button(wnd, text=text, command=command, state=bstate)
self.var = StringVar()
self.var.set(var)
self.entry = Entry(textvariable=self.var,
state=DISABLED, width=110)
self.button.grid(column=col, row=row)
self.entry.grid(row=row, column=col + 1,
padx=10, pady=10)

def val(self) -> str:
""" Value
"""
if self.var.get() == 'None':
return None
return self.var.get()

def set(self, val: str) -> None:
""" Set value
"""
self.var.set(val)
self.entry.update()
self.button['state'] = NORMAL

def __init__(self, window, config_dir: PathLikeOrNone,
init_folder: PathLikeOrNone) -> None:
self.window = window
self.window.title('HAMILTON Analysis')
self.window.geometry("800x80")
self.window.title('HAMILTON ELISA Analysis')
self.window.geometry("840x220")
self.init_folder = init_folder

self.analysis_folder = StringVar()
self.analysis_folder.set('')
self.config_folder = StringVar()
if config_dir:
self.config_folder.set(config_dir)
else:
self.config_folder.set(path.join(getcwd(), 'data'))
self.group = {}

def analysis_fn():
self.browse_analysis()
button_analysis = Button(self.window, text="Browse Analysis Folder",
command=analysis_fn)
button_analysis.grid(column=0, row=0)
self.group["analysis"] = self.BrowsePath(self.window, text="Browse Analysis Folder",
command=analysis_fn, row=0, col=0)

self.entry_analysis = Entry(textvariable=self.analysis_folder,
state=DISABLED, width=110)
self.entry_analysis.grid(row=0, column=1,
padx=10, pady=10)
cfg_folder = config_dir if config_dir else path.join(getcwd(), 'data')

def browse_fn():
self.browse_config()
button_config = Button(self.window, text="Browse Config Folder",
command=browse_fn)
button_config.grid(column=0, row=1)
entry_config = Entry(textvariable=self.config_folder,
state=DISABLED, width=110)
entry_config.grid(row=1, column=1,
padx=10, pady=10)
self.group["config"] = self.BrowsePath(self.window, text="Browse Config Folder",
command=browse_fn, row=1, col=0, var=cfg_folder)

def params_fn():
self.browse_params()
self.group["params"] = self.BrowsePath(self.window, text="Browse Parameters File",
command=params_fn, row=2, col=0, bstate=DISABLED)

def worklist_fn():
self.browse_worklist()
self.group["worklist"] = self.BrowsePath(self.window, text="Browse Worklist File",
command=worklist_fn, row=3, col=0, bstate=DISABLED)

def mdil_fn():
self.browse_mdil()
self.group["mdil"] = self.BrowsePath(self.window, text="Browse Manual Dilution File",
command=mdil_fn, row=4, col=0, bstate=DISABLED)

def browse_mdil(self) -> None:
"""Browse manual dilution filename"""
filename = filedialog.askopenfilename(initialdir=self.group["analysis"].val(),
title="Select Manual Dilution File",
filetypes=[('XLS Files', '*.xlsx')])
if filename:
self.group["mdil"].set(filename)
self.check_requirements(self.group["params"].val(),
self.group["worklist"].val(),
filename)

def browse_worklist(self) -> None:
"""Browse params filename"""
filename = filedialog.askopenfilename(initialdir=self.group["analysis"].val(),
title="Select Worklist File",
filetypes=[('XLS Files', '*.xls')])
if filename:
self.group["worklist"].set(filename)
self.check_requirements(self.group["worklist"].val(),
filename,
self.group["mdil"].val())

def browse_params(self) -> None:
"""Brows params filename"""
filename = filedialog.askopenfilename(initialdir=self.group["analysis"].val(),
title="Select Parameters File",
filetypes=[('CSV Files', '*.csv')])
if filename:
self.group["params"].set(filename)
self.check_requirements(filename,
self.group["worklist"].val(),
self.group["mdil"].val())

def browse_analysis(self) -> None:
""" Browse analysis folder
Expand All @@ -131,23 +211,51 @@ def browse_analysis(self) -> None:
dirname = filedialog.askdirectory(initialdir=initialdir,
title="Select a Hamilton Analysis Folder")
if dirname:
self.analysis_folder.set(dirname)
self.entry_analysis.update()
self.group["analysis"].set(dirname)
params_path = make_params_path(dirname)
worklist_path = make_worklist_path(dirname)
mdil_path = make_mdil_path(dirname)
self.check_requirements(params_path, worklist_path, mdil_path)

def check_requirements(self, params_path, worklist_path, mdil_path) -> None:
"""Check if all requirements are met"""
msg = None
if not params_path:
msg = add_msg(
msg, "Defalult parameters file is missing \nor file name is invalid.\n")
self.group["params"].set(params_path)

if not worklist_path:
msg = add_msg(
msg, "Defalult worklist file is missing or \nfile name is invalid.\n")
self.group["worklist"].set(worklist_path)

if not mdil_path:
msg = add_msg(
msg, "Defalult manual dilution worklist file is missing \nor file name is invalid.")
self.group["mdil"].set(mdil_path)

if msg:
messagebox.showwarning("Invalid file",
msg,
parent=self.window)
else:
self.window.destroy()

def browse_config(self) -> None:
""" Browse config folder
"""
dirname = filedialog.askdirectory(initialdir=self.config_folder.get(),
dirname = filedialog.askdirectory(initialdir=self.group["config"].val(),
title="Select a Config Folder")

if dirname:
self.config_folder.set(dirname)
self.group["config"].set(dirname)

def res(self) -> None:
""" Result
"""
return self.analysis_folder.get(), self.config_folder.get()
return (self.group["analysis"].val(), self.group["config"].val(),
self.group["params"].val(), self.group["worklist"].val(), self.group["mdil"].val())


def gui_fn(config_dir: PathLikeOrNone, init_folder: PathLikeOrNone) -> PathLikeOrNone:
Expand Down Expand Up @@ -177,13 +285,15 @@ def main() -> None:
init_folder = args.ifld

if not analysis_dir:
analysis_dir, config_dir = gui_fn(config_dir, init_folder)
analysis_dir, config_dir, params_file, worklist_file, mdil_file = gui_fn(
config_dir, init_folder)
if not analysis_dir:
print('Canceled.')
return

try:
main_report(analysis_dir, config_dir)
main_report(InputFiles(analysis_dir, config_dir,
params_file, worklist_file, mdil_file))
except (KeyError, ValueError, FileNotFoundError, ) as e:
print(e)
print('Failed!')
Expand Down
2 changes: 1 addition & 1 deletion elisarep/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from .typing import PathLike


VERSION = '0.1.6'
VERSION = '0.1.7'
DESCRIPTION = 'Hamilton report generation for ELISA'
LONG_DESCRIPTION = 'Genrate report from Hamilton photometer output for ELISA.'
NAME = 'elisarep'
Expand Down
42 changes: 34 additions & 8 deletions elisarep/mkinout.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from datetime import datetime
import re

from .typing import PathLike
from .typing import PathLike, PathLikeOrNone


def find_analysis(work_dir: PathLike, match_pattern: str) -> list:
Expand Down Expand Up @@ -121,6 +121,35 @@ def basename_from_inputdir(input_dir: PathLike) -> str:
return make_base_name(p['date'], p['gn'])


def make_worklist_path(input_dir: PathLikeOrNone) -> PathLikeOrNone:
"""Make worklist file path"""
base_name = basename_from_inputdir(input_dir)
worklist = path.join(input_dir, base_name + 'worklist-ELISA.xls')
if not path.isfile(worklist):
return None
return worklist


def make_mdil_path(input_dir: PathLikeOrNone) -> PathLikeOrNone:
"""Make manual dilution file path"""
base_name = basename_from_inputdir(input_dir)
mdil = path.join(input_dir, base_name + 'worklist-ELISA_ManualDil.xlsx')
if not path.isfile(mdil):
return None
return mdil


def make_params_path(input_dir: PathLikeOrNone) -> PathLikeOrNone:
"""Make params file path"""
p = parse_dir_name(input_dir)
base_name = basename_from_inputdir(input_dir)
params = path.join(input_dir, base_name +
p['protocol'] + '_Parameters.csv')
if not path.isfile(params):
return None
return params


def make_input_paths(input_dir: PathLike) -> dict:
"""Make worklist and parameters path names
Expand All @@ -136,15 +165,12 @@ def make_input_paths(input_dir: PathLike) -> dict:
dictionary
Paths to `worklist` and `params` files
"""
p = parse_dir_name(input_dir)
base_name = basename_from_inputdir(input_dir)
worklist = path.join(input_dir, base_name + 'worklist-ELISA.xls')
if not path.isfile(worklist):
worklist = make_worklist_path(input_dir)
if not worklist:
raise FileNotFoundError(f"Worklist file path is invlaid: {worklist}")

params = path.join(input_dir, base_name +
p['protocol'] + '_Parameters.csv')
if not path.isfile(params):
params = make_params_path(input_dir)
if not worklist:
raise FileNotFoundError("Parameters file path is invlaid: {params}")

return {'worklist': worklist, 'params': params}
Expand Down
Loading

0 comments on commit 2fa284c

Please sign in to comment.