Criação de Cadernos Computacionais com Org Babel
O Org Babel transforma o Emacs Org Mode em um ambiente interativo e multilíngue de cadernos computacionais. Assim como Jupyter ou Mathematica, o Org Babel intercala código executável, resultados de execução ao vivo, figuras, tabelas e prosa narrativa. Ao contrário dos cadernos baseados em JSON, os cadernos Org são texto puro, legíveis por humanos, nativamente versionáveis com Git e suportam a mistura de várias linguagens de programação em um único documento.
1. Arquitetura Central e Separação de Preocupações
Cada caderno Org Babel opera em cinco preocupações distintas, governadas por argumentos de cabeçalho. Conflitá-las é a principal fonte de bugs em cadernos Org:
| Preocupação | Argumentos de Cabeçalho Chave | O que Governa |
|---|---|---|
| Execução | :session, :eval, :dir, :var, :cache | O bloco é executado, em qual processo, onde e com quais entradas? |
| Resultados | :results (value vs output, formato, tipo, manipulação) | O que é capturado da execução e como é renderizado no buffer? |
| Exportação | :exports (code, results, both, none) | O que aparece nos relatórios exportados (HTML, PDF, Markdown)? |
| Extração | :tangle, :shebang, :noweb | O que é extraído para arquivos de código-fonte independentes no disco? |
| Composição | :var, #+CALL:, <<noweb>>, org-sbe | Como os blocos alimentam dados ou código uns nos outros? |
2. Estrutura do Caderno e Configuração do Preâmbulo
Um arquivo de caderno Org (.org) começa com metadados do documento e configurações padrão para todo o buffer, seguido por cabeçalhos hierárquicos contendo texto narrativo, fórmulas matemáticas e blocos de código.
2.1 Modelo de Preâmbulo Padrão do Caderno
#+TITLE: Análise Computacional do Experimento X
#+AUTHOR: João Silva
#+DATE: [2025-05-18 Dom]
#+OPTIONS: toc:2 num:t ^:{}
#+STARTUP: overview hideblocks inlineimages
# Padrões globais do Babel para todos os blocos neste buffer:
#+PROPERTY: header-args :eval yes :exports both :results drawer
# Padrões específicos de linguagem:
#+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
Configurações Chave no Buffer:
#+STARTUP: inlineimages: Exibe automaticamente gráficos/imagens gerados embutidos quando os resultados são inseridos ou quando o buffer é aberto.#+STARTUP: hideblocks: Inicia com blocos de código recolhidos, exibindo apenas narrativa e resultados para legibilidade.#+STARTUP: nohideblocks: Mostra todos os blocos de código expandidos.#+PROPERTY: header-args ...: Padrões para todo o buffer. Pode ser anexado comheader-args+.
2.2 Habilitando Linguagens na Configuração do Emacs
O Org habilita apenas a avaliação de Emacs Lisp por padrão. Todas as outras linguagens devem ser explicitamente carregadas na sua configuração do Emacs:
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(python . t)
(R . t)
(shell . t)
(sqlite . t)
(gnuplot . t)
(C . t)))
Para evitar diálogos de confirmação de execução interativa para cadernos confiáveis:
;; nil permite que blocos sejam executados sem solicitações de confirmação
(setq org-confirm-babel-evaluate nil)
3. Anatomia do Bloco de Código
#+NAME: <nome_do_bloco>
#+HEADER: <argumentos_de_cabeçalho_adicionais>
#+BEGIN_SRC <linguagem> <opções> <argumentos_de_cabeçalho>
<corpo>
#+END_SRC
#+NAME: <nome>: Identificador único opcional. Obrigatório se o bloco for referenciado como função, passado como entrada para outro bloco via:varou chamado via#+CALL:.<linguagem>: Identificador reconhecido pelo Babel (python,R,sh,emacs-lisp,sqlite,sql,julia,calc,gnuplot, etc.).<opções>: Opções opcionais (p. ex.,-npara numeração de linhas durante a exportação,-rpara remover rótulos).<argumentos_de_cabeçalho>: Pares chave-valor que controlam execução, resultados e exportação.#+HEADER:: Linhas secundárias para especificar listas longas de argumentos de cabeçalho de forma limpa.
Blocos de Código Embutidos
Para incorporar valores computados dinâmicos dentro de um parágrafo:
A precisão final calculada foi src_python[:session *py* :results value]{f"{acc * 100:.2f}%"}.
4. Referência de Argumentos de Cabeçalho
4.1 Gerenciamento de Sessões: Exploração Interativa vs Reprodutibilidade Hermética
:session none(Padrão): Avalia o bloco em um processo interpretador externo único. Hermético, limpo e evita poluição de estado, mas reinicializa importações e ambiente a cada execução.:session <nome>: Avalia em um buffer REPL inferior persistente do Emacs (p. ex.,*py-analysis*).- Variáveis, funções e módulos importados persistem em vários blocos que compartilham o mesmo nome de sessão.
- Essencial para conjuntos de dados pesados, grandes pesos de modelo e fluxos de trabalho exploratórios.
- Melhor Prática: Faça protótipo com
:session <nome>; para verificação final, reinicie a sessão ou teste seções críticas com:session nonepara garantir reprodutibilidade.
4.2 Diretórios de Trabalho e Ambientes Remotos
:dir /caminho/para/projeto: Executa o bloco dentro do diretório especificado.:mkdirp yes: Cria o diretório de destino se ele ainda não existir.- Execução Remota (TRAMP):
:dir /ssh:user@gpu-cluster:/workspace/dataexecuta o bloco remotamente em um servidor enquanto renderiza a saída dentro do seu buffer local do Emacs.
4.3 Armazenamento em Cache de Computações Custosas
:cache yes: Calcula um hash SHA1 do texto do bloco, entradas e parâmetros:var.- Se o hash corresponder ao armazenado na linha
#+RESULTS[hash]:, a avaliação é ignorada e os resultados em cache são retidos. - Use apenas para computações determinísticas e puras, sem efeitos colaterais externos.
5. Manipulação de Resultados: A Distinção Crítica
O argumento :results aceita até quatro componentes ortogonais:
:results [coleta] [tipo] [formato] [manipulação]
5.1 Coleta: Funcional (value) vs Script (output)
Entender esta diferença elimina 90% da confusão com Babel:
| Modo de Coleta | O que é Capturado | Comportamento Python | Comportamento Shell |
|---|---|---|---|
:results value (Padrão para Python, R, elisp) | Valor de retorno da última expressão ou return explícito. | Deve usar uma instrução explícita return <val>. Toda a saída print() é descartada. | Retorna o código de saída ou valor de string. |
:results output (Padrão para shell, bash) | Fluxo stdout emitido durante a execução. | Captura todas as instruções print(). Qualquer return é ignorado. | Captura todo o stdout do comando (echo, ls, etc.). |
Exemplo Funcional Python (:results value):
#+BEGIN_SRC python :results value
dados = [1, 2, 3, 4]
# No modo funcional, um return explícito é OBRIGATÓRIO em Python:
return sum(dados)
#+END_SRC
#+RESULTS:
: 10
Exemplo de Script Python (:results output):
#+BEGIN_SRC python :results output
for i in range(3):
print(f"Época {i}: perda={0.5/(i+1):.4f}")
#+END_SRC
#+RESULTS:
: Época 0: perda=0.5000
: Época 1: perda=0.2500
: Época 2: perda=0.1667
5.2 Tipos de Resultado
table/vector: Formata listas/arrays retornados como uma tabela do Org Mode.scalar/verbatim: Formata a saída como texto bruto entre aspas, sem formatação de tabela.file: Direciona a saída para um arquivo no disco (especificado com:file <nome_do_arquivo>) e insere um link de arquivo Org nos resultados.
5.3 Formatos de Resultado
drawer(Recomendado): Envolve os resultados em delimitadores:RESULTS:…:END:. Mantém os documentos organizados, especialmente para saídas de várias linhas.raw: Insere a saída diretamente como texto Org sem escape (útil para gerar cabeçalhos ou tabelas dinâmicas).code: Envolve a saída em#+BEGIN_SRC <lang>…#+END_SRC.link/graphics: Trata o resultado como um caminho para uma imagem/arquivo e gera[[file:caminho]].
5.4 Manipulação
replace(Padrão): Substitui o bloco#+RESULTS:anterior.append: Acrescenta novos resultados abaixo dos resultados existentes.prepend: Insere novos resultados acima dos resultados existentes.silent: Exibe resultados na área de eco/minibuffer do Emacs sem escrever no buffer Org.
6. Visualizações e Figuras em Cadernos
Para gerar gráficos e figuras que renderizam diretamente no caderno:
6.1 Gráfico Matplotlib Python
#+NAME: plot-distribuicao-normal
#+BEGIN_SRC python :session *py-vis* :results graphics file :file figuras/dist_normal.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("Distribuição Normal Padrão")
plt.xlabel("z")
plt.ylabel("Densidade")
plt.tight_layout()
plt.savefig("figuras/dist_normal.png", dpi=150)
plt.close()
#+END_SRC
#+RESULTS: plot-distribuicao-normal
[[file:figuras/dist_normal.png]]
6.2 Gráfico ggplot2 R
#+NAME: r-grafico-dispersao
#+BEGIN_SRC R :session *r-vis* :results graphics file :file figuras/r_dispersao.png :exports both
library(ggplot2)
p <- ggplot(mtcars, aes(x=wt, y=mpg, color=factor(cyl))) +
geom_point(size=3) +
theme_minimal() +
labs(title="Eficiência de Combustível vs Peso", x="Peso (1000 lbs)", y="MPG")
ggsave("figuras/r_dispersao.png", plot=p, width=6, height=4, dpi=150)
#+END_SRC
#+RESULTS: r-grafico-dispersao
[[file:figuras/r_dispersao.png]]
Dica: Execute M-x org-toggle-inline-images (C-c C-x C-v) no Emacs para alternar a exibição de gráficos gerados diretamente dentro do buffer.
7. Execução Interativa e Fluxo de Trabalho de Edição
Atalhos de Teclado Essenciais
| Atalho | Comando | Descrição |
|---|---|---|
C-c C-c | org-babel-execute-src-block | Executa o bloco sob o ponto e insere/atualiza resultados. |
C-c ' | org-edit-special | Abre o corpo do bloco em um buffer dedicado de modo principal (LSP completo, realce de sintaxe, autocompletar). Pressione C-c ' novamente para salvar e retornar. |
C-c C-v b | org-babel-execute-buffer | Executa todos os blocos de código no caderno sequencialmente (como "Executar Todas as Células"). |
C-c C-v s | org-babel-execute-subtree | Executa todos os blocos de código sob o cabeçalho atual. |
C-c C-o | org-open-at-point | Em um link #+RESULTS:, abre a imagem ou arquivo gerado em um visualizador externo ou buffer. |
M-<down> | org-babel-pop-to-session | Alterna o foco diretamente para o buffer REPL interativo para a sessão deste bloco. |
C-c C-v v | org-babel-expand-src-block | Visualiza o bloco totalmente expandido (com todas as expansões :var e noweb resolvidas). |
8. Exportando e Publicando Relatórios
Um caderno pode ser tecido em documentos HTML, PDF ou Markdown independentes.
8.1 Controlando o Conteúdo da Exportação com :exports
:exports code: Exporta apenas o bloco de código.:exports results: Exporta apenas a saída/figura (oculta o código, ideal para relatórios executivos).:exports both: Exporta tanto o código quanto a saída (ideal para documentação técnica).:exports none: Oculta tanto o código quanto os resultados do documento exportado (executa durante a avaliação, se necessário).
8.2 Controlando a Avaliação da Exportação com :eval
:eval never-export: Impede a reexecução de blocos durante a exportação, usando os#+RESULTS:existentes no buffer. Acelera a exportação e evita alterações não determinísticas.:eval query-export: Solicita confirmação antes de executar durante a exportação.
8.3 Comandos de Exportação
C-c C-e h h(org-html-export-to-html): Gera um relatório HTML.C-c C-e h o(org-html-export-to-html-and-open): Gera e abre HTML no seu navegador.C-c C-e l p(org-latex-export-to-pdf): Gera um relatório PDF tipografado via LaTeX.
9. Armadilhas Comuns e Lista de Verificação de Solução de Problemas
| Sintoma / Erro | Causa | Correção |
|---|---|---|
| Bloco Python não retorna resultados | Usou :results value com print(...) em vez de return ... | Substitua print(...) por return ... ou altere o cabeçalho para :results output. |
No org-babel-execute function for <lang> | Linguagem não está registrada em org-babel-load-languages | Adicione (<lang> . t) a org-babel-load-languages na sua configuração do Emacs e avalie. |
| Link de imagem é produzido, mas a imagem não é exibida | Imagens embutidas estão desativadas no Org Mode | Execute M-x org-toggle-inline-images (C-c C-x C-v) ou adicione #+STARTUP: inlineimages. |
Saídas da sessão contêm prompts repetidos (>>>) | Texto de prompt interativo remanescente no buffer REPL | Limpe ou reinicie o buffer da sessão (*nome-da-sessão*). |
| Exportação está lenta ou trava | Org está reexecutando todos os blocos do caderno durante a exportação | Defina :eval never-export em blocos de longa execução ou globalmente via #+PROPERTY: header-args :eval never-export. |
| Entrada de tabela produz erro em regras horizontais | Regras horizontais (` | -`) tratadas como linhas brutas |
10. Exemplo Completo de Caderno Anotado
#+TITLE: Análise de Frequência de Erupções Solares
#+AUTHOR: Dr. Alex Rivera
#+DATE: [2025-05-18 Dom]
#+OPTIONS: toc:nil num:nil
#+STARTUP: inlineimages nohideblocks
#+PROPERTY: header-args :session *solar* :results drawer :exports both
* Introdução
Analisamos as frequências observacionais de erupções registradas ao longo de uma janela de observação de 6 meses.
* Observações Brutas
Aqui está a tabela de medição de base:
#+NAME: observacoes_brutas
| Mês | Classe C | Classe M | Classe X |
|------+----------+----------+----------|
| Jan | 12 | 3 | 0 |
| Fev | 19 | 5 | 1 |
| Mar | 15 | 2 | 0 |
| Abr | 27 | 8 | 2 |
| Mai | 31 | 11 | 3 |
| Jun | 22 | 7 | 1 |
* Processamento de Dados e Estatísticas Resumidas
Calculamos a atividade solar total usando Python:
#+NAME: calcular_totais
#+BEGIN_SRC python :var obs=observacoes_brutas :colnames yes :results value table
total_eventos = []
for linha in obs:
mes = linha[0]
total = sum(linha[1:])
total_eventos.append([mes, total])
return [["Mês", "Total de Eventos"]] + total_eventos
#+END_SRC
#+RESULTS: calcular_totais
:RESULTS:
| Mês | Total de Eventos |
|-----+------------------|
| Jan | 15 |
| Fev | 25 |
| Mar | 17 |
| Abr | 37 |
| Mai | 45 |
| Jun | 30 |
:END:
* Visualização
Geramos um gráfico de barras da atividade solar:
#+NAME: grafico-atividade-solar
#+BEGIN_SRC python :session *solar* :results graphics file :file figuras/atividade_solar.png :exports both
import matplotlib.pyplot as plt
import numpy as np
meses = ["Jan", "Fev", "Mar", "Abr", "Mai", "Jun"]
totais = [15, 25, 17, 37, 45, 30]
plt.figure(figsize=(6, 3.5))
cores = plt.cm.Oranges(np.linspace(0.4, 0.8, len(meses)))
plt.bar(meses, totais, color=cores)
plt.title("Atividade Solar Total por Mês")
plt.xlabel("Mês")
plt.ylabel("Total de Eventos")
plt.tight_layout()
plt.savefig("figuras/atividade_solar.png", dpi=150)
plt.close()
#+END_SRC
#+RESULTS: grafico-atividade-solar
[[file:figuras/atividade_solar.png]]