pwquint24/org-babel-polyglot

Guide pour construire des pipelines d'analyse de données multilingues, passage de variables entre blocs, formules de tableaux avec org-sbe et appels de blocs à distance dans Org Babel.

Qu'est-ce que org-babel-polyglot ?

Ce skill guide les utilisateurs d'Org Babel, notamment dans Emacs, à travers la création de pipelines de données polyglottes où plusieurs langages de programmation (SQL, Python, R, Shell, Gnuplot, etc.) collaborent au sein d'un même document Org. Il explique en détail le mécanisme universel de passage de données via l'argument `:var`, le prétraitement des tableaux Org (noms de colonnes, noms de lignes, lignes horizontales), et le découpage/indexation des tableaux directement dans les déclarations `:var`. Le skill présente des motifs complets comme une chaîne SQL -> Python -> R -> graphiques, l'invocation programmatique de blocs avec `#+CALL:` et la macro `call_`, les feuilles de calcul réactives utilisant `org-sbe` dans les formules `#+TBLFM:`, le post-traitement des résultats avec `:post`, et la bibliothèque partagée Library of Babel. Il met enfin en garde contre les pièges courants (en-têtes non gérés, règles horizontales, blocs non nommés, citation dans org-sbe) et propose des bonnes pratiques pour garantir l'interopérabilité entre langages.

Compatible avec~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/pwquint24/org-babel-agent-skills/tree/HEAD/skills/org-babel-polyglot

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Pipelines de données polyglottes et interopérabilité avec Org Babel

L'une des capacités les plus puissantes d'Org Babel est l'interopérabilité indépendante du langage : les données peuvent circuler de manière transparente entre différents langages de programmation, tableaux Org et formules au sein d'un même document.

Un seul notebook peut interroger des données en SQL, les transformer et les nettoyer en Python, effectuer des modélisations statistiques en R, exécuter des commandes système en Shell, et visualiser les résultats en Gnuplot ou Matplotlib — avec Org Mode agissant comme le bus de données universel.


1. Le mécanisme universel de passage de données : :var

L'argument d'en-tête :var a une syntaxe identique pour tous les langages pris en charge :

:var NOM_VARIABLE=AFFECTATION
:var NOM_VARIABLE=FICHIER:RÉFÉRENCE

1.1 Types d'affectations pris en charge par :var

Source d'entréeExemple de syntaxeRemarques
Valeur littérale:var n=42 text="exemple"Nombres, booléens et chaînes.
Tableau Org nommé:var data=raw_measurementsPasse le tableau 2D sous forme de liste imbriquée / data frame.
Liste simple nommée:var items=todo_listPasse les éléments de la liste de premier niveau sous forme de tableau/vecteur.
Bloc de code sans arguments:var stats=compute_stats()Exécute compute_stats et passe sa valeur de retour.
Bloc de code avec arguments:var res=calc(rate=0.05, n=12)Évalue le bloc cible avec les paramètres spécifiés.
Contenu de bloc / Littéral:var template=config_template[]Passe le corps textuel d'un exemple ou d'un bloc de code.
Évaluation Emacs Lisp:var file=(buffer-file-name)Toute valeur commençant par (, [, ' ou ` est évaluée comme Elisp.
Fichier Org externe:var ext=other.org:data_tableRésout la référence dans un fichier externe.

2. Passage et formatage des tableaux Org

Les tableaux Org sont automatiquement convertis en structures natives (listes Python de listes, data frames R, etc.). Les arguments d'en-tête contrôlent le prétraitement des tableaux :

2.1 Arguments de prétraitement des tableaux

  • :colnames yes | no | nil (Défaut : nil) :
    • Lorsque nil : si le tableau a une règle horizontale sous la ligne 1, Babel supprime les en-têtes, convertit les lignes et réapplique les en-têtes aux tableaux retournés.
    • Lorsque yes : traite explicitement la première ligne comme des noms de colonnes / en-têtes.
    • Lorsque no : traite la première ligne comme des données normales.
  • :rownames yes | no (Défaut : no) :
    • Lorsque yes : supprime la première colonne avant le traitement et la restaure comme noms de lignes au retour.
  • :hlines yes | no (Défaut : no) :
    • Lorsque no (recommandé) : supprime toutes les règles horizontales (|-...) avant de passer les données à l'interpréteur. Cela évite les erreurs de type (comme None ou les chaînes 'hline' qui cassent les routines numériques).
    • Lorsque yes : laisse les règles horizontales en place sous forme de symboles 'hline.

2.2 Découpage et indexation des tableaux dans :var

Vous pouvez découper des lignes et des colonnes directement dans la déclaration :var en utilisant la notation d'index basée sur 0 [lignes, colonnes] :

#+NAME: full_dataset
| ID | Age | Score |
|----+-----+-------|
|  1 |  25 |  88.5 |
|  2 |  30 |  92.0 |
|  3 |  22 |  79.0 |
|  4 |  35 |  95.5 |

# Passage uniquement de la colonne 'Score' (index colonne 2, lignes 1 à fin) :
#+BEGIN_SRC python :var scores=full_dataset[1:, 2] :results value
  return sum(scores) / len(scores)
#+END_SRC

#+RESULTS:
: 88.75
  • Syntaxe d'indexation :
    • data[0] : Première ligne.
    • data[,1] : Deuxième colonne sur toutes les lignes.
    • data[1:3, :] : Lignes 1 à 3, toutes les colonnes (inclusif).
    • data[-1] : Dernière ligne.
    • data[*] ou data[0:-1] : Toutes les lignes.
  • Important : L'indexation a lieu avant la suppression de :colnames ou :hlines.

3. Motif de pipeline polyglotte : SQL -> Python -> R -> Graphiques

Voici un flux de travail de données complet multi-langage :

#+TITLE: Pipeline multi-langage

* Étape 1 : Requête de base de données (SQLite)
Extraire les comptes d'événements bruts :

#+NAME: raw_events
#+BEGIN_SRC sqlite :db telemetry.db :results table :colnames yes
  SELECT device_id, event_type, count(*) as count
  FROM events
  WHERE event_date >= '2025-01-01'
  GROUP BY device_id, event_type;
#+END_SRC

#+RESULTS: raw_events
| device_id | event_type | count |
|-----------+------------+-------|
| dev-01    | heartbeat  |  1420 |
| dev-01    | alert      |    12 |
| dev-02    | heartbeat  |  1380 |
| dev-02    | alert      |    45 |

* Étape 2 : Nettoyage & normalisation des données (Python)
Consommer le tableau SQLite dans Python :

#+NAME: clean_telemetry
#+BEGIN_SRC python :var events=raw_events :colnames yes :results value table
  cleaned = []
  for row in events:
      dev_id, ev_type, count = row[0], row[1], int(row[2])
      rate = round(count / 1440.0, 4)  # événements par minute
      cleaned.append([dev_id, ev_type, count, rate])
  return [["Device", "Event", "Count", "RatePerMin"]] + cleaned
#+END_SRC

#+RESULTS: clean_telemetry
| Device | Event     | Count | RatePerMin |
|--------+-----------+-------+------------|
| dev-01 | heartbeat |  1420 |     0.9861 |
| dev-01 | alert     |    12 |     0.0083 |
| dev-02 | heartbeat |  1380 |     0.9583 |
| dev-02 | alert     |    45 |     0.0313 |

* Étape 3 : Modélisation statistique (R)
Consommer la sortie Python nettoyée dans R :

#+NAME: r_stat_summary
#+BEGIN_SRC R :var df=clean_telemetry :colnames yes :results value table
  summary_df <- aggregate(RatePerMin ~ Event, data=df, FUN=mean)
  colnames(summary_df) <- c("Event", "AvgRatePerMin")
  summary_df
#+END_SRC

#+RESULTS: r_stat_summary
| Event     | AvgRatePerMin |
|-----------+---------------|
| alert     |        0.0198 |
| heartbeat |        0.9722 |

4. Appel programmatique de blocs : #+CALL: et call_ en ligne

Vous pouvez traiter n'importe quel bloc nommé comme une fonction réutilisable et l'invoquer sans réécrire le bloc.

4.1 Syntaxe

# Forme bloc :
#+CALL: <nom>[<en-têtes_évaluation_interne>](<arguments>) <en-têtes_résultat_final>

# Forme en ligne :
... call_<nom>[<en-têtes_évaluation_interne>](<arguments>)[<en-têtes_résultat_final>] ...
  • <nom> : Le #+NAME: du bloc cible.
  • <arguments> : Paramètres de style fonction, ex. (n=5, metric="accuracy").
  • [<en-têtes_évaluation_interne>] : Appliqués pendant l'exécution (ex. [:results output]).
  • [<en-têtes_résultat_final>] : Appliqués au formatage du résultat retourné (ex. :results raw).

4.2 Exemple

#+NAME: power_calc
#+BEGIN_SRC python :var base=2 exp=3 :results value
  return base ** exp
#+END_SRC

# Appel avec des arguments personnalisés :
#+CALL: power_calc(base=3, exp=4)

#+RESULTS:
: 81

# Invocation en ligne :
La capacité totale est de call_power_calc(base=2, exp=8) unités.

5. Feuilles de calcul réactives : Babel dans les formules de tableau (org-sbe)

Les tableaux Org disposent d'un calculateur de feuille de calcul intégré (#+TBLFM:). La macro org-sbe permet à toute formule de cellule de tableau d'appeler un bloc Babel arbitraire dans n'importe quel langage :

(org-sbe "nom-du-bloc" (param1 valeur1) (param2 valeur2))
;; Raccourci :
(sbe "nom-du-bloc" (param1 valeur1))

Exemple : Tableau alimenté par des formules Python & R

#+NAME: py_tax_rate
#+BEGIN_SRC python :var country="US" :results value
  rates = {"US": 0.08, "UK": 0.20, "DE": 0.19}
  return rates.get(country, 0.0)
#+END_SRC

#+NAME: invoice_table
| Item        | Country | Base Price | Tax Rate | Total Price |
|-------------+---------+------------+----------+-------------|
| Server Node | US      |       1200 |     0.08 |      1296.0 |
| Storage SAN | UK      |       3000 |      0.2 |      3600.0 |
| Gateway     | DE      |        800 |     0.19 |       952.0 |
#+TBLFM: $4='(org-sbe "py_tax_rate" (country $"$2")) :: $5=$3 * (1 + $4)
  • Dans le tableau, appuyer sur C-u C-c C-c sur la ligne #+TBLFM recalcule toutes les formules, évaluant le bloc Python dynamiquement pour chaque ligne !
  • $"$2" passe la valeur de la colonne 2 comme une chaîne littérale.

6. Post-traitement des résultats avec :post

L'argument d'en-tête :post chaîne la sortie d'un bloc via un bloc de formatage secondaire avant qu'elle ne soit insérée dans le document. La sortie du bloc principal est liée à *this* :

# Bloc de post-traitement qui ajoute des attributs d'export LaTeX personnalisés :
#+NAME: wrap_latex_figure
#+BEGIN_SRC emacs-lisp :var data="" caption="Figure"
  (format "#+CAPTION: %s\n#+ATTR_LATEX: :width 0.8\\textwidth\n%s" caption data)
#+END_SRC

# Bloc de traçage principal utilisant :post :
#+BEGIN_SRC python :results file link :file figures/out.pdf :post wrap_latex_figure(caption="Précision du modèle", data=*this*)
  import matplotlib.pyplot as plt
  plt.plot([1, 2, 3], [4, 5, 6])
  plt.savefig("figures/out.pdf")
  plt.close()
  return "figures/out.pdf"
#+END_SRC

7. La Bibliothèque de Babel : bibliothèques de fonctions globales partagées

La Bibliothèque de Babel vous permet d'importer et de partager des blocs nommés dans plusieurs fichiers .org distincts sans dupliquer le code.

  1. Créez un fichier de bibliothèque partagée (ex. ~/org/shared_babel.org) contenant des blocs nommés.
  2. Ingérez la bibliothèque dans votre session Emacs :
    (org-babel-lob-ingest "~/org/shared_babel.org")
    
    Ou via le raccourci clavier : C-c C-v i (org-babel-lob-ingest).
  3. Appelez n'importe quel bloc de ce fichier en utilisant #+CALL: nom_du_bloc(args) dans n'importe quel buffer !

8. Pièges courants polyglottes et bonnes pratiques

PiègeConséquenceRemède
En-têtes de colonnes non concordantsLes calculs numériques échouent car les chaînes d'en-tête sont lues comme des données de la ligne 0Toujours spécifier :colnames yes sur les blocs consommant des entrées tabulaires.
Règles horizontales de tableau (`-`) provoquant des plantagesPython/R reçoit le symbole 'hline' là où un nombre était attendu
Blocs non nommés dans :varErreur Référence 'xyz' introuvable dans le tamponAssurez-vous que le bloc d'entrée ou le tableau a un mot-clé #+NAME: xyz correspondant directement au-dessus.
Citation des variables de cellule de tableau dans org-sbeLes cellules de texte sans guillemets sont lues comme des symboles Lisp non définisEntourez les références de colonnes de guillemets : (country $"$2").
Ordre d'indexation avec les en-têtesdata[0] retourne la ligne d'en-tête lors de l'indexationNotez que le découpage du tableau a lieu avant la suppression de :colnames.

Individual skills in this repo

This repo contains 4 individual skills — each has its own dedicated page.

Skills associés