HH (version 2.3-27)

likert: Diverging stacked barcharts for Likert, semantic differential, rating scale data, and population pyramids.

Description

Constructs and plots diverging stacked barcharts for Likert, semantic differential, rating scale data, and population pyramids. These functions are available in R. They are not currently available in S-Plus.

Usage

likert(x, ...)
## S3 method for class 'likert':
plot(x, ...)
## S3 method for class 'formula':
plot.likert(x, data, ..., xName=deparse(sys.call()), main)
## S3 method for class 'default':
plot.likert(x,
            positive.order=FALSE,
            ylab=names(dimnames(x)[1]),
            xlab=if (as.percent != FALSE) "Percent" else "Count",
            main=xName,
            BrewerPaletteName="RdBu",
            ## These are the diverging palettes in RColorBrewer
            ## c("RdBu", "BrBG", "PiYG", "PRGn", "PuOr",
            ## "RdGy", "RdYlBu", "RdYlGn", "Spectral"),
            reference.line.col="gray65",
            middle.color="gray90",  ## "#F7F7F7" is the RColorBrewer default for middle.col in the RdBu scheme
            col.strip.background="gray97",
            col=likertColor(attr(x, "nlevels"),
              ReferenceZero, BrewerPaletteName, middle.color),
            as.percent=FALSE,
            par.settings.in=NULL,
            horizontal=TRUE,
            ReferenceZero=NULL,
            ...,
            key.border.white=TRUE,
            xName=deparse(substitute(x)),
            rightAxisLabels=rowSums(abs(x)),
            rightAxis=!missing(rightAxisLabels),
            ylab.right=if (rightAxis) "Row Count Totals" else NULL,
            panel=panel.barchart,
            xscale.components=xscale.components.top.HH,
            yscale.components=yscale.components.right.HH,
            xlimEqualLeftRight=FALSE,
            xTickLabelsPositive=TRUE,
            reverse=FALSE)

## S3 method for class 'array':
plot.likert(x,
            condlevelsName=paste(names(dimnames(x))[-(1:2)], collapse="."),
            xName=deparse(substitute(x)),
            main=paste("layers of", xName, "by", condlevelsName),
            layout=if (horizontal) c(1, length(dim(x))-2) else c(length(dim(x))-2, 1),
            positive.order=FALSE,
            strip=TRUE,
            strip.left=TRUE,
            strip.left.values=names(x.pl), ## constructed from dimnames(x)[-(1:2)]
            strip.values=names(x.pl),
            strip.left.par=list(cex=1, lines=1),
            horizontal=TRUE,
            ...,
            resize.height=c("nrow","rowSums"),
            resize.width=1)

## S3 method for class 'list':
plot.likert(x,  ## named list of matrices or 2D tables, ftables, structables
            condlevelsName="ListNames",
            xName=deparse(substitute(x)),
            main=paste("List items of", xName, "by", condlevelsName),
            layout=if (horizontal) c(1, length(x)) else c(length(x), 1),
            positive.order=FALSE,
            strip=!horizontal,
            strip.left=horizontal,
            strip.left.values=names(x),
            strip.values=names(x),
            strip.par=list(cex=1, lines=1),
            strip.left.par=list(cex=1, lines=1),
            horizontal=TRUE,
            ...,
            rightAxisLabels=sapply(x, function(x) rowSums(abs(x)), simplify = FALSE),
            rightAxis=!missing(rightAxisLabels),
            resize.height.tuning=-.5,
            resize.height=if (missing(layout)) {
              c("nrow","rowSums")
            } else {
              rep(1, layout[2])
            },
            resize.width=if (missing(layout)) {1 } else {
              rep(1, layout[1])
            },
            box.ratio=if (
              length(resize.height)==1 &&
              resize.height == "rowSums") 1000 else 2,
            xscale.components=xscale.components.top.HH,
            yscale.components=yscale.components.right.HH)

## S3 method for class 'table':
plot.likert(x, ..., xName=deparse(substitute(x)))
## S3 method for class 'ftable':
plot.likert(x, ..., xName=deparse(substitute(x)))
## S3 method for class 'structable':
plot.likert(x, ..., xName=deparse(substitute(x)))## S3 method for class 'data.frame':
plot.likert(x, ..., xName=deparse(substitute(x)))


xscale.components.top.HH(...)
yscale.components.right.HH(...)

Arguments

x
For the formula method, a model formula. Otherwise, any numeric object stored as a vector, matrix, array, data.frame, table, ftable, structable (as defined in the vcd package), or as a list of named two-dimensional object
data
For the formula method, a data.frame.
positive.order
If FALSE, the default value, the original order of the rows is retained. This is necessary for arrays, because each panel has the same rownames. If TRUE, rows are ordered within each panel with the row whose bar
as.percent
When as.percent==TRUE or as.percent=="noRightAxis", then the values in each row are rescaled to row percents. When as.percent==TRUE the original row totals are used as rightAxisLabels
par.settings.in
This is a placeholder that lets the user specify some lattice par.settings and still retain the ones that are prespecified in the plot.likert.default.
ReferenceZero
Numeric scalar or NULL. The position in the range seq(0, attr(x, "nlevels")+.5, .5) where the reference line at 0 will be placed. attr(x, "nlevels") is the number of columns of the original argument
ylab, xlab, ylab.right, main
Standard lattice graph labels in barchart.
BrewerPaletteName
RColorBrewer palette names. We default to the diverging palette RdBu. Diverging palettes are usually appropriate for two-directional scales (Agree--Disagree). S
col
Vector of color names for the levels of the agreement factor. Although the colors can be specified explicitly in the col argument, usually specifying one of the diverging palettes from
reference.line.col
Color for reference line at zero.
middle.color
Darker middle color than the default "#F7F7F7" in the RdBu scheme.
col.strip.background
Background color for the strip labels.
key.border.white
Logical. If TRUE, then place a white border around the rect in the key, else use the col of the rect itself.
horizontal
Logical, with default TRUE indicating horizontal bars, will be passed to the barchart function by the plot.likert method. In addition, it interchanges the meaning of resize.height and
...
other arguments. These will be passed to the barchart function by the plot.likert method. Arguments to the lattice auto.key=list() argument (described in
strip.left, strip
Logical. The default strip.left=TRUE places the strip labels on the left of each panel as in the first professional challenges example. The alternative strip.left=FALSE puts the strip labels on the top of
condlevelsName, strip.left.values, strip.values, strip.par, strip.left.par, layout
Arguments which will be passed to ResizeEtc.
xName
Name of the argument in its original environment.
rightAxis
logical. Should right axis values be displayed? Defaults to FALSE unless rightAxisLabels are specified.
rightAxisLabels
Values to be displayed on the right axis. The default values are the row totals. These are sensible for tables of counts. When the data is rescaled to percents by the as.percent=TRUE argument, then the rightAxisLabels<
resize.height.tuning
Tuning parameter used to adjust the space between bars as specified by the resize.height argument to the ResizeEtc function.
resize.height
Either character scalar or numeric vector. If "nrow", then the panels heights are proportional to the number of bars in each panel. If "rowSums" and there is exactly one bar per panel, then the panels heights
resize.width
Numeric vector. The panel widths are proportional to the numbers in the argument.
box.ratio
If there are more than one bar in any panel, then this defaults to the trellis standard value of 2. If there is exactly one bar in a panel, then the value is 1000, with the intent to minimize the white space in the panel. In t
panel
panel function eventually to be used by barchart.
xscale.components, yscale.components
See yscale.components.default. xscale.components.top.HH constructs the top x-axis labels, when needed, as the names of the bottom x-axis labels.
xlimEqualLeftRight
Logical. The default is FALSE. If TRUE, then the left and right x limits are set to negative and positive of the larger of the absolute value of the original x limits.
xTickLabelsPositive
Logical. The default is TRUE. If TRUE, then the tick labels on the negative side are displayed as positive values.
reverse
Logical. The default is FALSE. If TRUE, the rows of the input matrix are reversed. The default is to plot the rows from top-to-bottom for horizontal bars and from left-to-write for vertical bars. re

Value

  • A "trellis" object containing the plot. The plot will be automatically displayed unless the result is assigned to an object.

Details

The counts (or percentages) of respondents on each row who agree with the statement are shown to the right of the zero line; the counts (or percentages) who disagree are shown to the left. The counts (or percentages) for respondents who neither agree nor disagree are split down the middle and are shown in a neutral color. The neutral category is omitted when the scale has an even number of choices. It is difficult to compare lengths without a common baseline. In this situation, we are primarily interested in the total count (or percent) to the right or left of the zero line; the breakdown into strongly or not is of lesser interest so that the primary comparisons do have a common baseline of zero. The rows within each panel are displayed in their original order by default. If the argument positive.order=TRUE is specified, the rows are ordered by the counts (or percentages) who agree. Diverging stacked barcharts are also called "two-directional stacked barcharts". Some authors use the term "floating barcharts" for vertical diverging stacked barcharts and the term "sliding barcharts" for horizontal diverging stacked barcharts. All items in a list of named two-dimensional objects must have the same number of columns. If the items have different column names, the column names of the last item in the list will be used in the key. If the dimnames of the matrices are named, the names will be used in the plot. It is possible to produce a likert plot with a list of objects with different numbers of columns, but not with the plot.likert.list method. These must be done manually by using the ResizeEtc function on each of the individual likert plots. The difficulty is that the legend is based on the last item in the list and will have the wrong number of values for some of the panels. A single data.frame x will be plotted as data.matrix(x); therefore factor columns will be converted to integers and character columns will become NA and will be plotted as if they had value 0. A data.frame with only numeric columns will work in a named list. A data.frame with factors or characters won't work in a named list. ftable and structable arguments x will be plotted as as.table(x). This changes the display sequence. Therefore the user will probably want to use aperm on the ftable or structable before using plot.likert.

References

Richard Heiberger and Naomi Robbins (2011), "Alternative to Charles Blow's Figure in "Newt's War on Poor Children"", Forbes OnLine, December 20, 2011. http://www.forbes.com/sites/naomirobbins/2011/12/20/alternative-to-charles-blows-figure-in-newts-war-on-poor-children-2/ Naomi Robbins (2011), "Visualizing Data: Challenges to Presentation of Quality Graphics---and Solutions", Amstat News, September 2011, 28--30. http://magazine.amstat.org/blog/2011/09/01/visualizingdata/ Naomi B. Robbins and Richard M. Heiberger (2011). Plotting Likert and Other Rating Scales. In JSM Proceedings, Section on Survey Research Methods. Alexandria, VA: American Statistical Association, 1058--1066. https://www.amstat.org/membersonly/proceedings/2011/papers/300784_64164.pdf Luo, Amy and Tim Keyes (2005). "Second Set of Results in from the Career Track Member Survey," Amstat News. Arlington, VA: American Statistical Association.

See Also

barchart, ResizeEtc, as.likert, as.matrix.listOfNamedMatrices

Examples

Run this code
require(grid)
require(lattice)
require(latticeExtra)
require(HH)

data(ProfChal)  ## List of named matrices.  See below for discussion of the dataset.
ProfChal[[2]]

## Count plot
likert(ProfChal[[2]],
       main='Is your job professionally challenging?',
       sub="This plot looks better in a 9in x 4in window.")

## Percent plot calculated automatically from Count data
likert(ProfChal[[2]], as.percent=TRUE,
       main='Is your job professionally challenging?',
       sub="This plot looks better in a 9in x 4in window.")

## formula method
data(NZScienceTeaching)
NZScienceTeaching.df <- as.likertDataFrame(NZScienceTeaching)
likert(Question ~ . | Subtable, data=NZScienceTeaching.df)



## Examples with higher-dimensional arrays.
tmp3 <- array(1:24, dim=c(2,3,4),
              dimnames=list(A=letters[1:2], B=LETTERS[3:5], C=letters[6:9]))

## positive.order=FALSE is the default.  With arrays
## the rownames within each item of an array are identical.

## likert(tmp3)
likert(tmp3, layout=c(1,4))
likert(tmp3, layout=c(2,2), resize.height=c(2,1), resize.width=c(3,4))


## plot.likert interprets vectors as single-row matrices.
## http://survey.cvent.com/blog/customer-insights-2/box-scores-are-not-just-for-baseball
Responses <- c(15, 13, 12, 25, 35)
names(Responses) <- c("Strongly Disagree", "Disagree", "No Opinion",
                      "Agree", "Strongly Agree")
likert(Responses, main="Retail-R-Us offers the best everyday prices.",
       sub="This plot looks better in a 9in x 2.6in window.")
## reverse=TRUE  is needed for a single-column key with
## horizontal=FALSE and with space="right"
likert(Responses, horizontal=FALSE,
       aspect=1.5,
       main="Retail-R-Us offers the best everyday prices.",
       auto.key=list(space="right", columns=1,
                     reverse=TRUE, padding.text=2),
       sub="This plot looks better in a 4in x 3in window.")


## Color palettes from RColorBrewer can be named.
##
## Since age is always positive and increases in a single direction,
## this example uses colors from a sequential palette for the age
## groups.  In this example we do not use a diverging palette that is
## appropriate when groups are defined by a characteristic, such as
## strength of agreement or disagreement, that can increase in two directions.
## Initially we use the "Blues" palette in the BrewerPaletteName argument.
likert(AudiencePercent,
       auto.key=list(between=1, between.columns=2),
       xlab="Percentage of audience younger than 35 (left of zero) and older than 35 (right of zero)",
       main="Target Audience",
       BrewerPaletteName="Blues",
       sub="This plot looks better in a 7in x 3.5in window.")

## The really light colors in the "Not run" example are too light.
## Therefore we use the col argument directly.  We chose to use an
## intermediate set of Blue colors selected from the "Blues" palette.
likert(AudiencePercent,
       auto.key=list(between=1, between.columns=2),
       xlab="Percentage of audience younger than 35 (left of zero) and older than 35 (right of zero)",
       main="Target Audience",
       col=brewer.pal(9, "Blues")[4:7],
       sub="This plot looks better in a 7in x 3.5in window.")


## Population Pyramid
data(USAge.table)
USA79 <- USAge.table[75:1, 2:1, "1979"]/1000000
PL <- likert(USA79,
             main="Population of United States 1979 (ages 0-74)",
             xlab="Count in Millions",
             ylab="Age",
             scales=list(
               y=list(
                 limits=c(0,77),
                 at=seq(1,76,5),
                 labels=seq(0,75,5),
                 tck=.5))
             )
PL
as.pyramidLikert(PL)

likert(USAge.table[75:1, 2:1, c("1939","1959","1979")]/1000000,
       main="Population of United States 1939,1959,1979 (ages 0-74)",
       sub="Look for the Baby Boom",
       xlab="Count in Millions",
       ylab="Age",
       scales=list(
         y=list(
           limits=c(0,77),
           at=seq(1,76,5),
           labels=seq(0,75,5),
           tck=.5)),
       strip.left=FALSE, strip=TRUE,
       layout=c(3,1), between=list(x=.5))


Pop <- rbind(a=c(3,2,4,9), b=c(6,10,12,10))
dimnames(Pop)[[2]] <- c("Very Low", "Low", "High", "Very High")
likert(as.listOfNamedMatrices(Pop),
            as.percent=TRUE,
            resize.height="rowSums",
            strip=FALSE,
            strip.left=FALSE,
            main="Area and Height are proportional to 'Row Count Totals'.
Width is exactly 100%.")


## Professional Challenges example.
##
## The data for this example is a list of related likert scales, with
## each item in the list consisting of differently named rows.  The data
## is from a questionnaire analyzed in a recent Amstat News article.
## The study population was partitioned in several ways.  Data from one
## of the partitions (Employment sector) was used in the first example
## in this help file.  The examples here show various options for
## displaying all partitions on the same plot.
##
data(ProfChal)
## ProfChal
print(ProfChal, minlength=6)

## 1. Plot counts with rows in each panel sorted by positive counts.
##
likert(ProfChal,
       positive.order=TRUE,
       main="This works, but needs more specified arguments to look good",
       sub="This looks better in a 10inx7in window")
##
## Strip labels on left (the default for plot.likert).
## positive.order=TRUE is the recommended (but not default) setting for
## lists because the rownames within each item of the list are usually
## different.
##
ProfChalCountsPlot <-
likert(ProfChal, box.width=unit(.4,"cm"),
       strip.left.par=list(cex=.7, lines=5),
       main=list("Is your job professionally challenging?",
                 x=unit(.65, "npc")),
       xlab="Counts",
       positive.order=TRUE,
       rightAxis=TRUE,  ## display Row Count Totals
       sub="This plot looks better in a 10in x 7in window.")
ProfChalCountsPlot


## 2. Plot percents with rows in each panel sorted by positive percents.
##    This is a different sequence than the counts.  Row Count Totals are
##    displayed on the right axis.
ProfChalPctPlot <-
likert(ProfChal,
    as.percent=TRUE,    ## implies display Row Count Totals
    box.width=unit(.4,"cm"),
    strip.left.par=list(cex=.7, lines=5),
    main=list("Is your job professionally challenging?",
              x=unit(.65, "npc")),
    xlab="Percent",
    positive.order=TRUE,
    sub="This plot looks better in a 10in x 7in window.")
ProfChalPctPlot

## 3. Putting both percents and counts on the same plot, both in
##    original sort order.

## Change name in the "Attitude" panel
names(ProfChal)[6] <- "Prof Recog"

LikertPercentCountColumns(ProfChal,
                          main="Is your job professionally challenging?",
                          sub="LikertPercentCountColumns test, 9x8 window")

## Restore original name
names(ProfChal)[6] <- "Attitude\ntoward\nProfessional\nRecognition"

## The ProfChal data is done again with explicit use of ResizeEtc
## in ?HH:::ResizeEtc

## many more examples are in the demo(likertManyExamples)

Run the code above in your browser using DataCamp Workspace