Visualisation of Likert scale results

[This article was first published on Rcrastinate, and kindly contributed to R-bloggers]. (You can report issue about the content on this page here)
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

[EDIT: The function now also inludes the possibility to plot the IQR around the median. I shifted the median slightly downwards to prevent the SD and the IQR from overlapping.]

I wrote a function to visualise results of Likert scale items. Please find the function below the post. Here is an example plot:
The function is called ‘plot.likert’ and takes the following arguments:
– vec: The vector with the raw results
– possible.values: A vector with all the possible values. This is sometimes important if not all possible responses were actually ticked by your participants. Defaults to all values found in vec.
– left: Annotation for the left side of the plot
– right: Annotation for the right side of the plot
– plot.median: Plot the median as a little line at the top? Defaults to FALSE.
– plot.sd: Plot the standard deviation around the mean? Defaults to TRUE.
– plot.iqr: Plot the IQR around the median? Defaults to FALSE.
– include.absolutes: Include the absolute values as small bold black numbers above the plot? Defaults to TRUE.
– include.percentages: Include the percentage values as blue numbers above the plot? Defaults to TRUE.
– own.margins: Override the default margins for the plot. Defaults to c(2,2,3,2).
– othermean: Plot another mean into the visualisation as grey line above the bars. I used this to compare the results to older results for the same questions. Defaults to NULL (no other mean is plotted in this case).
– …: Other parameters might be passed that are used for the first call to plot().

The example call for the plot shown above is:
plot.likert(sample(-2:2, 75, replace = T,
                   prob = c(0, .2, .2, .3, .3)),
            left = “strongly disagree”,
            right = “strongly agree”,
            own.margins = c(2,2,5,2),
            main = “I like this visualisation of Likert scale
                    results.”,
            possible.values = -2:2,
            othermean = 1.09)

NB: I know of all the stuff regarding the calculation of means on Likert scale items. However, it is still done a lot and you can also include the median after all…

Here’s the function:

plot.likert <- function (vec, possible.values = sort(unique(vec)), left = "linker Pol", right = "rechter Pol",
                         plot.median = F, plot.sd = T, plot.iqr = F, include.absolutes = T, include.percentages = T, own.margins = c(2, 2, 3, 2),
                         othermean = NULL, …) {
  tab <- table(vec)
  if (length(tab) != length(possible.values)) {
    values.not.in.tab <- possible.values[!(possible.values %in% names(tab))]
    for (val in values.not.in.tab) {
      tab[as.character(val)] <- 0
    }
    tab <- tab[sort(names(tab))]
  }
  prop.tab <- prop.table(tab) * 100
  v.sd <- sd(vec, na.rm = T)
  v.m <- mean(vec, na.rm = T)
  v.med <- median(vec, na.rm = T)
  old.mar <- par("mar")
  par(mar = own.margins)
  # Setting-up plot region
  plot(x = c(min(as.numeric(names(tab)), na.rm = T) – 1.1, max(as.numeric(names(tab)), na.rm = T) + 1.1),
       y = c(0, 100), type = “n”, xaxt = “n”, yaxt = “n”,
       xlab = “”, ylab = “”, bty = “n”, …)
  # Bars
  rect(xleft = as.numeric(names(prop.tab)) – .4,
       ybottom = 0,
       xright = as.numeric(names(prop.tab)) + .4,
       ytop = prop.tab,
       border = “#00000000”, col = “#ADD8E6E6”)
  # Lower black line
  lines(x = c(min(as.numeric(names(tab)), na.rm = T) – .6, max(as.numeric(names(tab)), na.rm = T) + .6),
        y = c(0, 0), col = “black”, lwd = 2)
  # Upper black line
  lines(x = c(min(as.numeric(names(tab)), na.rm = T) – .6, max(as.numeric(names(tab)), na.rm = T) + .6),
        y = c(100, 100), col = “black”, lwd = 2)
  # Blue lines
  for (n.i in names(tab)) {
    lines(x = c(n.i, n.i), y = c(0, 100), col = “blue”)
  }
  # Grey rectangles at sides
  rect(xleft = min(as.numeric(names(tab)), na.rm = T) – 1.1,
       ybottom = 0,
       xright = min(as.numeric(names(tab)), na.rm = T) – .6,
       ytop = 100,
       border = “#00000000”, col = “grey”)
  rect(xleft = max(as.numeric(names(tab)), na.rm = T) + .6,
       ybottom = 0,
       xright = max(as.numeric(names(tab)), na.rm = T) + 1.1,
       ytop = 100,
       border = “#00000000”, col = “grey”)
  mtext(names(prop.tab), side = 1, at = names(prop.tab))
  # Percentages and numbers at the top
  if (include.percentages) mtext(paste(round(prop.tab, 0), “%”), side = 3, at = names(prop.tab), line = -.3, col = “blue”)
  if (include.absolutes) mtext(tab, side = 3, at = names(tab), line = .5, cex = .8, font = 2)
  # Mean line
  lines(x = c(v.m, v.m), y = c(95, 85), lwd = 6, col = “blue”)
  # Median line
  if (plot.median) lines(x = c(v.med, v.med), y = c(90, 80), lwd = 4, col = “#00FF00AA”)
  # Inter-Quartile range
  if (plot.iqr) {
    arrows(x0 = c(v.med, v.med), x1 = c(v.med – IQR(vec, na.rm = T), v.med + IQR(vec, na.rm = T)),
           y0 = c(85, 85), y1 = c(85, 85),
           angle = 90, length = 0, lwd = 1)
  }
  # Other mean line
  if (!is.null(othermean)) lines(x = c(othermean, othermean), y = c(85, 75), lwd = 6, col = “#00000099”)
  # SD lines
  if (plot.sd) { arrows(x0 = c(v.m, v.m), x1 = c(v.m – v.sd, v.m + v.sd), y0 = c(90, 90), y1 = c(90, 90),
                        angle = 90, length = 0, lwd = 1) }
  # Left label
  mtext(left, side = 2, line = -.5)
  # Right label
  mtext(right, side = 4, line = -.5)
  par(mar = old.mar)
}


To leave a comment for the author, please follow the link and comment on their blog: Rcrastinate.

R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.

Never miss an update!
Subscribe to R-bloggers to receive
e-mails with the latest R posts.
(You will not see this message again.)

Click here to close (This popup will not appear again)