# Dynamic Documents for Open Science

A dynamic document is a single source file that mixes prose, live code, and the results of that code. When you rebuild the file, every number, table, and figure is regenerated from the raw data. By the end of this article you will be able to build one yourself, knit it to HTML, PDF, or Word, place it under version control, and check that another person can rerun it on their machine. Dynamic documents are the workhorse of reproducible research, which is the practice of making analyses re-executable rather than merely readable.

To follow the walkthrough you need three free tools on your computer: R (version 4.0 or newer), the RStudio desktop environment, and the knitr and rmarkdown packages. If you plan to produce PDF output, you will also need a LaTeX distribution, which the tinytex package installs automatically. A Git account on a hosting service such as GitHub or GitLab is optional but strongly recommended for the sharing step.

## What a Dynamic Document Actually Is

The idea comes from literate programming, an approach introduced by the computer scientist Donald Knuth in which a program and its human explanation are written together as one narrative. Applied to research, the narrative is your methods and results section, and the program is the analysis that generates your figures and statistics. The result is a report where nothing shown to the reader was typed by hand.

Nolan, Peng, and Lang described this style of "dynamic documents" for statistics more than a decade ago, arguing that a document that generates its own content is the natural unit of reproducible analysis [1]. Xie's book on the knitr engine remains the standard reference for how R implements the idea. The core mechanics are simple. You write a plain-text file. Prose sits in normal paragraphs. Code lives in fenced blocks called chunks. When you compile, a rendering engine runs every chunk, captures its printed output, tables, and plots, and interleaves those results with your prose in the final document.

Because the source file is plain text, it works with version control, diff tools, and text editors. Because the code runs at compile time, the final document can never drift from the data. This coupling is what makes dynamic documents for open science more than a formatting preference. It turns the manuscript itself into an executable record of the analysis.

## Why Open Science Needs This Approach

The traditional journal article grew out of correspondence-era letter writing, and Parkes argues that the format still limits transparency. Readers who want to test assumptions, run additional analyses, or combine the study data with other datasets are stuck with the published summary or with emailing authors for code and data, which often fails. A dynamic document answers that criticism directly. The published artifact includes the full chain from raw data to printed result, and a reader can change one line and see the effect immediately.

The scale of the reproducibility problem motivated tools like lpEdit, whose authors point to evidence that a surprising proportion of published experiments are difficult or impossible to reproduce, and who built an editor that lowers the barrier for scientists new to statistics and programming [3]. Institutions have moved the same logic into their core workflows. The Department of [Biostatistics](/blog/data-analysis/what-is-biostatistics) at the University of Zurich rolled out a literate programming approach for all original research and most consulting work for the medical faculty, combining the computational and narrative parts of a paper into one dynamic report, and now teaches the method to every student in its biostatistics master's program [4].

There is also a career and collaboration dividend. DeWitt and Bennett showed that literate programming combined with distributed version control lets a team with mixed data-access privileges coauthor documents while sensitive data stay on secure institutional drives. And the executable-paper movement pushes the idea to its limit, publishing the manuscript itself as a script that generates the paper, code, data, and results, as the Lepton system does.

## Dynamic Documents for Open Science Step by Step

This walkthrough uses R Markdown, the most widely used implementation. Every step has a concrete command and the expected result, so you can verify your progress as you go.

### Step 1: Install the toolchain

Download R from the Comprehensive R Archive Network (CRAN), then install RStudio Desktop. Open RStudio and run this in the console:

```r
install.packages(c("rmarkdown", "knitr", "tinytex"))
tinytex::install_tinytex()
```

The first command installs the rendering engine. The second installs a minimal LaTeX distribution used for PDF output. It downloads several hundred megabytes, so run it once and let it finish.

### Step 2: Create the source file

In RStudio, choose File, New File, R Markdown. A dialog asks for a title, an author, and an output format. Pick HTML for your first document because it needs no LaTeX. RStudio creates a template file with the extension `.Rmd` and populates it with a sample analysis you can knit immediately.

### Step 3: Write the header

The top of the file is a YAML header, a short block of metadata wrapped between lines containing three hyphens. The header controls the title, author, date, and output format. A realistic example:

```yaml
title: "Effect of two treatments on plant growth"
author: "Your Name"
date: "`r Sys.Date()`"
output:
  html_document:
    toc: true
    code_folding: show
```

The date line is inline R code, which means the document stamps the date it was rendered, not a date you typed weeks earlier. The `code_folding: show` option makes code visible by default in HTML output, which suits open science. To make PDF instead, change the output to `pdf_document`. To make a Word file for a coauthor who insists on one, use `word_document`.

### Step 4: Add prose and code chunks

Below the header, write your introduction as ordinary markdown text. Then insert a chunk with the RStudio keyboard shortcut Ctrl+Alt+I (Cmd+Option+I on macOS). A chunk opens with a header inside triple backticks, contains R code, and closes with another set of backticks.

This walkthrough uses PlantGrowth, a small built-in dataset of 30 plant weights in three groups of ten. The analysis goal is to compare group means and test the difference between the control and treatment two.

```r
`​``{r setup, include=FALSE}
knitr::opts_chunk$set(echo = TRUE)
`​``
```

```r
`​``{r load-data}
data(PlantGrowth)
`​``
```

```r
`​``{r group-means}
aggregate(weight ~ group, data = PlantGrowth, FUN = mean)
`​``
```

The curly braces after the first set of backticks hold the chunk label, followed by options. The setup chunk uses `include=FALSE` so the code runs but nothing is printed, which keeps boilerplate out of the report. Knitting produces this output for the group means:

```
  group weight
1  ctrl 5.0320
2  trt1 4.6610
3  trt2 5.5260
```

Now add the inferential step and a figure:

```r
`​``{r t-test}
t.test(weight ~ group, data = PlantGrowth,
       subset = group %in% c("ctrl", "trt2"))
`​``
```

```r
`​``{r boxplot}
boxplot(weight ~ group, data = PlantGrowth,
        col = "lightblue",
        ylab = "Dry weight (mg)",
        xlab = "Group")
`​``
```

The t-test chunk prints the t statistic, degrees of freedom, p value, and a 95 percent confidence interval for the difference between the two group means. The boxplot chunk saves a figure into the rendered document and, because `fig.path` defaults to a figures folder, also writes the image file to disk where you can reuse it.

### Step 5: Knit and inspect the output

Click the Knit button or run:

```r
rmarkdown::render("analysis.Rmd")
```

Knitr executes every chunk in order from top to bottom, then hands the assembled markdown to pandoc, a universal document converter, which writes the HTML, PDF, or Word file. Open the finished document and confirm three things: every figure appears, every number in the text was produced by a chunk, and the document ends with a session summary. Adding this chunk at the bottom makes the software environment explicit:

```r
`​``{r session}
sessionInfo()
`​``
```

The output lists your R version, operating system, locale, and every attached package with its version. A reader can compare this against their own environment when debugging a failed rerun.

### Step 6: Put the project under version control

Create a folder containing the `.Rmd` file, the raw data file, and nothing else. Then:

```bash
git init
git add analysis.Rmd data/plants.csv .gitignore
git commit -m "First reproducible report"
git remote add origin https://github.com/yourname/plantgrowth-report.git
git push -u origin main
```

Now every edit to the analysis has a timestamped record, collaborators can propose changes through pull requests, and the repository URL can go in the manuscript as a permanent link. DeWitt and Bennett's workflow extends this pattern to teams where some members cannot see the raw data at all. The data live on a secure institutional drive and the repository references them through a Git submodule, so code and prose are shared publicly while the sensitive files never leave the institution [5].

### Step 7: Test the rerun before you publish

Close RStudio, reopen it, and knit the document in a fresh session. If it renders correctly from a cold start, a stranger with the same packages can probably rerun it too. This single habit catches most reproducibility failures before a reviewer does.

## A Reproducibility Checklist for Dynamic Documents

Run through this list before you share a dynamic report. It condenses the practices that the reproducible research literature and tools like lpEdit and Markdoc emphasize: sharing data, leaving an audit trail, and documenting the analysis rigorously [3] [6].

1. The raw data are stored read-only and never overwritten by a script.
2. The document knits successfully in a freshly started R session.
3. Every number, table, and figure in the narrative comes from a code chunk, not from manual typing.
4. Chunks that hide their code with `echo=FALSE` are limited to setup tasks, not analysis steps.
5. Any simulation or resampling sets a seed with `set.seed()` so random results are identical on rerun.
6. All file paths are relative to the project folder, never absolute paths like `C:/Users/you/...`.
7. `sessionInfo()` output is recorded in the document or a separate file, and package versions are pinned where possible.
8. The dataset needed to knit the document is included or linked with access instructions.
9. The repository contains the source file, the data, and a short README explaining how to run the analysis.
10. Caches are cleared or committed alongside the document so stale cached results cannot mislead a reader.

## Common Mistakes and Limitations

![Five cards listing interactive sessions, absolute paths, hidden analysis, stale caches and edited exports.](/article-images/illustrations/dynamic-documents-open-science-common-mistakes.webp)

Beginners tend to make the same handful of errors. Each one below produces a specific failure you can recognize and fix.

**Relying on the interactive session.** Your script works because you ran lines by hand, in a particular order, with objects left in memory. When knitted, the document fails with the error `object 'x' not found`. The fix is to make every chunk self-sufficient. Each library call, data load, and variable definition belongs inside a chunk. Restart R and run all chunks before every submission.

**Using absolute file paths.** A path such as `/home/you/Desktop/project/data.csv` works on your machine and nowhere else. When a collaborator knits, they see `cannot open file ... No such file or directory`. Keep the data inside the project folder and reference it with a relative path.

**Hiding the analysis.** Setting `echo=FALSE` on analysis chunks produces a clean-looking report that defeats the purpose of the method. Parkes's whole argument is that manuscripts should present full code and dataset structure rather than summaries alone. Reserve hidden chunks for loading packages and housekeeping, and let readers see the actual analysis.

**Leaving caches in a broken state.** The `cache=TRUE` option saves chunk results so later knits are faster, but if you change the data or the code above the cached chunk, the stale result persists silently. Clear the cache whenever you change upstream code, or keep caching off for short analyses.

**Editing the exported file.** When you export to Word or PDF, resist the urge to fix a typo directly in the output. Markdoc, which exports Stata analyses to formats including PDF, `.docx`, and `.odt`, exists precisely so the typeset document is a build product, and any manual edit will be lost on the next render and can silently diverge from the analysis [6]. Always fix the source.

**Assuming reproducible computing equals sound science.** A dynamic document guarantees that the printed results follow from the data and code. It does not guarantee that the design was appropriate, the measurements were valid, or the interpretation is correct. The Zurich group makes this point in practice by pairing their reproducible reporting workflow with teaching on research design and appropriate analysis [4].

**Committed sensitive data.** Pushing patient records or licensed data to a public repository is a serious error that is hard to undo. Use the submodule pattern described above so the public repository contains code and prose while restricted files stay behind institutional access controls.

## Practical Tips for Better Dynamic Documents

A few habits separate tidy, reusable projects from tangled ones.

**Name every chunk.** Labels such as `data-cleaning`, `model-fit`, and `figure-1` make warnings traceable, since errors report the chunk name.

**Parameterize reports.** If you produce the same report for many sites, batches, or years, use parameterized rendering so one source file generates all of them. Kane and colleagues formalize this idea, separating the components of a reproducible document that can be generated programmatically from the prose that requires a human author, and demonstrate it for clinical trial reporting with their listdown package. Their argument for efficiency carries over to any setting with repeated report structures.

**Automate recurring reporting.** In regulated settings, teams combine R Markdown with the Shiny web framework so clinical trial reports, tables, and figures update in real time as data arrive, reducing the manual transcription errors that plague traditional report preparation [7]. The same pattern works for routine lab or field reports.

**Get a fast feedback loop.** Haghish's weaver package for Stata builds a live log that renders as HTML or LaTeX in parallel with the analysis, giving a real-time preview of the document without recompiling everything, and supports figures, publication-ready dynamic tables, and math notation [8]. Whatever language you use, prefer tools that show you the rendered result quickly, because slow iteration is the main reason people abandon the workflow.

**Lower the barrier for your team.** Editors built for beginners, such as lpEdit, prove that templates and learning-by-example documentation shorten the path for researchers new to programming [3]. Write one polished example project for your lab and onboard colleagues with it.

**Pick the tool that matches your language.** R Markdown is the default for R, but the same idea spans ecosystems. Org-mode in Emacs lets one hierarchical plain-text file contain code in arbitrary programming languages, raw data, links, working notes, and publication text, with exports to LaTeX, HTML, beamer, and more. Stata users have markdoc, which recognizes Markdown, LaTeX, and HTML markup and exports to formats including PDF, `.docx`, `.odt`, and ePub [6]. Python users write the same style of documents in Markdown with live R or Python code, producing PDF, HTML, and Word output with the code properly formatted [9], an approach also used in teaching settings such as differential equations courses [9]. Even Microsoft Word has an option through the Analysis Manager tool, which generates dynamic documents for groups that must stay in Word [10].

## Frequently Asked Questions

### What is a dynamic document in open science?

It is a single source file that combines prose, live analysis code, and the code's output, so that the final report is regenerated automatically from the raw data. When a reader reruns the file, they reproduce every number and figure in it.

### Do I need to be a programmer to use dynamic documents?

You need basic scripting skills, not software engineering. If you can write a few lines of R or Python to compute a mean and draw a plot, you can write a dynamic document, and template-driven editors were designed specifically to reduce that learning burden.

### Which software supports dynamic documents?

R with knitr and R Markdown is the most common choice, Stata supports markdoc and weaver, Emacs Org-mode supports many languages in one file, and Python works through Markdown-based reports [6].

### How is a dynamic document different from a word processor file?

A word processor file stores a frozen snapshot of results that someone typed in by hand, so it can silently drift from the analysis. A dynamic document stores the instructions that produce the results, so the two can never disagree.

### How do I share a dynamic document with my published paper?

Publish the source file, the data, and a README in a version-controlled repository, and link the repository in your manuscript. Parkes demonstrated a full trial results paper written this way with the knitr, rmarkdown, and rticles packages, compiled to PDF, and the executable-paper model goes further by making the manuscript itself a runnable script.

### Can I use dynamic documents with restricted or sensitive data?

Yes, as long as the restricted data never enter the public repository. One documented workflow stores data on secure institutional drives, keeps code and prose in public Git repositories, and connects the two through Git submodules so collaborators with different access levels can still coauthor the document [5].

### Why does my document knit on my machine but fail for a collaborator?

![Decision path checking missing packages, absolute paths, missing data files and leftover session objects.](/article-images/illustrations/dynamic-documents-open-science-knit-fails-triage.webp)

The usual causes are missing packages, absolute file paths, data files left outside the project, and results that depended on objects in your interactive session. Include `sessionInfo()` output, use relative paths, ship the data with the code, and always test the document in a fresh session.

### Do journals accept dynamic documents?

Many accept them as supplementary material and a growing number publish executable papers. Medical journals in the BMJ evidence-based medicine community have showcased fully transparent trial manuscripts built with literate programming [2], and reproducibility evaluations now formally reward published artifacts that can be rerun and reused [11].

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@type": "FAQPage",
  "mainEntity": [
    {
      "@type": "Question",
      "name": "What is a dynamic document in open science?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "It is a single source file that combines prose, live analysis code, and the code's output, so the final report is regenerated automatically from the raw data. When a reader reruns the file, they reproduce every number and figure in it."
      }
    },
    {
      "@type": "Question",
      "name": "Do I need to be a programmer to use dynamic documents?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "You need basic scripting skills, not software engineering. If you can write a few lines of R or Python to compute a mean and draw a plot, you can write a dynamic document, and template-driven editors were designed specifically to reduce that learning burden."
      }
    },
    {
      "@type": "Question",
      "name": "Which software supports dynamic documents?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "R with knitr and R Markdown is the most common choice, Stata supports markdoc and weaver, Emacs Org-mode supports many languages in one file, and Python works through Markdown-based reports."
      }
    },
    {
      "@type": "Question",
      "name": "How is a dynamic document different from a word processor file?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "A word processor file stores a frozen snapshot of results that someone typed in by hand, so it can silently drift from the analysis. A dynamic document stores the instructions that produce the results, so the two can never disagree."
      }
    },
    {
      "@type": "Question",
      "name": "How do I share a dynamic document with my published paper?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Publish the source file, the data, and a README in a version-controlled repository, and link the repository in your manuscript. Trial results papers have been demonstrated this way with the knitr, rmarkdown, and rticles packages, and the executable-paper model goes further by making the manuscript itself a runnable script."
      }
    },
    {
      "@type": "Question",
      "name": "Can I use dynamic documents with restricted or sensitive data?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Yes, as long as the restricted data never enter the public repository. One documented workflow stores data on secure institutional drives, keeps code and prose in public Git repositories, and connects the two through Git submodules so collaborators with different access levels can still coauthor the document."
      }
    },
    {
      "@type": "Question",
      "name": "Why does my document knit on my machine but fail for a collaborator?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "The usual causes are missing packages, absolute file paths, data files left outside the project, and results that depended on objects in your interactive session. Include sessionInfo() output, use relative paths, ship the data with the code, and always test the document in a fresh session."
      }
    },
    {
      "@type": "Question",
      "name": "Do journals accept dynamic documents?",
      "acceptedAnswer": {
        "@type": "Answer",
        "text": "Many accept them as supplementary material and a growing number publish executable papers. Medical journals have showcased fully transparent trial manuscripts built with literate programming, and reproducibility evaluations now formally reward published artifacts that can be rerun and reused."
      }
    }
  ]
}
</script>

## Sources

1. [Enhanced Dynamic Documents for Reproducible Research](https://doi.org/10.1007/978-1-4419-5714-6_20)
2. [7 Papers as living documents: using literate programming to produce fully transparent, reproducible research manuscripts](https://doi.org/10.1136/bmjebm-2019-EBMLive.7)
3. [lpEdit: an editor to facilitate reproducible analysis via literate programming](https://doi.org/10.25080/MAJORA-8B375195-00E)
4. [The Center for Reproducible Science at the University of Zurich](https://doi.org/10.35430/jrn.2.2021.1727)
5. [Collaborative Reproducible Reporting - Git Submodules as a Data Security Solution](https://doi.org/10.5220/0006109302300235)
6. [Markdoc: Literate Programming in Stata](https://doi.org/10.1177/1536867X1601600409)
7. [Automating Clinical Trial Reporting with R Markdown and R Shiny](https://doi.org/10.36948/ijfmr.2024.v06i03.23809)
8. [Rethinking Literate Programming in Statistics](https://doi.org/10.1177/1536867X1601600408)
9. [Creating Dynamic Documents with R and Python as a Computational and Visualization Tool for Teaching Differential Equations](https://doi.org/10.1080/10511970.2018.1472161)
10. [Analysis Manager: A Reproducible Research Tool for Generating Dynamic Documents using Microsoft Word](https://www.semanticscholar.org/paper/f7cd34abf24bba84abc22168e332a1b6eb9f7b10)
11. [Reproducibility Report for the Paper: “DESL: A Literate Programming Language Framework for Interoperable Parallel Discrete Event Simulation”](https://doi.org/10.1145/3726301.3734837)