afex_plot: m-way Plot with Error Bars and Raw Data

Description Usage Arguments Details Value Note References Examples

View source: R/afex_plot.R

Description

Plots results from factorial experiments. Estimated marginal means and error bars are plotted in the foreground, raw data is plotted in the background. Error bars can be based on different standard errors (e.g., model-based, within-subjects, between-subjects). Functions described here return a ggplot2 plot object, thus allowing further customization of the plot.

afex_plot is the user friendly function that does data preparation and plotting. It also allows to only return the prepared data (return = "data").

interaction_plot does the plotting when a trace factor is present. oneway_plot does the plotting when a trace factor is absent.

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
afex_plot(object, ...)

## S3 method for class 'afex_aov'
afex_plot(
  object,
  x,
  trace,
  panel,
  mapping,
  error = "model",
  error_ci = TRUE,
  error_level = 0.95,
  error_arg = list(width = 0),
  data_plot = TRUE,
  data_geom,
  data_alpha = 0.5,
  data_arg = list(color = "darkgrey"),
  point_arg = list(),
  line_arg = list(),
  emmeans_arg = list(),
  dodge = 0.5,
  return = "plot",
  factor_levels = list(),
  legend_title,
  ...
)

## S3 method for class 'mixed'
afex_plot(
  object,
  x,
  trace,
  panel,
  mapping,
  id,
  error = "model",
  error_ci = TRUE,
  error_level = 0.95,
  error_arg = list(width = 0),
  data_plot = TRUE,
  data_geom,
  data_alpha = 0.5,
  data_arg = list(color = "darkgrey"),
  point_arg = list(),
  line_arg = list(),
  emmeans_arg = list(),
  dodge = 0.5,
  return = "plot",
  factor_levels = list(),
  legend_title,
  ...
)

## S3 method for class 'merMod'
afex_plot(
  object,
  x,
  trace,
  panel,
  mapping,
  id,
  error = "model",
  error_ci = TRUE,
  error_level = 0.95,
  error_arg = list(width = 0),
  data_plot = TRUE,
  data_geom,
  data_alpha = 0.5,
  data_arg = list(color = "darkgrey"),
  point_arg = list(),
  line_arg = list(),
  emmeans_arg = list(),
  dodge = 0.5,
  return = "plot",
  factor_levels = list(),
  legend_title,
  ...
)

## Default S3 method:
afex_plot(
  object,
  x,
  trace,
  panel,
  mapping,
  id,
  dv,
  data,
  within_vars,
  between_vars,
  error = "model",
  error_ci = TRUE,
  error_level = 0.95,
  error_arg = list(width = 0),
  data_plot = TRUE,
  data_geom,
  data_alpha = 0.5,
  data_arg = list(color = "darkgrey"),
  point_arg = list(),
  line_arg = list(),
  emmeans_arg = list(),
  dodge = 0.5,
  return = "plot",
  factor_levels = list(),
  legend_title,
  ...
)

interaction_plot(
  means,
  data,
  mapping = c("shape", "lineytpe"),
  error_plot = TRUE,
  error_arg = list(width = 0),
  data_plot = TRUE,
  data_geom = ggplot2::geom_point,
  data_alpha = 0.5,
  data_arg = list(color = "darkgrey"),
  point_arg = list(),
  line_arg = list(),
  dodge = 0.5,
  legend_title,
  col_x = "x",
  col_y = "y",
  col_trace = "trace",
  col_panel = "panel",
  col_lower = "lower",
  col_upper = "upper"
)

oneway_plot(
  means,
  data,
  mapping = "",
  error_plot = TRUE,
  error_arg = list(width = 0),
  data_plot = TRUE,
  data_geom = ggbeeswarm::geom_beeswarm,
  data_alpha = 0.5,
  data_arg = list(color = "darkgrey"),
  point_arg = list(),
  legend_title,
  col_x = "x",
  col_y = "y",
  col_panel = "panel",
  col_lower = "lower",
  col_upper = "upper"
)

Arguments

object

afex_aov, mixed, merMod or other model object supported by emmeans (for further examples see: vignette("afex_plot_supported_models")).

...

currently ignored.

x

A character vector or one-sided formula specifying the factor names of the predictors displayed on the x-axis. mapping specifies further mappings for these factors if trace is missing.

trace

An optional character vector or one-sided formula specifying the factor names of the predictors connected by the same line. mapping specifies further mappings for these factors.

panel

An optional character vector or one-sided formula specifying the factor names of the predictors shown in different panels.

mapping

A character vector specifying which aesthetic mappings should be applied to either the trace factors (if trace is specified) or the x factors. Useful options are any combination of "shape", "color", "linetype", or also "fill" (see examples). The default (i.e., missing) uses c("shape", "linetype") if trace is specified and "" otherwise (i.e., no additional aesthetic). If specific mappings should not be applied to specific graphical elements, one can override those via the corresponding further arguments. For example, for data_arg the default is list(color = "darkgrey") which prevents that "color" is mapped onto points in the background.

error

A scalar character vector specifying on which standard error the error bars should be based. Default is "model", which plots model-based standard errors. Further options are: "none" (or NULL), "mean", "within" (or "CMO"), and "between". See details.

error_ci

Logical. Should error bars plot confidence intervals (=TRUE, the default) or standard errors (=FALSE)?

error_level

Numeric value between 0 and 1 determing the width of the confidence interval. Default is .95 corresponding to a 95% confidence interval.

error_arg

A list of further arguments passed to geom_errorbar, which draws the errorsbars. Default is list(width = 0) which suppresses the vertical bars at the end of the error bar.

data_plot

logical. Should raw data be plotted in the background? Default is TRUE.

data_geom

Geom function used for plotting data in background. The default (missing) uses geom_point if trace is specified, otherwise geom_beeswarm (a good alternative is ggbeeswarm::geom_quasirandom) . See examples fo further options.

data_alpha

numeric alpha value between 0 and 1 passed to data_geom. Default is 0.5 which correspond to semitransparent data points in the background such that overlapping data points are plotted darker.

data_arg

A list of further arguments passed to data_geom. Default is list(color = "darkgrey"), which plots points in the background in grey.

point_arg, line_arg

A list of further arguments passed to geom_point or geom_line which draw the points and lines in the foreground. Default is list(). line_arg is only used if trace is specified.

emmeans_arg

A list of further arguments passed to emmeans. Of particular importance for ANOVAs is model, see afex_aov-methods.

dodge

Numerical amount of dodging of factor-levels on x-axis. Default is 0.5.

return

A scalar character specifying what should be returned. The default "plot" returns the ggplot2 plot. The other option "data" returns a list with two data.frames containing the data used for plotting: means contains the means and standard errors for the foreground, data contains the raw data in the background.

factor_levels

A list of new factor levels that should be used in the plot. The name of each list entry needs to correspond to one of the factors in the plot. Each list element can optionally be a named character vector where the name corresponds to the old factor level and the value to the new factor level. Named vectors allow two things: (1) updating only a subset of factor levels (if only a subset of levels is specified) and (2) reordering (and renaming) the factor levels, as order of names within a list element are the order that will be used for plotting. If specified, emits a message with old -> new factor levels.

legend_title

A scalar character vector with a new title for the legend.

id

An optional character vector specifying over which variables the raw data should be aggregated. Only relevant for mixed, merMod, and default method. The default (missing) uses all random effects grouping factors (for mixed and merMod method) or assumes all data points are independent. This can lead to many data points. error = "within" or error = "between" require that id is of length 1. See examples.

dv

An optional scalar character vector giving the name of the column containing the dependent variable for the afex_plot.default method. If missing, the function attempts to take it from the call slot of object. This is also used as y-axis label.

data

For the afex_plot.default method, an optional data.frame containing the raw data used for fitting the model and which will be used as basis for the data points in the background. If missing, it will be attempted to obtain it from the model via recover_data. For the plotting functions, a data.frame with the data that has to be passed and contains the background data points.

within_vars, between_vars

For the afex_plot.default method, an optional character vector specifying which variables should be treated as within-subjects (or repeated-measures) factors and which as between-subjects (or independen-sampels) factors. If one of the two arguments is given, all other factors are assumed to fall into the other category.

means

data.frames used for plotting of the plotting functions.

error_plot

logical. Should error bars be plotted? Only used in plotting functions. To suppress plotting of error bars use error = "none" in afex_plot.

col_y, col_x, col_trace, col_panel

A scalar character string specifying the name of the corresponding column containing the information used for plotting. Each column needs to exist in both the means and the data data.frame.

col_lower, col_upper

A scalar character string specifying the name of the columns containing lower and upper bounds for the error bars. These columns need to exist in means.

Details

afex_plot obtains the estimated marginal means via emmeans and aggregates the raw data to the same level. It then calculates the desired confidence interval or standard error (see below) and passes the prepared data to one of the two plotting functions: interaction_plot when trace is specified and oneway_plot otherwise.

Error Bars

Error bars provide a grahical representation of the variability of the estimated means and should be routinely added to results figures. However, there exist several possibilities which particular measure of variability to use. Because of this, any figure depicting error bars should be accompanied by a note detailing which measure the error bars shows. The present functions allow plotting of different types of confidence intervals (if error_ci = TRUE, the default) or standard errors (if error_ci = FALSE).

A further complication is that readers routinely misinterpret confidence intervals. The most common error is to assume that non-overlapping error bars indicate a significant difference (e.g., Belia et al., 2005). This is often too strong an assumption. (see e.g., Cumming & Finch, 2005; Knol et al., 2011; Schenker & Gentleman, 2005). For example, in a fully between-subjects design in which the error bars depict 95% confidence intervals and groups are of approximately equal size and have equal variance, even error bars that overlap by as much as 50% still correspond to p < .05. Error bars that are just touching roughly correspond to p = .01.

In the case of designs involving repeated-measures factors the usual confidence intervals or standard errors (i.e., model-based confidence intervals or intervals based on the standard error of the mean) cannot be used to gauge significant differences as this requires knowledge about the correlation between measures. One popular alternative in the psychological literature are intervals based on within-subjects standard errors/confidence intervals (e.g., Cousineau & O'Brien, 2014). These attempt to control for the correlation across individuals and thereby allow judging differences between repeated-measures condition. As a downside, when using within-subjects intervals no comparisons across between-subjects conditions or with respect to a fixed-value are possible anymore.

In the case of a mixed-design, no single type of error bar is possible that allows comparison across all conditions. Likewise, for mixed models involving multiple crossed random effects, no single set of error bars (or even data aggregation) adequately represent the true varibility in the data and adequately allows for "inference by eye". Therefore, special care is necessary in such cases. One possiblity is to avoid error bars altogether and plot only the raw data in the background (with error = "none"). The raw data in the background still provides a visual impression of the variability in the data and the precision of the mean estimate, but does not as easily suggest an incorrect inferences. Another possibility is to use the model-based standard error and note in the figure caption that it does not permit comparisons across repeated-measures factors.

The following "rules of eye" (Cumming and Finch, 2005) hold, when permitted by design (i.e., within-subjects bars for within-subjects comparisons; other variants for between-subjects comparisons), and groups are approximately equal in size and variance. Note that for more complex designs ususally analyzed with mixed models, such as designs involving complicated dependencies across data points, these rules of thumbs may be highly misleading.

Implemented Standard Errors

The following lists the implemented approaches to calculate confidence intervals (CIs) and standard errors (SEs). CIs are based on the SEs using the t-distribution with degrees of freedom based on the cell or group size. For ANOVA models, afex_plot attempts to warn in case the chosen approach is misleading given the design (e.g., model-based error bars for purely within-subjects plots). For mixed models, no such warnings are produced, but users should be aware that all options beside "model" are not actually appropriate and have only heuristic value. But then again, "model" based error bars do not permit comparisons for factors varying within one of the random-effects grouping factors (i.e., factors for which random-slopes should be estimated).

"model"

Uses model-based CIs and SEs. For ANOVAs, the variant based on the lm or mlm model (i.e., emmeans_arg = list(model = "multivariate")) seems generally preferrable.

"mean"

Calculates the standard error of the mean for each cell ignoring any repeated-measures factors.

"within" or "CMO"

Calculates within-subjects SEs using the Cosineau-Morey-O'Brien (Cousineau & O'Brien, 2014) method. This method is based on a double normalization of the data. SEs and CIs are then calculated independently for each cell (i.e., if the desired output contains between-subjects factors, SEs are calculated for each cell including the between-subjects factors).

"between"

First aggregates the data per participant and then calculates the SEs for each between-subjects condition. Results in one SE and t-quantile for all conditions in purely within-subjects designs.

"none" or NULL

Suppresses calculation of SEs and plots no error bars.

For mixed models, the within-subjects/repeated-measures factors are relative to the chosen id effects grouping factor. They are automatically detected based on the random-slopes of the random-effects grouping factor in id. All other factors are treated as independent-samples or between-subjects factors.

Value

Returns a ggplot2 plot (i.e., object of class c("gg", "ggplot")) unless return = "data".

Note

Only the DV/response variable can be called y, but no factor/variable used for plotting.

References

Belia, S., Fidler, F., Williams, J., & Cumming, G. (2005). Researchers Misunderstand Confidence Intervals and Standard Error Bars. Psychological Methods, 10(4), 389-396. https://doi.org/10.1037/1082-989X.10.4.389

Cousineau, D., & O'Brien, F. (2014). Error bars in within-subject designs: a comment on Baguley (2012). Behavior Research Methods, 46(4), 1149-1151. https://doi.org/10.3758/s13428-013-0441-z

Cumming, G., & Finch, S. (2005). Inference by Eye: Confidence Intervals and How to Read Pictures of Data. American Psychologist, 60(2), 170-180. https://doi.org/10.1037/0003-066X.60.2.170

Knol, M. J., Pestman, W. R., & Grobbee, D. E. (2011). The (mis)use of overlap of confidence intervals to assess effect modification. European Journal of Epidemiology, 26(4), 253-254. https://doi.org/10.1007/s10654-011-9563-8

Schenker, N., & Gentleman, J. F. (2001). On Judging the Significance of Differences by Examining the Overlap Between Confidence Intervals. The American Statistician, 55(3), 182-186. https://doi.org/10.1198/000313001317097960

Examples

  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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# note: use library("ggplot") to avoid "ggplot2::" in the following

##################################################################
##                2-factor Within-Subject Design                ##
##################################################################

data(md_12.1)
aw <- aov_ez("id", "rt", md_12.1, within = c("angle", "noise"))

##---------------------------------------------------------------
##                    Basic Interaction Plots                   -
##---------------------------------------------------------------

## all examples require emmeans and ggplot2:
if (requireNamespace("emmeans") && requireNamespace("ggplot2")) {

afex_plot(aw, x = "angle", trace = "noise") 
# or: afex_plot(aw, x = ~angle, trace = ~noise)

afex_plot(aw, x = "noise", trace = "angle")

### For within-subject designs, using within-subject CIs is better:
afex_plot(aw, x = "angle", trace = "noise", error = "within") 
(p1 <- afex_plot(aw, x = "noise", trace = "angle", error = "within"))

## use different themes for nicer graphs:
p1 + ggplot2::theme_bw()
}
## Not run: 
p1 + ggplot2::theme_light()
p1 + ggplot2::theme_minimal()
p1 + jtools::theme_apa()
p1 + ggpubr::theme_pubr()

### set theme globally for R session:
ggplot2::theme_set(ggplot2::theme_bw())

### There are several ways to deal with overlapping points in the background besides alpha
# 1. using the default data geom and ggplot2::position_jitterdodge
afex_plot(aw, x = "noise", trace = "angle", error = "within", dodge = 0.3,
          data_arg = list(
            position = 
              ggplot2::position_jitterdodge(
                jitter.width = 0, 
                jitter.height = 5, 
                dodge.width = 0.3  ## needs to be same as dodge
                ),
            color = "darkgrey"))

# 2. using ggbeeswarm::geom_beeswarm
afex_plot(aw, x = "noise", trace = "angle", error = "within", dodge = 0.5,
          data_geom = ggbeeswarm::geom_beeswarm,
          data_arg = list(
            dodge.width = 0.5,  ## needs to be same as dodge
            cex = 0.8,
            color = "darkgrey"))

# 3. do not display points, but use a violinplot: ggplot2::geom_violin
afex_plot(aw, x = "noise", trace = "angle", error = "within", 
          data_geom = ggplot2::geom_violin, 
          data_arg = list(width = 0.5))

# 4. violinplots with color: ggplot2::geom_violin
afex_plot(aw, x = "noise", trace = "angle", error = "within", 
          mapping = c("linetype", "shape", "fill"),
          data_geom = ggplot2::geom_violin, 
          data_arg = list(width = 0.5))

# 5. do not display points, but use a boxplot: ggplot2::geom_boxplot
afex_plot(aw, x = "noise", trace = "angle", error = "within", 
          data_geom = ggplot2::geom_boxplot, 
          data_arg = list(width = 0.3))
          
# 6. combine points with boxplot: ggpol::geom_boxjitter
afex_plot(aw, x = "noise", trace = "angle", error = "within", 
          data_geom = ggpol::geom_boxjitter, 
          data_arg = list(width = 0.3))
## hides error bars!

# 7. nicer variant of ggpol::geom_boxjitter
afex_plot(aw, x = "noise", trace = "angle", error = "within", 
          mapping = c("shape", "fill"),
          data_geom = ggpol::geom_boxjitter, 
          data_arg = list(
            width = 0.3, 
            jitter.width = 0,
            jitter.height = 10,
            outlier.intersect = TRUE),
          point_arg = list(size = 2.5), 
          error_arg = list(size = 1.5, width = 0))

# 8. nicer variant of ggpol::geom_boxjitter without lines
afex_plot(aw, x = "noise", trace = "angle", error = "within", dodge = 0.7,
          mapping = c("shape", "fill"),
          data_geom = ggpol::geom_boxjitter, 
          data_arg = list(
            width = 0.5, 
            jitter.width = 0,
            jitter.height = 10,
            outlier.intersect = TRUE),
          point_arg = list(size = 2.5), 
          line_arg = list(linetype = 0),
          error_arg = list(size = 1.5, width = 0))

## End(Not run)


##---------------------------------------------------------------
##                        One-Way Plots                         -
##---------------------------------------------------------------

## Not run: 
afex_plot(aw, x = "angle", error = "within") ## default

## with color we need larger points
afex_plot(aw, x = "angle", mapping = "color", error = "within", 
          point_arg = list(size = 2.5), 
          error_arg = list(size = 1.5, width = 0.05)) 

afex_plot(aw, x = "angle", error = "within", data_geom = ggpol::geom_boxjitter)

## nicer
afex_plot(aw, x = "angle", error = "within", data_geom = ggpol::geom_boxjitter, 
          mapping = "fill", data_alpha = 0.7, 
          data_arg = list(
            width = 0.6, 
            jitter.width = 0.07,
            jitter.height = 10,
            outlier.intersect = TRUE
          ),
          point_arg = list(size = 2.5), 
          error_arg = list(size = 1.5, width = 0.05))

## we can add a line connecting the means using geom_point(aes(group = 1)):
afex_plot(aw, x = "angle", error = "within") +
  ggplot2::geom_line(ggplot2::aes(group = 1))

## One-way plots also supports panels:
afex_plot(aw, x = "angle", panel = "noise", error = "within")

## And panels with lines:
afex_plot(aw, x = "angle", panel = "noise", error = "within") +
  ggplot2::geom_line(ggplot2::aes(group = 1))


## For more complicated plots it is easier to attach ggplot2:
library("ggplot2")

## We can hide geoms by plotting them in transparent color and add them
## afterward to use a mapping not directly supported. 
## For example, the next plot adds a line to a one-way plot with panels, but 
## with all geoms in the foreground having a color conditional on the panel.

afex_plot(aw, x = "angle", panel = "noise", error = "within", 
          point_arg = list(color = "transparent"), 
          error_arg = list(color = "transparent")) +
  geom_point(aes(color = panel)) +
  geom_linerange(aes(color = panel, ymin = lower, ymax = upper)) + 
  geom_line(aes(group = 1, color = panel)) +
  guides(color = guide_legend(title = "NOISE"))
## Note that we need to use guides explicitly, otherwise the legend title would 
## be "panel". legend_title does not work in this case.

##---------------------------------------------------------------
##                      Other Basic Options                     -
##---------------------------------------------------------------

## relabel factor levels via factor_levels (with message)
afex_plot(aw, x = "noise", trace = "angle", 
          factor_levels = list(angle = c("0°", "4°", "8°"),
                               noise = c("Absent", "Present")))

## factor_levels allows named vectors which enable reordering the factor levels 
### and renaming subsets of levels:
afex_plot(aw, x = "noise", trace = "angle", 
          factor_levels = list(
            angle = c(X8 = "8°", X4 = "4°", X0 = "0°"),
            noise = c(present = "Present")
          )
)


## Change title of legend
afex_plot(aw, x = "noise", trace = "angle", 
          legend_title = "Noise Condition")

## for plots with few factor levels, smaller dodge might be better:
afex_plot(aw, x = "angle", trace = "noise", dodge = 0.25) 

#################################################################
##                    4-factor Mixed Design                    ##
#################################################################

data(obk.long, package = "afex")
a1 <- aov_car(value ~ treatment * gender + Error(id/(phase*hour)), 
              data = obk.long, observed = "gender")

## too difficult to see anything
afex_plot(a1, ~phase*hour, ~treatment) +
  ggplot2::theme_light()

## better
afex_plot(a1, ~hour, ~treatment, ~phase) +
  ggplot2::theme_light()

## even better
afex_plot(a1, ~hour, ~treatment, ~phase, 
          dodge = 0.65, 
          data_arg = list(
            position = 
              ggplot2::position_jitterdodge(
                jitter.width = 0, 
                jitter.height = 0.2, 
                dodge.width = 0.65  ## needs to be same as dodge
                ),
            color = "darkgrey")) +
  ggplot2::theme_classic()

# with color instead of linetype to separate trace factor
afex_plot(a1, ~hour, ~treatment, ~phase, 
          mapping = c("shape", "color"),
          dodge = 0.65, 
          data_arg = list(
            position = 
              ggplot2::position_jitterdodge(
                jitter.width = 0, 
                jitter.height = 0.2, 
                dodge.width = 0.65  ## needs to be same as dodge
                ))) +
  ggplot2::theme_light()

# only color to separate trace factor
afex_plot(a1, ~hour, ~treatment, ~phase, 
          mapping = "color",
          dodge = 0.65, 
          data_arg = list(
            position = 
              ggplot2::position_jitterdodge(
                jitter.width = 0, 
                jitter.height = 0.2, 
                dodge.width = 0.65  ## needs to be same as dodge
                ))) +
  ggplot2::theme_classic()


## plot involving all 4 factors:
afex_plot(a1, ~hour, ~treatment, ~gender+phase, 
          dodge = 0.65, 
          data_arg = list(
            position = 
              ggplot2::position_jitterdodge(
                jitter.width = 0, 
                jitter.height = 0.2, 
                dodge.width = 0.65  ## needs to be same as dodge
                ),
            color = "darkgrey")) +
  ggplot2::theme_bw()


##---------------------------------------------------------------
##              Different Standard Errors Available             -
##---------------------------------------------------------------

## purely within-design
cbind(
  afex_plot(a1, ~phase, ~hour, 
            error = "model", return = "data")$means[,c("phase", "hour", "y", "SE")],
  multivariate = afex_plot(a1, ~phase, ~hour,
                           error = "model", return = "data")$means$error,
  mean = afex_plot(a1, ~phase, ~hour, 
                    error = "mean", return = "data")$means$error,
  within = afex_plot(a1, ~phase, ~hour, 
                     error = "within", return = "data")$means$error,
  between = afex_plot(a1, ~phase, ~hour, 
                      error = "between", return = "data")$means$error)
## mixed design
cbind(
  afex_plot(a1, ~phase, ~treatment, 
            error = "model", return = "data")$means[,c("phase", "treatment", "y", "SE")],
  multivariate = afex_plot(a1, ~phase, ~treatment,
                           error = "model", return = "data")$means$error,
  mean = afex_plot(a1, ~phase, ~treatment, 
                    error = "mean", return = "data")$means$error,
  within = afex_plot(a1, ~phase, ~treatment, 
                     error = "within", return = "data")$means$error,
  between = afex_plot(a1, ~phase, ~treatment, 
                      error = "between", return = "data")$means$error)

## End(Not run)

##################################################################
##                         Mixed Models                         ##
##################################################################
if (requireNamespace("MEMSS") && 
    requireNamespace("emmeans") && 
    requireNamespace("ggplot2")) {

data("Machines", package = "MEMSS") 
m1 <- mixed(score ~ Machine + (Machine|Worker), data=Machines)
pairs(emmeans::emmeans(m1, "Machine"))
# contrast   estimate       SE df t.ratio p.value
# A - B     -7.966667 2.420850  5  -3.291  0.0481
# A - C    -13.916667 1.540100  5  -9.036  0.0007
# B - C     -5.950000 2.446475  5  -2.432  0.1253

## Default (i.e., model-based) error bars suggest no difference between Machines.
## This contrasts with pairwise comparisons above.
afex_plot(m1, "Machine")

## Impression from within-subject error bars is more in line with pattern of differences.
afex_plot(m1, "Machine", error = "within")
}

## Not run: 
data("fhch2010") # load 
fhch <- droplevels(fhch2010[ fhch2010$correct,]) # remove errors
### following model should take less than a minute to fit:
mrt <- mixed(log_rt ~ task*stimulus*frequency + (stimulus*frequency||id)+
               (task||item), fhch, method = "S", expand_re = TRUE)

## way too many points in background:
afex_plot(mrt, "stimulus", "frequency", "task") 

## better to restrict plot of data to one random-effects grouping variable
afex_plot(mrt, "stimulus", "frequency", "task", id = "id")
## when plotting data from a single random effect, different error bars are possible:
afex_plot(mrt, "stimulus", "frequency", "task", id = "id", error = "within")
afex_plot(mrt, "stimulus", "frequency", "task", id = "id", error = "mean")

## compare visual impression with:
pairs(emmeans::emmeans(mrt, c("stimulus", "frequency"), by = "task"))

## same logic also possible for other random-effects grouping factor
afex_plot(mrt, "stimulus", "frequency", "task", id = "item")
## within-item error bars are misleading here. task is sole within-items factor.
afex_plot(mrt, "stimulus", "frequency", "task", id = "item", error = "within")
## CIs based on stanard error of mean look small, but not unreasonable given results.
afex_plot(mrt, "stimulus", "frequency", "task", id = "item", error = "mean")

### compare distribution of individual data for different random effects:
## requires package cowplot
p_id <- afex_plot(mrt, "stimulus", "frequency", "task", id = "id", 
                  error = "within", dodge = 0.7,
                  data_geom = ggplot2::geom_violin, 
                  mapping = c("shape", "fill"),
                  data_arg = list(width = 0.7)) +
  ggplot2::scale_shape_manual(values = c(4, 17)) +
  ggplot2::labs(title = "ID")

p_item <- afex_plot(mrt, "stimulus", "frequency", "task", id = "item", 
          error = "within", dodge = 0.7,
          data_geom = ggplot2::geom_violin, 
          mapping = c("shape", "fill"),
          data_arg = list(width = 0.7)) +
  ggplot2::scale_shape_manual(values = c(4, 17)) +
  ggplot2::labs(title = "Item")

### see: https://cran.r-project.org/package=cowplot/vignettes/shared_legends.html
p_comb <- cowplot::plot_grid(
  p_id + ggplot2::theme_light() + ggplot2::theme(legend.position="none"),
  p_item + ggplot2::theme_light() + ggplot2::theme(legend.position="none")
  )
legend <- cowplot::get_legend(p_id + ggplot2::theme(legend.position="bottom"))
cowplot::plot_grid(p_comb, legend, 
                   ncol = 1, 
                   rel_heights = c(1, 0.1))

##----------------------------------------------------------------
##                    Support for lme4::lmer                     -
##----------------------------------------------------------------

Oats <- nlme::Oats
## afex_plot does currently not support implicit nesting: (1|Block/Variety)
## Instead, we need to create the factor explicitly
Oats$VarBlock <- Oats$Variety:Oats$Block
Oats.lmer <- lmer(yield ~ Variety * factor(nitro) + (1|VarBlock) + (1|Block),
                        data = Oats)
afex_plot(Oats.lmer, "nitro", "Variety")
afex_plot(Oats.lmer, "nitro", panel = "Variety")

##################################################################
##     Default Method works for Models Supported by emmeans     ##
##################################################################

## lm
warp.lm <- lm(breaks ~ wool * tension, data = warpbreaks)
afex_plot(warp.lm, "tension")
afex_plot(warp.lm, "tension", "wool")

## poisson glm
ins <- data.frame(
    n = c(500, 1200, 100, 400, 500, 300),
    size = factor(rep(1:3,2), labels = c("S","M","L")),
    age = factor(rep(1:2, each = 3)),
    claims = c(42, 37, 1, 101, 73, 14))
ins.glm <- glm(claims ~ size + age + offset(log(n)), 
               data = ins, family = "poisson")
afex_plot(ins.glm, "size", "age")

## binomial glm adapted from ?predict.glm
ldose <- factor(rep(0:5, 2))
numdead <- c(1, 4, 9, 13, 18, 20, 0, 2, 6, 10, 12, 16)
sex <- factor(rep(c("M", "F"), c(6, 6)))
SF <- numdead/20  ## dv should be a vector, no matrix
budworm.lg <- glm(SF ~ sex*ldose, family = binomial, 
                  weights = rep(20, length(numdead)))
afex_plot(budworm.lg, "ldose")
afex_plot(budworm.lg, "ldose", "sex") ## data point is hidden behind mean!
afex_plot(budworm.lg, "ldose", "sex", 
          data_arg = list(size = 4, color = "red"))

## nlme mixed model
data(Oats, package = "nlme")
Oats$nitro <- factor(Oats$nitro)
oats.1 <- nlme::lme(yield ~ nitro * Variety, 
                    random = ~ 1 | Block / Variety,
                    data = Oats)
afex_plot(oats.1, "nitro", "Variety", data = Oats)
afex_plot(oats.1, "nitro", "Variety", data = Oats, id = "Block")
afex_plot(oats.1, "nitro", data = Oats)
afex_plot(oats.1, "nitro", data = Oats, id = c("Block", "Variety"))
afex_plot(oats.1, "nitro", data = Oats, id = "Block")


## End(Not run)

afex documentation built on July 22, 2021, 9:07 a.m.