Gráficos no Shiny: ggplot2

Gráficos são a alegria da festa em um aplicativo Shiny (ou dashboards em geral). Embora possamos usar tabelas, textos ou caixinhas coloridas com valores para comunicar nossos resultados, são eles que geralmente chamam e prendem a atenção de quem está utilizando o app.

Para dar a atenção que eles merecem, farei aqui uma série de posts para apresentar as principais alternativas para construção de gráficos dentro do Shiny. Falaremos do plotly, do echarts4r, do highcharter, começando neste post pelo nosso fiel companheiro: o ggplot2.


O pacote ggplot2 é uma ferramenta maravilhosa para produzirmos gráficos no R. Quando entendemos a sua sintaxe, nos tornamos capazes de fazer uma variedade enorme de gráficos e dar a eles a cara que quisermos.

Nada do que o pacote ggplot2 tem para oferecer se perde quando estamos construindo gráficos dentro de um Shiny app. Pelo contrário, ainda ganhamos um novo recurso!

Para inserir um ggplot em um aplicativo Shiny, utilizamos a dupla de funções plotOutput()/renderPlot(). Essas funções estão preparadas para receber um objeto gerado pelas funções do ggplot e renderizá-lo em uma imagem, que será inserida no HTML do app por meio da tag <img>. Veja um exemplo abaixo.

library(shiny)
library(ggplot2)

colunas <- names(mtcars)

ui <- fluidPage(
  titlePanel("Shiny app com um ggplot"),
  sidebarLayout(
    sidebarPanel(
      selectInput(
        "varX",
        label = "Variável eixo X",
        choices = colunas
      ),
      selectInput(
        "varY",
        label = "Variável eixo Y",
        choices = colunas,
        selected = colunas[6]
      )
    ),
    mainPanel(
      plotOutput("grafico")
    )
  )
)

server <- function(input, output, session) {
  output$grafico <- renderPlot({
    ggplot(mtcars, aes(x = .data[[input$varX]], y = .data[[input$varY]])) +
      geom_point()
  })
}

shinyApp(ui, server)
App com dois inputs especificando as variáveis do eixo x e y de um ggplot .

Figura 1: App com dois inputs especificando as variáveis do eixo x e y de um ggplot .

O objeto gerado pelo ggplot é uma lista com classe gg e ggplot, que contém todas as informações necessárias para o R desenhar o gráfico.

p <- ggplot(mtcars, aes(x = wt, y = mpg)) +
  geom_point()

class(p)
## [1] "gg"     "ggplot"
names(p)
## [1] "data"        "layers"      "scales"      "mapping"     "theme"      
## [6] "coordinates" "facet"       "plot_env"    "labels"

Repare que, se salvássemos o ggplot em um arquivo (.png por exemplo), poderíamos simplesmente usar a dupla imageOutput()/renderImage() para inserir um gráfico no nosso app, já que essas funções também criam uma tag <img>, mas a partir de um arquivo de imagem local.

Mas não precisar salvar o ggplot em um arquivo não é a única vantagem de utilizarmos as funções plotOutput()/renderPlot(). Essas funções inserem um objeto intermediário no diagrama de reatividade do app: um plotObj. Esse objeto é justamente a lista gerada pelas funções que utilizamos na construção do gráfico e que só é recalculado quando um dos inputs existentes no código da função renderPlot() muda.

Leia mais: Diagramas de reatividade no shiny (reactlog)

Já o gráfico renderizado depende não apenas desse plotObj, mas também do comprimento e altura da janela do navegador de quem estiver utilizando o app. Dessa maneira, o gráfico é renderizado não apenas quando o plotObj muda, mas também quando o espaço disponível para a tag <img> na tela também muda. Nesse segundo caso, o R gera o gráfico novamente, redesenhando seus elementos para a nova proporção de comprimento e altura. E o melhor é que ele faz isso sem precisar rodar o código da função renderPlot() novamente, pois tudo o que ele precisa já está salvo no plotObj.

Gráfico sendo redimensionado conforme diminuímos o comprimento da tela.

Figura 2: Gráfico sendo redimensionado conforme diminuímos o comprimento da tela.

Sem esse recurso, nossos gráficos seriam apenas imagens sendo esticadas e achatadas, o que provavelmente os deixaria pixelados. Ao contrário do que acontece no R Markdown, em um relatório HTML ou em um flexdashboard por exemplo, no Shiny não precisamos nos preocupar muito com as dimensões de um ggplot. Ele será sempre automaticamente otimizado para o espaço disponível na tela.

Mas nem tudo são flores… Por melhor que consigamos mexer no visual do nosso ggplot utilizando a função theme(), no fim do dia ele continuará sendo apenas uma imagem no nosso app. Isso significa que não será possível atribuir a ele qualquer comportamento interativo, como tooltips, drildown ou ações geradas por cliques no gráfico. Para isso, precisaremos utilizar bibliotecas gráficas próprias para a Web, que geralmente utilizam JavaScript para construir os gráficos e gerar interatividade.

No próximo post, falaremos da biblioteca e pacote plotly, que permite transformamos nossos ggplots em gráficos interativos.

É isso! Dúvidas, sugestões e críticas, mande aqui nos comentários. Até a próxima!

comments powered by Disqus