Authoring von Rechen-Notebooks mit Org Babel
Org Babel verwandelt Emacs Org Mode in eine interaktive, mehrsprachige Rechen-Notebook-Umgebung. Wie Jupyter oder Mathematica verbindet Org Babel ausführbaren Code, live Berechnungsergebnisse, Grafiken, Tabellen und erzählenden Fließtext. Im Gegensatz zu JSON-basierten Notebooks sind Org-Notebooks reine Textdateien, menschenlesbar, nativ mit Git versionierbar und unterstützen die Mischung mehrerer Programmiersprachen in einem einzigen Dokument.
1. Kernarchitektur & Trennung der Belange
Jedes Org Babel-Notebook arbeitet über fünf verschiedene Belange, die durch Header-Argumente gesteuert werden. Die Vermischung dieser Belange ist die Hauptursache für Fehler in Org-Notebooks:
| Belang | Wichtige Header-Argumente | Was wird gesteuert |
|---|---|---|
| Ausführung | :session, :eval, :dir, :var, :cache | Wird der Block ausgeführt, in welchem Prozess, wo und mit welchen Eingaben? |
| Ergebnisse | :results (value vs output, Format, Typ, Handhabung) | Was wird von der Ausführung erfasst und wie wird es im Puffer dargestellt? |
| Export | :exports (code, results, both, none) | Was erscheint in exportierten Berichten (HTML, PDF, Markdown)? |
| Tangeln | :tangle, :shebang, :noweb | Was wird in eigenständige Quellcodedateien auf der Festplatte extrahiert? |
| Komposition | :var, #+CALL:, <<noweb>>, org-sbe | Wie speisen Blöcke Daten oder Code ineinander ein? |
2. Notebook-Struktur & Präambel-Einrichtung
Eine Org-Notebook-Datei (.org) beginnt mit Dokumentmetadaten und pufferweiten Standardeinstellungen, gefolgt von hierarchischen Überschriften, die Fließtext, mathematische Formeln und Codeblöcke enthalten.
2.1 Standard-Notebook-Präambel-Vorlage
#+TITLE: Rechnerische Analyse von Experiment X
#+AUTHOR: Jane Doe
#+DATE: [2025-05-18 Sun]
#+OPTIONS: toc:2 num:t ^:{}
#+STARTUP: overview hideblocks inlineimages
# Globale Babel-Standardwerte für alle Blöcke in diesem Puffer:
#+PROPERTY: header-args :eval yes :exports both :results drawer
# Sprachspezifische Standardwerte:
#+PROPERTY: header-args:python :session *py-analysis* :results value :exports both
#+PROPERTY: header-args:R :session *R-analysis* :results value :exports both
#+PROPERTY: header-args:sh :session none :results output :exports both
Wichtige Puffer-interne Einstellungen:
#+STARTUP: inlineimages: Zeigt generierte Plots/Bilder automatisch inline an, wenn Ergebnisse eingefügt oder der Puffer geöffnet wird.#+STARTUP: hideblocks: Startet mit gefalteten Codeblöcken, zeigt nur Fließtext und Ergebnisse für bessere Lesbarkeit.#+STARTUP: nohideblocks: Zeigt alle Codeblöcke erweitert an.#+PROPERTY: header-args ...: Pufferweite Standardwerte. Können mitheader-args+ergänzt werden.
2.2 Aktivieren von Sprachen in der Emacs-Konfiguration
Org aktiviert standardmäßig nur die Auswertung von Emacs Lisp. Alle anderen Sprachen müssen explizit in Ihrer Emacs-Konfiguration geladen werden:
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(python . t)
(R . t)
(shell . t)
(sqlite . t)
(gnuplot . t)
(C . t)))
Um interaktive Ausführungsbestätigungsdialoge für vertrauenswürdige Notebooks zu vermeiden:
;; nil erlaubt das Ausführen von Blöcken ohne Bestätigungsaufforderungen
(setq org-confirm-babel-evaluate nil)
3. Codeblock-Anatomie
#+NAME: <block_name>
#+HEADER: <zusätzliche_header_argumente>
#+BEGIN_SRC <sprache> <schalter> <header_argumente>
<rumpf>
#+END_SRC
#+NAME: <name>: Optionaler eindeutiger Bezeichner. Erforderlich, wenn der Block als Funktion referenziert, als Eingabe an einen anderen Block über:varübergeben oder über#+CALL:aufgerufen wird.<sprache>: Von Babel erkannter Bezeichner (python,R,sh,emacs-lisp,sqlite,sql,julia,calc,gnuplot, usw.).<schalter>: Optionale Schalter (z. B.-nfür Zeilennummerierung beim Export,-rzum Entfernen von Labels).<header_argumente>: Schlüssel-Wert-Paare, die Ausführung, Ergebnisse und Export steuern.#+HEADER:: Sekundäre Zeilen zur sauberen Angabe langer Listen von Header-Argumenten.
Inline-Codeblöcke
Zum Einbetten dynamisch berechneter Werte innerhalb eines Absatzes:
Die endgültig berechnete Genauigkeit betrug src_python[:session *py* :results value]{f"{acc * 100:.2f}%"}.
4. Header-Argumente Referenz
4.1 Sitzungsverwaltung: Interaktive Erkundung vs. Hermetische Reproduzierbarkeit
:session none(Standard): Wertet den Block in einem einmaligen externen Interpreter-Prozess aus. Hermetisch, sauber und vermeidet Zustandsverschmutzung, initialisiert aber Importe und Umgebung bei jedem Durchlauf neu.:session <name>: Wertet in einem persistenten Emacs-Inferior-REPL-Puffer aus (z. B.*py-analysis*).- Variablen, Funktionen und importierte Module bleiben über mehrere Blöcke mit demselben Sitzungsnamen hinweg erhalten.
- Unverzichtbar für große Datensätze, schwere Modellgewichte und explorative Workflows.
- Bewährte Vorgehensweise: Prototyp mit
:session <name>; für die endgültige Überprüfung starten Sie die Sitzung neu oder testen Sie kritische Abschnitte mit:session none, um die Reproduzierbarkeit zu gewährleisten.
4.2 Arbeitsverzeichnisse & Remote-Umgebungen
:dir /pfad/zum/projekt: Führt den Block im angegebenen Verzeichnis aus.:mkdirp yes: Erstellt das Zielverzeichnis, falls es noch nicht existiert.- Remote-Ausführung (TRAMP):
:dir /ssh:user@gpu-cluster:/workspace/dataführt den Block remote auf einem Server aus, während die Ausgabe in Ihrem lokalen Emacs-Puffer dargestellt wird.
4.3 Zwischenspeichern teurer Berechnungen
:cache yes: Berechnet einen SHA1-Hash des Blocktextes, der Eingaben und der:var-Parameter.- Wenn der Hash mit dem in der
#+RESULTS[hash]:-Zeile gespeicherten übereinstimmt, wird die Auswertung übersprungen und die zwischengespeicherten Ergebnisse werden beibehalten. - Nur für deterministische, reine Berechnungen ohne externe Seiteneffekte verwenden.
5. Ergebnisverarbeitung: Die Kritische Unterscheidung
Das :results-Argument akzeptiert bis zu vier orthogonale Komponenten:
:results [sammlung] [typ] [format] [behandlung]
5.1 Sammlung: Funktional (value) vs. Skript (output)
Das Verständnis dieses Unterschieds beseitigt 90% der Babel-Verwirrung:
| Sammelmodus | Was wird erfasst | Python-Verhalten | Shell-Verhalten |
|---|---|---|---|
:results value (Standard für Python, R, elisp) | Rückgabewert des letzten Ausdrucks oder explizites return. | Muss eine explizite return <val>-Anweisung verwenden. Alle print()-Ausgaben werden verworfen. | Gibt den Exit-Code oder String-Wert zurück. |
:results output (Standard für Shell, Bash) | Stdout-Strom, der während der Ausführung erzeugt wird. | Erfasst alle print()-Anweisungen. Jegliches return wird ignoriert. | Erfasst alle Befehls-Stdout-Ausgaben (echo, ls, usw.). |
Python Funktionales Beispiel (:results value):
#+BEGIN_SRC python :results value
daten = [1, 2, 3, 4]
# Im funktionalen Modus ist ein explizites return in Python ERFORDERLICH:
return sum(daten)
#+END_SRC
#+RESULTS:
: 10
Python Skript-Beispiel (:results output):
#+BEGIN_SRC python :results output
for i in range(3):
print(f"Epoche {i}: verlust={0.5/(i+1):.4f}")
#+END_SRC
#+RESULTS:
: Epoche 0: verlust=0.5000
: Epoche 1: verlust=0.2500
: Epoche 2: verlust=0.1667
5.2 Ergebnistypen
table/vector: Formatiert zurückgegebene Listen/Arrays als Org Mode-Tabelle.scalar/verbatim: Formatiert Ausgabe als rohen, zitierten Text ohne Tabellenformatierung.file: Leitet die Ausgabe in eine Datei auf der Festplatte um (angegeben mit:file <dateiname>) und fügt einen Org-Dateilink in die Ergebnisse ein.
5.3 Ergebnisformate
drawer(Empfohlen): Umschließt Ergebnisse mit:RESULTS:…:END:-Begrenzern. Hält Dokumente ordentlich, insbesondere bei mehrzeiligen Ausgaben.raw: Fügt die Ausgabe direkt als unescapten Org-Text ein (nützlich zum Generieren dynamischer Überschriften oder Tabellen).code: Umschließt die Ausgabe mit#+BEGIN_SRC <lang>…#+END_SRC.link/graphics: Behandelt das Ergebnis als Pfad zu einem Bild/einer Datei und generiert[[file:pfad]].
5.4 Behandlung
replace(Standard): Ersetzt den vorherigen#+RESULTS:-Block.append: Fügt neue Ergebnisse unterhalb vorhandener Ergebnisse an.prepend: Fügt neue Ergebnisse oberhalb vorhandener Ergebnisse ein.silent: Zeigt Ergebnisse im Emacs-Echo-Bereich / Minibuffer an, ohne sie in den Org-Puffer zu schreiben.
6. Visualisierungen & Grafiken in Notebooks
Zum Erzeugen von Plots und Grafiken, die direkt im Notebook dargestellt werden:
6.1 Python Matplotlib-Plot
#+NAME: plot-normalverteilung
#+BEGIN_SRC python :session *py-vis* :results graphics file :file figures/normal_verteilung.png :exports both
import matplotlib.pyplot as plt
import numpy as np
plt.figure(figsize=(6, 3.5))
x = np.linspace(-3, 3, 200)
plt.plot(x, np.exp(-x**2 / 2) / np.sqrt(2 * np.pi), color="#2b5c8f", lw=2)
plt.title("Standardnormalverteilung")
plt.xlabel("z")
plt.ylabel("Dichte")
plt.tight_layout()
plt.savefig("figures/normal_verteilung.png", dpi=150)
plt.close()
#+END_SRC
#+RESULTS: plot-normalverteilung
[[file:figures/normal_verteilung.png]]
6.2 R ggplot2-Plot
#+NAME: r-streuungsdiagramm
#+BEGIN_SRC R :session *r-vis* :results graphics file :file figures/r_streuung.png :exports both
library(ggplot2)
p <- ggplot(mtcars, aes(x=wt, y=mpg, color=factor(cyl))) +
geom_point(size=3) +
theme_minimal() +
labs(title="Kraftstoffeffizienz vs. Gewicht", x="Gewicht (1000 lbs)", y="MPG")
ggsave("figures/r_streuung.png", plot=p, width=6, height=4, dpi=150)
#+END_SRC
#+RESULTS: r-streuungsdiagramm
[[file:figures/r_streuung.png]]
Tipp: Führen Sie M-x org-toggle-inline-images (C-c C-x C-v) in Emacs aus, um die Anzeige generierter Grafiken direkt im Puffer ein- und auszuschalten.
7. Interaktive Ausführung & Bearbeitungsworkflow
Wichtige Tastenkombinationen
| Tastenkombination | Befehl | Beschreibung |
|---|---|---|
C-c C-c | org-babel-execute-src-block | Führt den Block unter dem Cursor aus und fügt Ergebnisse ein/aktualisiert sie. |
C-c ' | org-edit-special | Öffnet den Blockrumpf in einem dedizierten Major-Mode-Puffer (volles LSP, Syntaxhervorhebung, Autovervollständigung). Drücken Sie erneut C-c ', um zu speichern und zurückzukehren. |
C-c C-v b | org-babel-execute-buffer | Führt alle Codeblöcke im Notebook nacheinander aus (wie „Alle Zellen ausführen"). |
C-c C-v s | org-babel-execute-subtree | Führt alle Codeblöcke unter der aktuellen Überschrift aus. |
C-c C-o | org-open-at-point | Öffnet bei einem #+RESULTS:-Link das Bild oder die generierte Datei in einem externen Betrachter oder Puffer. |
M-<down> | org-babel-pop-to-session | Wechselt den Fokus direkt zum interaktiven REPL-Puffer für die Sitzung dieses Blocks. |
C-c C-v v | org-babel-expand-src-block | Zeigt eine Vorschau des vollständig erweiterten Blocks (mit allen aufgelösten :var- und Noweb-Erweiterungen). |
8. Exportieren & Veröffentlichen von Berichten
Ein Notebook kann in eigenständige HTML-, PDF- oder Markdown-Dokumente verwoben werden.
8.1 Steuern des Exportinhalts mit :exports
:exports code: Exportiert nur den Codeblock.:exports results: Exportiert nur die Ausgabe/Grafik (versteckt den Code, ideal für Führungsberichte).:exports both: Exportiert sowohl Code als auch Ausgabe (ideal für technische Dokumentation).:exports none: Versteckt sowohl Code als auch Ergebnisse im exportierten Dokument (wird bei Bedarf während der Auswertung ausgeführt).
8.2 Steuern der Exportauswertung mit :eval
:eval never-export: Verhindert das erneute Ausführen von Blöcken während des Exports und verwendet die vorhandenen#+RESULTS:im Puffer. Beschleunigt den Export und verhindert nicht-deterministische Änderungen.:eval query-export: Fordert vor der Ausführung während des Exports zur Bestätigung auf.
8.3 Exportbefehle
C-c C-e h h(org-html-export-to-html): Erzeugt einen HTML-Bericht.C-c C-e h o(org-html-export-to-html-and-open): Erzeugt HTML und öffnet es im Browser.C-c C-e l p(org-latex-export-to-pdf): Erzeugt einen gesetzten PDF-Bericht über LaTeX.
9. Häufige Fallstricke & Checkliste zur Fehlerbehebung
| Symptom / Fehler | Ursache | Lösung |
|---|---|---|
| Python-Block liefert keine Ergebnisse | :results value mit print(...) anstelle von return ... verwendet | Ersetzen Sie print(...) durch return ... oder ändern Sie den Header zu :results output. |
No org-babel-execute function for <lang> | Sprache ist nicht in org-babel-load-languages registriert | Fügen Sie (<lang> . t) zu org-babel-load-languages in Ihrer Emacs-Konfiguration hinzu und werten Sie es aus. |
| Bildlink wird erzeugt, aber das Bild wird nicht angezeigt | Inline-Bilder sind im Org-Mode ausgeschaltet | Führen Sie M-x org-toggle-inline-images (C-c C-x C-v) aus oder fügen Sie #+STARTUP: inlineimages hinzu. |
Sitzungsausgaben enthalten wiederholte Eingabeaufforderungen (>>>) | Restlicher interaktiver Eingabeaufforderungstext im REPL-Puffer | Bereinigen oder starten Sie den Sitzungspuffer neu (*sitzungsname*). |
| Export ist langsam oder hängt | Org führt während des Exports alle Notebook-Blöcke erneut aus | Setzen Sie :eval never-export für langlaufende Blöcke oder global über #+PROPERTY: header-args :eval never-export. |
| Tabelleneingabe erzeugt Fehler bei horizontalen Linien | Horizontale Linien (` | -`) werden als Rohzeilen behandelt |
10. Vollständiges kommentiertes Notebook-Beispiel
#+TITLE: Analyse der Sonneneruptionshäufigkeit
#+AUTHOR: Dr. Alex Rivera
#+DATE: [2025-05-18 Sun]
#+OPTIONS: toc:nil num:nil
#+STARTUP: inlineimages nohideblocks
#+PROPERTY: header-args :session *solar* :results drawer :exports both
* Einleitung
Wir analysieren beobachtete Eruptionshäufigkeiten, die über ein 6-monatiges Beobachtungsfenster aufgezeichnet wurden.
* Rohbeobachtungen
Hier ist die Basismessungstabelle:
#+NAME: rohbeobachtungen
| Monat | C-Klasse | M-Klasse | X-Klasse |
|-------+----------+----------+----------|
| Jan | 12 | 3 | 0 |
| Feb | 19 | 5 | 1 |
| Mär | 15 | 2 | 0 |
| Apr | 27 | 8 | 2 |
| Mai | 31 | 11 | 3 |
| Jun | 22 | 7 | 1 |
* Datenverarbeitung & Zusammenfassende Statistiken
Wir berechnen die gesamte Sonnenaktivität mit Python:
#+NAME: summen_berechnen
#+BEGIN_SRC python :var obs=rohbeobachtungen :colnames yes :results value table
gesamtereignisse = []
for zeile in obs:
monat = zeile[0]
gesamt = sum(zeile[1:])
gesamtereignisse.append([monat, gesamt])
return [["Monat", "Gesamtereignisse"]] + gesamtereignisse
#+END_SRC
#+RESULTS: summen_berechnen
:RESULTS:
| Monat | Gesamtereignisse |
|-------+------------------|
| Jan | 15 |
| Feb | 25 |
| Mär | 17 |
| Apr | 37 |
| Mai | 45 |
| Jun | 30 |
:END:
* Visualisierung der monatlichen Aktivität
#+NAME: aktivitätsplot
#+BEGIN_SRC python :session *solar* :results graphics file :file figures/monatliche_aktivitaet.png :exports both
import matplotlib.pyplot as plt
monate = ["Jan", "Feb", "Mär", "Apr", "Mai", "Jun"]
gesamtereignisse = [15, 25, 17, 37, 45, 30]
plt.figure(figsize=(6, 3.5))
plt.plot(monate, gesamtereignisse, marker="o", color="#d62728", lw=2)
plt.title("Monatliche Sonnenaktivität (Gesamtereignisse)")
plt.xlabel("Monat")
plt.ylabel("Anzahl der Ereignisse")
plt.grid(linestyle="--", alpha=0.6)
plt.tight_layout()
plt.savefig("figures/monatliche_aktivitaet.png", dpi=150)
plt.close()
#+END_SRC
#+RESULTS: aktivitätsplot
[[file:figures/monatliche_aktivitaet.png]]
* Statistische Zusammenfassung mit R
#+NAME: r-statistik
#+BEGIN_SRC R :session *solar* :var daten=summen_berechnen :colnames yes :results value drawer
library(dplyr)
df <- as.data.frame(daten[-1,], stringsAsFactors=FALSE)
colnames(df) <- c("Monat", "Gesamtereignisse")
df$Gesamtereignisse <- as.numeric(df$Gesamtereignisse)
zusammenfassung <- df %>%
summarise(
Mittelwert = mean(Gesamtereignisse),
Median = median(Gesamtereignisse),
StdAbw = sd(Gesamtereignisse),
Maximum = max(Gesamtereignisse)
)
return(zusammenfassung)
#+END_SRC
#+RESULTS: r-statistik
:RESULTS:
| Mittelwert | Median | StdAbw | Maximum |
|--------------+--------+----------+---------|
| 28.166666667 | 27 | 11.43356 | 45 |
:END:
* Schlussfolgerung
Basierend auf den Beobachtungen nahm die Sonnenaktivität von Januar bis Mai kontinuierlich zu, mit einem leichten Rückgang im Juni. Die mittlere monatliche Ereignisrate betrug **28,2** Ereignisse pro Monat, mit einem Maximum von 45 Eruptionen im Mai.
Erstellt mit ❤️ für die Emacs Org Mode-Gemeinschaft. Verbessere deine reproduzierbare Forschung und dein literarisches Programmieren mit Org Babel.