Gráficos no Shiny: echarts

No último post, vimos como usar o pacote plotly para gerar gráficos dinâmicos do zero ou aproveitando um gráfico feito em ggplot. Neste post, falaremos de outra biblioteca gráfica em JavaScript que possui pacote em R: o echarts.

O pacote em questão se chama echarts4r, portanto, se você ainda não o estiver instalado, rode o código abaixo:

install.packages("echarts4r")

Leia mais:

O pacote echarts4r

O pacote echarts4r não possui uma função ggecharts, equivalente à ggplotly do pacote plotly, que possibilitaria transformar gráficos feitos em ggplot em gráficos echarts. Assim, precisamos sempre construir nossos gráficos do zero, usando a sintaxe do echarts/echarts4r.

O echarts4r possui semelhanças e diferenças com relação ao ggplot2. A semelhança mais importante é que construímos gráficos em camadas. A primeira diferença relevante é que essas camadas são unidas pelo %>%/|>, não pelo +. Outra diferença é que não temos uma função aes(), então o mapeamento das variáveis é feito diretamente nos argumentos das funções.

Vamos começar com um exemplo simples: um gráfico de dispersão.

library(echarts4r)

mtcars |> 
  e_charts(x = wt) |> 
  e_scatter(serie = mpg)

Veja que o gráfico não possui tooltip por padrão. Precisamos incluí-la na pipeline:

mtcars |> 
  e_charts(x = wt) |> 
  e_scatter(serie = mpg) |> 
  e_tooltip()

Para fazermos um gráfico de linhas, usamos a função e_line(). Cada tipo de gráfico será produzido a partir de uma função do tipo e_*(), equivalente às funções geom_*() no ggplot2.

ggplot2::txhousing |> 
  dplyr::mutate(year = as.character(year)) |> 
  dplyr::group_by(year) |> 
  dplyr::summarise(sales = mean(sales, na.rm = TRUE)) |> 
  e_charts(x = year) |> 
  e_line(serie = sales) |> 
  e_tooltip()

Ao contrário do ggplot2, dados agrupados com dplyr::group_by() influenciam a construção do gráfico. No código abaixo, a base sai do summarise agrupada por city, fazendo com que o echarts construa uma linha para cada cidade.

ggplot2::txhousing |> 
  dplyr::filter(city %in% c("Austin", "Dallas", "Houston")) |> 
  dplyr::mutate(year = as.character(year)) |> 
  dplyr::group_by(city, year) |> 
  dplyr::summarise(sales = mean(sales, na.rm = TRUE)) |> 
  e_charts(x = year) |> 
  e_line(serie = sales) |> 
  e_tooltip()

A biblioteca echarts possui uma extensa variedade de gráficos disponíveis. Você pode visitar a galeria de exemplos para ter uma boa ideia do que é possível fazer. Além disso, clicando nos exemplos, você tem acesso aos códigos JavaScript utilizados para construir os gráficos.

Com as funções do pacote echarts4r, podemos fazer bastante do que a biblioteca echarts tem para oferecer. O que mostramos neste post foi tão pouco que nem poderíamos chamar de uma introdução. Para aprender mais sobre o echarts4r vale bastante a pena olhar os tutoriais na página do pacote.

Em alguns casos, vamos encontrar gráficos ou elementos dentro de um gráfico que não podem ser construídos a partir dos parâmetros das funções do echarts4r. Nesses casos, vamos precisar nos socorrer da documentação do echarts e usar parâmetros que não estão definidos nas funções do echarts4r (o que é possível já que a maioria das funções possuem ...).

A documentação do echarts pode assustar à primeira vista, mas segue um modelo padrão de documentação de bibliotecas JavaScript. Conforme vamos usando mais essas bibliotecas, seja para fazer gráficos, tabelas, mapas ou o que for, vamos nos acostumando a consumir essas documentações.

Nesse sentido, uma forma de seguir a maneira JavaScript de construir um echarts é usar a função e_list(). Com ela, definimos os parâmetros do gráfico a partir de listas e conseguimos reproduzir linha a linha um exemplo feito em JS. A seguir, reproduzimos exatamente este exemplo. Veja que a sintaxe dos dois códigos é muito parecida.

e_chart() |> 
  e_list(list(
    tooltip = list(trigger = "item"),
    legend = list(top = "5%", left = "center"),
    series = list(
      list(
        name = "Access From",
        type = "pie",
        radius = c("40%", "70%"),
        avoidLabelOverlap = FALSE,
        itemStyle = list(
          borderRadius = 10,
          borderColor = "#fff",
          borderWidth = 2
        ),
        label = list(show = FALSE, position = "center"),
        emphasis = list(
          label = list(
            show = TRUE, 
            fontSize = 40,
            fontWeight = "bold"
          )
        ),
        labelLine = list(show = FALSE),
        data = list(
          list(value = 1048, name = "Search Engine"),
          list(value = 735, name = "Direct"),
          list(value = 580, name = "Email"),
          list(value = 484, name = "Union Ads"),
          list(value = 300, name = "Video Ads")
        )
      )
    )
  ))

No Shiny

Para adicionar um echarts no Shiny, utilizamos o par de funções echarts4r::echarts4rOutput() e echarts4r::renderEcharts4r(). Na função renderEcharts4r(), basta passarmos um código que retorne um gráfico echarts.

Rode o app abaixo para ver um exemplo.

library(shiny)
library(echarts4r)

vars <- ggplot2::txhousing |>
  dplyr::select(where(is.numeric), -year, -month, -date) |>
  names()

cidades <- unique(ggplot2::txhousing$city)

ui <- fluidPage(
  titlePanel("echarts"),
  sidebarLayout(
    sidebarPanel(
      selectInput(
        "cidades",
        "Selecione as cidades",
        multiple = TRUE,
        choices = cidades,
        selected = cidades[1]
      ),
      selectInput(
        "serie",
        "Selecione a série",
        choices = vars,
        selected = vars[1]
      )
    ),
    mainPanel(
      echarts4r::echarts4rOutput("plot")
    )
  )
)

server <- function(input, output, session) {
  output$plot <- echarts4r::renderEcharts4r({
    ggplot2::txhousing |>
      dplyr::filter(city %in% input$cidades) |>
      dplyr::mutate(year = as.character(year)) |>
      dplyr::group_by(city, year) |>
      dplyr::summarise(avg_serie = mean(.data[[input$serie]], na.rm = TRUE)) |>
      e_charts(x = year) |>
      e_line(serie = avg_serie) |>
      e_tooltip()
  })
}

shinyApp(ui, server)

É isso! Dúvidas, sugestões e críticas, mande aqui nos comentários.

Até a próxima!

comments powered by Disqus