Research Document

Questions codebook

Method of delivery

Question labels

Setup

Overview

See the “Code and logs” tab for, well, the code and logs.

Code and logs

###-----------------------------------------------------------------------------
### Setting paths and datafile name
###-----------------------------------------------------------------------------

basePath <- here::here();

### NOTE: until we add in the data, the repo isn't portable anyway,
###       so we might as well get the existing data from the old repo.

dataPath <- normalizePath(file.path(basePath, "..", "coronapreppers", "data"));

figureDataPath <- file.path(basePath, "figure_data");
metadataPath <- file.path(basePath, "metadata");
outputPath <- file.path(basePath, "images");

dataFilename <- "shield_gjames_21-09-20.csv";

###-----------------------------------------------------------------------------
### Setting URLs and column names
###-----------------------------------------------------------------------------

questionLabels_sheetURL <-
  "https://docs.google.com/spreadsheets/d/1BEX4W8XRGnuDk4Asa_pdKij3EIZBvhSPqHxFrDjM07k";

questionLabels_varNameCol <- "New variable name";
questionLabels_leftAnchorCol <- "English lo-anchor";
questionLabels_rightAnchorCol <- "English hi-anchor";
questionLabels_labelCol <- "Label short"; # "Label";
questionLabels_labelCol <- "Item english translation"; # "Label";
###-----------------------------------------------------------------------------
### Load data
###-----------------------------------------------------------------------------

#df <- read.csv("data/shield_gjames_21-06-10.csv")

### James: refactored a bit using paths defined above and to
### make this platform-independent
df <- df.raw <- read.csv(
  file.path(
    dataPath,
    dataFilename
  )
);

###-----------------------------------------------------------------------------
### Create new composite measure of intention and behavior
###-----------------------------------------------------------------------------

intentionVars <-
  grep("^intention_", names(df), value=TRUE);

### Note: intention response options are:
###   1 = I will wear a mask all the time
###   2 = I'm going to wear a mask part of the time
###   3 = I'm not going to wear a mask
###   4 = I'm not going to go at all
###
### We recode these so that the new categories reflect the
### risk due to potential unmasked exposure to SARS-CoV-2:
###   1 -> 0
###   2 -> 1
###   3 -> 2
###   4 -> 0

for (currentIntentionVar in intentionVars) {
  df[, paste0(currentIntentionVar, "_recoded")] <-
    ifelse(
      df[, currentIntentionVar] == 4,
      0,
      df[, currentIntentionVar] - 1
    );
}

df$intention_composite <-
  rowSums(df[, paste0(intentionVars, "_recoded")]);

### Behavior

behaviorVars <-
  grep("^behaviour_", names(df), value=TRUE);

behaviorVars_selected <-
  grep("indoors|unmasked", behaviorVars, value=TRUE);

### For these two behavior measures, the response
### options are different:
###
###   behaviour_indoors_nonhouseholders:
###     1 = Several times a day
###     2 = Every day
###     3 = 5-6 days
###     4 = 3-4 days
###     5 = 1-2 days
###     6 = Not at all
###
###   behaviour_unmasked:
###     1 = Every day
###     5-6 days
###     3-4 days
###     1-2 days
###     not at all
###
### These are recoded to ~ represent, respectively,
### 'mask wearing opportunities' and 'risk events'.

maskWearingOpportunities_recodingVector <-
  c(14/7, 1, 5.5/7, 3.5/7, 1.5/7, 0);

df[, paste0(behaviorVars_selected[1], "_recoded")] <-
  maskWearingOpportunities_recodingVector[
    df[, behaviorVars_selected[1]]
  ];

riskEvents_recodingVector <-
  c(1, 5.5/7, 3.5/7, 1.5/7, 0);

df[, paste0(behaviorVars_selected[2], "_recoded")] <-
  riskEvents_recodingVector[
    df[, behaviorVars_selected[2]]
  ];

df$behavior_composite <-
  df[, paste0(behaviorVars_selected[1], "_recoded")] *
  df[, paste0(behaviorVars_selected[2], "_recoded")];

df$behavior_composite_recoded <-
  df$behavior_composite * 5;

df$intention_behavior_composite <-
  rowMeans(
    df[,
       c('intention_composite',
         'behavior_composite_recoded')
      ],
    na.rm = TRUE);

### Invert the final measure so that higher scores represent the desirable
### behavior instead of the other way around.
df$intention_behavior_composite <-
  max(df$intention_behavior_composite, na.rm=TRUE) - 
  df$intention_behavior_composite;

###-----------------------------------------------------------------------------
### We now have two variables: a behavior composite that represents in which
### proportion of the situations where mask-wearing was the desirable behavior
### participants wore masks; and an intention-behavior composite, where this
### variable is averaged with intention.
###-----------------------------------------------------------------------------

### Use regular expressions to select variables:
###  - the | means "or";
###  - the ^ means "start of the text string"

determinantVars <- list(
  continuous =
    grep(
      
      ### We don't want intention as a determinant
      ### Also, leave out the SDT items because they're part of
      ### another study, and not easy to interpret as determinants
      ### as thet may measure two things.
      #   "^intention|^automaticity|attitude|^norms|^risk|^effective|^sdt",
      
      "^automaticity|attitude|^norms|^risk|^effective",
      
      names(df),
      value=TRUE
    ),
  dichotomous =
    grep(
      "barriers",
      names(df),
      value=TRUE
    )
);

### Superseded
#behaviorVarName <- "behaviour_unmasked";

### Using the new composite behavior measure
behaviorVarName <- "intention_behavior_composite";

#behaviorVarName_dichotomized <- "behaviour_unmasked_bool"; ### Redundant now
#
### Create dichotomized behavior measure
# df[, behaviorVarName_dichotomized] <-
#   ifelse(df[, behaviorVarName] < 5,
#          0,
#          1);

### Verify that
# table(df[, behaviorVarName],
#       df[, behaviorVarName_dichotomized]);

###-----------------------------------------------------------------------------
### Create factors for age and education
###-----------------------------------------------------------------------------

df$demographic_educationType <-
  ifelse(
    df$demographic_higher_education,
    "Theoretical",
    "Practical"
  );

df$demographic_educationType <-
  factor(
    df$demographic_educationType,
    levels = c("Practical", "Theoretical"),
    labels = c("Practical", "Theoretical"),
    ordered = TRUE
  );

ageRecodingVector <-
  c("18-29" = "Younger than 40",
    "30-39" = "Younger than 40",
    "40-49" = "40 to 59",
    "50-59" = "40 to 59",
    "60+" = "60 or older");

df$demographic_ageGroups <-
  ageRecodingVector[
    df$demographic_age
  ];

df$demographic_ageGroups <-
  factor(
    df$demographic_ageGroups,
    levels = unique(ageRecodingVector),
    labels = unique(ageRecodingVector),
    ordered=TRUE
  );

### Verify recoding

table(df$demographic_higher_education,
      df$demographic_educationType);
##    
##     Practical Theoretical
##   0      1219           0
##   1         0        1053
table(df$demographic_age,
      df$demographic_ageGroups);
##        
##         Younger than 40 40 to 59 60 or older
##   18-29             395        0           0
##   30-39             354        0           0
##   40-49               0      416           0
##   50-59               0      379           0
##   60+                 0        0         728
### For convenience later on
ageGroups <- levels(df$demographic_ageGroups);
eduGroups <- levels(df$demographic_educationType);

###-----------------------------------------------------------------------------
### Export processed data
###-----------------------------------------------------------------------------

write.csv(
  df,
  file = file.path(
    dataPath,
    "data--preprocessed-for-CIBER.csv"
  )
);
###-----------------------------------------------------------------------------
### Load labels, store local backup, prepare vectors
###-----------------------------------------------------------------------------

questionLabels_localBackupFilename <-
  file.path(metadataPath, "questionLabels.xlsx");

### Use tryCatch in case we're offline
tryCatch({
  
  googlesheets4::gs4_deauth();
  
  questionLabelDf <-
    as.data.frame(
      googlesheets4::read_sheet(questionLabels_sheetURL)
    );
  
  ### Store local backup in case we're offline next time and so that it
  ### gets archived along with the rest if we freeze an OSF registration
  openxlsx::write.xlsx(
    questionLabelDf,
    questionLabels_localBackupFilename,
    overwrite = TRUE
  );
  
}, error = function(e) {
  
  ### We're probably offline; try reading local copy, otherwise throw error
  if (file.exists(questionLabels_localBackupFilename)) {
    questionLabelDf <-
      openxlsx::read.xlsx(
        questionLabels_localBackupFilename
      );
  } else {
    stop("I cannot read the google sheet with the question labels, nor ",
         "do I manage to read the spreadsheet from the local backup file.");
  }
  
});
## v Reading from "Citizen Shield notes".
## v Range 'Variable names'.
## New names:
## * `` -> ...18
## * `` -> ...19
## * `` -> ...20
## * `` -> ...21
## * `` -> ...22
###-----------------------------------------------------------------------------
### Create vectors
###-----------------------------------------------------------------------------

questionLabels <-
  stats::setNames(
    questionLabelDf[, questionLabels_labelCol],
    nm = questionLabelDf[, questionLabels_varNameCol]
  );

leftAnchors <-
  stats::setNames(
    questionLabelDf[, questionLabels_leftAnchorCol],
    nm = questionLabelDf[, questionLabels_varNameCol]
  );

rightAnchors <-
  stats::setNames(
    questionLabelDf[, questionLabels_rightAnchorCol],
    nm = questionLabelDf[, questionLabels_varNameCol]
  );

###-----------------------------------------------------------------------------
### Wrap vectors with labels
###-----------------------------------------------------------------------------

questionLabel_maxWidth <- 60;
anchors_maxWidth <- 20;

wrapVector <- function(x, width) {
  res <-
    unlist(
      lapply(
        strwrap(x, width = width, simplify = FALSE),
        paste,
        collapse = "\n"
      )
    );
  names(res) <- names(x);
  return(res);
}

questionLabels_wrapped <-
  wrapVector(questionLabels, questionLabel_maxWidth);

# questionLabels_wrapped <- questionLabels <-
#   stats::setNames(determinantVars$continuous,
#                   nm=determinantVars$continuous);

leftAnchors_wrapped <-
  wrapVector(leftAnchors, anchors_maxWidth);

rightAnchors_wrapped <-
  wrapVector(rightAnchors, anchors_maxWidth);

fullLabels <-
  stats::setNames(
    wrapVector(
      paste0(
        questionLabels,
        " [ ",
        leftAnchors[names(questionLabels)],
        " | ",
        rightAnchors[names(questionLabels)],
        " ]"
      ),
      questionLabel_maxWidth
    ),
    nm = names(questionLabels)
  );

CIBER plots

Full sample

### No longer necessary, set-up now happens above and distinguishes
### continuous and dichotomous variables

# tmp <- df %>%
#   select(-behaviour_unmasked_bool, -behaviour_unmasked, -id, -demographic_age) %>%
#   as.data.frame()
# 
# determinants_list <- colnames(tmp)

### Rescale variables to 0-1 --- note that the way this is done now
### assumes that the scale max is observed at least once. If that
### assumption doesn't hold, we may want to extract the scale max
### values from the google sheet with the labels.
df[, determinantVars$continuous] <-
  lapply(
    df[, determinantVars$continuous],
    function(x) {
      return((x - 1) / (max(x, na.rm=TRUE) - 1));
    }
  );

ciberJitterWidth <- floor(100*1/7) / 100;

CIBERplots <- list();

CIBERplots$fullSample <-
  behaviorchange::CIBER(
    data=df,
    determinants = determinantVars$continuous,
    targets = behaviorVarName,
    orderBy = behaviorVarName,
    titleVarLabels = stats::setNames("mask wearing", nm=behaviorVarName),
    titleSuffix = "(full sample)",
    subQuestions = questionLabels_wrapped[determinantVars$continuous],
    leftAnchors = leftAnchors_wrapped[determinantVars$continuous],
    rightAnchors = rightAnchors_wrapped[determinantVars$continuous],
    jitterWidth = ciberJitterWidth,
    drawPlot = FALSE,
    returnPlotOnly = FALSE
  );

ufs::knitAndSave(
  CIBERplots$fullSample$output$plot,
  figCaption = paste0("CIBER plot for the full sample."),
  path = outputPath,
  figWidth = attr(CIBERplots$fullSample$output$plot, "width"),
  figHeight = attr(CIBERplots$fullSample$output$plot, "height"),
);
## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
CIBER plot for the full sample.

CIBER plot for the full sample.

selectedDeterminants <-
  c("automaticity_carry_mask",
    "automaticity_put_on_mask",
    "effective_means_masks",
    "effective_means_distance",
    "inst_attitude_protects_others",
    "norms_family_friends",
    "norms_officials",
    "aff_attitude_difficult_breathing",
    "risk_fear_restrictions")

CIBERplot_fullSample_selection <-
  behaviorchange::CIBER(
    data=df,
    determinants = selectedDeterminants,
    targets = behaviorVarName,
    orderBy = behaviorVarName,
    titleVarLabels = stats::setNames("mask wearing", nm=behaviorVarName),
    titleSuffix = "(full sample, selection)",
    subQuestions = questionLabels_wrapped[selectedDeterminants],
    leftAnchors = leftAnchors_wrapped[selectedDeterminants],
    rightAnchors = rightAnchors_wrapped[selectedDeterminants],
    jitterWidth = ciberJitterWidth,
    drawPlot = FALSE,
    returnPlotOnly = FALSE,
    xbreaks = c(0, .2, .4, .6, .8, 1)
  );

ufs::knitAndSave(
  CIBERplot_fullSample_selection$output$plot,
  figCaption = paste0("CIBER plot for the full sample (selection)."),
  path = outputPath,
  figWidth = attr(CIBERplot_fullSample_selection$output$plot, "width"),
  figHeight = attr(CIBERplot_fullSample_selection$output$plot, "height"),
);
## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
CIBER plot for the full sample (selection).

CIBER plot for the full sample (selection).

### Age

for (currentAgeGroup in levels(df$demographic_ageGroups)) {
  
  ufs::heading(currentAgeGroup,
               headingLevel = 2);

  CIBERplots[[currentAgeGroup]] <-
    behaviorchange::CIBER(
      data = df[df$demographic_ageGroups == currentAgeGroup, ],
      determinants = determinantVars$continuous,
      targets = behaviorVarName,
      orderBy = behaviorVarName,
      titleVarLabels = stats::setNames("mask wearing", nm=behaviorVarName),
      titleSuffix = paste0("(", currentAgeGroup, ")"),
      subQuestions = questionLabels_wrapped[determinantVars$continuous],
      leftAnchors = leftAnchors_wrapped[determinantVars$continuous],
      rightAnchors = rightAnchors_wrapped[determinantVars$continuous],
      jitterWidth = ciberJitterWidth,
      drawPlot = FALSE,
      returnPlotOnly = FALSE
    );

  ### Use `cat` as R inhibits output in for-loops
  cat(
    ufs::knitAndSave(
      CIBERplots[[currentAgeGroup]]$output$plot,
      figCaption = paste0("CIBER plot for age group: ", currentAgeGroup, "."),
      path = outputPath,
      figWidth = attr(CIBERplots[[currentAgeGroup]]$output$plot, "width"),
      figHeight = attr(CIBERplots[[currentAgeGroup]]$output$plot, "height"),
    )
  );
  
}

Younger than 40

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
CIBER plot for age group: Younger than 40.

CIBER plot for age group: Younger than 40.

40 to 59

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
CIBER plot for age group: 40 to 59.

CIBER plot for age group: 40 to 59.

60 or older

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
CIBER plot for age group: 60 or older.

CIBER plot for age group: 60 or older.

### Education

for (currentEduGroup in levels(df$demographic_educationType)) {
    
  ufs::heading(currentEduGroup,
               headingLevel = 2);

  CIBERplots[[currentEduGroup]] <-
    behaviorchange::CIBER(
      data = df[df$demographic_educationType == currentEduGroup, ],
      determinants = determinantVars$continuous,
      targets = behaviorVarName,
      orderBy = behaviorVarName,
      titleVarLabels = stats::setNames("mask wearing", nm=behaviorVarName),
      titleSuffix = paste0("(", currentEduGroup, ")"),
      subQuestions = questionLabels_wrapped[determinantVars$continuous],
      leftAnchors = leftAnchors_wrapped[determinantVars$continuous],
      rightAnchors = rightAnchors_wrapped[determinantVars$continuous],
      jitterWidth = ciberJitterWidth,
      drawPlot = FALSE,
      returnPlotOnly = FALSE
    );

  ### Use `cat` as R inhibits output in for-loops
  cat(
    ufs::knitAndSave(
      CIBERplots[[currentEduGroup]]$output$plot,
      figCaption = paste0("CIBER plot for education group: ", currentEduGroup, "."),
      path = outputPath,
      figWidth = attr(CIBERplots[[currentEduGroup]]$output$plot, "width"),
      figHeight = attr(CIBERplots[[currentEduGroup]]$output$plot, "height"),
    )
  );
 
}

Practical

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
CIBER plot for education group: Practical.

CIBER plot for education group: Practical.

Theoretical

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
CIBER plot for education group: Theoretical.

CIBER plot for education group: Theoretical.

Potential for Change Indices

Note: until we standardize the scales, these are incomparable, as they use the ‘room for improvement’ which is scale-dependent (i.e. it will always be smaller for a dichotomous variable).

Full sample

df_standardized <- df;

df_standardized[, determinantVars$continuous] <-
  lapply(
    df_standardized[, determinantVars$continuous],
    function(x) {
      lowestObservation <- min(x, na.rm = TRUE);
      highestObservation <- max(x, na.rm = TRUE);
      return(
        (x - lowestObservation) / highestObservation
      );
    }
  );

dstList <- list();

dstList$fullSample <-
  behaviorchange::determinant_selection_table(
    data=df_standardized,
    determinants = determinantVars$continuous,
    determinantLabels =
      paste0(questionLabels_wrapped[determinantVars$continuous],
             " [ ",
             leftAnchors_wrapped[determinantVars$continuous],
             " | ",
             rightAnchors_wrapped[determinantVars$continuous],
             " ]"),
    target = behaviorVarName,
    sortBy = 6
  );

print(
  behaviorchange:::knit_print.determinantSelectionTable(
    dstList[['fullSample']],
    render_preview = FALSE
  )
);
## No viewer found, probably documenting or testing

Determinant Selection Table

(Sub-)determinant Lower bound Current Upper bound Weight Potential for Change Index
When I use a face mask, I feel or would feel … [ Very uncomfortable | Very comfortable ] 0 0.431 1 0.36 0.205
How likely do you think you would get a coronavirus
infection in your free time in the next month if you did
nothing to protect yourself from it? [ Very unlikely | Very likely ]
0 0.421 1 0.326 0.188
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I produce
unnecessary waste | I do not produce
unnecessary waste ]
0 0.511 1 0.361 0.176
Consequences of measures taken to prevent the spread of the
coronavirus… [ Doesn’t scare me | Scares me ]
0 0.401 1 -0.287 -0.172
The fact that I would get infected myself .. [ Doesn’t scare me | Scares me ] 0 0.535 1 0.365 0.17
If you got a coronavirus infection, how serious a threat
would you rate it to your health? [ Not serious at all | Very serious ]
0 0.567 1 0.389 0.168
Spread of coronavirus… [ Doesn’t scare me | Scares me ] 0 0.582 1 0.388 0.163
When I use a face mask, I feel or would feel … [ Very anxious | Very calm ] 0 0.593 1 0.381 0.155
When I use a face mask, I feel or would feel … [ Very insecure | Very safe ] 0 0.66 1 0.413 0.141
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I get enough oxygen | I don’t get enough
oxygen ]
0 0.592 1 0.335 0.137
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ It decreases sense
of community | It increases sense
of community ]
0 0.621 1 0.33 0.125
Taking a mask with you to a store or public transport, for
example, has already become automatic for some and is done
without thinking. For others, taking a mask with them is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.761 1 0.521 0.125
Using a face mask [ Ineffective | Effective ] 0 0.776 1 0.52 0.117
Putting on a mask, for example in a shop or on public
transport, has already become automatic for some and it
happens without thinking. For others, putting on a mask is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.781 1 0.528 0.116
When I use a face mask, I feel or would feel … [ Very easy to
breathe | Very difficult to
breathe ]
0 0.54 1 -0.248 -0.114
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose myself to
coronavirus
infection | I protect myself
from coronavirus
infection ]
0 0.734 1 0.385 0.102
That my loved one would get infected… [ Doesn’t scare me | Scares me ] 0 0.72 1 0.356 0.1
In the indoors spaces I visit, people on the site think I
should… [ Not to use a mask | Use a mask ]
0 0.802 1 0.476 0.094
When I use a face mask, I feel or would feel … [ Very irresponsible | Very responsible ] 0 0.804 1 0.46 0.09
Who thinks you should use a face mask and who thinks not?
In the following questions, by using a face mask, we mean
holding a cloth or disposable face mask, surgical mask, or
respirator on the face so that it covers the nose and
mouth. The questions concern leisure time. My family and
friends think I should .. [ Not to use a mask | Use a mask ]
0 0.82 1 0.473 0.085
How likely do you think you will get a coronavirus
infection in your free time in the next month? [ Very unlikely | Very likely ]
0 0.187 1 0.085 0.069
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose others to
coronavirus
infection | I protect others
from coronavirus
infection ]
0 0.863 1 0.477 0.066
Keeping a safety distance (2 meters) [ Ineffective | Effective ] 0 0.826 1 0.358 0.062
Ventilation [ Ineffective | Effective ] 0 0.754 1 0.239 0.059
People at risk think I should .. [ Not to use a mask | Use a mask ] 0 0.889 1 0.398 0.044
If two unvaccinated people from different households meet
indoors, what means do you think would be effective in
preventing coronavirus infection? Hand washing and use of
gloves [ Ineffective | Effective ]
0 0.851 1 0.193 0.029
The authorities think I should .. [ Not to use a mask | Use a mask ] 0 0.918 1 0.323 0.027
### Age

for (currentAgeGroup in levels(df$demographic_ageGroups)) {
  
  ufs::heading(currentAgeGroup,
               headingLevel = 2);

  dstList[[currentAgeGroup]] <-
    behaviorchange::determinant_selection_table(
      data=df_standardized[
        df_standardized$demographic_ageGroups == currentAgeGroup,
      ],
      determinants = determinantVars$continuous,
      determinantLabels =
        paste0(questionLabels_wrapped[determinantVars$continuous],
               " [ ",
               leftAnchors_wrapped[determinantVars$continuous],
               " | ",
               rightAnchors_wrapped[determinantVars$continuous],
               " ]"),
      target = behaviorVarName,
      sortBy = 6,
      headingLevel = 3
    );
      
  print(
    behaviorchange:::knit_print.determinantSelectionTable(
      dstList[[currentAgeGroup]],
      render_preview = FALSE
    )
  );

}

Younger than 40

## No viewer found, probably documenting or testing

Determinant Selection Table

(Sub-)determinant Lower bound Current Upper bound Weight Potential for Change Index
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I produce
unnecessary waste | I do not produce
unnecessary waste ]
0 0.405 1 0.38 0.227
When I use a face mask, I feel or would feel … [ Very uncomfortable | Very comfortable ] 0 0.426 1 0.361 0.208
If you got a coronavirus infection, how serious a threat
would you rate it to your health? [ Not serious at all | Very serious ]
0 0.402 1 0.334 0.199
Spread of coronavirus… [ Doesn’t scare me | Scares me ] 0 0.533 1 0.408 0.19
The fact that I would get infected myself .. [ Doesn’t scare me | Scares me ] 0 0.447 1 0.342 0.189
When I use a face mask, I feel or would feel … [ Very anxious | Very calm ] 0 0.559 1 0.396 0.175
How likely do you think you would get a coronavirus
infection in your free time in the next month if you did
nothing to protect yourself from it? [ Very unlikely | Very likely ]
0 0.416 0.857 0.385 0.17
Taking a mask with you to a store or public transport, for
example, has already become automatic for some and is done
without thinking. For others, taking a mask with them is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.686 1 0.521 0.164
When I use a face mask, I feel or would feel … [ Very insecure | Very safe ] 0 0.623 1 0.421 0.159
Consequences of measures taken to prevent the spread of the
coronavirus… [ Doesn’t scare me | Scares me ]
0 0.457 1 -0.284 -0.154
Putting on a mask, for example in a shop or on public
transport, has already become automatic for some and it
happens without thinking. For others, putting on a mask is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.725 1 0.549 0.151
Using a face mask [ Ineffective | Effective ] 0 0.698 1 0.495 0.149
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I get enough oxygen | I don’t get enough
oxygen ]
0 0.581 1 0.351 0.147
When I use a face mask, I feel or would feel … [ Very easy to
breathe | Very difficult to
breathe ]
0 0.523 1 -0.293 -0.14
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ It decreases sense
of community | It increases sense
of community ]
0 0.612 1 0.346 0.134
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose myself to
coronavirus
infection | I protect myself
from coronavirus
infection ]
0 0.67 1 0.351 0.116
That my loved one would get infected… [ Doesn’t scare me | Scares me ] 0 0.707 1 0.393 0.115
When I use a face mask, I feel or would feel … [ Very irresponsible | Very responsible ] 0 0.769 1 0.471 0.109
In the indoors spaces I visit, people on the site think I
should… [ Not to use a mask | Use a mask ]
0 0.748 1 0.43 0.108
How likely do you think you will get a coronavirus
infection in your free time in the next month? [ Very unlikely | Very likely ]
0 0.204 0.857 0.164 0.107
Who thinks you should use a face mask and who thinks not?
In the following questions, by using a face mask, we mean
holding a cloth or disposable face mask, surgical mask, or
respirator on the face so that it covers the nose and
mouth. The questions concern leisure time. My family and
friends think I should .. [ Not to use a mask | Use a mask ]
0 0.794 1 0.484 0.1
Keeping a safety distance (2 meters) [ Ineffective | Effective ] 0 0.769 1 0.351 0.081
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose others to
coronavirus
infection | I protect others
from coronavirus
infection ]
0 0.85 1 0.533 0.08
Ventilation [ Ineffective | Effective ] 0 0.713 1 0.199 0.057
People at risk think I should .. [ Not to use a mask | Use a mask ] 0 0.867 1 0.358 0.048
The authorities think I should .. [ Not to use a mask | Use a mask ] 0 0.924 1 0.315 0.024
If two unvaccinated people from different households meet
indoors, what means do you think would be effective in
preventing coronavirus infection? Hand washing and use of
gloves [ Ineffective | Effective ]
0 0.82 1 0.11 0.02

40 to 59

## No viewer found, probably documenting or testing

Determinant Selection Table

(Sub-)determinant Lower bound Current Upper bound Weight Potential for Change Index
When I use a face mask, I feel or would feel … [ Very uncomfortable | Very comfortable ] 0 0.41 1 0.402 0.237
How likely do you think you would get a coronavirus
infection in your free time in the next month if you did
nothing to protect yourself from it? [ Very unlikely | Very likely ]
0 0.425 1 0.337 0.193
Consequences of measures taken to prevent the spread of the
coronavirus… [ Doesn’t scare me | Scares me ]
0 0.404 1 -0.279 -0.166
The fact that I would get infected myself .. [ Doesn’t scare me | Scares me ] 0 0.542 1 0.361 0.165
Spread of coronavirus… [ Doesn’t scare me | Scares me ] 0 0.578 1 0.384 0.162
When I use a face mask, I feel or would feel … [ Very anxious | Very calm ] 0 0.592 1 0.386 0.157
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I produce
unnecessary waste | I do not produce
unnecessary waste ]
0 0.485 1 0.3 0.154
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I get enough oxygen | I don’t get enough
oxygen ]
0 0.574 1 0.361 0.154
When I use a face mask, I feel or would feel … [ Very insecure | Very safe ] 0 0.648 1 0.399 0.141
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ It decreases sense
of community | It increases sense
of community ]
0 0.614 1 0.355 0.137
If you got a coronavirus infection, how serious a threat
would you rate it to your health? [ Not serious at all | Very serious ]
0 0.578 1 0.31 0.131
When I use a face mask, I feel or would feel … [ Very easy to
breathe | Very difficult to
breathe ]
0 0.562 1 -0.273 -0.12
Taking a mask with you to a store or public transport, for
example, has already become automatic for some and is done
without thinking. For others, taking a mask with them is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.764 1 0.492 0.116
That my loved one would get infected… [ Doesn’t scare me | Scares me ] 0 0.705 1 0.389 0.115
Using a face mask [ Ineffective | Effective ] 0 0.774 1 0.505 0.114
Putting on a mask, for example in a shop or on public
transport, has already become automatic for some and it
happens without thinking. For others, putting on a mask is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.784 1 0.521 0.113
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose myself to
coronavirus
infection | I protect myself
from coronavirus
infection ]
0 0.739 1 0.395 0.103
In the indoors spaces I visit, people on the site think I
should… [ Not to use a mask | Use a mask ]
0 0.795 1 0.465 0.095
Who thinks you should use a face mask and who thinks not?
In the following questions, by using a face mask, we mean
holding a cloth or disposable face mask, surgical mask, or
respirator on the face so that it covers the nose and
mouth. The questions concern leisure time. My family and
friends think I should .. [ Not to use a mask | Use a mask ]
0 0.809 1 0.481 0.092
When I use a face mask, I feel or would feel … [ Very irresponsible | Very responsible ] 0 0.797 1 0.44 0.089
How likely do you think you will get a coronavirus
infection in your free time in the next month? [ Very unlikely | Very likely ]
0 0.197 1 0.087 0.07
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose others to
coronavirus
infection | I protect others
from coronavirus
infection ]
0 0.86 1 0.471 0.066
Keeping a safety distance (2 meters) [ Ineffective | Effective ] 0 0.814 1 0.315 0.059
Ventilation [ Ineffective | Effective ] 0 0.746 1 0.225 0.057
People at risk think I should .. [ Not to use a mask | Use a mask ] 0 0.885 1 0.402 0.046
If two unvaccinated people from different households meet
indoors, what means do you think would be effective in
preventing coronavirus infection? Hand washing and use of
gloves [ Ineffective | Effective ]
0 0.843 1 0.189 0.03
The authorities think I should .. [ Not to use a mask | Use a mask ] 0 0.913 1 0.317 0.027

60 or older

## No viewer found, probably documenting or testing

Determinant Selection Table

(Sub-)determinant Lower bound Current Upper bound Weight Potential for Change Index
When I use a face mask, I feel or would feel … [ Very uncomfortable | Very comfortable ] 0 0.46 1 0.319 0.172
How likely do you think you would get a coronavirus
infection in your free time in the next month if you did
nothing to protect yourself from it? [ Very unlikely | Very likely ]
0 0.422 1 0.275 0.159
Consequences of measures taken to prevent the spread of the
coronavirus… [ Doesn’t scare me | Scares me ]
0 0.341 1 -0.206 -0.136
When I use a face mask, I feel or would feel … [ Very anxious | Very calm ] 0 0.63 1 0.323 0.12
Spread of coronavirus… [ Doesn’t scare me | Scares me ] 0 0.636 1 0.299 0.109
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ It decreases sense
of community | It increases sense
of community ]
0 0.638 1 0.295 0.107
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I get enough oxygen | I don’t get enough
oxygen ]
0 0.624 1 0.283 0.106
When I use a face mask, I feel or would feel … [ Very easy to
breathe | Very difficult to
breathe ]
0 0.534 1 -0.221 -0.103
When I use a face mask, I feel or would feel … [ Very insecure | Very safe ] 0 0.711 1 0.354 0.102
The fact that I would get infected myself .. [ Doesn’t scare me | Scares me ] 0 0.62 1 0.262 0.1
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I produce
unnecessary waste | I do not produce
unnecessary waste ]
0 0.65 1 0.248 0.087
If you got a coronavirus infection, how serious a threat
would you rate it to your health? [ Not serious at all | Very serious ]
0 0.724 1 0.305 0.084
Taking a mask with you to a store or public transport, for
example, has already become automatic for some and is done
without thinking. For others, taking a mask with them is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.834 1 0.459 0.076
Putting on a mask, for example in a shop or on public
transport, has already become automatic for some and it
happens without thinking. For others, putting on a mask is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.836 1 0.434 0.071
Using a face mask [ Ineffective | Effective ] 0 0.857 1 0.454 0.065
That my loved one would get infected… [ Doesn’t scare me | Scares me ] 0 0.749 1 0.258 0.065
When I use a face mask, I feel or would feel … [ Very irresponsible | Very responsible ] 0 0.846 1 0.419 0.064
In the indoors spaces I visit, people on the site think I
should… [ Not to use a mask | Use a mask ]
0 0.865 1 0.468 0.063
How likely do you think you will get a coronavirus
infection in your free time in the next month? [ Very unlikely | Very likely ]
0 0.159 0.857 0.09 0.063
Who thinks you should use a face mask and who thinks not?
In the following questions, by using a face mask, we mean
holding a cloth or disposable face mask, surgical mask, or
respirator on the face so that it covers the nose and
mouth. The questions concern leisure time. My family and
friends think I should .. [ Not to use a mask | Use a mask ]
0 0.859 1 0.423 0.06
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose myself to
coronavirus
infection | I protect myself
from coronavirus
infection ]
0 0.796 1 0.291 0.059
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose others to
coronavirus
infection | I protect others
from coronavirus
infection ]
0 0.879 1 0.415 0.05
Ventilation [ Ineffective | Effective ] 0 0.806 1 0.214 0.042
The authorities think I should .. [ Not to use a mask | Use a mask ] 0 0.916 1 0.424 0.036
People at risk think I should .. [ Not to use a mask | Use a mask ] 0 0.918 1 0.418 0.034
Keeping a safety distance (2 meters) [ Ineffective | Effective ] 0 0.899 1 0.265 0.027
If two unvaccinated people from different households meet
indoors, what means do you think would be effective in
preventing coronavirus infection? Hand washing and use of
gloves [ Ineffective | Effective ]
0 0.893 1 0.237 0.025
### Education

for (currentEduGroup in levels(df$demographic_educationType)) {
    
  ufs::heading(currentEduGroup,
               headingLevel = 2);

  dstList[[currentEduGroup]] <-
    behaviorchange::determinant_selection_table(
      data=df_standardized[
        df_standardized$demographic_educationType == currentEduGroup,
      ],
      determinants = determinantVars$continuous,
      determinantLabels =
        paste0(questionLabels_wrapped[determinantVars$continuous],
               " [ ",
               leftAnchors_wrapped[determinantVars$continuous],
               " | ",
               rightAnchors_wrapped[determinantVars$continuous],
               " ]"),
      target = behaviorVarName,
      sortBy = 6,
      headingLevel = 3
    );
  
  print(
    behaviorchange:::knit_print.determinantSelectionTable(
      dstList[[currentEduGroup]],
      render_preview = FALSE
    )
  );

}

Practical

## No viewer found, probably documenting or testing

Determinant Selection Table

(Sub-)determinant Lower bound Current Upper bound Weight Potential for Change Index
When I use a face mask, I feel or would feel … [ Very uncomfortable | Very comfortable ] 0 0.425 1 0.361 0.207
How likely do you think you would get a coronavirus
infection in your free time in the next month if you did
nothing to protect yourself from it? [ Very unlikely | Very likely ]
0 0.418 1 0.339 0.197
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I produce
unnecessary waste | I do not produce
unnecessary waste ]
0 0.52 1 0.378 0.181
The fact that I would get infected myself .. [ Doesn’t scare me | Scares me ] 0 0.541 1 0.366 0.168
Spread of coronavirus… [ Doesn’t scare me | Scares me ] 0 0.581 1 0.397 0.166
If you got a coronavirus infection, how serious a threat
would you rate it to your health? [ Not serious at all | Very serious ]
0 0.581 1 0.396 0.166
When I use a face mask, I feel or would feel … [ Very anxious | Very calm ] 0 0.571 1 0.368 0.158
Consequences of measures taken to prevent the spread of the
coronavirus… [ Doesn’t scare me | Scares me ]
0 0.401 1 -0.259 -0.155
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I get enough oxygen | I don’t get enough
oxygen ]
0 0.572 1 0.343 0.147
When I use a face mask, I feel or would feel … [ Very insecure | Very safe ] 0 0.662 1 0.399 0.135
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ It decreases sense
of community | It increases sense
of community ]
0 0.625 1 0.351 0.132
Taking a mask with you to a store or public transport, for
example, has already become automatic for some and is done
without thinking. For others, taking a mask with them is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.753 1 0.527 0.13
Putting on a mask, for example in a shop or on public
transport, has already become automatic for some and it
happens without thinking. For others, putting on a mask is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.772 1 0.526 0.12
Using a face mask [ Ineffective | Effective ] 0 0.773 1 0.513 0.117
When I use a face mask, I feel or would feel … [ Very easy to
breathe | Very difficult to
breathe ]
0 0.557 1 -0.252 -0.112
That my loved one would get infected… [ Doesn’t scare me | Scares me ] 0 0.719 1 0.364 0.102
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose myself to
coronavirus
infection | I protect myself
from coronavirus
infection ]
0 0.732 1 0.378 0.101
In the indoors spaces I visit, people on the site think I
should… [ Not to use a mask | Use a mask ]
0 0.8 1 0.485 0.097
Who thinks you should use a face mask and who thinks not?
In the following questions, by using a face mask, we mean
holding a cloth or disposable face mask, surgical mask, or
respirator on the face so that it covers the nose and
mouth. The questions concern leisure time. My family and
friends think I should .. [ Not to use a mask | Use a mask ]
0 0.803 1 0.478 0.094
When I use a face mask, I feel or would feel … [ Very irresponsible | Very responsible ] 0 0.801 1 0.468 0.093
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose others to
coronavirus
infection | I protect others
from coronavirus
infection ]
0 0.853 1 0.478 0.07
Keeping a safety distance (2 meters) [ Ineffective | Effective ] 0 0.818 1 0.383 0.07
How likely do you think you will get a coronavirus
infection in your free time in the next month? [ Very unlikely | Very likely ]
0 0.181 0.857 0.103 0.07
Ventilation [ Ineffective | Effective ] 0 0.743 1 0.254 0.065
People at risk think I should .. [ Not to use a mask | Use a mask ] 0 0.881 1 0.409 0.049
If two unvaccinated people from different households meet
indoors, what means do you think would be effective in
preventing coronavirus infection? Hand washing and use of
gloves [ Ineffective | Effective ]
0 0.86 1 0.243 0.034
The authorities think I should .. [ Not to use a mask | Use a mask ] 0 0.912 1 0.346 0.031

Theoretical

## No viewer found, probably documenting or testing

Determinant Selection Table

(Sub-)determinant Lower bound Current Upper bound Weight Potential for Change Index
When I use a face mask, I feel or would feel … [ Very uncomfortable | Very comfortable ] 0 0.438 1 0.357 0.201
Consequences of measures taken to prevent the spread of the
coronavirus… [ Doesn’t scare me | Scares me ]
0 0.402 1 -0.325 -0.194
How likely do you think you would get a coronavirus
infection in your free time in the next month if you did
nothing to protect yourself from it? [ Very unlikely | Very likely ]
0 0.424 1 0.307 0.177
If you got a coronavirus infection, how serious a threat
would you rate it to your health? [ Not serious at all | Very serious ]
0 0.55 1 0.386 0.174
The fact that I would get infected myself .. [ Doesn’t scare me | Scares me ] 0 0.528 1 0.366 0.173
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I produce
unnecessary waste | I do not produce
unnecessary waste ]
0 0.501 1 0.341 0.17
Spread of coronavirus… [ Doesn’t scare me | Scares me ] 0 0.582 1 0.377 0.158
When I use a face mask, I feel or would feel … [ Very anxious | Very calm ] 0 0.619 1 0.395 0.15
When I use a face mask, I feel or would feel … [ Very insecure | Very safe ] 0 0.658 1 0.436 0.149
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I get enough oxygen | I don’t get enough
oxygen ]
0 0.615 1 0.323 0.124
Taking a mask with you to a store or public transport, for
example, has already become automatic for some and is done
without thinking. For others, taking a mask with them is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.769 1 0.511 0.118
Using a face mask [ Ineffective | Effective ] 0 0.779 1 0.53 0.117
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ It decreases sense
of community | It increases sense
of community ]
0 0.617 1 0.304 0.116
When I use a face mask, I feel or would feel … [ Very easy to
breathe | Very difficult to
breathe ]
0 0.52 1 -0.24 -0.115
Putting on a mask, for example in a shop or on public
transport, has already become automatic for some and it
happens without thinking. For others, putting on a mask is
not automatic at all, but requires conscious thinking and
effort. [ 1 Not at all
automatic | 7 Fully automatic ]
0 0.791 1 0.53 0.111
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose myself to
coronavirus
infection | I protect myself
from coronavirus
infection ]
0 0.737 1 0.394 0.104
That my loved one would get infected… [ Doesn’t scare me | Scares me ] 0 0.721 1 0.347 0.097
In the indoors spaces I visit, people on the site think I
should… [ Not to use a mask | Use a mask ]
0 0.804 1 0.462 0.09
When I use a face mask, I feel or would feel … [ Very irresponsible | Very responsible ] 0 0.807 1 0.449 0.087
Who thinks you should use a face mask and who thinks not?
In the following questions, by using a face mask, we mean
holding a cloth or disposable face mask, surgical mask, or
respirator on the face so that it covers the nose and
mouth. The questions concern leisure time. My family and
friends think I should .. [ Not to use a mask | Use a mask ]
0 0.839 1 0.464 0.075
What consequences do you think it has if you use a face
mask in your free time? If or when I use a face mask… [ I expose others to
coronavirus
infection | I protect others
from coronavirus
infection ]
0 0.874 1 0.474 0.06
Keeping a safety distance (2 meters) [ Ineffective | Effective ] 0 0.837 1 0.321 0.052
Ventilation [ Ineffective | Effective ] 0 0.768 1 0.215 0.05
How likely do you think you will get a coronavirus
infection in your free time in the next month? [ Very unlikely | Very likely ]
0 0.194 1 0.059 0.048
People at risk think I should .. [ Not to use a mask | Use a mask ] 0 0.899 1 0.38 0.038
If two unvaccinated people from different households meet
indoors, what means do you think would be effective in
preventing coronavirus infection? Hand washing and use of
gloves [ Ineffective | Effective ]
0 0.841 1 0.138 0.022
The authorities think I should .. [ Not to use a mask | Use a mask ] 0 0.925 1 0.289 0.022
for (sampleName in names(dstList)) {
  
  write.csv(
    dstList[[sampleName]],
    file.path(
      figureDataPath,
      paste0(
        "determinant-selection-table-",
        sampleName,
        ".csv")
      ),
    row.names = FALSE
  );
  
  ### CIBERplots has the same names
  tmpDf <- CIBERplots[[sampleName]]$intermediate$meansDat;
  names(tmpDf)[1:3] <- c("mean_ci_lo", "mean_point", "mean_ci_hi");
  row.names(tmpDf) <- tmpDf$label;
  tmpDf[tmpDf$label, c("r_ci_lo", "r_point", "r_ci_hi")] <-
    CIBERplots[[sampleName]]$intermediate$assocDat[[1]][tmpDf$label, ];
  tmpDf$fullLabel <-
    fullLabels[tmpDf$label];
  
  write.csv(
    tmpDf,
    file.path(
      figureDataPath,
      paste0(
        "CIBER-plot-data-",
        sampleName,
        ".csv")
      ),
    row.names = FALSE
  );
  
}

SHAP plots

sampleLabels <-
  c(
    fullSample = "Full sample",
    `Practical` = "Education: practical",
    `Theoretical` = "Education: theoretical",
    `Younger than 40` = "Age: 18-39",
    `40 to 59` = "Age: 40-59",
    `60 or older` = "Age: 60+"
  );

shapFilenames <-
  c(
    fullSample = file.path(figureDataPath,
                           "All_shap_real_values.csv"),
    `Practical` = file.path(figureDataPath,
                            "Lower_Education_shap_real_values.csv"),
    `Theoretical` = file.path(figureDataPath,
                              "Higher_Education_shap_real_values.csv"),
    `Younger than 40` = file.path(figureDataPath,
                                  "18 - 39_shap_real_values.csv"),
    `40 to 59` = file.path(figureDataPath,
                           "40 - 59_shap_real_values.csv"),
    `60 or older` = file.path(figureDataPath,
                              "60+_shap_real_values.csv")
  );

shapDfs <-
  stats::setNames(
    lapply(
      shapFilenames,
      read.csv
    ),
    names(shapFilenames)
  );

shapDfs <-
  lapply(
    shapDfs,
    function(currentDf) {
      currentDf$label <-
        fullLabels[currentDf$variable];
      ### Reverse order because ggplot plots from bottom to top on Y axis
      currentDf$label <-
        factor(
          currentDf$label,
          levels = rev(unique(fullLabels[currentDf$variable])),
          ordered = TRUE
        );
      ### Store actual_value as factor, too
      currentDf$actualValue_factor <-
        factor(
          currentDf$actual_value,
          levels = seq(min(currentDf$actual_value, na.rm=TRUE),
                       max(currentDf$actual_value, na.rm=TRUE)),
          ordered = TRUE
        );
      return(currentDf);
    }
  );

shapPlots <-
  stats::setNames(
    lapply(
      names(shapDfs),
      function(currentSample) {
        return(
          ggplot2::ggplot(
            data = shapDfs[[currentSample]],
            mapping = ggplot2::aes_string(
              x = "shap_value",
              y = "label",
              fill = "actualValue_factor",
              color = "actualValue_factor"
            )
          ) +
            ggbeeswarm::geom_beeswarm(
              size = 2,
              alpha = .66
            ) +
            ggplot2::theme_minimal() +
            ggplot2::labs(title = sampleLabels[currentSample],
                          x = "SHAP Value",
                          y = NULL,
                          fill = "Score",
                          color = "Score")
        );
      }
    ),
    nm = names(shapDfs)
  );

for (currentSample in names(shapPlots)) {
  ufs::heading(sampleLabels[currentSample],
               headingLevel = 2);
  cat(
    ufs::knitAndSave(
      shapPlots[[currentSample]],
      path = outputPath,
      figCaption = paste0("SHAP values for ", sampleLabels[currentSample]),
      figWidth = 9,
      figHeight = 14
    )
  );
}

Full sample

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.

## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.

## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.
## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.
SHAP values for Full sample.

SHAP values for Full sample.

Education: practical

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.
## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.
SHAP values for Education: practical.

SHAP values for Education: practical.

Education: theoretical

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.
## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.
SHAP values for Education: theoretical.

SHAP values for Education: theoretical.

Age: 18-39

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.
## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.
SHAP values for Age: 18-39.

SHAP values for Age: 18-39.

Age: 40-59

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.
## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.
SHAP values for Age: 40-59.

SHAP values for Age: 40-59.

Age: 60+

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.
## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.
SHAP values for Age: 60+.

SHAP values for Age: 60+.

Combined plots

widths <- c(.8, .2);
plotWidths = 12;
plotHeights = 13;

for (i in names(CIBERplots)) {

  ufs::heading(i, headingLevel = 2);
  
  ufs::knitAndSave(
    patchwork::wrap_plots(CIBERplots[[i]]$output$plot,
                          shapPlots[[i]],
                          widths = widths),
    path = outputPath,
    figCaption = paste0("Combined plots for ", i),
    figWidth = plotWidths,
    figHeight = plotHeights
  )
  
}

fullSample

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments
## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.

## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.

## Warning in f(...): The default behavior of beeswarm has changed in version
## 0.6.0. In versions <0.6.0, this plot would have been dodged on the y-axis. In
## versions >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis.
## Please set grouponX=TRUE/FALSE to avoid this warning and ensure proper axis
## choice.

Younger than 40

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

40 to 59

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

60 or older

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

Practical

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

Theoretical

## Warning: Using ragg device as default. Ignoring `type` and `antialias` arguments

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

## Warning: The default behavior of beeswarm has changed in version 0.6.0. In
## versions <0.6.0, this plot would have been dodged on the y-axis. In versions
## >=0.6.0, grouponX=FALSE must be explicitly set to group on y-axis. Please set
## grouponX=TRUE/FALSE to avoid this warning and ensure proper axis choice.

Session information

utils::sessionInfo();
## R version 4.1.2 (2021-11-01)
## Platform: x86_64-w64-mingw32/x64 (64-bit)
## Running under: Windows 10 x64 (build 19042)
## 
## Matrix products: default
## 
## locale:
## [1] LC_COLLATE=English_United States.1252 
## [2] LC_CTYPE=English_United States.1252   
## [3] LC_MONETARY=English_United States.1252
## [4] LC_NUMERIC=C                          
## [5] LC_TIME=English_United States.1252    
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## loaded via a namespace (and not attached):
##  [1] Rcpp_1.0.7           svglite_2.0.0        here_1.0.1          
##  [4] rprojroot_2.0.2      digest_0.6.28        utf8_1.2.2          
##  [7] R6_2.5.1             cellranger_1.1.0     evaluate_0.14       
## [10] httr_1.4.2           ggplot2_3.3.5        highr_0.9           
## [13] pillar_1.6.4         rlang_0.4.12         ufs_0.5.2           
## [16] googlesheets4_1.0.0  curl_4.3.2           rstudioapi_0.13     
## [19] jquerylib_0.1.4      rmarkdown_2.11       textshaping_0.3.6   
## [22] labeling_0.4.2       webshot_0.5.2        googledrive_2.0.0   
## [25] stringr_1.4.0        pander_0.6.4         munsell_0.5.0       
## [28] vipor_0.4.5          compiler_4.1.2       xfun_0.27           
## [31] pkgconfig_2.0.3      systemfonts_1.0.3    ggbeeswarm_0.6.0    
## [34] htmltools_0.5.2      tidyselect_1.1.1     tibble_3.1.5        
## [37] gridExtra_2.3        fansi_0.5.0          viridisLite_0.4.0   
## [40] crayon_1.4.2         dplyr_1.0.7          withr_2.4.2         
## [43] grid_4.1.2           jsonlite_1.7.2       gtable_0.3.0        
## [46] lifecycle_1.0.1      magrittr_2.0.1       scales_1.1.1        
## [49] zip_2.2.0            cli_3.1.0            stringi_1.7.5       
## [52] farver_2.1.0         viridis_0.6.2        fs_1.5.0            
## [55] rmdpartials_0.5.8    xml2_1.3.2           bslib_0.3.1         
## [58] ellipsis_0.3.2       ragg_1.2.0           generics_0.1.1      
## [61] vctrs_0.3.8          openxlsx_4.2.4       kableExtra_1.3.4    
## [64] tools_4.1.2          beeswarm_0.4.0       behaviorchange_0.4.3
## [67] glue_1.4.2           purrr_0.3.4          fastmap_1.1.0       
## [70] yaml_2.2.1           colorspace_2.0-2     gargle_1.2.0        
## [73] rvest_1.0.2          knitr_1.36           patchwork_1.1.1     
## [76] sass_0.4.0