Tópicos Especiais em Estatística Comp.

Introdução ao Shiny em R

Prof. Jodavid Ferreira

UFPE






Shiny em R


O que é Shiny?



Shiny é um framework em linguagem R para a criação de aplicativos web. Por não exigir conhecimento prévio de HTML, CSS e JavaScript, ele democratiza o acesso a essa área de desenvolvimento, permitindo a criação de aplicativos bonitos e complexos a partir de scripts R.

Hex sticker do pacote Shiny: um hexágono de cor azul clara com a palavra Shiny escrita no meio.

Exemplos de Shiny?



Por que aprender Shiny?



  • Por ser gratuito e por não exigir de largada conhecimento em desenvolvimento Web, o framework Shiny vem sendo cada vez mais utilizado por empresas e por órgãos do governo para acomodar painéis analíticos ou para comunicar resultados de maneira interativa e dinâmica.


  • Nas universidades, o Shiny já é uma poderosa ferramenta de ensino, que substitui apresentações de dezenas de slides por apenas uma única tela interativa. Também é muito útil para a explicação de conceitos estatísticos, além de incentivar estudantes a programar. Na pesquisa, o Shiny facilita a colaboração entre cientistas de diferentes áreas e é uma excelente alternativa para aumentar e melhorar a comunicação científica.

Quais são os limites do Shiny?



  • O Shiny fornece uma estrutura para gerarmos código HTML a partir de funções em R. Também possui uma base de JavaScript e CSS para deixar os aplicativos funcionais e com um visual satisfatório. Além disso, podemos utilizar por trás todo o poderio de análise de dados que o R e seus pacotes fornecem. Com esses elementos, já conseguimos construir qualquer tipo de layout e lógica interna.

  • Contudo, o grande poder do Shiny está em não limitar as possibilidades apenas ao que foi feito pelos desenvolvedores do pacote1. Existem vários outros pacotes criados pela comunidade que trazem mais elementos visuais e funcionais para o Shiny, diminuindo ainda mais a necessidade de conhecermos HTML, CSS e JavaScript. É simples incluir tags HTML, folhas de estilo CSS e suas próprias funções JavaScript em um aplicativo Shiny.

Primeiro aplicativo Shiny



  • Antes de começarmos, você precisa ter o pacote shiny instalado.


install.packages("shiny")


  • A versão do pacote que estamos utilizando neste livro é a 1.8.1.1.


O que é um aplicativo Shiny?



  • Um aplicativo Shiny é um site, uma página na web. Ele terá um endereço (URL) que, quando acessado, exibirá informações em forma de texto e imagens1.

  • Ser uma página web também significa que ele será constituído de HTML, CSS e JavaScript. Se você não conhece essas linguagens, uma boa maneira de entender o papel de cada uma delas no desenvolvimento de um site é pensar na construção de um prédio.

  • Podemos pensar o HTML como a estrutura física do prédio: chão, paredes, colunas, teto, encanamento, fiação etc; o CSS é o responsável pela aparência: pintura, pisos, azulejos, decoração em geral; e o JavaScript traz elementos de funcionalidade ao prédio: portas, janelas, interruptores, elevadores etc.

O que é um aplicativo Shiny?



Prédio sem acabamento representando o HTML e prédio acabado representando HTML com CSS.
  • Com o Shiny, construiremos esse prédio utilizando funções de R.

O que é um aplicativo Shiny?



  • Um aplicativo Shiny também é uma aplicação web. Isso significa que, além de exibir informações, o nosso site/aplicativo também permitirá que a gente interaja com ele enviando dados que serão processados para criar novas informações. Essa interação gera um componente fundamental de um Shiny app: o servidor. Todo aplicativo Shiny será hospedado em um servidor com uma sessão de R rodando.


  • Um aplicativo Shiny tem dois componentes básicos: a interface de usuário e o servidor.

Os componentes básicos



Os componentes básicos



  • O primeiro componente se refere à(s) tela(s) do aplicativo, àquilo que veremos quando estivermos usando o app. Já o segundo componente se refere ao que não veremos: a lógica interna do app.


  • Desenvolver a interface de usuário ou UI (sigla para o termo user interface, em inglês) significa construir o código HTML que compõe o app. Retomando a analogia do prédio, você precisa determinar explicitamente quais são e onde ficam as paredes do seu aplicativo. Isso é feito a partir de funções do pacote Shiny que geram HTML.

Os componentes básicos



  • A princípio, você não precisará se preocupar com CSS, pois a aparência padrão do Shiny1 é bem razoável. O mesmo vale para o JavaScript: quando você programa em Shiny, todo o JavaScript necessário para o seu app funcionar corretamente já está pronto e será utilizado automaticamente.

  • A figura a seguir mostra a UI de um app bem simples, que permite a escolha de duas variáveis e apresenta o gráfico de dispersão delas:

UI de um app simples.

UI de um app simples.

Os componentes básicos



  • O lado do servidor (server side ou simplesmente server, em inglês) contém toda a lógica para a construção das visualizações apresentadas na UI. No exemplo da figura anterior, o código que gera o gráfico de dispersão fica dentro do servidor.


  • Embora precisemos aprender alguns conceitos e regras novas, a maior parte do código que compõe o servidor é aquele bom e velho R que já utilizamos no dia-a-dia para gerar tabelas, gráficos e qualquer outro tipo de visualização. Em resumo, para fazer um ggplot aparecer no Shiny, basta adaptar o código que gera esse gráfico para receber as informações que vêm da UI (inputs) e devolver o resultado (output) de maneira adequada.

Os componentes básicos



A UI e o servidor são os dois elementos básicos de um aplicativo Shiny. Embora sejam construídos separadamente, um depende do outro e a correta conexão desses componentes é o que gera a interatividade do app. Teremos sempre requisições sendo feitas pela UI, processadas pelo servidor e seus resultados devolvidos à UI. Esse processo está resumido no esquema a seguir:

Esquema UI/servidor de um aplicativo Shiny.

Esquema UI/servidor de um aplicativo Shiny.

Estrutura de um código Shiny



  • A construção do código HTML que compõe o aplicativo é feito utilizando funções do R que retornam HTML. Esse é um dos papéis do pacote shiny e um dos desafios da programação em Shiny. Não precisaremos aprender HTML formalmente, mas precisaremos aprender quais funções utilizar para construir uma UI bem estruturada.

  • Também falamos que o servidor é responsável por receber os códigos que geram as visualizações apresentadas na UI, conectando os inputs e outputs do aplicativo. No código, isso sempre será feito dentro de uma função chamada server.

Com isso em mente, o código de qualquer aplicativo Shiny terá a estrutura abaixo:

  • um objeto chamado ui;

  • uma função chamada server;

  • e uma chamada da função shinyApp().

Estrutura de um código Shiny



Como exemplo, observe o código a seguir. Ele representa um dos aplicativos mais simples que podemos construir:

library(shiny)

ui <- fluidPage("Olá, mundo!")

server <- function(input, output, session) {
  
}

shinyApp(ui, server)

Esse código resultará no aplicativo com a seguinte UI:

UI do aplicativo Olá, mundo!

UI do aplicativo “Olá, mundo!”.

Estrutura de um código Shiny



  • Vejam que a UI se trata apenas de uma página de fundo branco com a frase “Olá, mundo!” escrita no canto superior esquerdo. O app não possui nenhuma interatividade.

  • Olhando o código anterior, encontramos a frase “Olá, mundo!” na definição do objeto ui, dentro da função fluidPage(). Essa função do pacote shiny é uma entre várias que utilizaremos para retornar código HTML e precisamos utilizá-la para que o HTML do aplicativo funcione corretamente.

ui <- fluidPage("Olá, mundo!")

O importante por enquanto é sabermos que o objeto ui é responsável por receber todo o código HTML do nosso aplicativo.

Estrutura de um código Shiny



  • A função server sempre receberá os argumentos input, output e session. A partir desses argumentos, montaremos a lógica interna (ou reativa, guarde esse nome) do app. O código que gera as visualizações será escrito dentro dessa função. Como o nosso app Olá, mundo! não possui visualizações ou interatividade, a sua função server está vazia1.
server <- function(input, output, session) {
  # O código do server seria colocado aqui.
}
  • A última linha de código do nosso pequeno app contém a chamada shinyApp(ui, server). Essa função vai juntar o objeto ui e a função server, construir toda a arquitetura necessária e rodar o aplicativo. Não discutiremos aqui como tudo isso é feito pois envolve tópicos fora do escopo de um material introdutório. Por enquanto, é importante lembrar que essa função sempre deve ser chamada ao fim do código de um Shiny app.

Rodando um aplicativo



  • Para fazer o seu primeiro aplicativo em Shiny, abra o RStudio e copie o código do app Olá, mundo! (apresentado novamente a seguir) em um arquivo chamado app.R. Recomendamos fortemente que vocês utilizem projetos e que, neste primeiro momento, sempre salvem o script dos aplicativos na raiz do projeto.
library(shiny)

ui <- fluidPage("Olá, mundo!")

server <- function(input, output, session) {
  
}

shinyApp(ui, server)
  • Repare que algumas opções novas aparecerão no RStudio quando salvamos o arquivo. Isso acontece porque o RStudio reconhece a sintaxe do código como a de um aplicativo Shiny, habilitando para nós algumas ferramentas que são úteis apenas para trabalhar com apps. A mais importante por enquanto será o botão Run App.

Rodando um aplicativo



  • Como discutimos anteriormente, um aplicativo Shiny em funcionamento sempre terá um computador rodando uma sessão de R por trás. Esse computador, chamado genericamente de servidor, pode ser uma máquina virtual em um serviço de nuvem, uma máquina virtual em um serviço de hospedagem, um servidor dentro da sua empresa, um servidor na sua casa ou mesmo o seu próprio computador pessoal.

  • Normalmente, enquanto estamos desenvolvendo um aplicativo Shiny, queremos testá-lo localmente para verificar se tudo funciona corretamente, se está ficando bonito ou simplesmente para gastar alguns minutos apreciando a nossa obra de arte. Testar localmente significa que o seu próprio computador fará as vezes de servidor, embora isso não signifique que seu app ficará disponível na internet.

  • Quando servimos um app localmente, isto é, quando rodamos um app, ganhamos um endereço que será acessível apenas do nosso computador. A partir desse endereço, podemos testar nosso app no navegador, como se ele já estivesse em produção. No RStudio, para rodar nossos apps, utilizamos justamente o botão Run App.

Rodando um aplicativo



Botão Run App no Rstudio. Fica logo acima do script.

Botão Run App no Rstudio.
  • Ao clicar nesse botão, o seu navegador padrão será aberto1 e você verá a UI do nosso modesto app com apenas a frase “Olá, mundo!”.

Rodando um aplicativo



  • Se você voltar ao RStudio, eventualmente vai notar algo muito importante: a sua sessão de R estará ocupada! Mas isso não deveria ser uma surpresa, pois já discutimos que todo Shiny app tem uma sessão de R rodando por trás.

  • Essa sessão fornece a comunicação da UI (ou do nosso navegador) com o servidor e é responsável por atualizar as visualizações apresentadas na UI, sempre que alguém interagir com o app. Embora o nosso app Olá, mundo não possuir interatividade, a estrutura necessária para que a interatividade aconteça ainda assim é criada pelo Shiny.

  • Para liberar a sessão, basta clicar no botão “stop”, na parte de cima do Console, ou pressionar a tecla Esc. Veja que, ao fazer isso, a tela do app ficará cinza, indicando que ele foi desconectado do servidor e não funcionará mais corretamente.

Rodando um aplicativo


  • No console, após rodarmos o app, também aparecerá uma mensagem identificando o endereço do nosso aplicativo. Nesse caso, será um IP (http://127.0.0.1)1 com alguma porta que esteja disponível escolhida aleatoriamente (:4028). Esse endereço aparecerá no nosso navegador e poderemos copiá-lo e colá-lo em qualquer outra aba ou navegador que quisermos rodar o app.

Adicionando interatividade



  • A interatividade de um aplicativo Shiny é dada pela relação de inputs e outputs. Os inputs permitem enviarmos informação para o servidor, que é utilizada na construção dos outputs devolvidos para a tela.


  • A seguir, mostraremos como adicionar inputs e outputs a um Shiny app. Começaremos com os outputs, dando nossos primeiros passos na construção da função server.

Adicionando outputs



Outputs representam as saídas do nosso aplicativo, isto é, tudo que queremos que nosso código R retorne para a UI. Essas saídas podem ser tabelas, gráficos, mapas, texto, imagens ou qualquer outro elemento HTML.

Os outputs são definidos na UI e criados no server. Cada tipo de output é definido por uma função do tipo *Output(). Veja as principais funções dessa família:

Adicionando outputs


Essas funções especificam onde os outputs serão colocados dentro da UI. Elas não especificam como eles serão criados. Para isso, utilizamos as funções do tipo render*(), responsáveis por definir o código R que gera cada output. Além disso, elas renderizam os resultados para HTML, possibilitando que essas visualizações sejam inseridas no código HTML que gera a UI. Na grande maioria dos casos, teremos o par visualizacaoOutput() e renderVisualizacao().

Veja a seguir as principais funções render*() e como elas se comunicam com as funções *Output().

Adicionando outputs



O argumento outputId das funções *Output() é utilizado para identificarmos cada output dentro da função server. Todos os outputs criados ficarão dentro da lista output. Veja a seguir, o exemplo de um aplicativo que contém um histograma da variável mpg da base mtcars.

library(shiny)

ui <- fluidPage(
  "Histograma da variável mpg",
  plotOutput(outputId = "histograma")
)

server <- function(input, output, session) {
  
  output$histograma <- renderPlot({
    hist(mtcars$mpg)
  })
  
}

shinyApp(ui, server)

Adicionando outputs



No código anterior:

  • a função plotOutput() especifica o lugar na UI onde será colocado o histograma (no caso, logo abaixo do texto "Histograma da variável mpg");

  • para criar o histograma, atribuímos o resultado da função renderPlot() ao valor histograma da lista output, mesmo nome dado ao argumento outputId na função plotOutput();

  • a função renderPlot(), assim com qualquer outra função da família render*(), recebe como primeiro argumento o código para gerar o output;

  • o histograma é gerado com o código hist(mtcars$mpg).

Adicionando outputs



  • Embora tenhamos uma visualização sendo construída no servidor, ainda não temos interatividade, isto é, não conseguimos mudar nada no conteúdo dessa visualização a partir da UI.
  • Para solucionar isso, vamos incluir inputs.
  • Inputs representam as entradas do nosso aplicativo, isto é, a maneira como informações são transmitidas entre a pessoa usando o app e o servidor. Essas informações podem ser valores, textos, datas, arquivos ou até mesmo cliques em um botão. Para facilitar a escolha desses valores1, o pacote shiny possibilita diversas opções de widgets2, a depender do tipo de valor a ser passado.

Adicionando inputs


  • No campo Current Value(s) é mostrado qual valor será levado para dentro da função server em cada caso.

Adicionando inputs



  • Para criar esses widgets utilizamos as famílias de funções *Input() ou *Button.
  • De forma análoga ao outputId das funções *Output(), todas essas funções possuem inputId como primeiro argumento, que recebe uma string e será utilizado para acessar dentro da função server cada um dos inputs criados. Isso implica que dois inputs não podem ter o mesmo inputId.
  • No código a seguir, vamos no app uma caixa de seleção que permite a escolha da variável que será utilizada no histograma.

Adicionando inputs



library(shiny)

ui <- fluidPage(
  "Histograma da variável mpg",
  selectInput(
    inputId = "variavel",
    label = "Selecione uma variável",
    choices = names(mtcars)
  ),
  plotOutput(outputId = "histograma")
)

server <- function(input, output, session) {
  
  output$histograma <- renderPlot({
    hist(mtcars[[input$variavel]])
  })
  
}

shinyApp(ui, server)

Adicionando inputs



A caixa de seleção foi criada pela função selectInput(). Essa função requer 3 argumentos:

  • o inputId, como discutido anteriormente;

  • o label, que será mostrado na tela e indica a quem estiver usando o app o que está sendo escolhido nesse input1;

  • e o choices, um vetor com as possíveis escolhas da caixa de seleção.

Para acessar o valor do input na função server, utilizamos a lista input e o nome dado no argumento inputId da função selectInput() (no caso, "variavel"). A lista input guarda todos os inputs criados na UI.

Adicionando inputs



  • O widget selectInput() envia ao servidor uma string com o valor escolhido na caixa de seleção. Por isso utilizamos o operador [[ para fazer a seleção da variável


  • Quando o app é iniciado, por exemplo, input$variavel recebe o valor "mpg" e, por consequência, mtcars[[input$variavel]] será igual a mtcars[["mpg"]], que retorna um vetor com os valores da coluna mpg e será utilizado pela função hist() para gerar o gráfico.

Adicionando inputs



mtcars[["mpg"]]
 [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
[16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
[31] 15.0 21.4
hist(mtcars[["mpg"]])

Adicionando inputs



library(shiny)

variaveis <- names(mtcars)

ui <- fluidPage(
  selectInput(
    inputId = "variavel_A",
    label = "Variável A",
    choices = variaveis
  ),
  plotOutput(outputId = "histograma_A"),
  selectInput(
    inputId = "variavel_B",
    label = "Variável B",
    choices = variaveis,
    selected = variaveis[2],
  ),
  plotOutput(outputId = "histograma_B")
)

server <- function(input, output, session) {
  
  output$histograma_A <- renderPlot({
    print("Gerando histograma A...")
    hist(mtcars[[input$variavel_A]], main = "Histograma A")
  })
  
  output$histograma_B <- renderPlot({
    print("Gerando histograma B...")
    hist(mtcars[[input$variavel_B]], main = "Histograma B")
  })
  
}

shinyApp(ui, server)

Adicionando inputs



  • Repare pelas mensagens no Console1 que, quando alteramos o valor da variável A, apenas o histograma A é recalculado.


  • O mesmo vale para variável B e o histograma B. Isso acontece porque a relação entre inputs e outputs é mapeada quando rodamos o app e, quando modificamos um input, o Shiny roda novamente apenas o código necessário para recalcular os outputs associados a ele.






Parte 2 - GOLEM


Golem



  • Agora, vamos apresentar o framework Golem para a construção de aplicativos Shiny prontos para serem colocados em produção.

Motivação



  • O destino final de aplicativos Shiny costuma ser um ambiente de produção diferente do ambiente de desenvolvimento. Seja um servidor próprio, uma máquina na nuvem ou o shinyapps.io, o nosso app precisa funcionar nesses ambientes, não apenas na nossa máquina.

  • Uma vez no ambiente de produção, aplicativos Shiny costumam ficar lá por um bom tempo, gerando a necessidade de manutenção períodica e/ou atualizações. A depender de como o app foi desenvolvido, essas tarefas podem ficar muito mais trabalhosas. Seria interessante, nesse sentido, ter um framework de desenvolvimento que facilitasse a organização e documentação do código e o controle das dependências. É para isso que o Golem foi criado.

Motivação



  • O Golem é um framework para desenvolvimento de aplicativos Shiny prontos para serem colocados em produção. As vantagens são:

    • padroniza a organização dos scripts e demais arquivos do seu app;

    • integra com pacotes que aceleram o desenvolvimento do código;

    • motiva a documentação do código;

    • e facilita o compartilhamento e a reutilização de códigos em outros projetos e com outras pessoas.

Vamos ver como podemos utilizar o pacote golem para obter essas vantagens.

Como usar?



Antes de mais nada, precisamos instalar o pacote.

install.packages("golem")

Para criar um app dentro do framework Golem, basta rodar o seguinte código:

golem::create_golem("~/Documents/meuapp")

Esse código vai criar uma pasta chamada meuapp/ dentro de ~/Documents/ (você pode especificar qualquer outra pasta no seu computador). Essa pasta vai conter diversos arquivos que lhe permitirão iniciar o desenvolvimento do seu app dentro do Golem.

Como usar?



  • Antes de falarmos dos arquivos dessa pasta, precisamos ter em mente que usar o pacote golem diz muito mais respeito a seguir uma filosofia do que a aprender uma ferramenta. Como os próprios autores descrevem

Golem is an opinionated framework for building production-grade shiny applications.

  • Isto é, para usar o Golem precisamos construir nosso app de um jeito específico, que os autores consideram ser o melhor. Com relação ao pacote em si, criada a estrutura inicial com a função golem::create_golem(), você poderia continuar o desenvolvimento do app dentro desse framework sem utilizar nenhuma outra função do golem1.

Como usar?



O que realmente importa é seguir as seguintes premissas:


  • um aplicativo Golem é construído como um pacote R;

  • sempre que conveniente, devemos dividir o nosso app em módulos;

  • e devemos documentar as funções que compõem o aplicativo.


Para entender melhor o Golem, precisamos falar um pouco de pacotes.

Pacotes



O que é um pacote?


Um pacote de R é uma forma específica de organizar código, seguindo o protocolo descrito pela R Foundation1.


Pacotes são unidades fundamentais de código R reprodutíveis.

— Wickham & Bryan

Pacotes



  • Um pacote inclui funções em R, documentação sobre como usá-las, testes e dados de exemplo.

  • De maneira geral, as funções de um pacote tentam resolver bem um problema em específico. O pacote dplyr, por exemplo, possui funções especializadas em manipular bases de dados, já o pacote ggplot2 possui funções para a construção de gráficos.


Estrutura básica do pacote

A seguir, apresentaremos a estrutura básica (arquivos e pastas) de qualquer pacote R.

  • DESCRIPTION: define o nome, descrição, versão, licença, dependências e outras caracaterísticas do pacote. É um arquivo de metadados.

  • LICENSE: especifica os termos de uso e distribuição do seu pacote.

Pacotes



  • .Rbuildignore: lista arquivos que não devem ser incluídos ao compilar o pacote R a partir do código-fonte, isto é, arquivos que são úteis apenas no desenvolvimento e não serão enviados para quem instalar o pacote.

  • NAMESPACE: este arquivo declara as funções que o pacote exporta (que ficam disponível quando alguém usa library()) e as funções que seu pacote importa de outros pacotes. Ele é criado automaticamente a partir da documentação das funções do pacote. Não devemos editar este arquivo manualmente.

  • R/: pasta onde fica o código R das funções do pacote. Essa pasta não deve conter subdiretórios.

Pacotes



Criando pacotes

  • Uma forma de criarmos a estrutura básica de um pacote é usamos a função usethis::create_package().

  • É preciso informar um caminho como ~/Documents/meupacote e uma nova pasta chamada meupacote será criada dentro da pasta Documents. Essa pasta será tanto um projeto do RStudio quanto um pacote, ambos chamados meupacote.

Evite sempre adicionar acentos, caracteres especiais e espaços no nome do pacote, assim como nos arquivos que criar dentro dele.

usethis::create_package("~/Documents/meupacote")

Pacotes



A pasta R/

  • Dentro de um pacote, a pasta R/ só pode ter scripts R com funções.

  • Todas as funções que farão parte do pacote devem estar nessa pasta, mesmo que elas sejam apenas funções usadas internamente.

  • As funções colocadas dentro dessa pasta nunca devem ser rodadas diretamente.

  • Se você quiser testá-las, deve fazer isso “carregando as funções”, isto é, usando a função devtools::load_all().

  • Isso fará com que todas as funções dentro da pasta R/ fiquem disponíveis na sua sessão, algo equivalente a fazer library(meupacote), mas com a diferença de também carregar as funções não exportadas.

  • Para criar um arquivo script R dentro da pasta R/, deve usar usethis::use_r("nome-do-arquivo").

Pacotes



Dependências

  • Quando estamos construindo um script R, é comum querermos utilizar dentro dele outros pacotes que não apenas o R base.

  • Em geral utilizamos library(pacote) para carregar esses pacotes.

  • Quando estamos construindo um pacote, bibliotecas externas são chamadas de dependências.

  • Ao desenvolver um pacote, a função library() nunca deve ser utilizada1;

  • Todas as funções externas devem ter seus pacotes de origem explicitamente referenciados pelo operador ::.

Pacotes



  • Sempre que você utilizar um pacote dentro do pacote que está desenvolvendo, você deve especificá-lo como dependência no arquivo DESCRIPTION.

  • Isso informará ao R que, ao instalar o seu pacote, ele também precisa instalar todos os pacotes listados como dependência nesse arquivo.

  • Você pode fazer isso facilmente utilizando usethis::use_package(). O código abaixo registra o pacote dplyr como dependência de um pacote sendo construído.

usethis::use_package("dplyr")
  • Se você está usando um pacote em desenvolvimento a partir de um repositório do GitHub, por exemplo, você pode usar a função usethis::use_dev_package() para adicioná-lo como dependência.
usethis::use_dev_package("dplyr", remote = "tidyverse/dplyr")

Pacotes


Dados

  • Se o seu pacote possuir bases de dados, como a dplyr::starwars, ou qualquer outro tipo de objeto do R, como pi ou letters, você deve colocá-los dentro de uma pasta chamada data/, na raiz do projeto, com a extensão .rda1.

  • Isso pode ser feito a partir da função usethis::use_data().

  • Ao rodar o código abaixo, por exemplo, vamos criar uma pasta data/ na raiz do pacote, caso ela não exista ainda, e salvar nela o vetor base nomes no arquivo nomes.rda.

nomes <- c( "Hélter","Miguel", "Tácio", "Yessenia","Yuri","Will")
usethis::use_data(nomes)
  • Fazendo isso, quando alguém carregar esse pacote, o objeto nomes ficará disponível para ser utilizado (igual a base starwars fica disponível quando carregamos o dplyr).

Pacotes



Documentação de funções

Para documentar as funções do seu pacote (i.e., gerar aquele documento mostrado quando rodamos ?mean, por exemplo), escrevemos comentários antes da definição da função nos scripts da pasta R/. Fazemos isso usando um tipo de comentários especial, o #', e marcadores que indicam qual parte da documentação estamos escrevendo. A estrutura dos comentários deve ser a seguinte:

#' Título da função
#'
#' Descrição da função
#'
#' @param a Descrição do primeiro parâmetro.
#' @param b Descrição do segundo parâmetro.
#'
#' @return Descrição do resultado (valor que sai da função).
#'
#' @export
fun <- function(a, b) {
  a + b
}

Pacotes



  • O marcador @export indica que a função ficará disponível quando rodarmos library(meupacote). Se você não quer que a função fique disponível, basta não colocar esse marcador1.

  • Após escrever a documentação das suas funções dessa maneira, você deve rodar devtools::document() para que ela seja compilada e fique disponível no seu pacote (acessível pelo Help do R). Isso é feito pelo pacote roxygen2.

Dica: o RStudio disponibiliza um atalho para criar a estrutura da documentação de uma função. No menu superior, clique em Code -> Insert Roxygen Skeleton.

Pacotes


Instalando e compartilhando o seu pacote

  • Para verificar se desenvolvimento do pacote está de acordo com o exigido, é possivel utilizar a função devtools::check().

  • Essa função devolverá um relatório com possíveis problemas que o seu pacote pode ter, como erros de sintaxe, arquivos com extensões não permitidos, dependências não declaradas ou erros de documentação.

  • Para instalar o seu pacote localmente durante o desenvolvimento, rode a função devtools::install(). Isso é equivalente a ter o pacote instalado via install.packages().

Uma das formas de disponibilizar o seu pacote na internet é subi-lo para um repositório público no Github. Dessa maneira, qualquer pessoa pode instalá-lo com a função remotes::install_github(). Para subir um pacote para o CRAN, o processo é mais burocrático. Mas interessante se deseja atingir toda a comunidade científica que utiliza o R e instala os pacotes pelo install.packages().

Estrutura de um Golem app



Agora que já sabemos o básico sobre pacotes R, podemos voltar a falar do Golem.

Uma pasta criada pela função golem::create_golem() terá a seguinte estrutura:

#> ├── DESCRIPTION 
#> ├── NAMESPACE 
#> ├── R 
#> │   ├── app_config.R 
#> │   ├── app_server.R 
#> │   ├── app_ui.R 
#> │   └── run_app.R 
#> ├── dev 
#> │   ├── 01_start.R 
#> │   ├── 02_dev.R 
#> │   ├── 03_deploy.R 
#> │   └── run_dev.R 
#> ├── inst 
#> │   ├── app 
#> │   │   └── www 
#> │   │       └── favicon.ico 
#> │   └── golem-config.yml 
#> └── man 
#>     └── run_app.Rd

Estrutura de um Golem app



  • Ela possui, entre outras coisas, a estrutura básica de um pacote.
  • Vejamos cada arquivo mais detalhadamente e discutir a importância dele no contexto do desenvolvimento de um Shiny app:

  • O arquivo DESCRIPTION: guarda os metadados do pacote. No desenvolvimento de um aplicativo Shiny, ele vai guardar o nome do aplicativo, o que ele faz, as dependências dele, a versão (importante em projetos em produção que recebem atualizações periódicas) e quem contatar quando alguma coisa der errada. Com relação às dependências, isso quer dizer que, para rodar o seu app, o R precisará instalar todos os pacotes listados nesse arquivo.

Estrutura de um Golem app



  • O arquivo NAMESPACE: guarda metadados do pacote. Com esse arquivo, podemos carregar apenas funções específicas de um pacote dentro do nosso app1. O Golem faz isso com o pacote shiny nas funções app_ui() e app_server() para não precisarmos colocar shiny:: no início de cada função.

  • A pasta R/: guarda as funções do pacote. Como o app será feito dentro de um pacote R, todo o seu código será escrito em funções nessa pasta. O Golem já cria os arquivos para construirmos a UI e o servidor. Os scripts contendo os módulos do aplicativo também devem ser colocados nessa pasta, assim como scripts com funções úteis utilizadas em vários lugares do app.

Estrutura de um Golem app



  • O arquivo R/app_config.R: usado para especificar alguns mecanismos do Golem, como ler o arquivo de configuração localizado em inst/golem-config.yml.

  • O arquivo R/app_server.R: script com a função app_server(), onde será desenvolvido o servidor do seu aplicativo.

  • O arquivo R/app_ui.R: script com a função app_ui(), onde será desenvolvido a UI do seu aplicativo, e a função golem_add_external_resources(), utilizada para dizer ao Shiny que a pasta inst/app/www será utilizada como uma fonte de recursos externos, acessada pelo caminho www/nome_do_arquivo1. Além disso, o Golem inclui no HTML do seu app a conexão com todo arquivo CSS e JS que você coloca nessa pasta, então não precisamos fazer isso manualmente.

Estrutura de um Golem app



  • O arquivo R/run_app.R: script que contém a função run_app(), utilizada para rodar o app. Ela chama a função shiny::shinyApp(), que inicia o app localmente. A funcão shiny::shinyApp() está dentro da função golem::with_golem_options(), que recebe parâmetros passados para a run_app(). Esses parâmetros podem ser recuperados dentro do app com a função golem::get_golem_options(), deixando a parametrização de um aplicativo Shiny muito mais simples1.

  • dev/: pasta com scripts do golem que podem ser utilizados ao longo do desenvolvimento do app. Eles contêm uma lista de funções úteis que ajudam a configurar diversos aspectos do aplicativo. O uso desses scripts é opcional.

Estrutura de um Golem app



  • A pasta inst/app/www: local onde adicionaremos os recursos externos do aplicativo (imagens, arquivos CSS, fontes etc) que serão compartilhados com o navegador de quem estiver usando o app. A pasta inst é uma pasta especial no desenvolvimento de pacotes. Ela serve para adicionarmos arquivos que gostaríamos que fossem instalados com o pacote, como arquivos de teste, imagens etc. No contexto do Shiny, ela será utilizada para guardarmos arquivos auxiliares, como a própria pasta app/www, templates .Rmd de relatórios que o app gera, arquivos .md com textos que serão colocados no app, entre outros.

  • A pasta man/: contém a documentação do pacote, a ser gerada pelo roxygen2. É muito importante documentarmos todas as funções do nosso app, pois é muito comum que o código precise de ajustes ou atualizações no futuro. Uma breve descrição do que a função espera e o que ela devolve pode ser suficiente para ajudar a pessoa que for mexer no app no futuro (que pode ser você mesma) a economizar horas de debug.






Vamos criar nosso APP com GOLEM!





OBRIGADO!


Slide produzido com quarto




Referências