Skip to main content

coeftable

Lightweight, report-ready summary tables for estimates with uncertainty. Renders inline forest plots, builds on great_tables HTML output, and works with pandas, polars, or pyarrow frames.

Rendered experiment results table with grouped sections, nested variants, and an inline forest plot

Installation

uv add coeftable

Quick start

The one-line form declares a table with a single estimate column:

import polars as pl
import coeftable as ct

df = pl.DataFrame(
    {
        "metric": ["Revenue", "Latency"],
        "est": [3.4, 0.5],
        "lb": [1.2, -1.0],
        "ub": [5.7, 2.0],
    }
)

ct.CoefTable(df, rows="metric", estimate="est", ci=("lb", "ub"))

A CoefTable renders itself in marimo, Jupyter, and any other _repr_html_-aware viewer — leave it as the last expression in a cell, no extra call needed. Outside a notebook, use .gt() to reach the underlying great_tables object: table.gt().as_raw_html() for an HTML string, table.gt().save("t.png") for an image, table.gt().tab_options(...) to keep styling with great_tables' own API.

Experiment table

Build a complete experiment results table with multiple estimates, a forest plot column, grouped row sections, nested variants, and direction hints:

import polars as pl
import coeftable as ct

experiment = pl.DataFrame(
    {
        "area": ["Core", "Core", "Ops", "Ops"],
        "metric": ["Revenue", "Revenue", "Latency", "Latency"],
        "variant": ["B", "C", "B", "C"],
        "att": [12400.0, -3100.0, 40.0, 120.0],
        "att_lb": [4200.0, -9800.0, -80.0, 45.0],
        "att_ub": [20600.0, 3600.0, 160.0, 195.0],
        "rel": [3.4, -1.2, 0.5, 2.0],
        "rel_lb": [1.2, -4.0, -1.0, 0.8],
        "rel_ub": [5.7, 1.6, 2.0, 3.2],
    }
)

(
    ct.CoefTable(experiment, rows="metric", nest="variant", groups="area")
    .estimate("Lift Amount", "att", ci=("att_lb", "att_ub"), fmt=ct.Number(compact=True))
    .estimate("Lift %", "rel", ci=("rel_lb", "rel_ub"), fmt=ct.Percent(signed=True))
    .forest("Lift Plot", of="Lift %", ref=0.0, symmetric=True)
    .header("Experiment Results", "Example Experiment")
    .with_direction({"Latency": "lower_is_better"})
)

Comparing methods

Use split_columns to compare multiple methods side by side. Each value in the split column produces its own set of estimate / forest columns:

import polars as pl
import coeftable as ct

methods = pl.DataFrame(
    {
        "metric": ["Revenue", "Revenue", "Latency", "Latency"],
        "method": ["A", "B", "A", "B"],
        "est": [3.4, 3.1, 0.5, 0.6],
        "lb": [1.2, 1.0, -1.0, -0.8],
        "ub": [5.7, 5.2, 2.0, 2.1],
    }
)

(
    ct.CoefTable(
        methods, rows="metric", split_columns="method", estimate="est", ci=("lb", "ub")
    )
    .header("Cohort Revenue by Method")
)

Theming

Four built-in themes are available from coeftable.theme:

from coeftable.theme import BLUE, COLORBLIND, DEFAULT, MONO, TEXTUAL

DEFAULT       # Alias for TEXTUAL -- what CoefTable uses if you don't set a theme
TEXTUAL       # Minimal, publication-style: muted colours, light chrome
BLUE          # The original blue-grey palette
COLORBLIND    # Colourblind-safe palette
MONO          # Grayscale for mono journals

Apply one with .with_theme(...):

table.with_theme(BLUE)

Customise a theme with dataclasses.replace:

from dataclasses import replace

my_theme = replace(BLUE, favorable="#0072B2")

Use with_direction to mark rows where lower values are favourable (reusing the df frame from Quick start):

table = (
    ct.CoefTable(df, rows="metric", estimate="est", ci=("lb", "ub"))
    .with_direction({"Latency": "lower_is_better"})
)

Data shape

coeftable expects a dataframe where every row is a single comparison. The resolution logic maps pairs of upper / lower bound columns to each estimate, so your data should be wide in triples — one point-estimate column and (when applicable) its lower and upper bound columns — rather than in long format with a parameter column.

Dimensions:

  • rows — the label for each row in the table (e.g. a metric name).
  • nest — an optional secondary label stacked below each row.
  • groups — an optional column whose values produce section headers.
  • split_columns — an optional column whose values produce repeated column groups side by side, useful for comparing methods.

Metadata

Release files for coeftable 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 coeftable 0.1.0
File Size Uploaded
coeftable-0.1.0.tar.gz 157.3 kB Details

Built distribution (wheel)

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

Total release size: 180.1 kB

Release files / coeftable-0.1.0.tar.gz

Download URL coeftable-0.1.0.tar.gz
Size 157.3 kB
Tags Source
SHA-256 checksum
How to use checksums
c49a1d6bf349bebe2f8e332d179cc07abe273df66ab2512174dd947b38afaa94
BLAKE2b-256 checksum
How to use checksums
21507e852b873a1e43cd4fe561140b9c73a6d4bce30296792f7b76d7043ec09a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 28, 2026.

Transparency log

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

Download URL coeftable-0.1.0-py3-none-any.whl
Size 22.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
1680a6def746a2d50e65b5ca9f1b94a4ec3e1294c18cf830c68010e1860ef8d8
BLAKE2b-256 checksum
How to use checksums
39be5fa018cfa0eb1342531731486b819f1ecfa04195c38e15d97b8103b9883a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.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 Jul 28, 2026.

Transparency log

Release history Release notifications | RSS feed

0.13.1

2 release files

0.13.0

2 release files

0.12.1

2 release files

0.12.0

2 release files

0.11.0

2 release files

0.10.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

0.6.0

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.1

2 release files

This release

0.1.0 This release

2 release files

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