# Visualisation of Likert scale results

[This article was first published on

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.]**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.

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.