How to retrieve the selection from Pie Chart and use it to filter next boxplot

Hi,
I have a pie chart and based on the piece of pie that the user clicks on, i want to filter the next box plot.

For example, my pie chart shows the number of mtcars with 3,4 and 5 gears. And my boxplot shows the mpg for each gear.

If i click on pie for 3 gears, i want to show only one boxplot, boxplot for gear = 3.

I tried the plot_click function, but i cannot understand how to retrieve the value of gear on which the user clicked. And how to use that criteria to filter the data for the boxplot.

Greatly appreaciate any help. Thanks! My server and ui code are below and a picture of how the shiny looks like.


library(ggplot2)
library(dplyr)
library(shiny)
library(shinyWidgets)
library(shinydashboard)

ui <- fluidPage(
    
    useShinydashboard(),
    
    titlePanel("My Pie Chart"),
        
        mainPanel(
            box(
                plotOutput(outputId = "piePlot", click = "plot_click"),
                verbatimTextOutput("mouse")
                ),
            box(
                plotOutput(outputId = "boxPlot")
        )
    )
)




# Define server logic required to draw pie chart and boxplot
server <- function(input, output) {

# Display pie chart
    output$piePlot <- renderPlot({

        bp <- mtcars %>%
            group_by(gear) %>%
            summarise(count = n()) %>%
            mutate(per=count/sum(count)) %>%
            ungroup %>%
            ggplot(aes(x="", y=per*100, fill=gear,label=round(per*100,1)))+
            geom_bar(width = 1, stat = "identity") + geom_col() +
            geom_text(size = 3, position = position_stack(vjust = 0.5)) +
            ylab("Percent") + xlab("")

        piePlot <- bp + coord_polar("y", start=0)
        return(piePlot)
    })
    
    #display the return on pie click below the pie
    output$mouse <- renderPrint({
        text <- str(input$plot_click)
        return(text)
    })
    
# Display the boxplot
    output$boxPlot <- renderPlot({
        
        mtcars$gear = as.factor(mtcars$gear)
        box <- ggplot(mtcars, aes(x = gear, y = mpg), color = gear)+geom_boxplot()
        
        return(box)
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

Suggestion : I think your reprex would be greatly improved by also providing the necessary UI code to make it runnable.

1 Like

Hi Nir,
Thanks for the suggestion, I have updated the full code.
Regards,
Rakendu

given that the plot if formed from a stacked bar chart, we can use knowledge of the stack height to determine what group is clicked.

p.s. I've ignored the boxplot entirely


library(ggplot2)
library(dplyr)
library(shiny)
library(shinyWidgets)
library(shinydashboard)

ui <- fluidPage(
  
  useShinydashboard(),
  
  titlePanel("My Pie Chart"),
  
  mainPanel(
    box(
      plotOutput(outputId = "piePlot", click = "plot_click"),
      verbatimTextOutput("result"),
      verbatimTextOutput("mouse")
    ),
    box(
      plotOutput(outputId = "boxPlot", click = "plot_click")
    )
  )
)




# Define server logic required to draw pie chart and boxplot
server <- function(input, output) {
  
  bp_data  <- mtcars %>%
    group_by(gear) %>%
    summarise(count = n()) %>%
    mutate(per=round(100*count/sum(count),1)) %>%
    ungroup ()
  
  
  bp_decode <- bp_data %>% arrange((gear)) %>%
    mutate(csum=cumsum(per),
           lagcsum=lag(csum,default=0))
  
# Display pie chart
output$piePlot <- renderPlot({
  bp <- bp_data %>%
    ggplot(aes(x = "", y = per, fill = gear, label = per)) +
    geom_bar(width = 1, stat = "identity") +
    geom_col() +
    geom_text(size = 3, position = position_stack(vjust = 0.5)) +
    ylab("Percent") +
    xlab("")

  piePlot <- bp + coord_polar("y", start = 0)
  return(piePlot)
})
  
  click_result <- reactive({
    ipc <- req(input$plot_click)
    y_val <- ipc$y
    bp_decode %>% rowwise %>% filter(
           between(y_val,
                   lagcsum,
                   csum)) %>% pull(gear)
  })
  
  output$result <- renderPrint({
  req(click_result())
  })
  
  
  #display the return on pie click below the pie
  output$mouse <- renderPrint({
    text <- str(input$plot_click)
    return(text)
  })
  
  # Display the boxplot
  output$boxPlot <- renderPlot({
    
    mtcars$gear = as.factor(mtcars$gear)
    box <- ggplot(mtcars, aes(x = gear, y = mpg), color = gear)+geom_boxplot()
    
    return(box)
  })
}

# Run the application 
shinyApp(ui = ui, server = server)
1 Like

Thanks so much, Nir! i could use the click value to filter the boxplot.
Realised that for pie, the click returns the value based on the height and not the piece of pie that is clicked.

So i guess i will have to go with the bar chart after all. That works too !

Pasting the updated code here. But noticed that the boxplot do not load at all on initial page render now. The box plot appears only after the bar is clicked. Any thoughts on that?

library(ggplot2)
library(dplyr)
library(shiny)
library(shinyWidgets)
library(shinydashboard)

ui <- fluidPage(
    
    useShinydashboard(),
    
    titlePanel("My Pie Chart"),
    
    mainPanel(
        fluidRow(
            box(
                plotOutput(outputId = "piePlot", click = "plot_click"),
                verbatimTextOutput("result")
                #verbatimTextOutput("mouse")
            ),
            box(
                plotOutput(outputId = "boxPlot")
            ) 
        ),
        fluidRow(
            box(
                plotOutput(outputId = "barPlot", click = "bplot_click"),
                verbatimTextOutput("barresult")
                #verbatimTextOutput("mouse")
            ),
            box(
                plotOutput(outputId = "boxPlot1")
            ) 
        )
    )
)




# Define server logic required to draw pie chart and boxplot
server <- function(input, output) {
    
    
    bp_data  <- mtcars %>%
        group_by(gear) %>%
        summarise(count = n()) %>%
        mutate(per=round(100*count/sum(count),1)) %>%
        ungroup ()
    
    
    bp_decode <- bp_data %>% arrange((gear)) %>%
        mutate(csum=cumsum(per),
               lagcsum=lag(csum,default=0))
    
    ################
    ###Pie Chart####
    ################
    

    output$piePlot <- renderPlot({
        bp <- bp_data %>%
            ggplot(aes(x = "", y = per, fill = gear, label = per)) +
            geom_bar(width = 1, stat = "identity") +
            geom_col() +
            geom_text(size = 3, position = position_stack(vjust = 0.5)) +
            ylab("Percent") +
            xlab("")
        
        piePlot <- bp + coord_polar("y", start = 0)
        return(piePlot)
    })
    
    click_result <- reactive({
        ipc <- req(input$plot_click)
        y_val <- ipc$y
        bp_decode %>% rowwise %>% filter(
            between(y_val,
                    lagcsum,
                    csum)) %>% pull(gear)
    })
    
    output$result <- renderPrint({
        req(click_result())
    })
    
    
    #display the return on pie click below the pie
    output$mouse <- renderPrint({
        text <- str(input$plot_click)
        return(text)
    })
    
    
#Boxplot corresponding to pie chart
    output$boxPlot <- renderPlot({
        
        mtcars$gear = as.factor(mtcars$gear)
        box <- ggplot(mtcars, aes(x = gear, y = mpg), color = gear)+geom_boxplot()
        
        
        if (!is.null(req(click_result()))){
            mtcars_new <- mtcars %>%
                filter(gear == req(click_result()))
            box <- ggplot(mtcars_new, aes(x = gear, y = mpg), color = gear)+geom_boxplot()
            
        }
        
        return(box)
    })
    
    ################
    ###Bar Chart####
    ################
    
    output$barPlot <- renderPlot({
        bp <- bp_data %>%
            ggplot(aes(x = "", y = per, fill = gear, label = per)) +
            geom_bar(width = 1, stat = "identity") +
            geom_col() +
            geom_text(size = 3, position = position_stack(vjust = 0.5)) +
            ylab("Percent") +
            xlab("")
        
        return(bp)
    })
    
    # Display the boxplot1 corresponding to bar chart
    output$boxPlot1 <- renderPlot({
        
        mtcars$gear = as.factor(mtcars$gear)
        box <- ggplot(mtcars, aes(x = gear, y = mpg), color = gear)+geom_boxplot()
        
        
        if (!is.null(req(bclick_result()))){
            mtcars_new <- mtcars %>%
                filter(gear == req(bclick_result()))
            box <- ggplot(mtcars_new, aes(x = gear, y = mpg), color = gear)+geom_boxplot()
            
        }
        
        
        return(box)
    })
    
    bclick_result <- reactive({
        ipc <- req(input$bplot_click)
        y_val <- ipc$y
        bp_decode %>% rowwise %>% filter(
            between(y_val,
                    lagcsum,
                    csum)) %>% pull(gear)
    })
    
    output$barresult <- renderPrint({
        req(bclick_result())
    })
}

# Run the application 
shinyApp(ui = ui, server = server)

I think my point is that thats exactly equivalent, so you can use a bar /or/ a pie, its just that the interpretation of what is clicked comes from the understanding of the Y height as a bar.

You have made the render function for the boxplot require the click req( if you dont want it to require the click, then remove req

1 Like

Thank you so much for the help!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.