Using Jason Bryer’s likert package, amended to summarise and plot using a summary of results, without requiring the underlying data.

The results object is akin to many summaries of data published for ordinal responses, where the underlying data is inaccessible (e.g. polling results), and also to many wide format summaries for ordinal outcomes generated from raw data (e.g. examination grades).

Changes to likert.R and summary.likert.r allow much of the same functionality using results alone, without underlying data items. It also allows for many smaller likert objects to be held in memory, without necessarily copying the underlying items in each object.

Package

Install and load the amended package from github:

library("devtools")
install_github("m-dev-/likert")
library("likert")
## Loading required package: ggplot2
## Loading required package: xtable

Data

data("pisaitems")

Using l29 from the likert demo to make a complete object, including a copy of the underlying data held as items:

##### Item 29: How often do you read these materials because you want to?
title <- "How often do you read these materials because you want to?"
    
items29 <- pisaitems[,substr(names(pisaitems), 1,5) == 'ST25Q']
    
head(items29); ncol(items29)
##                     ST25Q01               ST25Q02               ST25Q03
## 68038    A few times a year  Several times a week Several times a month
## 68039    About once a month    A few times a year Never or almost never
## 68040    About once a month Never or almost never    A few times a year
## 68041 Several times a month    A few times a year    About once a month
## 68042    About once a month    A few times a year    About once a month
## 68043    A few times a year Never or almost never Never or almost never
##                     ST25Q04               ST25Q05
## 68038    A few times a year    A few times a year
## 68039 Never or almost never  Several times a week
## 68040 Never or almost never    A few times a year
## 68041    A few times a year  Several times a week
## 68042 Never or almost never Several times a month
## 68043 Never or almost never    A few times a year
## [1] 5
names(items29) = c("Magazines", "Comic books", "Fiction", "Non-fiction books", "Newspapers")
    
l29 <- likert(items29)

str(l29)
## List of 6
##  $ results :'data.frame':    5 obs. of  6 variables:
##   ..$ Item                 : Factor w/ 5 levels "Comic books",..: 3 1 2 5 4
##   ..$ Never or almost never: num [1:5] 10.2 36.7 17 30.9 18.8
##   ..$ A few times a year   : num [1:5] 20 25.7 24.7 30.6 18.5
##   ..$ About once a month   : num [1:5] 21.3 15.8 19.6 19.6 15.7
##   ..$ Several times a month: num [1:5] 31 14.5 22.3 13.5 23.9
##   ..$ Several times a week : num [1:5] 17.43 7.27 16.31 5.55 23.12
##  $ items   :'data.frame':    66690 obs. of  5 variables:
##   ..$ Magazines        : Factor w/ 5 levels "Never or almost never",..: 2 3 3 4 3 2 4 3 3 1 ...
##   ..$ Comic books      : Factor w/ 5 levels "Never or almost never",..: 5 2 1 2 2 1 1 1 3 3 ...
##   ..$ Fiction          : Factor w/ 5 levels "Never or almost never",..: 4 1 2 3 3 1 2 2 3 4 ...
##   ..$ Non-fiction books: Factor w/ 5 levels "Never or almost never",..: 2 1 1 2 1 1 2 1 3 1 ...
##   ..$ Newspapers       : Factor w/ 5 levels "Never or almost never",..: 2 5 2 5 4 2 3 2 3 1 ...
##  $ grouping: NULL
##  $ factors : NULL
##  $ nlevels : int 5
##  $ levels  : chr [1:5] "Never or almost never" "A few times a year" "About once a month" "Several times a month" ...
##  - attr(*, "class")= chr "likert"

Summary results

Create a likert object from results, rather than from the underlying data:

l29s <- likert(summary = l29$results)

str(l29s)
## List of 5
##  $ results :'data.frame':    5 obs. of  6 variables:
##   ..$ Item                 : Factor w/ 5 levels "Comic books",..: 3 1 2 5 4
##   ..$ Never or almost never: num [1:5] 10.2 36.7 17 30.9 18.8
##   ..$ A few times a year   : num [1:5] 20 25.7 24.7 30.6 18.5
##   ..$ About once a month   : num [1:5] 21.3 15.8 19.6 19.6 15.7
##   ..$ Several times a month: num [1:5] 31 14.5 22.3 13.5 23.9
##   ..$ Several times a week : num [1:5] 17.43 7.27 16.31 5.55 23.12
##  $ items   : NULL
##  $ grouping: NULL
##  $ nlevels : num 5
##  $ levels  : chr [1:5] "Never or almost never" "A few times a year" "About once a month" "Several times a month" ...
##  - attr(*, "class")= chr "likert"

The items are not present, but the likert object can still be summarised:

summary(l29s)
##                Item      low  neutral     high     mean       sd
## 1         Magazines 30.21689 21.33091 48.45219 3.252525 1.248210
## 2       Comic books 62.43096 15.78368 21.78536 2.288660 1.298707
## 3           Fiction 41.77380 19.61739 38.60882 2.959184 1.354019
## 4 Non-fiction books 61.42466 19.55493 19.02042 2.309278 1.193392
## 5        Newspapers 37.29377 15.72688 46.97935 3.154639 1.453016

Plots

Scale figure height and width, and reduce size of legend.text for plots:

scale_height = knitr::opts_chunk$get('fig.height')*0.5
scale_width = knitr::opts_chunk$get('fig.width')*1.25
knitr::opts_chunk$set(fig.height = scale_height, fig.width = scale_width)

theme_update(legend.text = element_text(size = rel(0.7)))
# Plots
plot(l29s) + ggtitle(title)

plot(l29s, centered=FALSE) + ggtitle(title)

plot(l29s, include.center=FALSE) + ggtitle(title)

plot(l29s, center=2) + ggtitle(title)

plot(l29s, center=2.5) + ggtitle(title)

# ideally, if center%%0.5 == 0, plot.percent.neutral=FALSE
plot(l29s, center=2.5, plot.percent.neutral=FALSE) + ggtitle(title)

plot(l29s, type = 'heat') + ggtitle(title) + 
    theme(legend.position = 'none')

# scale_y_discrete(labels = function(x) stringer::str_wrap(x, width = 15))
# to wrap labels would sort `Mean (SD)` column out of order.
# given values, legend is removed to make space for axes labels
# Density plots on likert summary results are not supported.
# plot(l29s, type='density') + ggtitle(title)

# plot(l29s, type='density', facet=FALSE, legend='Material') + ggtitle(title)

Grouped Summary results

Grouped by country, using l29g from the likert demo:

l29g <- likert(items29, grouping=pisaitems$CNT)

str(l29g$results)
## 'data.frame':    15 obs. of  7 variables:
##  $ Group                : Factor w/ 3 levels "Canada","Mexico",..: 1 1 1 1 1 2 2 2 2 2 ...
##  $ Item                 : Factor w/ 5 levels "Magazines","Comic books",..: 1 2 3 4 5 1 2 3 4 5 ...
##  $ Never or almost never: num  11.1 48.2 15 27.9 18.6 ...
##  $ A few times a year   : num  16.1 24.8 23.4 31.8 17.4 ...
##  $ About once a month   : num  24.9 13.2 20.3 20.8 18.6 ...
##  $ Several times a month: num  31.04 8.58 21.11 13.34 24.88 ...
##  $ Several times a week : num  16.86 5.2 20.21 6.13 20.48 ...

Make a summary from results, grouped by the variable in column 1 of results:

l29gs <- likert(summary = l29g$results, grouping = l29g$results[,1])

str(l29gs)
## List of 5
##  $ results :'data.frame':    15 obs. of  7 variables:
##   ..$ Group                : Factor w/ 3 levels "Canada","Mexico",..: 1 1 1 1 1 2 2 2 2 2 ...
##   ..$ Item                 : Factor w/ 5 levels "Magazines","Comic books",..: 1 2 3 4 5 1 2 3 4 5 ...
##   ..$ Never or almost never: num [1:15] 11.1 48.2 15 27.9 18.6 ...
##   ..$ A few times a year   : num [1:15] 16.1 24.8 23.4 31.8 17.4 ...
##   ..$ About once a month   : num [1:15] 24.9 13.2 20.3 20.8 18.6 ...
##   ..$ Several times a month: num [1:15] 31.04 8.58 21.11 13.34 24.88 ...
##   ..$ Several times a week : num [1:15] 16.86 5.2 20.21 6.13 20.48 ...
##  $ items   : NULL
##  $ grouping: Factor w/ 3 levels "Canada","Mexico",..: 1 1 1 1 1 2 2 2 2 2 ...
##  $ nlevels : num 5
##  $ levels  : chr [1:5] "Never or almost never" "A few times a year" "About once a month" "Several times a month" ...
##  - attr(*, "class")= chr "likert"

Grouped plots

Rescale figures to full height:

knitr::opts_chunk$set(fig.height = knitr::opts_chunk$get('fig.height')*2)
plot(l29gs) + ggtitle(title)

plot(l29gs, centered=FALSE) + ggtitle(title)

plot(l29gs, include.center=FALSE) + ggtitle(title)

plot(l29gs, center=2) + ggtitle(title)

plot(l29gs, center=2.5, include.center=FALSE) + ggtitle(title)

# heat plots on likert summary results with grouping are not supported.
# plot(l29gs, type = 'heat') + ggtitle(title)