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.
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.
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
eidh_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 pacoteKnitr
, tendo como argumentos o objetotabela_1
criado na linha anterior eformat.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 objetotabela_1
, além de permitir alguns ajustes.O argumento
format.args
permite passar uma lista de argumentoslist()
para formatar os valores de uma tabela. Neste caso passamos o argumentobig.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 apenasfunção()
, sem precisar, então, utilizar olibrary(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
egrafico_2
, e atribuímos a cada um deles um gráfico criado utilizando as funções do pacoteggplot2
e também do pacotescales
(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 pacotecowplot
, utilizando como argumentos os objetosgrafico_1
egrafico_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.
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.
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.
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 serTRUE
ouFALSE
. Se forFALSE
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 serTRUE
ouFALSE
. Se forFALSE
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
, eerror
Lógico. O valor pode serTRUE
ouFALSE
. Se forFALSE
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 serTRUE
ouFALSE
. Se forFALSE
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 serTRUE
ouFALSE
. 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
efig.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
eout.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 serleft
,center
ouright
. -
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
eclass.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 quetabela_1$cidade
referencia a colunacidade
do Data Frametabela_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 quetabela_1$cidade[1]
retornaria o valor de índice 1 da colunacidade
do Data Frametabela_1
. -
A sintaxe em R para encontrar o índice do maior valor em um vetor de valores é
which.max(vetor)
, de modo quewhich.max(populacao)
vai retornar o índice (a posição no vetor) do maior valor do vetorpopulacao
(ou, neste caso, da colunatabela_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
eidh_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
eidh_m
, que foram criados no chunk Rdados-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 Rcidade
no índice 1 do vetor (que é o segundo valor do vetor, uma vez que Python indexa vetores a partir do0
, diferentemente do R, que começa do1
), agora armazenado na variável Pythoncid_1
. A mesma lógica ocorre para as variáveispop_1
eidh_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çãoprettyNum()
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
-
CONE, Matt. The Markdown Guide. Independently Published, 2018;
-
GALILI, Tal. R-bloggers. r-bloggers.com, 2021. Acessado em: 04/10/2021;
-
GIORDANELLI, Fabrício. R com Rstudio: do zero ao relatório. Publicação independente, 2021;
-
MACFARLANE, John. Pandoc. Pandoc.org, 2020. Acessado em: 02/04/2020;
-
R FOUNDATION. R: The R Project for Statistical Computing. R-project, 2021. Acessado em: 11/09/2021;
-
XIE, Yihui; DERVIEUX, Christophe; RIEDERER, Emily. R Markdown Cookbook. Boca Raton: CRC Press, 2020.
0 Comentários