Search code examples
rggplot2r-plotlypolar-coordinates

Annotation / Text for ticklabels in R plotly polar chart


Let's say, I have a simple polar chart:

R code:

library(plotly)

p <- plot_ly(
  type = 'scatterpolar',
  r = c(0,1,2,4),
  theta = c(0,45,90,120),
  size = c(10, 20, 30, 40),
  sizes = c(100, 300),
  mode = 'markers'
) %>%
  layout(
    showlegend = FALSE,
    polar = list(
      angularaxis = list(
        showticklabels = TRUE#,
        #tickmode="array",
        #tickvals = c(22.5, 67.5, 112, 157.5, 202, 247.5, 292, 337.5),
        #ticktext = c('A', "B", "C", "D", "E", "F", "G", "H")
    ),
      radialaxis = list(
        tickmode="array",
        tickvals = c(0, 1, 2, 3, 4, 5, 6, 7),
        ticktext = c('', "One", "Two", "Three", "Four", "Five", "Six", "Seven")
      )
  )
  )
ggplotly(p)

Chart plotted: enter image description here

When I set showticklabels = FALSE, the angle tick labels disappears, and then I want to put A,B,C,D,E,F,G and H at angles c(22.5, 67.5, 112, 157.5, 202, 247.5, 292, 337.5).

I am not able to get the below expected plot using ticktexts and tickvals. Can someone please help me with getting me to the solution, or if it is possible with add_text or add_annotation ?

Expected plot:

enter image description here


Solution

  • you could remove all grid lines altogether in the angularaxis with showgrid = FALSE, or you can have a line per 22.5 degree starting from 0 and then the ticktext would be something like this c('', 'A', '', 'B', '', 'C', .......) , or you could tediously add the lines you expect to have and then remove the grid lines like this:

    p <- plot_ly() %>% 
      # data points
      add_trace(type = 'scatterpolar',
                r = c(0,1,2,4),
                theta = c(0,45,90,120),
                size = c(10, 20, 30, 40),
                sizes = c(100, 300),
                mode = 'markers') %>%
      # straight line from 0 dg to 180 dg
      add_trace(type = 'scatterpolar',
                r = c(0,4.3,4.3),
                theta = c(0, 180, 360),
                mode = 'lines', 
                line = list(color = 'grey', width = 1)) %>%
      # straight line from 45 dg to 225 dg
      add_trace(type = 'scatterpolar',
                r = c(0,4.3,4.3),
                theta = c(0, 45, 225),
                mode = 'lines', 
                line = list(color = 'grey', width = 1)) %>%
      # straight line from 90 dg to 270 dg
      add_trace(type = 'scatterpolar',
                r = c(0,4.3,4.3),
                theta = c(0, 90, 270),
                mode = 'lines', 
                line = list(color = 'grey', width = 1)) %>%
      # straight line from 135 dg to 315 dg
      add_trace(type = 'scatterpolar',
                r = c(0,4.3,4.3),
                theta = c(0, 135, 315),
                mode = 'lines', 
                line = list(color = 'grey', width = 1)) %>%
      # fill circle of radius 1
      add_trace(type = 'scatterpolar', 
                mode = 'lines', 
                r = 1, 
                theta =seq(0, 360, 0.1),
                line = list(color = 'grey'), 
                fill = 'toself', 
                fillcolor = 'grey', 
                opacity = 0.5) %>%
      layout(
        showlegend = FALSE,
        polar = list(
          angularaxis = list(
            showticklabels = TRUE,
            # remove grid lines and ticks
            showgrid = FALSE,
            ticks = '',
            # if you want the axis to go the other way around
            # direction = 'clockwise',
            tickmode="array",
            tickvals = seq(22.5, 337.5, 45),
            ticktext = LETTERS[1:8]
          ),
          radialaxis = list(
            tickmode="array",
            tickvals = c(0, 1, 2, 3, 4, 5, 6, 7),
            ticktext = c('', "One", "Two", "Three", "Four", "Five", "Six", "Seven")
          )
        )
      )
    ggplotly(p)
    

    Output chart:

    enter image description here

    I noticed that the expected output you have there, lists the letters the other way around as you have them in your code. If this is something you also want just change the order of the letters to match the angles like this c("A", "H", "G", "F", "E", "D", "C", "B") (reversed order starting from A)