From 574335682fbe015066307930679060b7325dda01 Mon Sep 17 00:00:00 2001 From: Daniel Bridges Date: Wed, 28 Jan 2026 10:15:06 +0200 Subject: [PATCH 1/4] Initial commit to extract data from user tab --- src/nomadic/util/metadata.py | 40 ++++++++++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/src/nomadic/util/metadata.py b/src/nomadic/util/metadata.py index e287d74..d2b6528 100644 --- a/src/nomadic/util/metadata.py +++ b/src/nomadic/util/metadata.py @@ -4,10 +4,11 @@ from typing import List, Optional import pandas as pd +from openpyxl import load_workbook +from openpyxl.utils import get_column_letter from .exceptions import MetadataFormatError - STANDARD_METADATA_FILENAME = "samples.csv" @@ -49,6 +50,9 @@ def correct_barcode_format(barcode: str, try_to_fix: bool = True) -> str: EXPECTED = "barcode[0-9]{2}$" EXAMPLE = "barcode01" + if isinstance(barcode, float): + barcode = int(barcode) + if not isinstance(barcode, str): barcode = str(barcode) @@ -96,7 +100,7 @@ class MetadataTableParser: # If the required columns are not found, try these alternative names, case insensitive ALTERNATIVE_NAMES = { - "barcode": ["barcodes"], + "barcode": ["barcodes", "barcode#"], "sample_id": [ "sample", "sampleid", @@ -133,17 +137,35 @@ def _load_metadata(self, path: str): _, ext = os.path.splitext(path) ext = ext.lower() if ext == ".xlsx": - xlsx = pd.ExcelFile(path, engine="openpyxl") + warnings.filterwarnings("ignore", category=UserWarning, module="openpyxl") + xlsx = load_workbook(path, data_only=True) # name in nomadic excel template, and in the (legacy) warehouse template - target_sheets = ["nomadic", "rxn_metadata"] + target_sheets = ["Library", "rxn_metadata"] # Find first matching sheetname or use first sheet sheet_names = [ - sheetname - for sheetname in target_sheets - if sheetname in xlsx.sheet_names - ] + [xlsx.sheet_names[0]] - data = pd.read_excel(path, sheet_name=sheet_names[0], engine="openpyxl") + sheetname for sheetname in target_sheets if sheetname in xlsx.sheetnames + ] + [xlsx.sheetnames[0]] + # Get the sheet and extract the data from the table + ws = xlsx[sheet_names[0]] + tbl_name = "tbl_SeqLib" + tbl = ws.tables[tbl_name] + # Identify visible column indices + cells = ws[tbl.ref] + start_col = cells[0][0].column # numeric index + visible_cols = [] + for i in range(len(cells[0])): + col_letter = get_column_letter(start_col + i) + dim = ws.column_dimensions.get(col_letter) + if not (dim and dim.hidden): + visible_cols.append(i) + cells = ws[tbl.ref] + rows = [[cell.value for cell in row] for row in cells] + rows_filt = [[row[i] for i in visible_cols] for row in rows] + data = pd.DataFrame(rows_filt[1:], columns=rows_filt[0]) + + # Ensure that empty rows or those with missing sample_id are not included data.dropna(how="all", inplace=True) + data = data.dropna(subset=["Sample ID"]) self.df = data else: self.df = pd.read_csv(path, delimiter=get_csv_delimiter(path)) From 7c56ae0308df26a3213a99d804f785a09088ae2d Mon Sep 17 00:00:00 2001 From: Daniel Bridges Date: Wed, 28 Jan 2026 11:11:10 +0200 Subject: [PATCH 2/4] Remove surplus nomadic tab --- .../start/data/NOMADS_Library_Worksheet.xlsx | Bin 74190 -> 67463 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/nomadic/start/data/NOMADS_Library_Worksheet.xlsx b/src/nomadic/start/data/NOMADS_Library_Worksheet.xlsx index 4d547a87054182c164b05d6e291595a41219e5f0..10f4dd4b3dc8605d50249a06b378ed009b7d13a3 100644 GIT binary patch delta 20570 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 delta 27259 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 Q5F-}(kR%Q|WGamR0Kfr{E&u=k From 95d824f1982f893c5fa44be894337199baafe82d Mon Sep 17 00:00:00 2001 From: Daniel Bridges Date: Wed, 28 Jan 2026 13:38:48 +0200 Subject: [PATCH 3/4] Removed the barcode pattern warning as seems superfluous --- src/nomadic/util/metadata.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/nomadic/util/metadata.py b/src/nomadic/util/metadata.py index d2b6528..246c934 100644 --- a/src/nomadic/util/metadata.py +++ b/src/nomadic/util/metadata.py @@ -62,11 +62,6 @@ def correct_barcode_format(barcode: str, try_to_fix: bool = True) -> str: f"Barcode '{barcode}' has bad format: must conform to '{EXAMPLE}'." ) - # Raise a warning - warnings.warn( - f"Barcode '{barcode}' has bad format: must conform to '{EXAMPLE}'. Trying to fix..." - ) - nums = re.findall("[0-9]+", barcode) if not nums: From 0bddfa00ed5bb7fe1f31dcd105d243c421d7e5c1 Mon Sep 17 00:00:00 2001 From: Daniel Bridges Date: Wed, 28 Jan 2026 14:43:16 +0200 Subject: [PATCH 4/4] Handling ranges of col that are hidden --- src/nomadic/util/metadata.py | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/nomadic/util/metadata.py b/src/nomadic/util/metadata.py index 246c934..c70fcbf 100644 --- a/src/nomadic/util/metadata.py +++ b/src/nomadic/util/metadata.py @@ -5,7 +5,6 @@ import pandas as pd from openpyxl import load_workbook -from openpyxl.utils import get_column_letter from .exceptions import MetadataFormatError @@ -140,19 +139,29 @@ def _load_metadata(self, path: str): sheet_names = [ sheetname for sheetname in target_sheets if sheetname in xlsx.sheetnames ] + [xlsx.sheetnames[0]] - # Get the sheet and extract the data from the table + # Get the sheet and table ws = xlsx[sheet_names[0]] tbl_name = "tbl_SeqLib" tbl = ws.tables[tbl_name] - # Identify visible column indices cells = ws[tbl.ref] - start_col = cells[0][0].column # numeric index + start_col = cells[0][0].column # 1-based worksheet column index + + # Collect ALL hidden column ranges (including grouped ones) to identify only + # visible columns + hidden_ranges = [ + (dim.min, dim.max) + for dim in ws.column_dimensions.values() + if dim.hidden is True + ] visible_cols = [] for i in range(len(cells[0])): - col_letter = get_column_letter(start_col + i) - dim = ws.column_dimensions.get(col_letter) - if not (dim and dim.hidden): + col_idx = start_col + i + hidden = any(lo <= col_idx <= hi for lo, hi in hidden_ranges) + + if not hidden: visible_cols.append(i) + + # Extract data from visible columns ONLY cells = ws[tbl.ref] rows = [[cell.value for cell in row] for row in cells] rows_filt = [[row[i] for i in visible_cols] for row in rows]