Template - Methods and Results Notebook

How to use this

You are going to build five small files. Each one is tiny and does exactly one job. Copy them in the order below, swap in your own variables and analyses, and then render report.qmd. Out comes a Word document in which every number is produced by your code — so when your data changes, you re-render and everything updates itself. Nothing is ever typed by hand.

This is the workflow from the post "Make Your Analysis Reproducible: A Document That Updates Itself" — prefilled, so you don't start from a blank file.

One rule to hold onto as you read: your .qmd is a document, not a script. The prose reads like a real Methods and Results section; the code chunks just source() the scripts that do the work. Keep the analysis in the scripts and the writing in the document.

The map

my-report/
├─ report.qmd          ← THE file you render (your writing + hidden code)
├─ setup.R             ← loads your packages
├─ R/│   ├─ prepare_data.R  ← load → clean → (impute) → one tidy dataset
│   ├─ analysis.R      ← run your tests, SAVE each result
│   └─ apa.R           ← helpers that format results the APA way
└─ data/    
└─ data.csv            ← your data

① setup.R 

You add packages to this file when you need them

# The only place you load packages.
library(dplyr)       # cleaning
library(mice)        # imputation (optional)
library(broom)       # tidy model results
library(flextable)   # tables that render straight to Word

② R/prepare_data.R 

This is where you do anything related to cleaning data.

# 1. Load
raw <- read.csv("data/data.csv")

# 2. Clean — keep only what you need
df <- raw |>  select(outcome, predictor, group) |>  mutate(across(everything(), as.numeric))

# 3. Impute missing values (optional — delete these lines if you don't need it)
df <- mice(df, m = 5, printFlag = FALSE) |> complete(1)

# => df is now clean and ready.

Build the files (2 of 2)

③ R/analysis.R — run the tests, save the results

model  <- lm(outcome ~ predictor, data = df)   # Notes on choice can be placed here
t_test <- t.test(outcome ~ group, data = df)   # References can also be placed here

④ R/apa.R — format results the APA way

Reusable helpers, so every result looks consistent everywhere it appears.

# Inline sentence, e.g. "R² = .42, F(2, 97) = 12.30, p = .001"

apa_fit <- function(m) {
  g <- broom::glance(m)
  sprintf("R² = %.2f, F(%.0f, %.0f) = %.2f, p = %.3f",
    g$r.squared, g$df, g$df.residual, g$statistic, g$p.value)
    }
    
# A clean Word table from any model
apa_table <- function(m) {
flextable(broom::tidy(m)) |> autofit()
}

The main file

⑤ report.qmd — the document that ties it all together

---
title: "Methods & Results"
format: docx
execute:
  echo: false       # hide all code  
  warning: false    # hide all warnings
  message: false    # hide all messages
---

```{r}
#| include: false
source("setup.R")
source("R/prepare_data.R")   # -> df
source("R/apa.R")            # -> apa_fit(), apa_table()
```

# Methods
A linear regression predicted the outcome from the predictor.

```{r}
#| include: false
source("R/analysis.R")       # -> model (saved, not printed)
```

# Results
The model explained the outcome, `r apa_fit(model)`.

```{r}
apa_table(model)             # the only line that prints
```

That's the whole thing. Render report.qmd and you get a Word document with your Methods and Results, the statistics woven into the prose by apa_fit(), and a formatted table from apa_table(). Change the data in data/data.csv, render again, and every number updates on its own.