macros.qmd is consumed raw across four different paths, and no comment
syntax works in all of them:
| Path | How macros.qmd is used |
% comment |
<!-- --> comment |
|---|---|---|---|
macros-table.qmd (MathJax embed + searchable table) |
parsed line-by-line in R | breaks (only <!-- is stripped; a % line is appended to and corrupts the preceding definition) |
stripped, OK |
macros-header.html loader (HTML / RevealJS) |
parsed line-by-line in JS | skipped, OK | skipped, OK |
include-in-header: macros.qmd (PDF) |
inserted raw into the LaTeX preamble | OK (LaTeX comment) | breaks (Missing \begin{document}) |
{{< include macros.qmd >}} shortcode (PDF) |
included as markdown body, run through pandoc | breaks (Missing $; pandoc emits the prose + stray \commands) |
OK (pandoc drops it) |
Because no comment style is safe in every column (% breaks the R parser and
the shortcode PDF; <!-- --> breaks the include-in-header PDF), the only
safe choice is no comments at all. Keep macros.qmd as a flat list of
\def / \providecommand definitions. Put any explanatory notes here instead.
When you add a new estimand macro group (probability, risk, odds, rate,
hazard, ratio/factor types, …) near the top of macros.qmd, add the matching
estimator (hat-wrapped) versions in the estimator section at the bottom,
following these rules:
- Zero-arg:
\def\hfoo{\hat{\foo}} - One-arg function:
\providecommand{\hfoof}[1]{\hfoo\paren{#1}} - One
\defalias per estimand alias, pointing at the canonical estimator:\def\hfooalias{\hfoo}(zero-arg) and\def\hfoofalias{\hfoof}(function form). For example,\risk/\prevare estimand aliases of\prob, so\hrisk/\hprevare defined as\def\hrisk{\hprob}/\def\hprev{\hprob}. - Add an entry for every new macro to
interpretations.tsv— themacros-table.qmdbuild fails if any macro is missing an interpretation.
See issue #58 for background and motivation on the estimator macros.
\hfoo-style macros (e.g. \hb, \hsurv, \hhazratio) are the legacy
estimator family: they apply the hat accent directly (\hat{...} /
\widehat{...}), frozen for backward compatibility. Do not rename or
remove them.
\efoo-style macros are the parallel, forward-looking family: same
estimators, but composed through the indirection macros \est{#1}
(\hat{#1}) and \Est{#1} (\widehat{#1}) instead of applying the accent
directly. If the estimator symbol ever changes, only \est/\Est need to
change — every \efoo macro picks it up automatically, while the \hfoo
family stays pinned to \hat/\widehat forever.
When adding a new estimator macro group, define both:
- Legacy (
\h...): as above —\hat{...}/\widehat{...}directly. - Forward-looking (
\e...): the same macro name with the leadinghreplaced bye, composed through\est/\Estinstead of\hat/\widehat. Use\estfor macros that used\hat(single symbols/short expressions) and\Estfor macros that used\widehat(operatorname-wrapped multi-letter symbols, e.g.Var,Cov,SD,SE) — mirror whichever width the original\h...macro chose. Alias chains mirror too: if\def\hfooalias{\hfoo}, then\def\efooalias{\efoo}. - Add an
interpretations.tsventry for every new\e...macro too (same rule as above).
See issue #75's follow-up discussion for background on this split.
A script after a delimiter macro attaches to the empty \mathclose{} atom.
The delimiter macros are the ones whose body ends in \mathclose{},
such as \paren, \sb, \cb, \angb, \abs, \norm, \floor, \ceiling and \cbmat.
An exponent then does not rise over a tall argument
(macros#147).
Wrap the whole body in one extra pair of braces:
\providecommand{\Pf}[1]{{\P \paren{#1}}}.
python3 tools/check_latex.py fails on a definition
(\providecommand, \renewcommand, \newcommand, \def, \gdef or \DeclareRobustCommand)
whose body ends in a delimiter group and is not wrapped.
It also fails, because it cannot read them, on \NewDocumentCommand and the other xparse definition commands,
and on a definition whose body brace is never closed.
It also fails when a script (^, _ or ') follows a delimiter group at any depth of a body,
and when a zero-argument alias such as \def\set{\cb} names a delimiter macro,
because the alias passes its argument on and so cannot be braced.
Give the alias an argument instead: \providecommand{\set}[1]{{\cb{#1}}}.
Whenever you add, rename, remove or change the output of a macro in macros.qmd,
update notation-choices.qmd in the same pull request.
Each entry there states our convention, the reasons for it, and the other conventions readers will meet in other sources.
If the page is already accurate after your change, add the no-notation-change label.
Then explain in the pull request description why the page needs no change.
CI will fail a pull request that changes macros.qmd without changing notation-choices.qmd
once two things have happened:
Morrison-Lab/gha has published its check-paired-file-change check in the v3 tag,
and a caller workflow for it is added here (#248).
Until then nothing catches the omission, so check it yourself.
Render the site and both demos to make sure nothing broke across the four consumption paths above:
quarto render # whole site (HTML)
quarto render demo-include-in-header.qmd --to pdf
quarto render demo-shortcode.qmd --to pdf