Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Likert style plot using the likert package in R: Variables with different scales

This is my first time working with R in RStudio. I would like to know whether it is possible to create a likert style graph that plots two survey questions with different likert scales. In my case, the variables do have the same amount of levels but those translate into the different scales.

I've created a data sample and a basic version of a likert plot using the likert package:

library(likert)
set.seed(1)
n <- 150
df1 <- data.frame(
  country=factor(sample(1:2, n, replace=T), labels=c("US","Canada")), 
  treatment=factor(sample(1:2, n, replace=T), labels=c("Base","Treatment")), 
  item1=factor(sample(1:5,n, replace=T), labels=c("Strongly Disagree","Disagree","Neutral","Agree","Strongly Agree")),
  item2=factor(sample(1:5,n, replace=T), labels=c("Very Unlikely","Unlikely","Neutral","Likely","Very Likely"))
)
names(df1) <- c("Country", "Treatment", 
                         "1. An Agreement Question", 
                         "2. A Frequency Question")
## plot differentiating between treatments:
df1_likert <- likert(items=df1[,3:4], grouping=df1[,2])
plot(df1_likert)

Here of course the colors and the legend for both questions are the same (the scale from item2 is used). I would like to use different colors and show two legends to correctly display each question's likert scale. I'm not set on the likert package and happy to use something else if that's a better fit.

I have a second question regarding facets, happy to open a new thread if that's more appropriate. In the example above, I have only differentiated between the two treatments via grouping. I would love a way to differentiate between not only the different treatments, but also the different countries. Ideally, I would like two graphs next to each other, left one for US, right one for Canada, each differentiating between treatments like the plot above.

Thank you!

like image 296
anna Avatar asked Oct 28 '25 20:10

anna


1 Answers

I tried to achieve your expected plot by generating four different likert-scale plots (an agreement plot and a frequency plot for each of US and Canada) using plot_likert() function, and then combining them into a single layout by using plot_layout() from patchwork package.

The function can be used to select the country and the type of question from your df1 data frame and to control the position of the legend for the resulted plot. Because there are four plots but only two sets of legends (agreement and frequency) are necessary, the legends from two plots are removed by using none. The color palettes for agreement plots and frequency plots are selected from https://colorbrewer2.org/#type=diverging&scheme=PRGn&n=5.

The size of the texts in the legends are controlled inside the function, or if you like, you can add an argument in the function for the text size. For more information on options to control elements of a likert plot in likert package, run ?plot.likert and ?likert.options.

Here are the details and the result.

library(patchwork)
plot_likert <- function(country, type, legend_pos) {
  agree_cols <- c("#a6611a", "#018571", "grey80")
  freq_cols <- c("#7b3294", "#008837", "grey90")
  if (type == "agreement") {
    plot(likert(df1[df1$Country == country, "1. An Agreement Question", 
                    drop = FALSE], 
               grouping = df1[df1$Country == country,2]),
      low.color = agree_cols[1],
      high.color = agree_cols[2],
      neutral.color = agree_cols[3]
    ) +
      labs(title = country) +
      theme(legend.position = legend_pos, legend.title = element_text(size = 7))
  } else if (type == "frequency") {
    plot(likert(df1[df1$Country == country, "2. A Frequency Question", 
                    drop = FALSE], 
                grouping = df1[df1$Country == country,2]),
      low.color = freq_cols[1],
      high.color = freq_cols[2],
      neutral.color = freq_cols[3]
    ) +
      labs(title = country) +
      theme(legend.position = legend_pos, legend.title = element_text(size = 7))
  }
}

US_agree <- plot_likert("US", "agreement", "none")
US_freq <- plot_likert("US", "frequency", "bottom")
Canada_agree <- plot_likert("Canada", "agreement", "bottom")
Canada_freq <- plot_likert("Canada", "frequency", "none")

US_agree + Canada_agree + US_freq + Canada_freq +
  plot_layout(guides = "collect") & theme(legend.position = "bottom")

The result:

enter image description here

Edit : How to reduce the height of the bars?

I found no parameter in likert.options() or plot.likert() functions that directly controls the height (or the width) of the bars in the likert plots. Fortunately, because a likert plot in likert package is built from ggplots package, we can get all parameters of the plots by using ggplot_build(), just as any other plot generated from ggplot() function. The bars in the likert plots are generated from geom_bar(), and if you refer to ?geom_bar, you find the width parameter that controls the width of the bars (which becomes the height in the likert bar plots). By default, the width is set to 0.9. By using ggplot_build applied to a likert plot, you can assign values less than 0.9 to the width parameters to get shorter bars.

Here is an example using Canada_agree plot, which is one of the four plots generated using plot_likert():

CA <- ggplot_build(Canada_agree)
CA$plot$layers[[2]]$geom_params$width <- 0.5
CA$plot$layers[[3]]$geom_params$width <- 0.5
Canada_agree

The result:

enter image description here References:

Remove legend ggplot 2.2

Change size of legend in ggplot2

like image 169
Abdur Rohman Avatar answered Oct 31 '25 13:10

Abdur Rohman