Illumina v1 Sample Sheet Example

This example demonstrates how to parse an Illumina v1 sample sheet using elsheeto and extract key information including header metadata and sample details.

Sample Sheet Format

Illumina v1 sample sheets are organized into sections:

  • [Header]: Experiment metadata and configuration

  • [Reads]: Read length specifications

  • [Settings]: Runtime settings (optional)

  • [Data]: Sample information with indexing details

Example Script

Here’s the complete example script (examples/read_illumina_v1.py):

  1#!/usr/bin/env python3
  2"""Example: Reading an Illumina v1 sample sheet.
  3
  4This example demonstrates how to parse an Illumina v1 sample sheet and extract
  5key information including header metadata and sample details.
  6
  7Usage:
  8    python examples/read_illumina_v1.py
  9    # or with uv:
 10    uv run python examples/read_illumina_v1.py
 11"""
 12
 13from pathlib import Path
 14
 15from elsheeto import parse_illumina_v1
 16
 17
 18def main():
 19    """Parse Illumina v1 sample sheet and display key information."""
 20    # Path to the example Illumina v1 sample sheet
 21    sample_sheet_path = Path(__file__).parent / "illumina_v1_example1.csv"
 22
 23    # Get relative path from current working directory for display
 24    try:
 25        relative_path = sample_sheet_path.relative_to(Path.cwd())
 26    except ValueError:
 27        # Fallback to absolute path if relative path can't be computed
 28        relative_path = sample_sheet_path
 29
 30    print(f"Reading Illumina v1 sample sheet: {relative_path}")
 31    print("=" * 60)
 32
 33    # Parse the sample sheet using elsheeto's facade function
 34    try:
 35        sample_sheet = parse_illumina_v1(sample_sheet_path)
 36    except Exception as e:
 37        print(f"Error parsing sample sheet: {e}")
 38        return
 39
 40    # Extract and display header information
 41    header = sample_sheet.header
 42    print("HEADER INFORMATION:")
 43    print("-" * 30)
 44
 45    # Display date
 46    if header.date:
 47        print(f"Date: {header.date}")
 48    else:
 49        print("Date: Not specified")
 50
 51    # Display experiment description
 52    if header.experiment_name:
 53        print(f"Experiment Name: {header.experiment_name}")
 54    else:
 55        print("Experiment Name: Not specified")
 56
 57    if header.description:
 58        print(f"Description: {header.description}")
 59    else:
 60        print("Description: Not specified")
 61
 62    # Display additional header fields
 63    print(f"Workflow: {header.workflow}")
 64    if header.application:
 65        print(f"Application: {header.application}")
 66    if header.instrument_type:
 67        print(f"Instrument Type: {header.instrument_type}")
 68    if header.assay:
 69        print(f"Assay: {header.assay}")
 70
 71    print()
 72
 73    # Display reads information
 74    if sample_sheet.reads:
 75        print("READS INFORMATION:")
 76        print("-" * 30)
 77        print(f"Read lengths: {sample_sheet.reads.read_lengths}")
 78        print()
 79
 80    # Display sample information
 81    print("SAMPLE INFORMATION:")
 82    print("-" * 30)
 83    print(f"Total samples: {len(sample_sheet.data)}")
 84    print()
 85
 86    # Display sample names and IDs
 87    print("Sample Details:")
 88    for i, sample in enumerate(sample_sheet.data, 1):
 89        sample_name = sample.sample_name or "(No name)"
 90        print(f"  {i:2d}. Sample ID: {sample.sample_id}")
 91        print(f"      Sample Name: {sample_name}")
 92        if sample.sample_project:
 93            print(f"      Project: {sample.sample_project}")
 94        if sample.description:
 95            print(f"      Description: {sample.description}")
 96        if sample.index:
 97            print(f"      Index: {sample.index}")
 98        if sample.index2:
 99            print(f"      Index2: {sample.index2}")
100        print()
101
102    # Display index information summary
103    print("INDEX SUMMARY:")
104    print("-" * 30)
105    indexed_samples = [s for s in sample_sheet.data if s.index]
106    dual_indexed_samples = [s for s in sample_sheet.data if s.index and s.index2]
107
108    print(f"Samples with index: {len(indexed_samples)}")
109    print(f"Samples with dual indexing: {len(dual_indexed_samples)}")
110
111    if indexed_samples:
112        print("Index adapters used:")
113        unique_i7_ids = {s.i7_index_id for s in indexed_samples if s.i7_index_id}
114        unique_i5_ids = {s.i5_index_id for s in indexed_samples if s.i5_index_id}
115        if unique_i7_ids:
116            print(f"  I7 Index IDs: {', '.join(sorted(unique_i7_ids))}")
117        if unique_i5_ids:
118            print(f"  I5 Index IDs: {', '.join(sorted(unique_i5_ids))}")
119
120
121if __name__ == "__main__":
122    main()

Key Features Demonstrated

Import and Parsing

The script uses the simple facade function:

from elsheeto import parse_illumina_v1
sample_sheet = parse_illumina_v1(sample_sheet_path)

This single function call handles the entire three-stage parsing process.

Header Information Access

The parsed header provides access to experiment metadata:

header = sample_sheet.header
print(f"Date: {header.date}")
print(f"Experiment Name: {header.experiment_name}")
print(f"Description: {header.description}")

Sample Data Processing

Individual samples can be accessed and processed:

for sample in sample_sheet.data:
    print(f"Sample ID: {sample.sample_id}")
    print(f"Index: {sample.index}")
    print(f"Index2: {sample.index2}")

Index Analysis

The script demonstrates how to analyze indexing patterns:

indexed_samples = [s for s in sample_sheet.data if s.index]
dual_indexed_samples = [s for s in sample_sheet.data if s.index and s.index2]

Sample Data File

The example uses illumina_v1_example1.csv:

 1[Header],,,,,,,,,,
 2IEMFileVersion,5,,,,,,,,,
 3Experiment Name,MyExperimentName,,,,,,,,,
 4Date,11.11.2011,,,,,,,,,
 5Workflow,GenerateFASTQ,,,,,,,,,
 6Application,NextSeq FASTQ Only,,,,,,,,,
 7Instrument Type,NovaSeq/MiSeq,,,,,,,,,
 8Assay,TruSeq DNA Exome Enrichment,,,,,,,,,
 9Index Adapters,TruSeq DNA CD Indexes (96 Indexes),,,,,,,,,
10Description,The Description,,,,,,,,,
11Chemistry,Amplicon,,,,,,,,,
12,,,,,,,,,,
13[Reads],,,,,,,,,,
14149,,,,,,,,,,
15149,,,,,,,,,,
16,,,,,,,,,,
17[Settings],,,,,,,,,,
18,,,,,,,,,,
19[Data],,,,,,,,,,
20Sample_ID,Sample_Name,Sample_Plate,Sample_Well,Index_Plate_Well,I7_Index_ID,index,I5_Index_ID,index2,Sample_Project,Description
21L11-00001_01,,,,A11,AD81,ATCACTCACA,AD81,TTACGGTAAC,,NGS_Seq1_20111111_01
22L11-00002_01,,,,B11,AD82,CGGAGGTAGA,AD82,TTCAGATGGA,,NGS_Seq1_20111111_01
23L11-00003_01,,,,C11,AD83,GAGTTGACAA,AD83,TAGCATCTGT,,NGS_Seq1_20111111_01
24L11-00004_01,,,,D11,AD84,GCCGAACTTG,AD84,GGACGAGATC,,NGS_Seq1_20111111_01

Expected Output

When you run the example script, you should see output like this:

Reading Illumina v1 sample sheet: examples/illumina_v1_example1.csv
============================================================
HEADER INFORMATION:
------------------------------
Date: 11.11.2011
Experiment Name: MyExperimentName
Description: The Description
Workflow: GenerateFASTQ
Application: NextSeq FASTQ Only
Instrument Type: NovaSeq/MiSeq
Assay: TruSeq DNA Exome Enrichment

READS INFORMATION:
------------------------------
Read lengths: [149, 149]

SAMPLE INFORMATION:
------------------------------
Total samples: 4

Sample Details:
   1. Sample ID: L11-00001_01
      Sample Name: (No name)
      Description: NGS_Seq1_20111111_01
      Index: ATCACTCACA
      Index2: TTACGGTAAC

   2. Sample ID: L11-00002_01
      Sample Name: (No name)
      Description: NGS_Seq1_20111111_01
      Index: CGGAGGTAGA
      Index2: TTCAGATGGA

   3. Sample ID: L11-00003_01
      Sample Name: (No name)
      Description: NGS_Seq1_20111111_01
      Index: GAGTTGACAA
      Index2: TAGCATCTGT

   4. Sample ID: L11-00004_01
      Sample Name: (No name)
      Description: NGS_Seq1_20111111_01
      Index: GCCGAACTTG
      Index2: GGACGAGATC

INDEX SUMMARY:
------------------------------
Samples with index: 4
Samples with dual indexing: 4
Index adapters used:
  I7 Index IDs: AD81, AD82, AD83, AD84
  I5 Index IDs: AD81, AD82, AD83, AD84

Key Output Sections

  1. Header Information: Date, experiment name, description, and technical details

  2. Sample Information: Complete list of all samples with their metadata

  3. Index Summary: Statistics about indexing patterns used in the experiment

The output shows:

  • 4 dual-indexed samples with both I7 and I5 indices

  • Index adapter IDs AD81-AD84 for systematic indexing

  • Complete sample metadata including projects and descriptions

Error Handling

The script includes proper error handling:

try:
    sample_sheet = parse_illumina_v1(sample_sheet_path)
except Exception as e:
    print(f"Error parsing sample sheet: {e}")
    return

This ensures graceful handling of malformed files or parsing issues.

Running the Example

You can run this example in several ways:

# Using uv (recommended)
uv run python examples/read_illumina_v1.py

# Or generate output file
make examples

# Direct execution (if elsheeto is installed)
python examples/read_illumina_v1.py

The example demonstrates elsheeto’s type-safe parsing and shows how easy it is to extract meaningful information from Illumina sample sheets.