likert {HH}
Description
Constructs and plots diverging stacked barcharts for Likert, semantic differential, rating scale data, and population pyramids.
Usage
likert(x, ...)
likertplot(x, ...)
## S3 method for class 'likert':
plot((x, ...))
## S3 method for class 'formula':
plot.likert((x, data, ReferenceZero=NULL, value, levelsName="",
scales.in=NULL, ## use scales=
between.in=NULL, ## use between=
auto.key.in=NULL, ## use auto.key=
panel.in=NULL, ## use panel=
horizontal=TRUE,
par.settings.in=NULL, ## use par.settings=
...,
as.percent = FALSE,
transposeAxisLabels=TRUE, ## meaningful only when (!horizontal)
## titles
ylab= if (horizontal) as.character(x[[2]])
else
if (as.percent != FALSE) "Percent" else "Count",
xlab= if (!horizontal) as.character(x[[2]])
else
if (as.percent != FALSE) "Percent" else "Count",
main = x.sys.call,
## right axis
rightAxisLabels = rowSums(data.list$Nums),
rightAxis = !missing(rightAxisLabels),
ylab.right = if (rightAxis) "Row Count Totals" else NULL,
## scales
xscale.components = xscale.components.top.HH,
yscale.components = yscale.components.right.HH,
xlimEqualLeftRight = FALSE,
xTickLabelsPositive = TRUE,
## row sequencing
as.table=TRUE,
positive.order=FALSE,
reverse=ifelse(horizontal, as.table, FALSE),
## resizePanels arguments
h.resizePanels=sapply(result$y.used.at, length),
w.resizePanels=sapply(result$x.used.at, length),
## color options
reference.line.col="gray65",
key.border.white=TRUE,
col=likertColor(Nums.attr$nlevels,
ReferenceZero=ReferenceZero)
))
## 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,
reference.line.col="gray65",
col.strip.background="gray97",
col=likertColor(attr(x, "nlevels"),
ReferenceZero),
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(", xName, "))[-(1:2)]", sep=""),
xName=deparse(substitute(x)),
main=paste("layers of", xName, "by", condlevelsName),
...))
## S3 method for class 'list':
plot.likert((x, ## named list of matrices, 2D tables, 2D ftables, or 2D structables, or all-numeric data.frames
condlevelsName="ListNames",
xName=deparse(substitute(x)),
main=paste("List items of", xName, "by", condlevelsName),
layout=if (length(dim.x) > 1) dim.x else {
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) || length(dim.x) != 2) {
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
vcdpackage), or as a list of named two-dimensional objects. This is the only required argument. See the Details section for restrictions on the form of data.frame, list, ftable, and structable arguments. - data
- For the formula method, a
data.frame. - ReferenceZero
- Numeric scalar or
NULL. The position in the rangeseq(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 argumentx, before it has been coerced to a"likert"object. The defaultNULLcorresponds to the middle level if there are an odd number of levels, and to half-way between the two middle levels if there are an even number of levels. This argument is used when the number of positive levels and the number of negative levels are not the same. For example, with 4 levelsc("Disagree", "Neutral", "Weak Agree", "Strong Agree"), the argument would be specifiedReferenceZero=2indicating that the graphical split would be in the middle of the second group with label"Neutral". - value
- Name of the numeric variable containing the data when the formula method is used with the long data form. The predictor in the formula will be a factor name. The name of the predictor will be used as the title in the key.
- levelsName
- (optional) Name of the implied factor distinguishing the columns of the response variables when the formula method is used with the wide data form. This name will be used as the title in the key.
- 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. IfTRUE, rows are ordered within each panel with the row whose bar goes farthest to the right at the top of a panel of horizontal bars or at the left of a panel of vertical bars.positive.orderis frequently set toTRUEfor lists. - as.percent
- When
as.percent==TRUEoras.percent=="noRightAxis", then the values in each row are rescaled to row percents. Whenas.percent==TRUEthe original row totals are used asrightAxisLabels,rightAxisis set toTRUE, theylab.rightis by default set to"Row Count Totals"(the user can change its value in the calling sequence). Whenas.percent=="noRightAxis", thenrightAxiswill be set toFALSE. - as.table
- Standard
latticeargument. Seebarchart. - par.settings.in, scales.in, between.in, auto.key.in,
panel.in - These are placeholders for
latticearguments that lets the user specify some latticepar.settingsand still retain the ones that are prespecified in theplot.likert.default. - ylab, xlab, ylab.right, main
- Standard
latticegraph labels inbarchart. - col
- Vector of color names for the levels of the agreement factor. Although the colors can be specified as an arbitrary vector of color names, for example,
col=c('red','blue','#4AB3F2'), usually specifying one of the diverging palettes fromdiverge_hclor sequential palettes fromsequential_hclwill suffice. For less intense colors, you can use the middle colors from a larger set of colors; e.g.,col=sequential_hcl(11)[5:2]. See the lastAudiencePercentexample below for this usage. - reference.line.col
- Color for reference line at zero.
- col.strip.background
- Background color for the strip labels.
- key.border.white
- Logical. If
TRUE, then place a white border around therectin the key, else use thecolof the rect itself. - horizontal
- Logical, with default
TRUEindicating horizontal bars, will be passed to thebarchartfunction by theplot.likertmethod. In addition, it interchanges the meaning ofresize.heightandresize.widtharguments to thelikertfunctions applied to arrays and lists. - ...
- other arguments. These will be passed to the
barchartfunction by theplot.likertmethod. Arguments to thelatticeauto.key=list()argument (described inbarchart) will be used in the legend. See the examples. - strip.left, strip
- Logical. The default
strip.left=TRUEplaces the strip labels on the left of each panel as in the first professional challenges example. The alternativestrip.left=FALSEputs the strip labels on the top of each panel, the traditional lattice strip label position. - 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
FALSEunlessrightAxisLabelsare 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=TRUEargument, then therightAxisLabelsare still defaulted to the row totals for the counts. We illustrate this usage in theProfChalexample. - resize.height.tuning
- Tuning parameter used to adjust the space between bars as specified by the
resize.heightargument to theResizeEtcfunction. - h.resizePanels, 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 are proportional to the total count in each bar, and see the discussion of thebox.ratioargument. If a numeric vector, the panel heights are proportional to the numbers in the argument. - w.resizePanels, 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
trellisstandard 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 this way, whenas.percent==TRUE, the bar total area is the count and the bar widths are all equal at 100%. See the example below. - panel
- panel function eventually to be used by
barchart. - xscale.components, yscale.components
- See
yscale.components.default.xscale.components.top.HHconstructs the top x-axis labels, when needed, as the names of the bottom x-axis labels.yscale.components.right.HHconstructs the right y-axis labels, when needed, as the names of the left y-axis labels. The names are placed automatically by theplot.likertmethods based on the value of the argumentsas.percent,rightAxis, andrightAxisLabels. By default, whenrightAxis != FALSEthelayout.widthsare set tolist(ylab.right=5, right.padding=0). Otherwise, those arguments are left at their default values. They may be adjusted with an argument of the formpar.settings.in=list(layout.widths=list(ylab.right=5, right.padding=0)). Similarly, spacing for the top labels can be adjusted with an argument of the formpar.settings.in=list(layout.heights=list(key.axis.padding=6)). - xlimEqualLeftRight
- Logical. The default is
FALSE. IfTRUE, 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. IfTRUE, then the tick labels on the negative side are displayed as positive values. - reverse
- Logical. The default is
FALSE. IfTRUE, 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.reverse,positive.order, andhorizontalare independent. All eight combinations are possible. See theEight sequences and orientationssection in the example for all eight. - transposeAxisLabels
- Default is
TRUE. SettingtransposeAxisLabels=FALSEis meaningful only when(!horizontal), and useful only when the x labels and y labels don't look right.
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[sapply(x, is.numeric)]). The subscripting on the class of the columns is there to remove columns of characters (which would otherwise be coerced to NA) and factor columns (which would otherwise be coerced to integers). A data.frame with only numeric columns will work in a named list. A list of data.frame with factors or characters will be plotted by automatically removing columns that are not numeric.
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.
Values
A "trellis" object containing the plot. The plot will be automatically displayed unless the result is assigned to an object.
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.
Note
- Documentation note:
- Most of the plots drawn by
plot.likerthave a long left-axis tick label. They therefore require a wider window than R's default of a nominal 7in x 7in window. The comments with the examples suggest aesthetic window sizes. - Technical note:
- There are three (almost) equivalent calling sequences for likert plots.
likert(x) ## recommended
likertis an alias forplot.likert().plot.likert(x)
plot.likertis both a method ofplotfor"likert"objects, and a generic function in its own right. There are methods ofplot.likertfor"matrix","array","table", and several other classes of input objects.plot(as.likert(x))
Bothlikertandplot.likertwork by calling theas.likertfunction on their argumentx. Onceas.likerthas converted its argument to a"likert"object, the method dispatch technology for the genericplot.likertis in play. The user can make the explicit callas.likert(x)to see what a"likert"object looks like, but is very unlikely to want to look a second time.
See Also
barchart, ResizeEtc, as.likert, as.matrix.listOfNamedMatrices
Examples
## See file HH/demo/likert-paper.r for a complete set of examples using ## the formula method into the underlying lattice:::barchart plotting ## technology. See file HH/demo/likert-paper-noFormula.r for the same ## set of examples using the matrix and list of matrices methods. See ## file HH/demo/likertMosaic-paper.r for the same set of examples using ## the still experimental functions built on the vcd:::mosaic as the ## underlying plotting technology require(grid) require(lattice) require(latticeExtra) require(HH) data(ProfChal) ## ProfChal is a data.frame. ## See below for discussion of the dataset. ## Count plot likert(Question ~ . , ProfChal[ProfChal$Subtable=="Employment sector",], main='Is your job professionally challenging?', ylab=NULL, sub="This plot looks better in a 9in x 4in window.") ## Percent plot calculated automatically from Count data likert(Question ~ . , ProfChal[ProfChal$Subtable=="Employment sector",], as.percent=TRUE, main='Is your job professionally challenging?', ylab=NULL, sub="This plot looks better in a 9in x 4in window.") ## formula method data(NZScienceTeaching) likert(Question ~ . | Subtable, data=NZScienceTeaching, ylab=NULL, scales=list(y=list(relation="free")), layout=c(1,2)) ## Not run: ## formula notation with expanded right-hand-side likert(Question ~ "Strongly disagree" + Disagree + Neutral + Agree + "Strongly agree" | Subtable, data=NZScienceTeaching, ylab=NULL, scales=list(y=list(relation="free")), layout=c(1,2)) ## End(Not run) ## Not run: ## formula notation with long data arrangement NZScienceTeachingLong <- melt(NZScienceTeaching, id.vars=c("Question", "Subtable")) names(NZScienceTeachingLong)[3] <- "Agreement" head(NZScienceTeachingLong) likert(Question ~ Agreement | Subtable, value="value", data=NZScienceTeachingLong, ylab=NULL, scales=list(y=list(relation="free")), layout=c(1,2)) ## End(Not run) ## 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. ## <a href="http://survey.cvent.com/blog/customer-insights-2/box-scores-are-not-just-for-baseball<br /> Responses" title="http://survey.cvent.com/blog/customer-insights-2/box-scores-are-not-just-for-baseball<br /> Responses">http://survey.cvent.com/blog/customer-insights-2/box-scores-are-not-just...</a> <- c(15, 13, 12, 25, 35) names(Responses) <- c("Strongly Disagree", "Disagree", "No Opinion", "Agree", "Strongly Agree") ## Not run: likert(Responses, main="Retail-R-Us offers the best everyday prices.", sub="This plot looks better in a 9in x 2.6in window.") ## End(Not run) ## 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.") ## Not run: ## 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 default Blue palette in the sequential_hcl function. 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=rev(sequential_hcl(4)), sub="This plot looks better in a 7in x 3.5in window.") ## The really light colors in the previous example are too light. ## Therefore we use the col argument directly. We chose to use an ## intermediate set of Blue colors selected from a longer Blue palette. likert(AudiencePercent, positive.order=TRUE, auto.key=list(between=1, between.columns=2), xlab=paste("Percentage of audience younger than 35", "(left of zero) and older than 35 (right of zero)"), main="Brand A has the most even distribution of ages", col=sequential_hcl(11)[5:2], scales=list(x=list(at=seq(-90,60,10), labels=as.vector(rbind("",seq(-80,60,20))))), sub="This plot looks better in a 7in x 3.5in window.") ## End(Not run) ## Not run: ## See the ?as.pyramidLikert help page for these examples ## 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)) ## End(Not run) 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'.\nWidth 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) levels(ProfChal$Subtable)[6] <- "Prof Recog" ## reduce length of label ## 1. Plot counts with rows in each panel sorted by positive counts. ## ## Not run: likert(Question ~ . | Subtable, ProfChal, positive.order=TRUE, main="This works, but needs more specified arguments to look good") likert(Question ~ . | Subtable, ProfChal, scales=list(y=list(relation="free")), layout=c(1,6), positive.order=TRUE, between=list(y=0), strip=FALSE, strip.left=strip.custom(bg="gray97"), par.strip.text=list(cex=.6, lines=5), main="Is your job professionally challenging?", ylab=NULL, sub="This looks better in a 10inx7in window") ## End(Not run) ProfChalCountsPlot <- likert(Question ~ . | Subtable, ProfChal, scales=list(y=list(relation="free")), layout=c(1,6), positive.order=TRUE, box.width=unit(.4,"cm"), between=list(y=0), strip=FALSE, strip.left=strip.custom(bg="gray97"), par.strip.text=list(cex=.6, lines=5), main="Is your job professionally challenging?", rightAxis=TRUE, ## display Row Count Totals ylab=NULL, sub="This looks better in a 10inx7in window") ProfChalCountsPlot ## Not run: ## 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(Question ~ . | Subtable, ProfChal, as.percent=TRUE, ## implies display Row Count Totals scales=list(y=list(relation="free")), layout=c(1,6), positive.order=TRUE, box.width=unit(.4,"cm"), between=list(y=0), strip=FALSE, strip.left=strip.custom(bg="gray97"), par.strip.text=list(cex=.6, lines=5), main="Is your job professionally challenging?", rightAxis=TRUE, ## display Row Count Totals ylab=NULL, sub="This looks better in a 10inx7in window") ProfChalPctPlot ## 3. Putting both percents and counts on the same plot, both in ## the order of the positive percents. LikertPercentCountColumns(Question ~ . | Subtable, ProfChal, layout=c(1,6), scales=list(y=list(relation="free")), ylab=NULL, between=list(y=0), strip.left=strip.custom(bg="gray97"), strip=FALSE, par.strip.text=list(cex=.7), positive.order=TRUE, main="Is your job professionally challenging?") ## Restore original name ##levels(ProfChal$Subtable)[6] <- "Attitude toward Professional Recognition" ## End(Not run) ## The ProfChal data is done again with explicit use of ResizeEtc ## in ?HH:::ResizeEtc
Documentation reproduced from package HH, version 2.3-37. License: GPL (>= 2)
