Display grouped percentages in Likert plot with Plotly R

609 views Asked by At

I have a dataframe like this:

library(tidyverse)
data <- tibble(Question_num =  rep(c("Question_1", "Question_2"),each= 5),
               Answer = rep(c('Strongly disagree',
                              'Disagree',
                              'Neutral',
                              'Agree',
                              'Strongly agree'), 2),
               n = c(792, 79, 69, 46, 24, 34, 34, 111, 229, 602),
               prop = c(78.4, 7.82, 6.83, 4.55, 2.38, 3.37, 3.37, 11.0, 22.7, 59.6))

where:

  • Question_num is the label of a question;

  • Answer is the response mode;

  • n is a simple count for each response mode;

  • prop is proportion, in percentage;

I would like to represent it graphically through a dynamic bar graph with divergent colours. Perhaps, this would be a starting point:

library(plotly)
library(RcolorBrewer)
data %>%
  plot_ly(x = ~prop,
          y = ~Question_num,
          color = ~Answer) %>% 
  add_bars(colors = "RdYlBu") %>% 
  layout(barmode = "stack")

Is it possible, with Plotly in R, to obtain an ordered plot, which has the neutral category clearly delineated (in the center) and the percentages summarised by grouping the extreme categories together (even if they are in their plotted in different colours)? What I would like to obtain is a plot similar to this one:

enter image description here

The plot in the picture is obtained from a dataset in a different format (wide, not long) and with the likert package, which computes everything automatically. Could such a result be achieved with plotly (both for percentages and for counts)? If so, how?

I could not find any documentation to answer this challenging question.

Thank you very much to those who can help me.

1

There are 1 answers

0
ismirsehregal On

The following isn't addressing all of the issues your post is raising (It might be better to split this into multiple questions).

However, I'd like to share what I was able to get so far.

(Sorry for switching from tidyverse to data.table - I'm not familar with the tidyverse and I'm not planning to familiarize any time soon).

To get the desired plot we can switch to barmode = 'relative'

Run schema() and navigate: object ► traces ► bar ► layoutAttributes ► barmode

Determines how bars at the same location coordinate are displayed on the graph. With stack, the bars are stacked on top of one another. With relative, the bars are stacked on top of one another, with negative values below the axis, positive values above

library(data.table)
library(plotly)

DF <- data.frame(Question_num =  rep(c("Question_1", "Question_2"),each= 5),
                 Answer = rep(c('E - Strongly disagree',
                                'D - Disagree',
                                'A - Neutral',
                                'B - Agree',
                                'C - Strongly agree'), 2),
                 n = c(792, 79, 69, 46, 24, 34, 34, 111, 229, 602),
                 prop = c(78.4, 7.82, 6.83, 4.55, 2.38, 3.37, 3.37, 11.0, 22.7, 59.6))

DT <- as.data.table(DF)
DT[, order := .GRP, by = Answer]


DT[Answer == "A - Neutral", c("n", "prop") := .(n/2, prop/2)][Answer %in% c("E - Strongly disagree", "D - Disagree"), prop := -prop]
DT <- rbindlist(list(DT, DT[Answer == "A - Neutral", .(Question_num = Question_num, Answer = Answer, n = n, prop = -prop, order = order-0.5)]))
setorder(DT, -Question_num, order)
# setorder(DT, order)

fig <- plot_ly(
  data = DT,
  type = "bar",
  x = ~ prop,
  y = ~ Question_num,
  color = ~ Answer,
  colors = c("E - Strongly disagree" = "#a6611a",
             "D - Disagree" = "#d2b08c",
             "A - Neutral" = "#b3b3b3",
             "B - Agree" = "#80c2b8",
             "C - Strongly agree" = "#018571"),
  text = ~ paste0(prop, "%"),
  textfont = list(
    size = 12,
    color = 'black')
)

fig <- layout(
    fig,
    barmode = "relative",
    xaxis = list(title ="Percentage"),
    yaxis = list(
      categoryorder = "array",
      categoryarray = sort(unique(DT$Question_num), decreasing = TRUE),
      title = ""
    ),
    legend = list(orientation = "h")
  )

print(fig)

result

Here a related question can be found.