This article is originally published at https://rcrastinate.blogspot.com/

[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)

}

**Thanks for visiting r-craft.org**

This article is originally published at https://rcrastinate.blogspot.com/

Please visit source website for post related comments.