likert: Diverging stacked barcharts for Likert, semantic... In HH: Statistical Analysis and Data Display: Heiberger and Holland

Description

Constructs and plots diverging stacked barcharts for Likert, semantic differential, rating scale data, and population pyramids.

Usage

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 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=list(x=1 + (horizontal), y=.5 + 2*(!horizontal)), auto.key.in=NULL, ## use auto.key= panel.in=NULL, ## use panel= horizontal=TRUE, par.settings.in=NULL, ## use par.settings= ..., as.percent = FALSE, ## titles ylab= if (horizontal) { if (length(x)==3) deparse(x[]) else "Question" } else if (as.percent != FALSE) "Percent" else "Count", xlab= if (!horizontal) { if (length(x)==3) deparse(x[]) else "Question" } 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, xlab.top = NULL, right.text.cex = if (horizontal) { ## lazy evaluation if (!is.null(scales\$y\$cex)) scales\$y\$cex else .8 } else { if (!is.null(scales\$x\$cex)) scales\$x\$cex else .8 }, ## 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, data.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", col.strip.background="gray97", key.border.white=TRUE, col=likertColor(Nums.attr\$nlevels, ReferenceZero=ReferenceZero, colorFunction=colorFunction, colorFunctionOption=colorFunctionOption), colorFunction="diverge_hcl", colorFunctionOption="lighter" ) ## S3 method for class 'matrix' plot.likert(x, positive.order=FALSE, ylab=names(dimnames(x)), xlab=if (as.percent != FALSE) "Percent" else "Count", main=xName, reference.line.col="gray65", col.strip.background="gray97", col=likertColor(attr(x, "nlevels"), ReferenceZero=ReferenceZero, colorFunction=colorFunction, colorFunctionOption=colorFunctionOption), colorFunction="diverge_hcl", colorFunctionOption="lighter", 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) ## Default S3 method: plot.likert(x, ...) ## calls plot.likert.matrix ## 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 'likert' plot.likert(x, ...) ## See Details ## 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) }, resize.width=if (missing(layout)) {1 } else { rep(1, layout) }, 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. All terms in the formula must be the names of columns in the data.frame argument data or the special abbreviation . only on the right-hand-side. Functions of the names will not work. The right-hand-side must be either . or the sum of the names of numeric variables in data. Non-syntactic names must be in quotes (single ' or double "), but not backticks `. The . on the right-hand-side is expanded to the formula containing the sum of all remaining (after the response and the conditioning variables) numeric columns in data. An empty left-hand-side is interpreted as the rownames(data). See the examples for all possible forms of formula recognized by the likert function. 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 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. Do not use variable names ".value" or ".variable". 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 x, before it has been coerced to a "likert" object. The default NULL corresponds 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 levels c("Disagree", "Neutral", "Weak Agree", "Strong Agree"), the argument would be specified ReferenceZero=2 indicating 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. If TRUE, 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.order is frequently set to TRUE for lists. data.order formula method only. If positive.order is TRUE, this data.order variable is ignored. If FALSE, the default value, and the rows are specified by a factor, then they are ordered by their levels. If TRUE, then the rows are ordered by their order in the input data.frame. 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, rightAxis is set to TRUE, the ylab.right is by default set to "Row Count Totals" (the user can change its value in the calling sequence). When as.percent=="noRightAxis", then rightAxis will be set to FALSE. as.table Standard lattice argument. See barchart. par.settings.in, scales.in, auto.key.in, panel.in These are placeholders for lattice arguments that lets the user specify some lattice par.settings and still retain the ones that are prespecified in the plot.likert.default. ylab, xlab, ylab.right, xlab.top, main Standard lattice graph labels in barchart. right.text.cex The right axis, as used here for the "Row Count Totals", has non-standard controls. It's cex follows the cex of the left axis, unless this argument is used to override that value. When horizontal=FALSE, then the top axis defaults to follow the bottom axis unless overridden by right.text.cex. between Standard lattice argument. 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 from diverge_hcl or sequential palettes from sequential_hcl will 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 last AudiencePercent example below for this usage. colorFunction, colorFunctionOption See likertColor. 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 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 resize.width arguments to the likert functions applied to arrays and lists. ... other arguments. These will be passed to the barchart function by the plot.likert method. The most useful of these is the border argument which defaults to make the borders of the bars the same color as the bars themselves. A scalar alternative (border="white" being our first choice) puts a border around each bar in the stacked barchart. This works very well when the ReferenceZero line is between two levels. It gives a misleading division of the central bar when the ReferenceZero is in the middle of a level. See the example in the examples section. Arguments to the lattice auto.key=list() argument (described in barchart) will be used in the legend. See the examples.
 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 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 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 are still defaulted to the row totals for the counts. We illustrate this usage in the ProfChal example. resize.height.tuning Tuning parameter used to adjust the space between bars as specified by the resize.height argument to the ResizeEtc function. 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 the box.ratio argument. 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 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 this way, when as.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.HH constructs the top x-axis labels, when needed, as the names of the bottom x-axis labels. yscale.components.right.HH constructs the right y-axis labels, when needed, as the names of the left y-axis labels. The names are placed automatically by the plot.likert methods based on the value of the arguments as.percent, rightAxis, and rightAxisLabels. By default, when rightAxis != FALSE the layout.widths are set to list(ylab.right=5, right.padding=0). Otherwise, those arguments are left at their default values. They may be adjusted with an argument of the form par.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 form par.settings.in=list(layout.heights=list(key.axis.padding=6)). xlimEqualLeftRight Logical. The default is FALSE. If TRUE and at and labels are not explicitly specified, 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. When !horizontal, this argument applies to the y coordinate. xTickLabelsPositive Logical. The default is TRUE. If TRUE and at and labels are not explicitly specified, then the tick labels on the negative side are displayed as positive values. When !horizontal, this argument applies to the y coordinate. 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. reverse, positive.order, and horizontal are independent. All eight combinations are possible. See the Eight sequences and orientations section in the example for all eight.

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.

The likert method is designed for use with "likert" objects created with the independent likert package. It is not recommended that the HH package and the likert package both be loaded at the same time, as they have incompatible usage of the exported function names likert and plot.likert. If the likert package is installed, it can be run without loading by using the function calls likert::likert() and likert:::plot.likert().

Value

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

Note

The current version of the likert function uses the default diverging palette from diverge_hcl as the default. Previous versions used the RColorBrewer palette "RdBu" as the default color palette. The previous color palette is still available with an explicit call to likertColorBrewer, for example

col=likertColorBrewer(nc, ReferenceZero=ReferenceZero,
BrewerPaletteName="RdBu", middle.color="gray90")

Note

Ann Liu-Ferrara was a beta tester for the shiny app.

Note

Documentation note:

Most of the plots drawn by plot.likert have 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.

1. likert(x) ## recommended
likert is an alias for plot.likert().

2. plot.likert(x)
plot.likert is both a method of plot for "likert" objects, and a generic function in its own right. There are methods of plot.likert for "formula", "matrix", "array", "table", and several other classes of input objects.

3. plot(as.likert(x))
Both likert and plot.likert work by calling the as.likert function on their argument x. Once as.likert has converted its argument to a "likert" object, the method dispatch technology for the generic plot.likert is in play. The user can make the explicit call as.likert(x) to see what a "likert" object looks like, but is very unlikely to want to look a second time.

Author(s)

Richard M. Heiberger, with contributions from Naomi B. Robbins <naomi@nbr-graphs.com>.

Maintainer: Richard M. Heiberger <rmh@temple.edu>

References

Richard M. Heiberger, Naomi B. Robbins (2014)., "Design of Diverging Stacked Bar Charts for Likert Scales and Other Applications", Journal of Statistical Software, 57(5), 1–32, doi: 10.18637/jss.v057.i05.

Richard Heiberger and Naomi Robbins (2011), "Alternative to Charles Blow's Figure in \"Newt's War on Poor Children\"", Forbes OnLine, December 20, 2011. https://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/

Luo, Amy and Tim Keyes (2005). "Second Set of Results in from the Career Track Member Survey," Amstat News. Arlington, VA: American Statistical Association.