Making a research result rerunnable
A practical way to preserve the input, calculation, assumptions, and evidence behind a small numerical result.
A small numerical result can be difficult to reconstruct a month after it was made. Perhaps a plot showed a nearly straight response, and a fitted slope went into a draft. The calculation itself may have taken seconds. Yet the input file has since been renamed, a column was changed by hand, and the script depends on a library version that is no longer obvious. A rerun then becomes an exercise in guessing which choices mattered.
The example uses four synthetic rows of load in newtons and extension in millimetres. They are teaching values, not laboratory measurements or evidence about a material.
Decide what rerunning means
The National Academies uses reproducibility for obtaining consistent computational results from the same inputs, methods, code, and analysis conditions. Replicability means that studies addressing the same question, each with its own data, obtain consistent results (chapter 3 of its 2019 report). Collecting new data is a replication attempt; agreement determines whether it replicates the earlier result. Terminology varies across fields, so state which convention you use. Re-running this CSV calculation checks the computation with its inputs; it does not repeat the physical study.
A rerun can reveal that a program no longer starts, a dependency has changed, or the recorded input no longer produces the reported number. When a rerun fails, the documented command and environment help locate the break.
Before organizing files, write down the particular output to preserve. A result could mean a slope printed to the terminal, a table of fitted values, or a plotted line. If the figure includes a selection of rows, a transformation, or a normalization, those choices are part of the result even when the central calculation is only a few lines. A useful record says what output is under discussion and what inputs and conditions produced it.
Keep the input identifiable
Start with the original data as received or generated. Keep a copy that later processing will not overwrite, then write transformed or cleaned data separately. Wilson et al.'s practice recommendations include preserving original data and recording transformations. Sandve et al.'s guidance on reproducible computational research emphasizes tracking provenance and avoiding undocumented manual processing. Both offer practical recommendations; neither estimates productivity gains experimentally.
Save these rows as measurements.csv. The headers load_N and extension_mm identify the quantities and units. The values are invented for this example; a real CSV still needs a note describing its source, row selection, and missing-value convention.
load_N,extension_mm
0,0.0
1,2.1
2,3.9
3,6.2A small script can make the input assumptions visible. Python's CSV documentation describes csv.DictReader for reading records by header name. Converting fields explicitly to numbers makes a non-numeric or blank cell fail near the point where it is read. Values spelled nan or inf still parse as floating-point numbers; a real analysis needs a separate finite-value check. The analysis still needs a rule for whether that row is incomplete or invalid. Record the rule and any excluded row identifiers. Replacing blanks with zero changes the input and can change the fitted line.
Save the code as fit.py in the same folder as measurements.csv, then run it from that folder:
python fit.pyimport csv
x = []
y = []
with open("measurements.csv", newline="", encoding="utf-8") as source:
for row in csv.DictReader(source):
x.append(float(row["load_N"]))
y.append(float(row["extension_mm"]))
mean_x = sum(x) / len(x)
mean_y = sum(y) / len(y)
denominator = sum((value - mean_x) ** 2 for value in x)
if denominator == 0:
raise ValueError("The input values must vary to fit a slope.")
slope = sum((a - mean_x) * (b - mean_y)
for a, b in zip(x, y)) / denominator
intercept = mean_y - slope * mean_x
print(f"slope: {slope:.2f} mm/N")
print(f"intercept: {intercept:.2f} mm")This is an unweighted least-squares line fit using mean-centred sums. With these synthetic rows, the expected output is:
slope: 2.04 mm/N
intercept: -0.01 mmThe slope has units of millimetres per newton, which are units of compliance; a spring constant would have force-per-length units. The denominator check matters because the fit has no defined slope if every input value is identical. A real analysis may also need checks for empty data, missing values, duplicate records, or uncertainty weighting.
The format specifier .2f rounds the displayed values to two decimal places; the internal slope keeps more precision until printing. For a larger computation, decide whether an expected-output check compares displayed text or a full-precision value. State a numerical tolerance in the same units and explain why it suits the comparison. Then a small floating-point difference has a defined meaning rather than being silently ignored.
The two lists preserve row pairing: each x value remains matched with the y value from the same CSV row. The means locate the centers of the two lists. The numerator sums paired deviations from those centers, while the denominator sums squared deviations in x. Their ratio gives the least-squares slope when every row has equal weight. The intercept places that line through the two means. Reading these operations alongside the code helps reveal a swapped column or a change to the selected rows.
Record the choices around the calculation
The code does not answer every question raised by the result. Why is a straight line appropriate? Were all rows included? Does the intercept remain free, or was the fit constrained through zero? Did the plot show raw points, averages, or both? Were any values removed, and under what stated rule? Those choices can change what the slope means while leaving the same few lines of arithmetic intact.
A short README.md can answer these questions without becoming a second paper. It can identify the question, name measurements.csv, describe row selection and transformations, state the fitted relation, define the units, and give the command used to run the script. For a graph, record its axis labels, range, scale, and any smoothing or normalization. Those choices are part of the result even if they are absent from the fitting code.
The README.md should also state the range or conditions to which the result applies. This teaching fit summarizes only the four rows in the displayed file. For actual data, record a relevant operating range, temperature, sample, or selection rule.
If the pipeline modifies data, record each step and its output. For example, a rule to remove blank rows needs a definition of blankness and a note that the original file remains available. Spreadsheet edits can be part of the work, but unrecorded clicks are difficult to reproduce. Record a manual selection rule and its rationale before using the processed file as an input.
Check the bytes and the history
When an input file is important, a checksum can help identify it. A cryptographic hash function maps file bytes to a fixed-size digest. Python's hashlib documentation includes SHA-256. Saving a digest beside the file lets a later reader check whether its bytes match. A match says nothing about the data's accuracy or interpretation.
A short check calculates the digest:
import hashlib
with open("measurements.csv", "rb") as source:
digest = hashlib.sha256(source.read()).hexdigest()
print(digest)For a larger file, read fixed-size blocks instead of loading everything at once. Store the digest with the filename and known origin or version. If the file changes, record whether it was corrected, converted, or filtered, and retain the earlier version when it remains relevant.
Version control records file changes over time so earlier versions can be recovered and compared. Git's version-control guide explains this role. A commit identifier helps locate a tracked code version; it does not include an untracked input file, an uncommitted edit, or software installed on the computer. Pair the code revision with the identities of the data and the environment.
Describe the software environment honestly
A Python virtual environment separates a project's installed packages from packages used elsewhere in the same Python installation. The Python venv documentation shows creating one with python -m venv .venv. A library is reusable software that a program calls for work such as reading a format or fitting a model.
A virtual environment does not include the operating system or provide a portable copy of the full setup. Recreate it on the target computer. The pip command python -m pip freeze reports installed package versions in requirements.txt format. The pip documentation describes it as an inventory of installed packages, not a dependency solver; it may omit bootstrap tools depending on Python version. Record Python, operating-system, and native-library details separately.
The short example uses only Python's standard library. For a larger project, record the installation steps and package information. Hardware or numerical libraries can still shift low-order digits, so state a tolerance for the expected output instead of requiring identical digits on every machine.
Test the result outside the rerun
After a rerun, check whether the setup makes sense. For this fit, inspect the headers and confirm that the program uses load_N as x and extension_mm as y. Swapping columns changes the slope's units. Label a plot's axes consistently with the table. Checking a few rows by hand can catch a parsing or selection error that a clean program run would preserve.
Look at the points and residuals, the differences between each observed value and the fitted line. A pattern in those differences can show that a straight line summarizes the chosen points poorly, even when the program returns a slope. Compare the plotted points with the input rows and confirm that the same selection appears in both. These checks examine whether the computation matches the stated analysis; they do not replace domain-specific checks of the measurements or model.
Run the documented command in a fresh process from the stated folder. If the script relies on variables loaded interactively, selections held in memory, or an editor's hidden path, a clean run exposes that dependency. Record where generated tables or figures are written, and make sure the plotted file comes from the same input and code release as the reported fit.
Leave an archive someone can cite
An archive should bring together the exact code release, shareable data, README.md, software details, and a license that explains permitted reuse. Include a small output or figure when it helps identify the result, along with the command, relevant options, and tolerance for floating-point differences. If an input cannot be redistributed, describe its identity and access conditions and preserve the provenance that can be shared.
The command should work from a stated starting location, such as the project folder, and name any expected input paths. That detail matters when a script runs in an editor that silently sets its working directory. A person who unpacks the archive should be able to create the environment, place or locate the inputs, run the documented command, and compare the resulting output. If one step depends on a local file outside the archive, note the dependency.
Zenodo's DOI documentation explains that a DOI gives a persistent identifier and link for a published research-output record. It helps readers cite and find an archive; it is not scientific peer review. Include a descriptive title, accurate version, and material connecting the archived inputs to the reported output. Preserve the relationship between code versions so a citation identifies the release used.
For the hypothetical line fit, a handoff might contain measurements.csv, the fitting script, README.md, a short environment record, and the expected output with its numerical tolerance. The README.md would identify the synthetic values as teaching data. For actual research, the same set of questions applies: which file is the input, what operation was applied, which code version ran, what environment was used, what output should appear, and what independent check could catch a wrong assumption?
A rerunnable result can begin as a small folder that makes these connections explicit. Someone opening it should be able to identify the inputs, follow the documented command, and compare the result with the stated tolerance.
Sources
- Wilson et al., “Good enough practices in scientific computing”, PLOS Computational Biology, 22 June 2017.
- Sandve et al., “Ten Simple Rules for Reproducible Computational Research”, PLOS Computational Biology, 24 October 2013.
- National Academies, Reproducibility and Replicability in Science, chapter 3, publicly released 7 May 2019.
- Git maintainers, Pro Git, “About Version Control”, living documentation, accessed 29 October 2026.
- Python maintainers, venv, CSV, and hashlib documentation, accessed 29 October 2026.
- pip maintainers, pip freeze documentation, accessed 29 October 2026.
- Zenodo maintainers, DOI reservation documentation, accessed 29 October 2026.
