Preceptor Table | ||||||
---|---|---|---|---|---|---|
Unit/Time
|
Potential Outcomes
|
Treatment
|
Covariates
|
|||
Senator | Session Year | Support Bill | Oppose Bill | Lobbying Contact | Senator Age | More |
… | … | … | … | … | … | … |
… | … | … | … | … | … | … |
… | … | … | … | … | … | … |
… | … | … | … | … | … | … |
Overview
This vignette introduces the make_p_tables()
function in the primer.tutorials
package, which inserts a three-chunk Quarto-ready template into your open document for creating Preceptor Tables and Population Tables.
These tables are designed to support both causal and predictive modeling workflows by clearly labeling variables with spanners and encouraging detailed documentation via footnotes.
What Are Preceptor and Population Tables?
Preceptor Tables and Population Tables help represent structured information about observational units, treatment status, potential or predicted outcomes, and covariates in a standardized format. They are especially useful in modeling workflows, particularly in education or social science contexts where modeling assumptions must be made transparent.
This format draws inspiration from the Cardinal Virtues article, and aims to make tables interpretable in isolation by including both clear labeling and explanatory footnotes.
Preceptor Table
A Preceptor Table contains hypothetical or expected outcomes for units (such as students or senators). It often includes unknowns (denoted by "..."
) where real data is not yet available, and reflects researcher or instructor expectations. The table automatically includes a blank third row and a “More” column for additional covariates.
Population Table
A Population Table contains a merged view of observed data (from the population) alongside preceptor-defined expectations. It includes an additional column Source
that distinguishes between actual data ("Data"
) and expectations ("Preceptor"
). The table follows an 11-row structure with proper spacing between data and preceptor sections.
Key Features
The output of make_p_tables()
includes:
- Editable footnotes for documentation
- An empty
tibble
for the Preceptor Table (p_tibble
) - An empty
tibble
for data input (d_tibble
) -
gt
code to render both tables with grouped column headers (“spanners”) - Automatic addition of missing rows and “More” column during rendering
- Column alignment in the tribble code for easier editing
Spanner Structure
Each table includes spanners for:
- Unit/Time (for the unit columns)
- Potential Outcomes (for causal models) or Outcome (for predictive models)
- Treatment (included only in causal models)
- Covariates (includes the covariate column and the “More” column)
Note: All table entries must be surrounded by double quotes, even for numeric values (e.g.,
"42"
).
The goal is to visually communicate which variables play which roles in your modeling. Each spanner groups columns of a shared type. Footnotes help document the rationale and context for each set of variables.
Package Requirements
It automatically constructs code using these libraries:
Running make_p_tables()
Preceptor and Population Tables are inserted together. The Population Table includes a "Source"
column as its first column (controlled by the source_col
argument), which takes values "Data"
or "Preceptor"
depending on origin. This structure encourages comparison between expected and observed values.
Behind the scenes, these tables are generated using tibble::tribble()
for easier manual editing by row. The tribble code is formatted with aligned columns to help authors maintain visual structure while editing.
When you run primer.tutorials::make_p_tables()
without any argument values, you’ll get an error because the function requires specific labels to create the template.
Understanding the Function Arguments
The make_p_tables()
function takes a set of user-defined labels and options that control how the Preceptor and Population tables are built and displayed. Each argument serves a clear conceptual role and is used to populate column headers, spanner labels, and the default content in tibble::tribble()
calls. Here is a detailed breakdown:
- We use the term “label” rather than “vars” to indicate that these are the labels in the table rather than the variable names from the data. As such, they are often human-readable phrases with spaces, like “Math Score if in Small Class”. These descriptions should be concise but meaningful.
type
(Character)
- Set to
"causal"
to generate a causal table structure, which includes:- Multiple columns for Potential Outcomes (specified in
outcome_label
). - A Treatment column representing an intervention or assigned condition.
- Multiple columns for Potential Outcomes (specified in
- Set to
"predictive"
for a predictive model:- Includes outcome columns as specified in
outcome_label
. - Treatment column is still included but represents the predictor variable.
- Includes outcome columns as specified in
- This determines not only what variables appear in the tables, but also how they are spanned and labeled in the rendered
gt
tables.
unit_label
(Character vector of length 2)
- Human-readable names for the unit of analysis — e.g.,
c("Senator", "Session Year")
orc("Student", "Grade Level")
. - These will appear as the first two columns and are grouped under the
"Unit/Time"
spanner. - The labels should be capitalized and concise.
outcome_label
(Character vector)
- Describes the key outcomes being predicted or causally modeled.
- For causal models, typically includes multiple potential outcomes like
c("Support Bill", "Oppose Bill")
. - For predictive models, might be a single outcome like
c("Test Score")
. - Should be interpretable phrases that clearly describe the outcomes.
treatment_label
(Character)
- Label for the treatment/predictor column, such as
"Phone Call"
or"Tutoring Program"
. - Used to title the corresponding
gt::tab_spanner()
. - Required for both causal and predictive models.
covariate_label
(Character)
- Label for the main covariate column relevant to the analysis.
- This is grouped under the
"Covariates"
spanner along with the “More” column. - Should be a simple phrase like
"Age"
or"School Type"
.
source_col
(Logical, default TRUE)
- Controls whether the Population Table includes a
"Source"
column. - When
TRUE
, adds a column distinguishing between"Data"
and"Preceptor"
rows. - When
FALSE
, the Population Table omits the source column.
Each of these labels should be understood as descriptive display names, not as variable names from an existing dataset. The goal is clarity and interpretability for readers of the resulting Quarto document.
Understanding the Footnotes
Footnotes in these tables are not decorative — they are an essential part of documenting analytical intent. When you use make_p_tables()
, it generates editable placeholders for ten footnotes, five for each table. These can be filled in or deleted, and they appear in the rendered table using gt::tab_footnote()
.
Below is a guide to what each footnote is for:
Preceptor Table Footnotes
pre_title_footnote
: Explains the background or motivation for the expectations shown. Useful for describing who the preceptors are, when the expectations were made, or why these units were selected.pre_units_footnote
: Clarifies the definition of a “unit” in this context — e.g., “Each row represents a senator during the 2022 election.” Also helpful to include time span or location info if applicable.pre_outcome_footnote
: Documents why these potential outcomes are meaningful. May include a note on how they were estimated or what they signify.pre_treatment_footnote
: Defines what the treatment actually entails and how it is operationalized. For example, a phone call campaign, assignment to tutoring, or access to a program.pre_covariates_footnote
: Explains why the selected covariates were chosen and their role in forming expectations. Should also clarify the “More” column purpose.
Population Table Footnotes
pop_title_footnote
: Describes the purpose of the population table — usually to compare expected vs. observed outcomes, merged with preceptor rows.pop_units_footnote
: Defines what each unit represents in the population — e.g., “Each row represents an observed student or a preceptor-generated scenario.”pop_outcome_footnote
: Documents the source of outcome data. For example: “Outcomes observed from the 2022 voter file” or “Final grades from school records.”pop_treatment_footnote
: Explains how actual treatment status was observed or inferred. May differ from the assumptions made in the Preceptor Table.pop_covariates_footnote
: Describes where the covariate data comes from in the population table and whether it’s measured identically to the preceptor rows.
These footnotes ensure that both the data structure and the logic of your modeling assumptions are transparent to readers. They serve as a form of embedded documentation and can be styled or omitted as needed.
Examples
When you run:
make_p_tables(
type = "causal",
unit_label = c("Senator", "Session Year"),
outcome_label = c("Support Bill", "Oppose Bill"),
treatment_label = "Lobbying Contact",
covariate_label = "Senator Age"
)
The following chunks are inserted:
1. Footnotes and Data Setup
2. Preceptor Table
3. Population Table
Population Table | |||||||
---|---|---|---|---|---|---|---|
Unit/Time
|
Potential Outcomes
|
Treatment
|
Covariates
|
||||
Source | Senator | Session Year | Support Bill | Oppose Bill | Lobbying Contact | Senator Age | More |
… | … | … | … | … | … | … | … |
Data | … | … | … | … | … | … | … |
Data | … | … | … | … | … | … | … |
Data | … | … | … | … | … | … | … |
Data | … | … | … | … | … | … | … |
… | … | … | … | … | … | … | … |
Preceptor | … | … | … | … | … | … | … |
Preceptor | … | … | … | … | … | … | … |
Preceptor | … | … | … | … | … | … | … |
Preceptor | … | … | … | … | … | … | … |
… | … | … | … | … | … | … | … |
After filling in the tibbles and footnotes with actual data, you would see properly formatted tables with:
- Preceptor Table: 4 rows (3 content + 1 blank) with a “More” column
- Population Table: 11 rows with proper separation between data and preceptor sections
- Column alignment: Easy-to-edit tribble format with aligned columns
- Source labeling: Clear distinction between “Data” and “Preceptor” rows
Table Structure Details
Preceptor Table
- Uses
p_tibble
as input (3 rows of placeholders) - Automatically adds a blank third row and “More” column via
expand_input_tibble()
- Results in 4 total rows for the final table
Population Table
- Uses
d_tibble
for data input (3 rows of placeholders) - Creates 4 data rows (3 content + 1 blank in 3rd position)
- Uses the expanded preceptor table (4 rows)
- Combines into 11-row structure: blank + 4 data + blank + 4 preceptor + blank
- All rows are properly labeled in the Source column
Column Alignment
The tribble code is formatted with aligned columns to make editing easier: - Headers and values are padded to align vertically - Minimum column width accommodates the "..."
placeholder - Makes it easy to see which column you’re editing
Summary
The make_p_tables()
function simplifies the creation of interpretable, spanner-labeled tables for modeling workflows. It promotes clarity, transparency, and rigor by encouraging authors to:
- Replace placeholders with meaningful values
- Use proper formatting with double quotes around all entries
- Fill in footnotes with useful context
- Take advantage of the aligned column structure for easy editing
- Understand the automatic row and column additions during rendering
This workflow supports better modeling documentation and instructional design.
For more on how and why to use these tables, see:
- The Cardinal Virtues article from primer.tutorials