Research Helpers
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.
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
- 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
- Structured Logging: Console and file output at separate levels, with progress bars and colour output
Installation
The core package has no third-party dependencies. Capabilities are installed as extras:
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 and running 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 walltime 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. 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:
- Configuration: Every section, key, type, and default, plus units and settings resolution
- Guides: Task-focused walkthroughs
- Adding a generated table: Full table pipeline
- Figures: Profiles, scoped styling, saving versus rendering
- LaTeX tables: Assembling tables and reading them back
- Parameter sweeps: Planning, running, resuming, and collecting
- arXiv and Zenodo: Submission checks and reproducible archives
- Logging: Setup, levels, colour, and progress bars
- API Reference: Complete API documentation
License
The project is licensed under the MIT License, allowing free use, modification, and distribution.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file research_helpers-1.0.0.tar.gz.
File metadata
- Download URL: research_helpers-1.0.0.tar.gz
- Upload date:
- Size: 72.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f9a18b86a3b131014315950bb56ad9850a785ed4159ba88a060b83f9e9d32a7
|
|
| MD5 |
f52a2c838a8d9d0def6fe15988d09c85
|
|
| BLAKE2b-256 |
1a83d29cd4e34016be0c2d3ec0227219db3c162a9c4fc173f7073acc259be487
|
Provenance
The following attestation bundles were made for research_helpers-1.0.0.tar.gz:
Publisher:
publish.yml on gpizzorno/research-helpers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
research_helpers-1.0.0.tar.gz -
Subject digest:
1f9a18b86a3b131014315950bb56ad9850a785ed4159ba88a060b83f9e9d32a7 - Sigstore transparency entry: 2799593505
- Sigstore integration time:
-
Permalink:
gpizzorno/research-helpers@2724dce38a7dc704df252482e0dffff81f13e45c -
Branch / Tag:
refs/heads/main - Owner: https://github.com/gpizzorno
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2724dce38a7dc704df252482e0dffff81f13e45c -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file research_helpers-1.0.0-py3-none-any.whl.
File metadata
- Download URL: research_helpers-1.0.0-py3-none-any.whl
- Upload date:
- Size: 52.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
78f81928533e6b45d8a8be81b73ea1372dac26dd9307b8b6bb4bc6858286e90f
|
|
| MD5 |
f38e252b6374ac36837b8fd88293d309
|
|
| BLAKE2b-256 |
5ecf5307a66d104ed5948868eb6d28755f58bd5abec9f4790721818a950418e3
|
Provenance
The following attestation bundles were made for research_helpers-1.0.0-py3-none-any.whl:
Publisher:
publish.yml on gpizzorno/research-helpers
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
research_helpers-1.0.0-py3-none-any.whl -
Subject digest:
78f81928533e6b45d8a8be81b73ea1372dac26dd9307b8b6bb4bc6858286e90f - Sigstore transparency entry: 2799593580
- Sigstore integration time:
-
Permalink:
gpizzorno/research-helpers@2724dce38a7dc704df252482e0dffff81f13e45c -
Branch / Tag:
refs/heads/main - Owner: https://github.com/gpizzorno
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@2724dce38a7dc704df252482e0dffff81f13e45c -
Trigger Event:
workflow_dispatch
-
Statement type: