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"))