Skip to main content

crosstab

ci/cd codecov Documentation Status PyPI Latest Release PyPI Downloads Python Version Support

crosstab rearranges data from a normalized CSV format to a crosstabulated XLSX workbook, with styling. The pivot is computed in a single pass by DuckDB and the workbook is produced by XlsxWriter, so even very large inputs crosstab in seconds. Column names containing spaces, parentheses, embedded quotes, unicode, leading digits, or SQL reserved words pass through unmodified.

Go from this:

Crosstab Input

To this:

Crosstab Output

Installation

You can install crosstab via pip from PyPI:

pip install crosstab

There is also a Docker image available on the GitHub Container Registry:

docker pull ghcr.io/geocoug/crosstab:latest

Usage

The output workbook contains:

  1. Crosstab — the pivoted table. Row-header values are listed on the left; each distinct combination of column-header values fans out across the top, with one sub-column per requested value column.
  2. Source Data (optional) — a verbatim copy of the input CSV, written when keep_src=True.

Each of the examples below produces the same output.

Python

from pathlib import Path

from crosstab import Crosstab

Crosstab(
    incsv=Path("data.csv"),
    outxlsx=Path("crosstabbed_data.xlsx"),
    row_headers=("location", "sample"),
    col_headers=("cas_rn", "parameter"),
    value_cols=("concentration", "units"),
    keep_src=True,
).crosstab()

Command Line

-r, -c, and -v each accept one or more column names following the flag:

crosstab -s \
    -f data.csv \
    -o crosstabbed_data.xlsx \
    -r location sample \
    -c cas_rn parameter \
    -v concentration units

Run crosstab --help for the full option list.

Docker

docker run --rm -v $(pwd):/data ghcr.io/geocoug/crosstab:latest \
    -s -f /data/data.csv -o /data/crosstabbed_data.xlsx \
    -r location sample \
    -c cas_rn parameter \
    -v concentration units

Behavior

  • Strings preserved. All CSV cells are read as strings via DuckDB's read_csv(..., all_varchar=True), so values like 01 and 2026-05-04 are not coerced to numbers or dates.
  • Deterministic ordering. Row keys and column keys are sorted before being written, so re-running the same input produces a byte-identical output.
  • Strict duplicate detection. If any (row_key, col_key) combination appears more than once in the input, the run fails with a clear ValueError rather than silently dropping data. Pre-aggregate the CSV with DuckDB, pandas, polars, etc. before crosstabbing if your source data has duplicates that should be combined.

Filling empty cells

By default, cells with no matching (row_key, col_key) row are left blank. Pass fill="—" (or any string) to substitute a placeholder:

crosstab --fill "N/A" \
    -f results.csv \
    -r station -c parameter -v concentration

Persisting the database

Pass keep_duckdb=True (or --keep-duckdb / -k) to save the staged input as a DuckDB database at <input>.duckdb so it can be queried again later — handy when you want to follow up the pivot with ad-hoc SQL without re-reading the CSV.

Release files for crosstab 0.3.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 crosstab 0.3.0
File Size Uploaded
crosstab-0.3.0.tar.gz 270.7 kB Details

Built distribution (wheel)

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

Total release size: 306.4 kB

Release files / crosstab-0.3.0.tar.gz

Download URL crosstab-0.3.0.tar.gz
Size 270.7 kB
Tags Source
SHA-256 checksum
How to use checksums
5eb0d78a7a5f996dc2313c58366be28bccdd7062ead093360ee23c71d53a5528
BLAKE2b-256 checksum
How to use checksums
d33379bf78ef7395024bc2b427e653d0f2378377a60c76d5bb1f06196930b2c8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 May 5, 2026.

Transparency log

Release files / crosstab-0.3.0-py3-none-any.whl

Download URL crosstab-0.3.0-py3-none-any.whl
Size 35.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7c8fcde7c17ad1d34058908ada4883165e6fe4e983071d818fd51ab1e7d9e1ca
BLAKE2b-256 checksum
How to use checksums
58d0f29233f1f47c0a6cf6ba33c568cda6009c4b7131f85fdcc46a6534841df0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

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 May 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.0.15

2 release files

0.0.14

2 release files

0.0.13

2 release files

0.0.12

2 release files

0.0.9

2 release files

0.0.8

2 release files

0.0.7

2 release files

0.0.6

2 release files

0.0.5

2 release files

0.0.4

2 release files

0.0.3

2 release files

0.0.2

2 release files

0.0.1

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