4 Executable content
Executable cells against a warm kernel: what a language label decides, how to set up Python, and how an output becomes a block.
A {python} cell runs against a warm Jupyter kernel; its outputs become their own
blocks tied to the cell’s id. Everything on this page is produced from its own .tmd
source.
4.1 Code cells
np.int64(10)
On save, only cells whose source changed (plus downstream cells) re-execute,
and the kernel never cold-starts. Point the server at a Python with ipykernel via
TALIESIN_PYTHON (one-time setup).
{js} cells run in the browser (Live, browser-side content)
and {mermaid} blocks render there as diagrams; a cell in any other language, or a
{python} cell with no kernel available, renders as highlighted source rather than
failing. The first cell of a session pays the interpreter’s own start-up (booting
Python and importing what the cell reaches for); every edit after that reuses the
kernel that boot produced.
Output streams into the preview as the cell produces it, beside a running-elapsed badge, so a training loop’s epoch lines appear as they are printed rather than all at once at the end. Progress bars that redraw with a carriage return (tqdm and friends) render as one updating line, not one line per frame.
If the kernel crashes mid-session, the server respawns it on the next run, and a wedged
cell is interrupted instead of locking up the kernel. The cap is on silence, not on
runtime: a cell that produces no output for TALIESIN_CELL_SILENCE seconds (default
600) is sent SIGINT, and the budget resets on every line the cell prints, so a long job
that reports progress runs to completion however long it takes. The dev menu’s
Restart kernel action drops the kernel, re-runs every cell against a fresh one, and
reloads so define values re-bind. See Troubleshooting
for the symptoms these answer.
4.1.1 echo, include, and cache: three different switches
These three boolean options look similar but control different stages:
| Option | Does the cell run? | Source shown? | Output shown? | Cached in _freeze/? |
|---|---|---|---|---|
| (defaults) | yes | yes | yes | yes |
#| echo: false | yes | no | yes | yes |
#| include: false | yes | no | no | yes |
#| cache: false | yes | yes | yes | never |
echo: false hides the source listing only, for when the reader should see a plot or a
table but not the code that made it.
include: false goes further and hides both source and output, but the cell
still executes (kernel state is kept), so a later cell still sees its variables.
This is the option for a setup cell whose result you never want to see but whose state
you need downstream, and a define(...) in it still reaches your {js} cells, since that
bridge is not output. If it fails, its traceback is hidden along with the rest of its
output, so the failure is reported as an error diagnostic at the cell instead, and it
fails build --strict. To skip execution entirely, run the whole document with
--no-exec / TALIESIN_NO_EXEC.
cache: false is orthogonal to both: the cell runs and shows normally, but its
output is never frozen, and everything downstream of it re-runs and is likewise
never cached (a downstream output follows from this cell’s value, which the
cache key cannot see: only its code).
#| include: false
#| cache: false
=
The _freeze/ key is built from cell code, every upstream cell’s code, and the
interpreter’s identity, so it cannot see anything a cell reads that
is not code: a data file, an environment variable, a URL it fetches, the clock, an
installed library you upgraded in place.
Edit data.csv without touching a line of Python and the numbers on the page will
not change, because the cache key has not changed. Mark any cell with an out-of-band
input #| cache: false, as above. The preview does not watch data files either, so a
cache: false cell re-runs on the next save of the .tmd, not when data.csv changes.
To force one fresh run without editing anything, use the dev-menu Restart
kernel or run with TALIESIN_NO_CACHE.
cache (and only cache) also exists as a document-wide default under the execute:
front-matter key, and a per-cell #| option always overrides it. See the
cell-options reference for the full option table
and the Configuration reference for execute:.
4.1.2 Captions: figures, listings, and tables
#| fig-cap: captions a cell’s output and numbers it as a figure; #| lst-cap: and
#| tbl-cap: do the same for a code listing and for a table the cell publishes. Pair
any of them with a matching #| label: fig-x / lst-x / tbl-x and the output is
cross-referenceable as @fig-x, @lst-x or @tbl-x from anywhere in the book. A
caption is inline Markdown, so *emphasis*, `code` and $x^2$ render in it the
same way whichever kind of cell carries it. An executed image is published with an empty
alt, since in a figure the caption describes it, so a cell whose output shows an image
and has no fig-cap draws a warning. The
cell-options reference has the
routing rules.
4.1.3 Publishing a table, rather than printing one
#| tbl-cap: captions whatever the cell publishes, and the shortest way to write a
table publishes something you did not mean. The page still builds and the lint stays
clean; the defect is visible only in the rendered output.
A bare df on its own line emits pandas’ own repr: a table tagged border="1" and
class="dataframe", a row-index column, and a <style scoped> block, which no browser
scopes, so it leaks to the whole page. Publish the markup yourself instead:
to_html(index=False, border=0) on a DataFrame, or any other HTML string handed to
display(HTML(…)), emits plain markup that the page’s own table styling reaches. Keep
the index when its labels carry meaning (a describe() table, where they name the
statistic) and drop it when it is a bare row number. Table 4.1 below is a hand-built
HTML string published that way.
=
=
+= f
| seed | mean | sd |
|---|---|---|
| 0 | -0.048 | 0.977 |
| 1 | -0.054 | 0.986 |
| 2 | -0.022 | 1.013 |
4.1.4 Folded code
#| code-fold: true collapses a listing behind a summary (label it with
code-summary), so long setup code stays out of the way until clicked, as
Listing 4.1 does:
Show the setup
=
=
(0.006, 0.998)
4.1.5 Writing a figure to disk
Inline {python} figures are themed for the web (Figure 4.1 below has a transparent
background and neutral grey axes that read on light and dark), but that theming
never touches global rcParams, so a plain fig.savefig("x.pdf") in a cell already
writes a clean, print-ready figure (black on white):
, =
;
A cell runs with its document’s directory as the working directory, so a relative path lands beside the source rather than wherever you launched Taliesin.
4.2 Live, browser-side content
{js} cells run in your browser rather than against the kernel. See
Interactive and explorable documents.