Skip to main content

Research Helpers

License Python Tests Documentation

Research Helpers is a set of utilities for managing code-intensive research projects and their accompanying papers. Includes shared figure styling, LaTeX table generation and rendering, a build pipeline that keeps a paper's generated tables and figures from drifting out of date, submission packaging for arXiv and Zenodo, structured logging, and a parameter-sweep engine for scheduler job arrays.

Read the documentation

Features

  • Generated Tables and Figures: Build the paper's tables and figures from the repository's own data
  • Drift Detection: Detect when the paper and the data differ, even in a repository that publishes the floats without the paper
  • Numbers in the Prose: Track every number a sentence states back to the data that supports it, and audit the prose for any untracked values
  • Several Documents: Give a technical note or a supplement its own generated tables, figures, and checks
  • LaTeX Assembly: Compose tables for LaTeX and also display them in Jupyter
  • Shared Figure Styling: Consistent look across LaTeX and Jupyter
  • Submission Packaging: Automatic preparation and pre-checking for arXiv and Zenodo
  • Parameter Sweeps: Plan a grid, run it as a scheduler job array, resume if necessary, and collect the results
  • Campaigns: Put hundreds of sweeps through a few arrays, resume them, and recover from elements that ran twice
  • Aggregation: Combine repeated runs into confidence intervals, with no dependencies on the cluster side
  • Structured Logging: Console and file output at separate levels, with progress bars and colour output

Installation

The core package has no third-party dependencies. Specifically, the code path that runs on a cluster only depends on the standard library. Planning a sweep, running an array task, checking its status, sizing the array and computing a confidence interval all work on a node with nothing but Python on it. Everything that needs a library is a capability, installed as an extra:

pip install research-helpers[figures]   # matplotlib, seaborn
pip install research-helpers[latex]     # LaTeX table assembly and rendering (stdlib only)
pip install research-helpers[log]       # structlog, colorama, tqdm
pip install research-helpers[sweep]     # pandas, pyarrow (planning, running, and intervals need neither)

Requires Python 3.11 or newer.

Quick Start

Wire up the project

A project's wiring—i.e., where the paper lives, how wide it is, where runs are written—goes in the [tool.research-helpers] section of the pyproject.toml file.

[tool.research-helpers.paper]
main = "tex/paper.tex"
tables-dir = "tex/tables"
figures-dir = "tex/figures"
text-width-pt = 468.0 # as reported by \showthe\textwidth

[tool.research-helpers.figures]
profile = "print"
palette = "colorblind"
dpi = 300

research-helpers doctor shows every setting, the value in force, and where it came from.

Keys and values are described in the configuration reference.

Generate a table from data

import json

from research_helpers.build import TABLES, Registry
from research_helpers.latex import half_up, header, table

tables = Registry(TABLES)


@tables.register('tab:scores')
def scores() -> str:
    """Accuracy on the held-out set."""
    data = json.loads(SCORES_PATH.read_text())
    return table(
        spec='lr',
        header_rows=[[header('System'), header('Accuracy')]],
        body_rows=[[name.title(), half_up(v['accuracy'] * 100)] for name, v in data.items()],
        caption='Accuracy on the held-out set.',
        label='tab:scores',
    )


if __name__ == '__main__':
    raise SystemExit(tables.main())

The label names the file, so this is written to scores.tex and the paper reads it with \input{tables/scores}:

$ python -m demo.tables --install
wrote build/tables/scores.tex
installed tex/tables/scores.tex

Check for drift

$ python -m demo.tables --check
OK: all 1 tables in the paper are current

If the data is changed without rebuilding, the check fails:

$ python -m demo.tables --check
stale, the paper is behind the data: tab:scores
to fix: rebuild and install the tables
$ echo $?
1

For a full example, see adding a generated table.

Style a figure for the page

import matplotlib.pyplot as plt

from research_helpers.figures import apply_style, save

apply_style(profile='print')  # \textwidth across, paper font sizes
fig, ax = plt.subplots()  # the profile's size is already in rcParams
ax.plot(iterations, accuracy, marker='o')
save(fig, 'tex/figures/learning-curve.png')

See details in the figures guide.

Run a parameter sweep

from research_helpers.sweep import Sweep

sweep = Sweep()


@sweep.context
def prepare(manifest, run_dir):
    """Loaded once per array task."""
    return load_corpus(manifest.metadata['corpus'])


@sweep.evaluate
def evaluate(params, corpus):
    """One parameter combination."""
    return {'f1': score(corpus, **params)}


if __name__ == '__main__':
    raise SystemExit(sweep.main())
$ python sweep_demo.py plan --config sweep.toml --run-dir runs/demo --tasks 4
planned 12 combinations over 4 array tasks (~3 per task)
manifest: runs/demo/manifest.json

submit with:
  sbatch --array=1-4 <your sbatch script> runs/demo

The manifest is written once and the tasks read it, so re-submitting the two that were killed reproduces exactly their original slices instead of repartitioning the grid. Resumption is per combination, not per task, so a job that hits its wall-time keeps everything it finished. status and run need only the standard library, so nothing needs to be installed to run a progress check from a login node.

Full details are discussed in the sweeps guide.

Package a submission

$ research-helpers arxiv --dry-run
  paper.tex                       43.1 KB
  paper.bbl                       82.1 KB
  tables/scores.tex                0.3 KB
  figures/learning-curve.png      66.3 KB

  4 files, 0.19 MB
  bbl format 3.3 (TeX Live 2025)

ready to upload: select xelatex and TeX Live 2025

(dry run, nothing written)

The target files are keyed by the path they take inside the submission, so what resolves locally will also resolve at the destination. The checks cover filenames arXiv rejects, a .bbl that is missing, stale, or in a format the selected TeX Live will not read, and microtype font expansion under an engine that has none. --tar packs it reproducibly, so re-packing an unchanged submission gives an identical file.

See the submission guide.

Logging

from research_helpers.log import get_logger, setup_logging

setup_logging()
log = get_logger(__name__)

log.info('scoring', corpus='perseus', sentences=18_000)
[INFO    ] 19:41:47 __main__ scoring (corpus=perseus, sentences=18000)

The console and the log file take separate levels, and other libraries' loggers are held at WARNING so their routine output stays out of both. Colour is applied only when the stream is a terminal, so no escape codes are included in a redirected log.

Details in the logging guide.

Documentation

The full documentation includes:

License

The project is licensed under the MIT License, allowing free use, modification, and distribution.

Metadata

Release files for research-helpers 1.4.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 research-helpers 1.4.0
File Size Uploaded Provenance
research_helpers-1.4.0.tar.gz 128.0 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for research-helpers 1.4.0
File Interpreter ABI Platform
research_helpers-1.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 217.5 kB

Release files / research_helpers-1.4.0.tar.gz

Download URL research_helpers-1.4.0.tar.gz
Size 128.0 kB
Tags Source
SHA-256 checksum
How to use checksums
ea0b63f5b4324be54171e683b2131c2828ea0ce643a6adc449c97966ef2177c8
BLAKE2b-256 checksum
How to use checksums
d83e5ea4166a8a8380e8b279e0c83170f2ad244e321b3991954007d84e14e868
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 23, 2026.

Transparency log

Release files / research_helpers-1.4.0-py3-none-any.whl

Download URL research_helpers-1.4.0-py3-none-any.whl
Size 89.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a4f307cc0b6525b3c52e3d55195b6c31d55406356e00f927a4dc56afec591ebe
BLAKE2b-256 checksum
How to use checksums
ea9243b9074d7907cb6ed725fb9ac0f84b88f72e6d701a115ac89e685ee9230b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 23, 2026.

Transparency log

Security for research-helpers 1.4.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 research_helpers-1.4.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 23, 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.

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