sjp.likert {sjPlot}

This document shows examples for using the sjp.likert function of the sjPlot package.

Ressources:

(back to table of content)

Data initialization

Please refer to this document.

# load package
library(sjPlot)
library(sjmisc)
# load sample data set.
data(efc)
# set theme
sjp.setTheme(theme = "539",
             geom.label.color = "black", 
             geom.label.size = 2.5,
             axis.textsize = .8, 
             axis.title.size = .9,
             legend.size = .7,
             legend.item.size = .5)
# seed
set.seed(1)

Customizing plot appearance

Please refer to this document

Plotting Likert-scales with 4 categories

First, some data preparation needs to be done. We create a dummy data set with five items (columns) of 500 observations. Each items has 4 category values, two so-called “positive” values (agree and strongly agree) versus two negative values (disagree and strongly disagree).

Please note that the sjp.likert function can only plot an even number of category values (without middle / indifferent category like neither)! For additional neutral categories, see example below!

mydf <- data.frame(
  question1 = as.factor(sample(1:4, 500, replace = TRUE, prob = c(0.25, 0.33, 0.14, 0.28))),
  question2 = as.factor(sample(1:4, 500, replace = TRUE, prob = c(0.5, 0.25, 0.15, 0.1))),
  question3 = as.factor(sample(1:4, 500, replace = TRUE, prob = c(0.25, 0.1, 0.39, 0.26))),
  question4 = as.factor(sample(1:4, 500, replace = TRUE, prob = c(0.17, 0.27, 0.38, 0.16))),
  question5 = as.factor(sample(1:4, 500, replace = TRUE, prob = c(0.37, 0.26, 0.16, 0.21)))
)
# create labels
labels <- c("Strongly agree", "Agree", "Disagree", "Strongly disagree")
# create item labels
items <- c("Question 1", "Question 2", "Question 3", "Question 4", "Question 5")

Now we can produce simple Likert plots like this:

sjp.likert(mydf)

To add proper axis and legend labels, use the legend.labels and axis.labels parameter:

sjp.likert(mydf, axis.labels = items, legend.labels = labels)

Sorting items

With the sort.frq parameter you can sort the items according to “positive” or “negative” values. Furthermore, sorting may be done in ascending or descneding order. Following options are accepted by the sort.frq parameter:

sjp.likert(mydf,
           axis.labels = items,
           legend.labels = labels,
           sort.frq = "pos.asc")

sjp.likert(mydf,
           axis.labels = items,
           legend.labels = labels,
           sort.frq = "neg.asc")

Printing value labels

With the values parameter you can determine the style and position of percentage value labels on the bars. Following options are accepted by the values parameter:

Furthermore, the show.prc.sign parameter indicates whether a percentage sign should be printed to the labels or not.

sjp.likert(mydf,
           axis.labels = items,
           legend.labels = labels,
           values = "sum.outside", # labels outside bars
           geom.colors = "PRGn",   # purple (agree) to green (disagree)
           reverse.colors = TRUE)  # reverse colors, so agree is green

sjp.likert(mydf,
           axis.labels = items,
           legend.labels = labels,
           values = "sum.inside", # labels inside bars
           show.prc.sign = TRUE)  # show percentage sign

sjp.likert(mydf,
           axis.labels = items,
           legend.labels = labels,
           values = "hide",       # hide value labels
           sort.frq = "neg.desc", # sort negativ categories descending
           geom.colors = "RdBu",
           geom.size = 0.3)       # reduce bar size (thickness)

Dealing with neutral categories and odd numbers of categories

The option cat.neutral is intended for use with additional “neutral” categories that don’t belong to the Liker scale range, e.g. don’t know. However, it is also possible to extract middle category like neither. This is necessary, because the sjp.likert function can only plot an even number of category values. See following examples:

Again some data preparation needs to be done to create a dummy data set with five items (columns) of 500 observations, where each question has four valid category values plus an additonal don’t know category.

# prepare data for 4-category likert scale, with neutral category 5 items
mydf <- data.frame(
  q1 = as.factor(sample(1:5, 500, replace = TRUE, prob = c(0.2,0.3,0.1,0.35,0.05))),
  q2 = as.factor(sample(1:5, 500, replace = TRUE, prob = c(0.5,0.25,0.15,0.1,0.0))),
  q3 = as.factor(sample(1:5, 500, replace = TRUE, prob = c(0.22,0.1,0.38,0.27,0.03))),
  q4 = as.factor(sample(1:5, 500, replace = TRUE, prob = c(0.08,0.14,0.41,0.24,0.13))),
  q5 = as.factor(sample(1:5, 500, replace = TRUE, prob = c(0.37,0.23,0.13,0.24, 0.03)))
)
# create labels
labels <- c("Strongly agree", "Agree", "Disagree", "Strongly Disagree", "Don't know")
# view results, for validation.
# value 1 is "strongly agree" (dark brown)
# value 2 is "agree" (light brown)
# value 3 is "disagree" (light green)
# value 4 is "strongly disagree" (dark green)
# value 5 is "don't know" (grey)
prop.table(table(mydf$q1))
## 
##     1     2     3     4     5 
## 0.160 0.302 0.104 0.376 0.058
prop.table(table(mydf$q2))
## 
##     1     2     3     4 
## 0.486 0.228 0.170 0.116
prop.table(table(mydf$q3))
## 
##     1     2     3     4     5 
## 0.216 0.090 0.414 0.242 0.038

We now have four values plus a don’t know option. To plot this category as well, you need to specify the related category index number with cat.neutral.

sjp.likert(mydf,
           cat.neutral = 5, # "5" is value for "don't know"
           axis.labels = items,
           legend.labels = labels,
           values = "hide")

sjp.likert(mydf,
           cat.neutral = 5, # "5" is value for "don't know"
           axis.labels = items,
           legend.labels = labels,
           values = "sum.outside")

In some cases, like in the figure above, labels may overlap or being printed outside the plot range. In such cases, you may increase the x-axis limits with grid.range. By default, it is 1, which means 100 percent. If this parameter value is increased, the x-axis range increases accordingly. The neutral category is always printed to the left most border.

# Note that axis labels beyond 100% are not printed, although
# the x-axis range goes beyond 100%
sjp.likert(mydf,
           cat.neutral = 5,   # "5" is value for "don't know"
           axis.labels = items,
           legend.labels = labels,
           values = "sum.outside",
           show.prc.sign = TRUE,
           show.n = FALSE,    # hide N's in axis labels
           grid.range = 1.4)  # set axis from -140 to +140.

Colors for the neutral category bars can also be defined via cat.neutral.color.

library(ggplot2)
sjp.setTheme(geom.label.size = 3,    # specify value label size
             axis.textsize = 0.8,    # specify axis label size
             base = theme_classic()) # use classic theme
sjp.likert(mydf,
           cat.neutral = 5, # "5" is value for "don't know"
           cat.neutral.color = "#aaddaa",
           intercept.line.color = "white", # vertical middle line color
           axis.labels = items,
           legend.labels = labels,
           values = "sum.outside",
           expand.grid = FALSE, # no inner margins in plot
           show.n = FALSE,    # hide N's in axis labels
           grid.range = 1.2)     # set axis from -120 to +120.

You can also specify an indifferent category. If this category lies “in between” positive and negative values, simply specify the category value and make sure that the indifferent category label still appears as last index of the category label vector.

In the following example, we take the data frame used above, however, we assume that category 3 is the indifferent neither. Therefor, we have to fix the labels.

# create labels
labels <- c("Strongly agree",
            "Agree",
            "Disagree",
            "Strongly Disagree",
            "Neither") # indifferent category, though it has value 3,
                       # we place the category label at the end.

sjp.likert(mydf,
           cat.neutral = 3, # "3" is the new value for "neither"
           intercept.line.color = "white", # vertical middle line color
           axis.labels = items,
           legend.labels = labels,
           values = "sum.outside",
           expand.grid = FALSE, # no inner margins in plot
           show.n = FALSE,    # hide N's in axis labels
           grid.range = 1.2)     # set axis from -120 to +120.

You still can plot only the positive and negative values from a Likert scale from a data frame with neutral or indifferent category. Simple leave out the cat.neutral parameter (defaults to NULL) and only the proportions of negative and positive values are shown.

In such cases, the last category (in case the items have odd numbers of categories) is assumed to be the neutral category. Note that, although the same data frame is used, the values differ. Tjis is because, in the following plot, the neutral category is 5 (the last category in the items), while in the above plot, cat.neutral = 3.

# the  data frame's items still have 5 categories,
# however, in case of odd numbers, the last category
# value will be ignored.
sjp.likert(mydf,
           intercept.line.color = "white", # vertical middle line color
           axis.labels = items,
           legend.labels = labels,
           values = "sum.inside")