Home > Software engineering >  How can I get polar-transformed click data for an Shiny interactive ggplot that uses `coord_polar`?
How can I get polar-transformed click data for an Shiny interactive ggplot that uses `coord_polar`?

Time:02-15

I'm working on an interactive, polar ggplot bar with polar coordinates. The end goal is for the bars in each segment to 'rise' to meet the position of a mouse click in that sector.

The trouble is that click data for polar ggplots is cartesian, rather than polar: The bottom-left of the plot is c(0,0), rather than the centre. How can I get around this problem? Is there a simple coordinate transform I could use, or an option I could set?

You can see a prototype of the app here, and my code is below:

library(shiny)
library(ggplot2)
library(tibble)

xNames <-  c("Authentic", "Visionary", "Sustainable",
             "Inspiring", "Collaborative", "Raising up\nnew leaders")
segments <- length(xNames)


ui <- fluidPage(
mainPanel(
  plotOutput("evaluation_wheel", click = "plot_click"),
  p("Coordinates: "), textOutput("coordinates")
)
)

server <- function(input, output) {
  
  ## Plot evaluation wheel
  wheel_plot <- function(wheel.data){
    ggplot2::ggplot(wheel.data, aes(x = name, y = value))   
      geom_bar(stat = "identity")  
      scale_y_continuous(limits = c(0,10))  
      coord_polar()
  }
  
  modify_plot_data <- function(click.value, old.plot.data){
    print(click.value)
    if(is.null(click.value))(click.value <- c(0,0))
    else{
      cat("x: ")
      print(click.value$x)
      cat("y: ")
      print(click.value$y)
      click.value <- c(click.value$x, click.value$y)
    }
    click.value <- floor(click.value)
    new.plot.data <- old.plot.data
    new.plot.data[click.value[1]] <- click.value[2]
    new.plot.data
  }
  
  plotData <- reactiveVal(integer(segments))
  
    output$evaluation_wheel <- renderPlot({
      # plotData <- modify_plot_data(input$plot_click, plotData)
      plotData(modify_plot_data(input$plot_click, plotData()))
      
      plotTibble <- tibble(
        name = xNames,
        value = plotData()
      )
      wheel_plot(plotTibble)
        
    })
    
    output$coordinates <- renderText({
      paste0("c(", input$plot_click$x, ",", input$plot_click$y, ")")
    })
}

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

CodePudding user response:

You "just" need to convert back from polar projection.

 modify_plot_data <- function(click.value, old.plot.data){
    print(click.value)
    if(is.null(click.value))(click.value <- c(0,0))
    else{
      # Number of categories
      N_CAT = length(xNames)
      # Max value
      Y_LIMIT = 10 

      # Center and rescale X
      x=(click.value$x -( (N_CAT   1) / 2 ) ) / N_CAT * Y_LIMIT / .4 

      # Center and rescale Y
      y=(click.value$y - ( Y_LIMIT / 2 ) ) / Y_LIMIT * Y_LIMIT / .4

      # Compute angle from X and Y
      angle = atan2( y, x)

      # Compute item number from angle (might be simplified)
      i = (( 5 * pi / 2 - angle ) %% ( 2 * pi )) / pi * ( N_CAT / 2 )   1

      # Compute length from angle and X
      j = min( Y_LIMIT, x / cos(angle) ) # length
      
      click.value <- c(i, j)
    }
    new.plot.data <- old.plot.data
    new.plot.data[floor(click.value[1])] <- click.value[2]
    new.plot.data
  }

Also for it to work as-is, you need to sort your values:

xNames <-  sort(c("Authentic", "Visionary", "Sustainable",
                  "Inspiring", "Collaborative", "Raising up\nnew leaders"))
  • Related