R Markdown é uma ferramenta que permite criar documentos dinâmicos misturando códigos de programação com texto em Markdown

Este é nosso quinto artigo da série sobre produção de documentos com Markdown, uma linguagem de marcação simples e muito útil para produzir praticamente qualquer tipo de documento técnico, acadêmico, para a Web, etc.

No primeiro artigo da série fizemos uma pequena introdução sobre linguagens de marcação, apresentamos as características principais do Markdown e sua sintaxe básica.

No segundo artigo da série apresentamos o Pandoc, que é um software gratuito e open-source conversor entre diversos tipos de linguagens de marcação e arquivos de texto, e que também possui a sua própria implementação Markdown.

No terceiro artigo da série apresentamos o Limarka, que é uma ferramenta capaz de gerar arquivos PDF de documentos acadêmicos, como artigos, dissertações e teses, em conformidade com as Normas da ABNT a partir de textos escritos em Markdown.

No texto anterior iniciamos um artigo de duas partes sobre o R Markdown, que é uma ferramenta capaz de produzir documentos dinâmicos a partir da incorporação de trechos de código em R (e em outras linguagens de programação) em arquivo de texto com sintaxe Markdown.

O texto anterior se concentrou em apresentar o R Markdown e o RStudio, as instalações e dependências necessárias, e a estrutura básica do documento.

Neste artigo, que é uma continuação do anterior, nos detemos no funcionamento e na estrutura do documento, sobretudo nas formas de inserção de código, configurações e interações, a partir de um exemplo prático.

Documentação com Markdown: Documentos dinâmicos com R Markdown 2/2

Sumário do artigo

Introdução

Este texto é uma continuação do artigo anterior, no qual apresentamos o R Markdown, que é um arquivo com extensão .Rmd capaz de conter tanto texto simples com sintaxe Markdown quanto trechos de código executável em R e em outras linguagens de programação.

Tratamos dos principais pacotes R e dependências utilizadas no processo de renderização de um documento R Markdown e também apresentamos o software RStudio, que é um ambiente de desenvolvimento integrado - IDE criado para a linguagem R.

Tratamos das instalações necessárias e começamos a apresentar a estrutura e anatomia de um documento R Markdown.

Nesta segunda parte continuaremos a partir deste ponto, detalhando principalmente o funcionamento e as formas de inserção de código, configurações e interações possíveis.

Estrutura do R Markdown

Conforme já apresentamos, a estrutura de um arquivo R Markdown .Rmd é composta por três elementos básicos:

  • Metadados;
  • Corpo do texto;
  • Código.

Metadados

Os metadados são inseridos no início do documento R Markdown através de um cabeçalho YAML (também chamado de YAML front matter), a respeito do qual já tratamos de forma mais detida no artigo anterior.

Conforme vimos, o cabeçalho YAML do nosso arquivo R Markdown criado no artigo anterior possuia apenas duas linhas:

---
title: "Inteligência Urbana"
output: html_document
---

Para construir nosso pequeno exemplo prático, vamos manter os metadados de subtítulo, autor e data que acrescentamos no artigo anterior, deixando-o assim:

---
title: "Inteligência Urbana"
subtitle: "Dados urbanos em R Markdown"
author: "Elson Fabiano Alves"
date: "11/09/2021"
output: html_document
---

Corpo do texto

Através de Markdown podem ser inseridos virtualmente todos os elementos necessários a um documento. Para os elementos do corpo do texto do documento R Markdown utiliza-se a sintaxe Markdown com os elementos da sintaxe estendida Pandoc’s Markdown, que apresentamos detalhadamente no primeiro e no segundo artigos desta série, que como já dissemos, é importante que sejam lidos antes.

Código

A possibilidade de inserir e “processar” códigos de linguagens de programação, seus resultados e outputs em meio ao corpo do texto é a essência e o coração do que é o R Markdown.

Existem duas formas de inserir código em meio a um documento R Markdown: Blocos de código executável, que são chamados de Chunks, e são inseridos antes ou depois de um elemento do documento, como um parágrafo ou uma imagem; e expressões de código R inline, que podem ser inseridas no meio do documento, dentro de um parágrafo Markdown, por exemplo.

Código em chunks

Chunks são blocos de código a serem executados durante o processamento - ou renderização - do documento. Os outputs eventualmente gerados por estes trechos de código - como gráficos, tabelas, dados, imagens, etc - incorporam-se ao documento final de saída.

A sintaxe para inserção de um Chunk de código consiste em “cercá-lo” com três ``` (crases, ou backtricks), antes e depois do código. Ao lado do primeiro trio de crases ```, entre chaves {}, deve vir necessariamente a informação de qual linguagem está sendo utilizada no chunk (haja vista que o R Markdown suporta diversas outras linguagens além do R).

Além de inserir chunks “manualmente” digitando ```{r} e ```, também pode ser utilizado o atalho de teclado ctrl+shift+k (no windows ou Linux) ou command+shift+k (no MacOS) para inserir um chunk de código R n local onde o cursor estiver posicionado no documento.

Outra forma de inserir um chunk é através do botão “insert” na barra de ferramentas do editor R Markdown. Ao clicar no botão “insert”, no menu que se abre, é possível selecionar a linguagem do chunk a ser criado, dentre as opções R, Python, RCPP, SQL e Stan, conforme Figura 1.

rmarkdown-insertchunk

Interface do RStudio - inserir chunk

Vamos iniciar o corpo do documento do nosso exemplo prático:

## Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de **São Paulo**, **Rio de Janeiro** e **Belo Horizonte**.

```{r}
options(OutDec = ",")

cidade <- c("São Paulo", "Rio de Janeiro", "Belo Horizonte")
populacao <- c(12396372, 6775561, 2530701)
idh_m <- c(0.805, 0.799, 0.810)

tabela_1 <- data.frame(cidade,populacao,idh_m)

knitr::kable(tabela_1, format.args = list(big.mark = "."))
```

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

No trecho de documento R Markdown acima nós temos um chunk de código em linguagem R entre dois parágrafos Markdown. Não é objetivo deste texto apresentar a linguagem R em si, mas vamos descrever sucintamente o conteúdo do chunk:

  • Na primeira linha do código chamamos a função options(), que nos permite configurar algumas opções globais que afetam a maneira como o R calcula e exibe seus resultados.

    Neste caso usamos o argumento OutDec = "," para definir a vírgula , como caractere decimal preferido nas conversões de saída (o padrão seria o ponto .);

  • Nas três linhas seguintes do código são criados três objetos - ou variáveis - chamados cidade, populacao e idh_m e é atribuído um vetor de valores a cada um dos três objetos.

    A sintaxe em R para criar objetos e atribuir valores a eles é simplesmente nome_do_objeto <- valor_do_objeto.

    A sintaxe em R para criar um vetor é simplesmente c(valor_1, valor_2, valor_n, etc);

  • Na quinta linha do código é criado um objeto chamado tabela_1, para o qual é atribuído um Data Frame construído a partir da reunião dos três vetores de valores criados nas linhas anteriores.

    Um Data Frame é uma espécie de tabela.

    A sintaxe em R para criar um Data Frame é data.frame(valores_do_dataframe);

  • Na quinta linha do código é chamada a função knitr::kable(), do pacote Knitr, tendo como argumentos o objeto tabela_1 criado na linha anterior e format.args = list(big.mark = ".").

    Esta função faz parte do pacote Knitr e simplesmente produz como output uma tabela formatada a partir de valores que sejam colocados como argumento, neste caso o objeto tabela_1, além de permitir alguns ajustes.

    O argumento format.args permite passar uma lista de argumentos list() para formatar os valores de uma tabela. Neste caso passamos o argumento big.mark = "." para definir o ponto . como caractere separador de milhares na conversão de saída (por padrão não haveria nenhum separador).

Desta forma, após a renderização (após clicarmos no botão “Knit” ou utilizarmos o atalho de teclado ctrl+shift+k), o trecho acima produzirá um trecho de saída semelhante a este:

Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de São Paulo, Rio de Janeiro e Belo Horizonte.

options(OutDec = ",")

cidade <- c("São Paulo", "Rio de Janeiro", "Belo Horizonte")
populacao <- c(12396372, 6775561, 2530701)
idh_m <- c(0.805, 0.799, 0.810)

tabela_1 <- data.frame(cidade, populacao, idh_m)

knitr::kable(tabela_1, format.args = list(big.mark = "."))
cidade populacao idh_m
São Paulo 12.396.372 0,805
Rio de Janeiro 6.775.561 0,799
Belo Horizonte 2.530.701 0,810

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

Um aspecto muito interessante a respeito do R Markdown é que os diferentes chunks de código compartilham do mesmo ambiente, de uma mesma “sessão” de código.

Neste sentido, os chunks de código são todos como continuações um do outro, e podemos utilizar e manipular um objeto criado num chunk anterior em um chunk posterior.

Como podemos ver na continuação do nosso exemplo prático:

Abaixo temos dois gráficos com os dados da tabela anterior:

```{r}
library(ggplot2)
library(cowplot)
library(scales)

options(scipen = 999)

grafico_1 <- ggplot(tabela_1) +
 aes(x = cidade, weight = populacao) +
 geom_bar(fill = "#779ca9") +
 ggtitle("População") +
 labs(x = "", y = "População", title = "População das cidades") +
 theme_minimal() +
 scale_y_continuous(labels = function(y) format(y, big.mark = "."))

grafico_2 <- ggplot(tabela_1) +
 aes(y = cidade, weight = idh_m) +
 geom_bar(fill = "#779ca9") +
 ggtitle("IDH M") +
 coord_cartesian(xlim=c(0.75,0.82)) +
 labs(x = "IDH M", y = "", title = "IDH M das cidades") +
 theme_minimal()

plot_grid(grafico_1, grafico_2)
```

No trecho de R Markdown acima temos um segundo chunk de código R. Neste segundo chunk nós criamos dois gráficos extremamente simples utilizando os dados do objeto tabela_1, que foi criado no chunk anterior.

Novamente, apenas descrevendo de forma sucinta o conteúdo do chunk:

  • Nas três primeiras linhas do código carregamos três pacotes R que já estavam instalados.

    • O pacote ggplot2, que é um pacote para criação de gráficos, um dos mais conhecidos e utilizados do ambiente R.

    • O pacote cowplot, que é um pacote que oferece funções que ajudam a alinhar e ajustar a posição e distribuição de gráficos. Vamos utilizá-lo para para colocar os dois gráficos em uma mesma linha.

    • O pacote scales, que é um pacote que fornece métodos para determinar automaticamente quebras e rótulos para eixos e legendas. Vamos utilizá-lo para para definir o ponto . como caractere separador de milhares na legenda do gráfico;

    A sintaxe em R para instalar um pacote é install.packages("nome_do_pacote"). Só é necessário instalar cada pacote uma vez, e então o pacote precisará apenas ser carregado nos documentos que pretendam utilizá-lo (embora seja possível, não seria aconselhável chamar a função de instalação de um pacote dentro de um arquivo R Markdown, é melhor fazer isso no Console do RStudio).

    A sintaxe em R para carregar um pacote é library(nome_do_pacote), e depois de carregado em um chunk, as funções do pacote podem ser chamadas em todo o restante do documento.

    Alternativamente, se quisermos utilizar apenas uma função de um pacote sem carregar o pacote inteiro podemos utilizar a sintaxe nome_do_pacote::função(), em vez de apenas função(), sem precisar, então, utilizar o library(nome_do_pacote) antes.

  • Na quarta linha do código chamamos a função options(), que nos permite configurar algumas opções globais que afetam a maneira como o R calcula e exibe seus resultados.

    Neste caso usamos o argumento scipen = 999 para forçar o R a não usar notação exponencial nos números;

  • Nos dois conjuntos de linhas de código seguintes criamos dois objetos, grafico_1 e grafico_2, e atribuímos a cada um deles um gráfico criado utilizando as funções do pacote ggplot2 e também do pacote scales (apenas no primeiro gráfico).

    • O primeiro gráfico é um grafico de barras verticais que mostra a população das cidades;

    • O segundo gráfico é um gráfico de barras horizontais que mostra o IDH M das cidades;

  • Na última linha do código chamamos a função plot_grid(), do pacote cowplot, utilizando como argumentos os objetos grafico_1 e grafico_2, o que fará com que os dois gráficos sejam “plotados” em uma mesma linha, lado a lado.

Após a renderização o trecho R Markdown acima produzirá um trecho de saída semelhante a este:

Abaixo temos dois gráficos com os dados da tabela anterior:

library(ggplot2)
library(cowplot)
library(scales)

options(scipen = 999)

grafico_1 <- ggplot(tabela_1) +
 aes(x = cidade, weight = populacao) +
 geom_bar(fill = "#779ca9") +
 ggtitle("População") +
 labs(x = "", y = "População", title = "População das cidades") +
 theme_minimal() +
 scale_y_continuous(labels = function(y) format(y, big.mark = "."))

grafico_2 <- ggplot(tabela_1) +
 aes(y = cidade, weight = idh_m) +
 geom_bar(fill = "#779ca9") +
 ggtitle("IDH M") +
 coord_cartesian(xlim=c(0.75,0.82)) +
 labs(x = "IDH M", y = "", title = "IDH M das cidades") +
 theme_minimal()

plot_grid(grafico_1, grafico_2)

Ao renderizar o documento é gerado um arquivo de imagem (neste caso .png) com os dois gráficos lado a lado como output deste chunk de código.

Como pode ser observado nestes exemplos, ao se renderizar o documento, por padrão, o código dos chunks em si é apresentado em um quadro, com realce de sintaxe e fonte monoespaçada, demonstrando visualmente tratar-se de um bloco de código, seguido pelo output deste código, se existir um, como os gráficos do último exemplo e a tabela do exemplo anterior.

Este comportamento, bem como diversas outras características, pode ser alterado a partir dos atributos dos chunks.

Execução do código dos chunks

Conforme já vimos, ao se renderizar o arquivo R Markdown para produzir o documento de saída (quandro clicamos no botão “Knit” ou utilizamos o atalho de teclado ctrl+shift+k) é chamada automaticamente a função rmarkdown::render() que internamente chama a função knitr::knit() que “executa” todos os chunks de código do documento e incorpora seus outputs na sequência do bloco de código de um arquivo .md intermediário (que posteriormente é convertido no formato de saída especificado utilizando o Pandoc, ainda “dentro” da função render()).

Todavia, é possível executar o código dos chunks enquanto estamos produzindo o documento, antes de renderizá-lo.

Para executar o código de um chunk específico pode-se utilizar o atalho de teclado ctrl+alt+c (no Windows ou Linux) ou command+option+c (no MacOS) ou então clicar no botão “Run current chunk”, uma seta verde apontando para a direita no canto superior direito de cada chunk, conforme Figura 2.

rmarkdown-runcurrentchunk

Interface do RStudio - executar chunk atual

Imediatamente à esquerda do botão “Run current chunk” há o botão “Run all chunks above” (fIGURA 3), que executa todos os chunks do documento até o chunk atual.

rmarkdown-runchunksabove

Interface do RStudio - executar todos os chunks até o atual

Além disso, na barra de ferramentas do editor R Markdown há o botão “Run” que, ao ser clicado, no menu que se abre, apresenta uma série de opções para execução de chunks, como pode ser visto na Figura 4.

rmarkdown-runchunksoptions

Interface do RStudio - opções para execução de chunks

Como também pode ser observado na Figura 4, a maior parte das opções também possui um atalho de teclado correspondente.

Atributos e Rótulos dos chunks

Em um chunk, dentro das chaves {} que se seguem ao primeiro trio de crases ``` que o abre, além da linguagem de programação utilizada pode ser designado um rótulo para o chunk, o que pode ser útil ao permitir referenciá-lo em outro ponto do documento e reutilizar seu conteúdo em outro chunk, e um conjunto de atributos, que podem definir e configurar diversas características do chunk e de seus eventuais outputs.

Caso seja atribuído um rótulo este deve vir logo após o nome - ou alias - da linguagem, separado apenas por um espaço, caso seja inserido um atributo este deve vir após o rótulo, ou após o nome da linguagem, separado por uma vírgula, e caso sejam inseridos mais de um atributo estes devem estar separados entre si por vírgulas.

Atributos

A sintaxe para definição de atributos para o chunk consiste em chaves e valores no formato chave = "valor".

Existem inúmeras possibilidades, a seguir listamos algumas das principais opções de atributos:

  • eval
    Lógico. O valor pode ser TRUE ou FALSE. Se for FALSE o código do chunk não será executado e não produzirá output, mas aparecerá no documento final.

  • echo
    Lógico. O valor pode ser TRUE ou FALSE. Se for FALSE o código não será aparecerá no documento final renderizado, mas será executado e um eventual output será incluído no documento.

  • warning, message, e error
    Lógico. O valor pode ser TRUE ou FALSE. Se for FALSE no documento final renderizado serão omitidos os alertas, as mensagens e os avisos de erro, respectivamente, que sejam eventualmente gerados pela execução do código (estas mensagens continuarão aparecendo no Console apenas).

  • include
    Lógico. O valor pode ser TRUE ou FALSE. Se for FALSE tanto o código quanto qualquer eventual output será omitido do documento final renderizado. Todavia, o código será executado, se for criado um objeto ele poderá ser utilizado em outra parte do documento, por exemplo.

  • cache
    Lógico. O valor pode ser TRUE ou FALSE. Controla se o chunk poderá usar cache para criar uma pasta com arquivos cacheados. Útil para chunks de códigos que levam muito tempo para rodar.

  • fig.width e fig.height
    Refere-se ao tamanho - largura e altura, respectivamente - dos gráficos R, em polegadas. Os gráficos R que são output de código são inicialmente gravados por meio de um dispositivo gráfico pelo knitr e, em seguida, salvos como arquivos.

  • out.width e out.height

    Refere-se ao tamanho de outputs gráficos no documento de saída. Essas opções podem dimensionar imagens também. É possível usar porcentagens, por exemplo: out.width = "80%" significa 80% da largura da página.

  • fig.align
    Refere-se ao alinhamento dos outputs gráficos. Pode ser left, center ou right.

  • dev
    Trata-se do formato utilizado para salvar os outputs gráficos. Por padrão é .pdf para saída LaTeX e .png para saída HTML, mas é possível utilizar outros formatos, como .svg ou .jpeg, por exemplo.

  • fig.cap
    A legenda de uma figura.

  • child
    Permite incluir um documento “filho” no documento principal. Esta opção deve receber um caminho - ou path - para um arquivo externo.

  • ref.label
    Permite reutilizar o conteúdo de um ou mais chunks, utilizando como valor deste atributo os rótulos dos chunks a serem reutilizados.

  • class.source e class.output
    Permite designar uma classe para o bloco de código e/ou para o output do código, respectivamente, o que pode ser particularmente útil caso o documento de saída seja um HTML por exemplo.

A documentação completa para as opções e atributos de chunks pode ser encontrada aqui.

Retomando nosso exemplo prático, vamos acrescentar rótulos e alguns atributos aos chunks deste documento R Markdown, conforme trecho a seguir.

## Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de **São Paulo**, **Rio de Janeiro** e **Belo Horizonte**.

```{r dados-tabela, echo = FALSE}
options(OutDec = ",")

cidade <- c("São Paulo", "Rio de Janeiro", "Belo Horizonte")
populacao <- c(12396372, 6775561, 2530701)
idh_m <- c(0.805, 0.799, 0.810)

tabela_1 <- data.frame(cidade, populacao, idh_m)

knitr::kable(tabela_1, format.args = list(big.mark = "."))
```

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

Abaixo temos dois gráficos com os dados da tabela anterior:

```{r graficos, echo = FALSE, fig.width = 10}
library(ggplot2)
library(cowplot)
library(scales)

options(scipen = 999)

grafico_1 <- ggplot(tabela_1) +
 aes(x = cidade, weight = populacao) +
 geom_bar(fill = "#779ca9") +
 ggtitle("População") +
 labs(x = "", y = "População", title = "População das cidades") +
 theme_minimal() +
 scale_y_continuous(labels = function(y) format(y, big.mark = "."))

grafico_2 <- ggplot(tabela_1) +
 aes(y = cidade, weight = idh_m) +
 geom_bar(fill = "#779ca9") +
 ggtitle("IDH M") +
 coord_cartesian(xlim=c(0.75,0.82)) +
 labs(x = "IDH M", y = "", title = "IDH M das cidades") +
 theme_minimal()

plot_grid(grafico_1, grafico_2)
```

Como pode ser visto, atribuímos o rótulo dados-tabela ao primeiro chunk e o rótulo graficos ao segundo chunk.

Também inserimos o atributo echo = FALSE nos dois chunks para que, no documento renderizado, o código em si seja omitido. Esta é uma necessidade muito comum quando estamos produzindo um documento R Markdown, na maioria das vezes não iremos querer que o código apareça no documento final formatado, apenas seus resultados (outputs).

Por fim, adicionamos o atributo fig.width = 10 no chunk graficos, no sentido de ajustar a largura da imagem gerada para que ocupe toda a largura do documento, uma vez que no exemplo anterior não tinha ficado tão legal, os gráficos estavam “meio apertados” à esquerda.

Assim sendo, após a renderização, o trecho acima produzirá uma saída semelhante a esta:

Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de São Paulo, Rio de Janeiro e Belo Horizonte.

cidade populacao idh_m
São Paulo 12.396.372 0,805
Rio de Janeiro 6.775.561 0,799
Belo Horizonte 2.530.701 0,810

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

Abaixo temos dois gráficos com os dados da tabela anterior:

Rótulos

A utilização dos rótulos, por sua vez, facilita muito a reutilização de chunks ao longo do documento, sem a necessidade de “copiar e colar” o seu conteúdo.

Existem três formas de reutilizar um chunk através de seu rótulo.

Incorporar um chunk em outro chunk

A sintaxe para incorporar o conteúdo de um chunk dentro de outro é <<rotulo>>. Assim, se quisermos inserir novamente, em outro ponto do documento, os nossos dois gráficos do chunk graficos do nosso exemplo, bastaria inserir um novo chunk da seguinte maneira:

```{r}
<<graficos>>
```

Este método permite incorporar mais de um de chunk inclusive. Neste sentido, o seguinte chunk incorporaria os dois chunks do nosso trecho de exemplo, e geraria como output uma tabela seguida de dois gráficos.

```{r}
<<dados-tabela>>
<<graficos>>
```
Usar o mesmo rótulo de um chunk em outro chunk

Outra forma de repetir o conteúdo de um chunk em outro chunk em outra parte do documento é repetir o mesmo rótulo do chunk que se pretende replicar em outro chunk vazio.

Assim, se quisermos repetir o nosso chunk de rótulo dados-tabela em outra parte do documento basta criar outro chunk da seguinte maneira.

```{r dados-tabela}
```

Um chunk como este acima reproduzirá o mesmo conteúdo e gerará o mesmo output do chunk “original”.

É interessante observar que, embora o chunk vazio que replica o rótulo de um chunk anterior esteja reutilizando e replicando exatamente o mesmo conteúdo, este novo chunk pode receber atributos diferentes. Assim, por exemplo, embora o chunk original tenha o atributo echo = FALSE, este que o replica poderia receber o atributo echo = TRUE.

Usar o atributo ref.label

Uma terceira forma de replicar o conteúdo de um chunk anterior em um novo chunk é através do atributo ref.label, o qual deve receber como valor o rótulo do chunk cujo conteúdo se pretenda replicar. Conforme o seguinte trecho.

```{r, ref.label = "dados-tabela"}
```

O chunk vazio acima também replicará o conteúdo e o output do chunk dados-tabela, e também pode receber outros atributos além do atributo ref.label, inclusive atributos diferentes dos atributos do chunk original.

Este método também permite replicar mais de um chunk anterior em um mesmo chunk novo e vazio. Para isto basta inserir como valor do atributo ref.label um vetor com os rótulos de todos os chunks que se pretenda replicar. A sintaxe em R para criar um vetor é simplesmente c(valor_1, valor_2, valor_n, etc). Assim, para replicarmos os dois chunks anteriores deste exemplo em um terceiro chunk através do atributo ref.label ficaria assim:

```{r, ref.label = c("dados-tabela", "graficos")}
```
Organização dos chunks

Também é possível tomar partido das possibilidades que os atributos e rótulos dos chunks nos oferecem e do seu comportamento em “sessão única” para deixar o nosso arquivo R Markdown mais organizado, e também para facilitar a sua escrita.

Por exemplo, caso se pretenda que ao longo de todo o documento todos - ou a maior parte - dos trechos de código sejam omitidos (como fizemos) não precisamos necessariamente inserir o atributo echo = FALSE em cada um dos chunks do documento inteiro. Podemos criar um chunk para configurações como esta no início do documento e chamar dentro dele funções que modifiquem o comportamento padrão dos demais chunks do documento ou do documento como um todo.

Também é possível, por exemplo, reunir neste chunk de “configurações”, o carregamento de todos os pacotes que utilizaremos ao longo do documento. Isto mantém o código mais organizado e deixa cada chunk específico responsável apenas por produzir dados ou outputs específicos.

Vamos reorganizar desta maneira o trecho do exemplo que estamos construindo.

```{r setup, include = FALSE}
knitr::opts_chunk$set(echo = FALSE)

options(scipen = 999, OutDec = ",")

library(ggplot2)
library(cowplot)
library(scales)
```

## Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de **São Paulo**, **Rio de Janeiro** e **Belo Horizonte**.

```{r dados-tabela, echo = FALSE}
cidade <- c("São Paulo", "Rio de Janeiro", "Belo Horizonte")
populacao <- c(12396372, 6775561, 2530701)
idh_m <- c(0.805, 0.799, 0.810)

tabela_1 <- data.frame(cidade, populacao, idh_m)

knitr::kable(tabela_1, format.args = list(big.mark = "."))
```

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

Abaixo temos dois gráficos com os dados da tabela anterior:

```{r graficos, fig.width = 10}
grafico_1 <- ggplot(tabela_1) +
 aes(x = cidade, weight = populacao) +
 geom_bar(fill = "#779ca9") +
 ggtitle("População") +
 labs(x = "", y = "População", title = "População das cidades") +
 theme_minimal() +
 scale_y_continuous(labels = function(y) format(y, big.mark = "."))

grafico_2 <- ggplot(tabela_1) +
 aes(y = cidade, weight = idh_m) +
 geom_bar(fill = "#779ca9") +
 ggtitle("IDH M") +
 coord_cartesian(xlim=c(0.75,0.82)) +
 labs(x = "IDH M", y = "", title = "IDH M das cidades") +
 theme_minimal()

plot_grid(grafico_1, grafico_2)
```

Como pode ser observado, criamos um novo chunk de código R no início do documento, ao qual atribuímos o rótulo setup. Neste chunk inserimos o atributo include = FALSE, porque queremos que o código contido nele seja executado, mas que não seja mostrado no documento, nem o trecho de código em si nem qualquer output.

Neste chunk setup chamamos a função knitr::opts_chunk$set(), do pacote Knitr. Esta função permite definir configurações que serão o comportamento padrão dos chunks do documento. Neste sentido, inserimos como argumento echo = FALSE, para que em todos os chunks os códigos sejam omitidos e apenas os outputs renderizados, o que elimina a necessidade de inserir o mesmo atributo echo = FALSE nos dois chunks seguintes

Se por ventura, ao longo do documento, se pretenda que o trecho de código de algum chunk específico seja renderizado basta inserir o atributo echo = TRUE a este chunk específico.

Repare que foi mantido no segundo chunk o atributo fig.width = 10. Embora fosse possível transferir esta opção também para a função knitr::opts_chunk$set() no chunk setup, consideramos que, neste caso, isto é uma característica específica deste chunk e não deveria ser um atributo global.

Também chamamos neste chunk a função options(), que nos permite configurar algumas opções globais que afetam a maneira como o R calcula e exibe seus resultados, na qual inserimos os argumentos scipen = 999 e OutDec = ",", os que também eliminou a necessidade de chamar esta mesma função nos dois chunks seguintes.

Por fim, também carregamos neste chunk setup os pacotes utilizados até agora, o que elimina a necessidade de carrega-los nos chunks seguintes.

Estas alterações apenas organizaram o código do arquivo R Markdown, de modo que a saída permanece idêntica à mostrada anteriormente.

Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de São Paulo, Rio de Janeiro e Belo Horizonte.

cidade populacao idh_m
São Paulo 12.396.372 0,805
Rio de Janeiro 6.775.561 0,799
Belo Horizonte 2.530.701 0,810

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

Abaixo temos dois gráficos com os dados da tabela anterior:

Existem algumas “boas práticas” para atribuição de rótulos a chunks (e também para caminhos - paths - de arquivos). Deve-se evitar utilizar espaços, pontos . e sublinhado _ (underline), porque isso poderia “confundir” da sintaxe do R Markdown. Quando se pretender utilizar nomes compostos é mais adequado utilizar o hifen -. Assim, o rótulo dados-tabela é melhor do que dados tabela, dados.tabela ou dados_tabela, por exemplo.

Além disso, o “cabeçalho” do chunk - o conjunto de valores dentro das chaves {} após as três crases ``` que abrem o chunk, onde ficam o nome da linguagem, o rótulo e os atributos - deve necessariamente ser escrito em uma única linha, não se pode quebrar esta linha (como seria possível - e até adequado de se fazer - em uma função, por exemplo).

Código R inline

Outra forma de executar código em um documento R Markdown é incorporar pequenos trechos de código R inline, no meio de um parágrafo por exemplo.

A sintaxe para incorporar um código R inline é simplesmente `r `, entre crases simples, com a letra r logo após a primeira crase e o código em si separado da letra r por apenas um espaço.

Neste sentido, se inserirmos no meio de um parágrafo o código `r 2 + 2` será renderizado o número 4, como se o tivéssemos digitado (isto porque a sintaxe em R para somar dois números é simplesmente n + n).

Assim, vamos prosseguir com nosso documento de exemplo.

```{r maiores}
maior_pop <- tabela_1$cidade[which.max(populacao)]
maior_idh <- tabela_1$cidade[which.max(idh_m)]
```

Como podemos observar, a cidade com maior população é `r maior_pop`, enquanto a cidade com maior IDH M é `r maior_idh`.

No trecho R Markdown acima, uma continuação de nosso exemplo, criamos um novo chunk com rótulo maiores e nele criamos dois objetos, maior_pop e maior_idh, depois, em meio a um parágrafo Markdown “chamamos” estes dois objetos através de código R inline.

Embora não seja o objetivo, vamos explicar sucintamente a sintaxe dos valores atribuídos às variáveis.

  • A sintaxe em R para referenciar uma coluna de uma tabela (ou Data Frame) é nome_da_tabela$_nome_da_coluna, de modo que tabela_1$cidade referencia a coluna cidade do Data Frame tabela_1.

  • A sintaxe em R para referenciar um valor de um vetor (ou de uma coluna de um Data Frame, que é, na verdade, um vetor) a partir de sua posição no vetor é vetor[índice], de modo que tabela_1$cidade[1] retornaria o valor de índice 1 da coluna cidade do Data Frame tabela_1.

  • A sintaxe em R para encontrar o índice do maior valor em um vetor de valores é which.max(vetor), de modo que which.max(populacao) vai retornar o índice (a posição no vetor) do maior valor do vetor populacao (ou, neste caso, da coluna tabela_1$populacao, o R entende que estamos nos referindo a esta coluna).

Desta forma, o valor recebido pelo objeto maior_pop será o valor que está na coluna cidade na linha correspondente ao maior valor da coluna populacao, ou em outras palavras, o nome da cidade que tenha maior população. O valor recebido pelo objeto maior_idh, por sua vez, será o nome da cidade que tenha maior IDH M.

Neste sentido, o trecho R Markdown acima produzirá uma saída semelhante a esta:

Como podemos observar, a cidade com maior população é São Paulo, enquanto a cidade com maior IDH M é Belo Horizonte.

Como podemos ver, é apenas um parágrafo, com os nomes das cidades de São Paulo e Belo Horizonte automaticamente preenchidos (o código do chunk não aparece porque isto é uma continuação dos exemplos anteriores, e já havíamos definido echo = FALSE como uma configuração global).

Qualquer código pode ser colocado inline. Considerando o exemplo acima, poderíamos ter dispensado o chunk e os objetos e inserido o pequeno algorítimo diretamente inline, e o resultado de saída seria o mesmo, mais ou menos desta forma:

Como podemos observar, a cidade com maior população é `r tabela_1$cidade[which.max(populacao)]`, enquanto a cidade com maior IDH M é `r tabela_1$cidade[which.max(idh_m)]`.

Todavia, escrever algorítimos muito longos inline não é uma boa prática, pode deixar o documento muito desorganizado e é mais difícil de recuperar informações mais adiante no documento.

Os códigos R inline podem ser adicionados não apenas no corpo de texto Markdown, também é possível adicionar estes códigos inline no cabeçalho YAML, tornando dinâmicos também os metadados do documento.

Isto pode ser útil de diversas formas, por exemplo, podemos fazer com que a data do documento seja atualizada automaticamente no momento em que ele seja renderizado, inserindo um código R inline como valor para date no cabeçalho YAML. Da seguinte forma:

---
title: "Inteligência Urbana"
subtitle: "Dados urbanos em R Markdown"
author: "Elson Fabiano Alves"
date: "`r format(Sys.time(), '%d %B %Y')`"
output: html_document
---

O código R acima inserido em meio ao cabeçalho YAML utiliza a função format() em conjunto com a função Sys.time() para inserir a data do sistema, adequadamente formatada, como valor para o metadado date.

Outras linguagens

Conforme já mencionado, em que pese o R Markdown - e o RStudio - tenham sido feitos pelo e para o R, hoje em dia outras linguagens também são suportadas, através da instalação de pacotes adicionais que estendem os pacotes Knitr e rmarkdown.

No momento em que escrevo este artigo a lista de linguagens suportadas é a seguinte: awk, bash, coffee, gawk, groovy, haskell, lein, mysql, node, octave, perl, psql, Rscript, ruby, sas, scala, sed, sh, stata, zsh, highlight, Rcpp, tikz, dot, c, cc, fortran, fortran95, asy, cat, asis, stan, block, block2, js, css, sql, go, python, julia, sass, scss, R, bslib, targets.

A lista acima foi gerada pela função knitr::knit_engines$get(), que lista as engines suportadas.

O funcionamento dos chunks de código é essencialmente o mesmo, basta que um chunk de código Python, por exemplo, seja aberto com ```{python} em vez de ```{r}.

Algumas linguagens suportadas - nem todas - também podem “compartilhar” a mesma sessão de código dentro do documento R Markdown. Python, por exemplo, pode, o que significa que é possível utilizar código Python e R no mesmo documento R Markdown e ainda utilizar objetos criados em um chunk R dentro de um chunk Python e vice versa.

Python, por exemplo

A essência do funcionamento é a mesma para as demais linguagens, assim como para R, mas cada linguagem exigirá a instalação de pacotes adicionais específicos e terá algum poder e limitações próprias também, vamos exemplificar sucintamente como funciona no caso de Python, que é uma linguagem também muito utilizada para ciência de dados, juntamente com R.

Para utilizar Python no R Markdown só é necessário, a princípio, ter Python instalado na máquina. Para instalar o Python basta acessar o site oficial do Python e, na guia downloads baixar a última versão para o sistema operacional adequado. O próprio site irá identificar a partir de qual sistema operacional está sendo acessado e ajustar o link de download correto. Basta fazer o download e instalar como qualquer outro software.

Isso já será suficiente - desde a versão 1.2 do RStudio, pelo menos - para fazer com que um chunk Python seja executado e que diferentes chunks Python preservem a mesma sessão.

Para não apenas utilizar Python em um documento R Markdown, mas também poder “compartilhar” objetos entre Python e R é necessário instalar o pacote reticulate.

O pacote reticulate vai facilitar o uso do Python no RStudio, ele oferece uma interface para módulos, classes e funções Python, de modo que ao “chamar” o Python, os tipos de dados R são automaticamente convertidos em seus tipos Python equivalentes, e quando os valores são retornados de Python para R, eles são convertidos de volta para tipos R.

O pacote reticulate pode ser instalado através da função install.packages("reticulate"). Como com qualquer pacote só é necessário instalar uma vez, e então só precisará ser carregado nos documentos que pretendam utilizá-lo. Embora seja possível, não é aconselhável chamar a função de instalação de um pacote dentro de um arquivo R Markdown, é melhor fazer isso no Console do RStudio.

Além disso, também é possível e aconselhável instalar o pacote rminiconda, que funciona em conjunto com o reticulate.

O pacote rminiconda fornece utilitários para instalar ambientes Python “miniconda” isolados, foi criado para permitir que desenvolvedores de pacotes R escrevessem pacotes R que envolvam bibliotecas Python sem que os usuários tenham que se preocupar em instalar ou configurar nada fora do R. O rminiconda “isola” a versão do Python que utilizamos no RStudio. O conflito entre diferentes versões do Python instaladas em um mesmo sistema operacional é muito comum, e o rminiconda resolve esse problema.

O pacote rminiconda - ainda - não pode ser instalado através da função install.packages(), mas pode ser instalado de pelo menos duas outras formas: através de uma função específica do pacote reticulate, reticulate::install_miniconda (é necessário instalar o pacote reticulate primeiro), ou através de uma instalação externa utilizando o pacote remotes, remotes::install_github("hafen/rminiconda") (é necessário ter instalado o pacote remotes). Como no caso anterior, é melhor fazer isso no Console.

Então basta carregar o pacote reticulate em algum chunk R do documento através da função library(reticulate) e pode-se começar a usar Python no R Markdown, e “mesclado” com R. Vamos fazer isso no nosso chunk setup no início do documento, só para manter as coisas organizadas.

```{r setup, include = FALSE}
knitr::opts_chunk$set(echo = FALSE)

options(scipen = 999, OutDec = ",")

library(ggplot2)
library(cowplot)
library(scales)
library(reticulate)
```
Chamar objetos R no Python e vice-versa

Um chunk Python, como já dissemos, funciona da mesma forma que um chunk R, com a diferença que ele deve ser aberto com ```{python} em vez de ```{r}.

Vamos retomar nosso documento R Markdown de exemplo e criar algumas variáveis - ou objetos - Python, atribuir a estas variáveis valores construídos a partir de objetos R criados nos chunks anteriores e então utilizar estes objetos Python em um trecho de código R inline. E vamos fazer isso da forma mais resumida possível para não estender ainda mais este artigo.

```{python rj}
cid_1 = r.cidade[1]
pop_1 = r.populacao[1]
idh_1 = r.idh_m[1]
```

A população da cidade do `r py$cid_1` é de `r prettyNum(py$pop_1, big.mark = ".")` habitantes e seu IDH M é `r py$idh_1`.

Vamos descrever sucintamente o que fizemos no chunk Python acima e no parágrafo Markdown que o segue.

  • No chunk Python de rótulo rj criamos três variáveis Python: cid_1, pop_1 e idh_1.

    A sintaxe em Python para criar variáveis - ou objetos - e atribuir valores a eles é simplesmente nome_da_variavel = valor_da_variavel.

  • Atribuímos às variáveis valores construídos a partir dos objetos R cidade, populacao e idh_m, que foram criados no chunk R dados-tabela.

    A sintaxe para utilizar um objeto R no Python é simplesmente r.objeto. Os objetos que utilizamos são vetores de valores (ou colunas de tabela).

    r.cidade[1] será o valor do vetor R cidade no índice 1 do vetor (que é o segundo valor do vetor, uma vez que Python indexa vetores a partir do 0, diferentemente do R, que começa do 1), agora armazenado na variável Python cid_1. A mesma lógica ocorre para as variáveis pop_1 e idh_1.

  • No parágrafo Markdown seguinte inserimos estas variáveis Python dentro de trechos de código R inline.

    A sintaxe para utilizar um objeto Python no R é py$objeto.

    No caso da variável pop_1 a inserimos como argumento da função prettyNum() para que pudéssemos formatar sua saída no sentido de utilizar o ponto . como caractere separador de milhares.

Desta forma, o trecho R Markdown acima produzirá uma saída semelhante a esta:

A população da cidade do Rio de Janeiro é de 6.775.561 habitantes e seu IDH M é 0,799.

Como podemos ver, é apenas um parágrafo, com os dados das variáveis Python preenchidos automaticamente dentro de código R inline (o código do chunk não aparece porque isto é uma continuação dos exemplos anteriores, e já havíamos definido echo = FALSE como uma configuração global, o que também vale para chunks Python).

É relevante observar que o código inline é sempre R, apenas os chunks podem ser de outras linguagens. Todavia os eventuais outputs de um chunk Python - ou de outra linguagem - também seriam renderizados na sequência do chunk e podem - como de fato fizemos - ser inseridos no meio do texto também, bastando utilizar o código R inline para isso, com o comando py$ (no caso do Python). O mesmo comando py$ pode ser usado para inserir um objeto Python dentro de um chunk R.

Exemplo final

Apenas para concluir, o pequeno documento R Markdown que construímos aos poucos desde o artigo anterior, agora completo, ficou assim:

---
title: "Inteligência Urbana"
subtitle: "Dados urbanos em R Markdown"
author: "Elson Fabiano Alves"
date: "11/09/2021"
output: html_document
---
```{r setup, include = FALSE}
knitr::opts_chunk$set(echo = FALSE)

options(scipen = 999, OutDec = ",")

library(ggplot2)
library(cowplot)
library(scales)
library(reticulate)
```
## Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de **São Paulo**, **Rio de Janeiro** e **Belo Horizonte**.

```{r dados-tabela}
cidade <- c("São Paulo", "Rio de Janeiro", "Belo Horizonte")
populacao <- c(12396372, 6775561, 2530701)
idh_m <- c(0.805, 0.799, 0.810)

tabela_1 <- data.frame(cidade, populacao, idh_m)

knitr::kable(tabela_1, format.args = list(big.mark = "."))
```

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

Abaixo temos dois gráficos com os dados da tabela anterior:

```{r graficos, fig.width = 10}
grafico_1 <- ggplot(tabela_1) +
 aes(x = cidade, weight = populacao) +
 geom_bar(fill = "#779ca9") +
 ggtitle("População") +
 labs(x = "", y = "População", title = "População das cidades") +
 theme_minimal() +
 scale_y_continuous(labels = function(y) format(y, big.mark = "."))

grafico_2 <- ggplot(tabela_1) +
 aes(y = cidade, weight = idh_m) +
 geom_bar(fill = "#779ca9") +
 ggtitle("IDH M") +
 coord_cartesian(xlim=c(0.75,0.82)) +
 labs(x = "IDH M", y = "", title = "IDH M das cidades") +
 theme_minimal()

plot_grid(grafico_1, grafico_2)
```

```{r maiores}
maior_pop <- tabela_1$cidade[which.max(populacao)]
maior_idh <- tabela_1$cidade[which.max(idh_m)]
```

Como podemos observar, a cidade com maior população é `r maior_pop`, enquanto a cidade com maior IDH M é `r maior_idh`.

```{python rj}
cid_1 = r.cidade[1]
pop_1 = r.populacao[1]
idh_1 = r.idh_m[1]
```

A população da cidade do `r py$cid_1` é de `r prettyNum(py$pop_1, big.mark = ".")` habitantes e seu IDH M é `r py$idh_1`.

O resultado final, após a renderização será parecido com este:

Inteligência Urbana

Dados urbanos em R Markdown

Elson Fabiano Alves

11/09/2021

Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de São Paulo, Rio de Janeiro e Belo Horizonte.

cidade populacao idh_m
São Paulo 12.396.372 0,805
Rio de Janeiro 6.775.561 0,799
Belo Horizonte 2.530.701 0,810

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

Abaixo temos dois gráficos com os dados da tabela anterior:

Como podemos observar, a cidade com maior população é São Paulo, enquanto a cidade com maior IDH M é Belo Horizonte.

A população da cidade do Rio de Janeiro é de 6.775.561 habitantes e seu IDH M é 0,799.

Apenas para fins de visualização, se substituirmos os valores dos parâmetros echo e include dos chunks de FALSE para TRUE, de modo que os trechos de código sejam renderizados, o resultado seria semelhante a este:

Inteligência Urbana

Dados urbanos em R Markdown

Elson Fabiano Alves

11/09/2021

knitr::opts_chunk$set(echo = TRUE)

options(scipen = 999, OutDec = ",")

library(ggplot2)
library(cowplot)
library(scales)
library(reticulate)

Cidades e dados

A seguir temos uma tabela com a população e o Índice de Desenvolvimento Humano das cidades de São Paulo, Rio de Janeiro e Belo Horizonte.

cidade <- c("São Paulo", "Rio de Janeiro", "Belo Horizonte")
populacao <- c(12396372, 6775561, 2530701)
idh_m <- c(0.805, 0.799, 0.810)

tabela_1 <- data.frame(cidade, populacao, idh_m)

knitr::kable(tabela_1, format.args = list(big.mark = "."))
cidade populacao idh_m
São Paulo 12.396.372 0,805
Rio de Janeiro 6.775.561 0,799
Belo Horizonte 2.530.701 0,810

Estas cidades são as cidades-sede das três maiores regiões metropolitanas do país.

Abaixo temos dois gráficos com os dados da tabela anterior:

grafico_1 <- ggplot(tabela_1) +
 aes(x = cidade, weight = populacao) +
 geom_bar(fill = "#779ca9") +
 ggtitle("População") +
 labs(x = "", y = "População", title = "População das cidades") +
 theme_minimal() +
 scale_y_continuous(labels = function(y) format(y, big.mark = "."))

grafico_2 <- ggplot(tabela_1) +
 aes(y = cidade, weight = idh_m) +
 geom_bar(fill = "#779ca9") +
 ggtitle("IDH M") +
 coord_cartesian(xlim=c(0.75,0.82)) +
 labs(x = "IDH M", y = "", title = "IDH M das cidades") +
 theme_minimal()

plot_grid(grafico_1, grafico_2)

maior_pop <- tabela_1$cidade[which.max(populacao)]
maior_idh <- tabela_1$cidade[which.max(idh_m)]

Como podemos observar, a cidade com maior população é São Paulo, enquanto a cidade com maior IDH M é Belo Horizonte.

cid_1 = r.cidade[1]
pop_1 = r.populacao[1]
idh_1 = r.idh_m[1]

A população da cidade do Rio de Janeiro é de 6.775.561 habitantes e seu IDH M é 0,799.

Conclusão

Neste artigo apresentamos o R Markdown, uma ferramenta capaz de produzir documentos dinâmicos a partir da incorporação de trechos de código de linguagens de programação em arquivo de texto com sintaxe Markdown. Esta foi a segunda parte de um artigo de duas partes, e nos concentramos no funcionamento e na estrutura do documento, sobretudo nas formas de inserção de código, configurações e interações, a partir de um exemplo prático.

Além do blog, a plataforma Inteligência Urbana disponibiliza páginas com referências para livros, cursos e leis e normas relacionadas aos temas que tratamos aqui. Caso você tenha interesse pode conferir nossos serviços oferecidos e entrar em contato quando quiser. Se quiser ser alertado da publicação de material novo pode assinar a nossa newsletter, e muito obrigado pela atenção até aqui!

Principais referências