Skip to main content

Banner for captainslog


PyPi Release CI Python Versions basedpyright mypy uv Ruff

Typed dataclasses for the metrics files that Riker and Picard write.

Open a Riker or Picard metrics file, plain or compressed, and get a list of frozen dataclasses with typed fields. Integer columns are int, decimal columns are float, Y and N are bool, categorical columns are enumerations, and Picard's ? is NaN.

Installation

The package can be installed with pip:

pip install captainslog-ngs

At a Glance

Read two Riker metrics files from the same run, and combine their typed fields without casting:

from captainslog.riker import AlignmentMetrics
from captainslog.riker import IsizeMetrics
from captainslog.riker import ReadCategory
from captainslog.riker import RikerReader

with (
    RikerReader.from_path[AlignmentMetrics]("tests/data/riker/s.alignment-metrics.txt") as alignments,
    RikerReader.from_path[IsizeMetrics]("tests/data/riker/s.isize-metrics.txt") as isizes,
):
    alignment = {row.category: row for row in alignments}
    [isize] = isizes

frac_reads_in_fr_pairs = 2 * isize.read_pairs / alignment[ReadCategory.PAIR].total_reads

assert round(frac_reads_in_fr_pairs, 3) == 0.972

Quickstart

Reading Riker Metrics

A RikerReader reads a Riker metrics file into dataclasses, one per row.

from captainslog import riker
from captainslog.riker import HybcapMetrics
from captainslog.riker import IsizeHistogram

assert riker.metrics_class("tests/data/riker/s.hybcap-metrics.txt") is HybcapMetrics

with RikerReader.from_path[HybcapMetrics]("tests/data/riker/s.hybcap-metrics.txt") as reader:
    [hybcap] = reader

assert hybcap.sample == "NA12891"
assert hybcap.mean_target_coverage == 70.54

with RikerReader.from_path[IsizeHistogram]("tests/data/riker/s.isize-histogram.txt") as reader:
    isize = riker.columns(list(reader))

assert isize.insert_size[:3] == (112, 128, 134)
assert isize.fr_count[:3] == (1, 1, 1)

Reading Picard Metrics

A PicardReader reads a Picard metrics file into dataclasses, one per row.

from captainslog.picard import HsMetrics
from captainslog.picard import PicardReader

with PicardReader.from_path[HsMetrics]("tests/data/picard/hs.hs_metrics") as reader:
    [hs_metrics] = reader

assert hs_metrics.mean_target_coverage == 70.54
assert hs_metrics.hs_library_size == 14903
assert reader.header.command_line.startswith("CollectHsMetrics BAIT_INTERVALS=")
assert reader.header.started_on == "Sat Oct 24 21:42:22 HST 2026"

Writing Metrics

Each reader has a writer, which makes realistic files for unit tests:

  • RikerWriter
  • PicardWriter, with write_histogram
  • PicardHistogramWriter
  • PicardCoverageWriter
from pathlib import Path
from tempfile import TemporaryDirectory

from captainslog.picard import PicardWriter

temp_dir = TemporaryDirectory()
path = Path(temp_dir.name) / "s.hs_metrics"

with PicardWriter.from_path[HsMetrics](path) as writer:
    writer.write(hs_metrics)

with PicardReader.from_path[HsMetrics](path) as reader:
    assert list(reader) == [hs_metrics]

Interacting with Metrics

Finding the Class of a File

The metrics_class and histogram_class functions return the metric type in a data file.

from captainslog import picard
from captainslog.picard import HsHistogram
from captainslog.picard import MeanQualityByCycle

assert picard.metrics_class("tests/data/picard/hs.hs_metrics") is HsMetrics
assert picard.histogram_class("tests/data/picard/hs.hs_metrics") is HsHistogram
assert picard.histogram_class("tests/data/picard/cmm.quality_by_cycle_metrics") is MeanQualityByCycle

Histograms and Columns

A PicardHistogramReader reads the histogram of a file into one dataclass per bin, and columns transposes the bins into one tuple per column. For the histograms whose columns Picard names after samples, libraries, and read groups, these functions turn the columns into typed series and the series back into bins:

  • insert_size_series and insert_size_bins, for an InsertSizeHistogram
  • rna_coverage_series and rna_coverage_bins, for an RnaCoverageHistogram
  • library_complexity_series and library_complexity_bins, for a LibraryComplexityHistogram
from captainslog.picard import InsertSizeHistogram
from captainslog.picard import PairOrientation
from captainslog.picard import PicardHistogramReader

with PicardHistogramReader.from_path[InsertSizeHistogram]("tests/data/picard/cmm.insert_size_metrics") as reader:
    hist = picard.columns(list(reader))

assert hist.insert_size[:3] == (112, 128, 134)

series = picard.insert_size_series(hist)
all_reads = next(s for s in series if s.name is None and s.orientation is PairOrientation.FR)

assert all_reads.counts[:3] == (1, 1, 1)
assert sum(all_reads.counts) == 478
assert [s.name for s in series] == [None, "NA12891", "Pond-492101", "NormPond-544932", "NA12891.r1", "NA12891.r2"]

Histogram-only files read the same way:

from captainslog.picard import QualityScoreDistribution

with PicardHistogramReader.from_path[QualityScoreDistribution]("tests/data/picard/cmm.quality_distribution_metrics") as reader:
    qualities = list(reader)

assert qualities[0].quality == 1
assert qualities[0].count_of_q == 2

Accumulation Levels

Picard writes a row for each accumulation level: all reads, then each sample, library, and read group.

from captainslog.picard import AccumulationLevel
from captainslog.picard import InsertSizeMetrics

with PicardReader.from_path[InsertSizeMetrics]("tests/data/picard/cmm.insert_size_metrics") as reader:
    rows = list(reader)

assert [picard.accumulation_level(row) for row in rows] == [
    AccumulationLevel.ALL_READS,
    AccumulationLevel.SAMPLE,
    AccumulationLevel.LIBRARY,
    AccumulationLevel.LIBRARY,
    AccumulationLevel.READ_GROUP,
    AccumulationLevel.READ_GROUP,
]

[all_reads] = [row for row in rows if picard.accumulation_level(row) is AccumulationLevel.ALL_READS]

assert all_reads.read_pairs == 478
assert all_reads.pair_orientation is PairOrientation.FR

Per-Target and Per-Base Coverage

CollectHsMetrics and CollectTargetedPcrMetrics can also write plain tables of coverage per target and per base.

from captainslog.picard import PerTargetCoverage
from captainslog.picard import PicardCoverageReader

with PicardCoverageReader.from_path[PerTargetCoverage]("tests/data/picard/hs.per_target_coverage.txt") as reader:
    targets = list(reader)

assert targets[0].name == "rs7555566"
assert targets[0].frac_gc == 0.41

Deriving Metrics

To derive metrics, subclass a dataclass, add properties or methods, and read into the subclass.

class MyHsMetrics(HsMetrics):
    @property
    def frac_bases_on_target(self) -> float:
        return self.on_target_bases / self.pf_bases_aligned

with PicardReader.from_path[MyHsMetrics]("tests/data/picard/hs.hs_metrics") as reader:
    [hs_metrics] = reader

assert round(hs_metrics.frac_bases_on_target, 4) == 0.2398

Development and Testing

See the contributing guide for more information.

Metadata

Release files for captainslog-ngs 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for captainslog-ngs 0.1.0
File Size Uploaded Provenance
captainslog_ngs-0.1.0.tar.gz 201.6 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for captainslog-ngs 0.1.0
File Interpreter ABI Platform
captainslog_ngs-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 277.9 kB

Release files / captainslog_ngs-0.1.0.tar.gz

Download URL captainslog_ngs-0.1.0.tar.gz
Size 201.6 kB
Tags Source
SHA-256 checksum
How to use checksums
573002b4b61d4a9f9f86b0bb26663ee491c220b6ca8765d0e6e39cf18a63169e
BLAKE2b-256 checksum
How to use checksums
5c7bfab4b26893570c8d639350f4ac24368b93b0b8bb25ee10cd0d7763321fd7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Release files / captainslog_ngs-0.1.0-py3-none-any.whl

Download URL captainslog_ngs-0.1.0-py3-none-any.whl
Size 76.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
733d97df94c49f014f26a89664c504acfdf8c6d38792e9b2d79d916c7ae3863c
BLAKE2b-256 checksum
How to use checksums
35c4a35120ba1c81a3e721a91c5946d5345c0c5f2681039ade88358c1852bd39
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

Security for captainslog-ngs 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for captainslog_ngs-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 27, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page