Markdown Interpolation
How to embed live Python or R values inside markdown cells using the {{ expression }} syntax.
Markdown interpolation lets you embed computed values directly in prose. Instead of hardcoding numbers or copy-pasting results, you write {{ expression }} in a markdown cell and InkRider evaluates it against the current session and inlines the result.
Basic Syntax
Use double curly braces around any Python (or R) expression:
The final total is {{ grand_total }} euros.
Revenue grew by {{ round(growth_rate * 100, 1) }}% year-over-year.
The dataset contains {{ df.shape[0] }} rows.
When the markdown cell is rendered:
- each
{{ expression }}is replaced with the string representation of the evaluated result Nonevalues render as an empty string- expressions that raise errors render as
[error: message]
Spacing inside the braces is optional, i.e., {{x}}, {{ x }}, and {{ x }} are all equivalent.
Language Directive
By default, InkRider evaluates expressions using the language configured in Application Settings. You can override this per-cell by placing a directive comment anywhere in the markdown cell:
<!-- interpolate: python -->
The result is {{ result }}.
<!-- interpolate: r -->
Mean value: {{ mean(values) }}
To disable interpolation for a specific cell regardless of the global setting:
<!-- interpolate: off -->
This cell renders {{ literally }} without evaluation.
none is an alias for off.
The directive comment is stripped from the rendered output, so it never appears in the document or the inserted text.
Priority
When InkRider resolves the effective language for a cell, it uses:
- Inline directive: the
<!-- interpolate: X -->comment in the cell source (takes precedence over everything else) - Cell metadata: the
inkrider.markdownInterpolationEnabledandmarkdownInterpolationDefaultLanguagefields in the cell's metadata - App-level default: the setting in Application Settings → Markdown
Escaping Expressions
To include a literal {{ expression }} in the output without evaluating it, prefix the expression with !:
Use {{ !{{ variable_name }} }} as the placeholder syntax.
This renders as:
Use {{ variable_name }} as the placeholder syntax.
The ! prefix is stripped; only the literal braces and expression text remain.
When Interpolation Runs
Interpolation expressions are evaluated as part of a separate lightweight execution step. They are not run alongside the cell's main code. The evaluation happens:
- when you manually trigger a cell render after running code cells
- automatically if InkRider detects that session variables have changed and the markdown cell is anchored to the document
The interpolation code is sent to the same kernel session that ran the preceding code cells, so it has access to all variables defined in that session.
Using Formatting in Expressions
Format values directly in the expression to control how they appear in the prose:
<!-- interpolate: python -->
Revenue: {{ f"${revenue:,.0f}" }}
Date: {{ report_date.strftime("%B %d, %Y") }}
Percentage: {{ f"{rate:.1%}" }}
This is more readable than building the formatted string in a code cell and storing it in a variable just for insertion.
Multi-Line Expressions
Expressions can span multiple lines inside the braces:
{{
total_sales
/ number_of_days
}}
The result is the same as a single-line expression. The multi-line form is just for readability when the expression is long.
Export Behavior
Markdown interpolation is designed to keep the notebook portable:
- Standard
.ipynbexport:{{ expression }}placeholders are preserved as-is in the exported file. Another Jupyter tool that opens the file sees the raw markdown source and will not attempt evaluation. The notebook stays valid Jupyter format. - Materialized export: InkRider can produce a snapshot of the notebook with all interpolation expressions already replaced by their last evaluated values. This is suitable for archiving or sharing a result document that others should read without re-running.
Practical Example
# Code cell
import pandas as pd
df = pd.read_csv("/jupyter/data/sales.csv")
total = df["amount"].sum()
top_product = df.groupby("product")["amount"].sum().idxmax()
report_month = "April 2026"
<!-- interpolate: python -->
## Sales Summary ({{ report_month }})
Total revenue this month was **{{ f"${total:,.2f}" }}**.
The best-performing product was **{{ top_product }}**,
accounting for {{ f"{df[df.product == top_product].amount.sum() / total:.1%}" }} of all sales.
When inserted into a Word document via an anchor, the rendered paragraph reads:
Sales Summary (April 2026)
Total revenue this month was $142,850.00. The best-performing product was Widget Pro, accounting for 38.4% of all sales.