dreamRs / apexcharter

:bar_chart: R Htmlwidget for ApexCharts.js
https://dreamrs.github.io/apexcharter
Other
138 stars 15 forks source link

Plot click interactivity #16

Closed Alik-V closed 4 years ago

Alik-V commented 4 years ago

Hi Victor,

I am back with another potentially easy/silly question, hope you don't mind :)

I have data that is plotted in three categories x, y, z through different years on x-axis. Each category in turn consists of different subcategories. Ideally, I would like to make a faceted grouped and stacked plot similar to this , however I don't think it is possible with apexcharter.

Instead, I was thinking to allow user to click on a particular bar of interest which will zoom in and provide a breakdown of that particular category over the years. Could you help me with it please? Here example data and code:

library(apexcharter)
library(dplyr)
library(shiny)

ui <-
  fluidPage(apexchartOutput("main_chart"),
            verbatimTextOutput("click1"),
            apexchartOutput("secondary_chart"))

server <- function(input, output, session) {
  df <- data.frame(
    time = c(2020, 2025, 2030, 2035, 2040),
    x1 = c(10.1, 20.3, 30.4, 40.7, 50.8),
    y1 = c(3.4, 6.7, 10.1, 13.6, 16.9),
    z1 = c(6.8, 13.6, 20.3, 27.1, 33.9),

    x2 = c(20.1, 30.3, 40.4, 50.7, 60.8),
    y2 = c(6.4, 12.7, 20.1, 26.6, 32.9),
    z2 = c(12.8, 26.6, 40.3, 52.1, 66.9)
  )

  output$main_chart <- renderApexchart({
    # summarise data by x, y, z
    df_sum <- df %>% mutate(x = x1 + x2,
                            y = y1 + y2,
                            z = z1 + z2)

    ax <- apexchart(auto_update = FALSE) %>%
      ax_chart(type = "bar") %>%
      ax_grid(show = FALSE) %>%
      ax_series(
        list(name = "x",
             data = df_sum$x),
        list(name = "y",
             data = df_sum$y),
        list(name = "z",
             data = df_sum$z)
      ) %>%
      ax_xaxis(categories = df_sum$time) %>%
      ax_title(text = "Output of plot 1") %>%
      set_input_click("click")
  })

  # I want the main chart to turn into a 
  # breakdown of category similar to this
  # (only one chart has to be displayed at any given time)
  # breakdown chart example
  output$secondary_chart <- renderApexchart({
    # need to generate data dynamically based on click?
    df_breakdown <- df %>%
      select(time, contains("x"))

    ax <- apexchart(auto_update = FALSE) %>%
      ax_chart(type = "bar") %>%
      ax_grid(show = FALSE) %>%
      ax_series(
        #need to generate series dynamically based on click?
        list(name = "x1",
             data = df_breakdown$x1), 
        list(name = "x2",
             data = df_breakdown$x2)
      ) %>%
      ax_xaxis(categories = df_breakdown$time) %>%
      ax_title(text = "Output of plot 2")
  })

  output$click1 <- renderPrint({
    input$click
  })
}

shinyApp(ui = ui, server = server)

Best, Alik

pvictor commented 4 years ago

Hello Alik,

I think its easier if you use apex() instead of apexcharter (moreover there is a bug, normally it should not display NULL but the year...)

With apex() you have to format your data lightly differently: you need rows not columns, I used tidyr::pivot_longer() to make the change, here's your example modified:

library(apexcharter)
library(dplyr)
library(tidyr)
library(shiny)

ui <- fluidPage(
  apexchartOutput("main_chart"),
  verbatimTextOutput("click1"),
  apexchartOutput("secondary_chart")
)

server <- function(input, output, session) {
  df <- data.frame(
    time = c(2020, 2025, 2030, 2035, 2040),
    x1 = c(10.1, 20.3, 30.4, 40.7, 50.8),
    y1 = c(3.4, 6.7, 10.1, 13.6, 16.9),
    z1 = c(6.8, 13.6, 20.3, 27.1, 33.9),

    x2 = c(20.1, 30.3, 40.4, 50.7, 60.8),
    y2 = c(6.4, 12.7, 20.1, 26.6, 32.9),
    z2 = c(12.8, 26.6, 40.3, 52.1, 66.9)
  )

  output$main_chart <- renderApexchart({
    # summarise data by x, y, z
    df %>% 
      mutate(
        x = x1 + x2,
        y = y1 + y2,
        z = z1 + z2
      ) %>% 
      select(time, x:z) %>% 
      pivot_longer(cols = x:z) %>% # transform column in row
      apex(aes(time, value, group = name), auto_update = FALSE) %>%
      ax_grid(show = FALSE) %>%
      ax_title(text = "Output of plot 1") %>%
      set_input_click("click")
  })

  output$secondary_chart <- renderApexchart({

    req(input$click)

    df %>%
      select(time, contains(names(input$click))) %>% 
      pivot_longer(cols = -time) %>% # transform column in row
      apex(aes(time, value, group = name), auto_update = FALSE) %>%
      ax_grid(show = FALSE) %>%
      ax_title(text = "Output of plot 2")
  })

  output$click1 <- renderPrint({
    input$click
  })
}

shinyApp(ui = ui, server = server)

Victor

Alik-V commented 4 years ago

Thanks a lot!