1 Overview & Methodology

  • Study of third party forced-choice judgments of donors motivated by a justice or generosity virtue
  • Data collected March 14th, 2023
  • N = 100

2 Key Findings

  • Participants think justice-motivated donors are less moral, but more motivated by norm signaling desires

3 Setup

Libraries and functions

knitr::opts_chunk$set(warning = FALSE, message = FALSE) 

Mypackages <-
  c("lme4","tidyverse","effects","ggplot2","psych",
    "MASS","Rmisc","lmerTest","ggthemes", "knitr",
    "lsmeans","pastecs","sjstats","car","ordinal",
    "Rcpp","corrplot", "ggpubr", "EnvStats",
    "easyStats", "cowplot","see","datawizard", "ggcorrplot", "RColorBrewer")

# install.packages(Mypackages) #you must remove the # in this comment if you need to install the packages! 
lapply(Mypackages,
       require,
       character.only = TRUE)

options(knitr.kable.NA = '—')
set.seed(1)  

3.1 Load Data

# read in data files
setwd("~/Desktop")
gjg <-read.csv("/Users/mtrenfield17/Desktop/Research/Boston College Research/Morality Lab Research/Generosity Vs Justice Project/gen_vs_just_pilot2.csv")

3.2 Reshaping data

# changing appropriate DVs to factor
# gjg <- gjg %>% mutate_at(vars(genuine:norm_signal, gender, race, education, political_overall), as.factor)

# changing appropriate DVs to numeric
gjg <- gjg %>% mutate_at(vars(age, income, ses, political_social, political_economic), as.numeric)

## renaming donors to their virtues
gjg <- gjg %>% 
  mutate_at(vars(genuine:norm_signal), ~ ifelse(. == "Jon", "Justice", 
                                 ifelse(. == "Will", "Generosity", "XX")))

4 Demographics

# Subset your data frame to include only the demographic columns
numeric_demos <- gjg[,c("age", "income", "ses", "political_social", "political_economic")]
categorical_demos <- gjg[, c("gender", "race", "education", "political_overall")]

# descsriptive stats for numeric demos
describeBy(numeric_demos)
##                    vars   n  mean    sd median trimmed   mad min max range
## age                   1 100 35.34 11.90     32   33.94 10.38  18  66    48
## income                2 100  5.45  2.34      6    5.56  2.97   1   9     8
## ses                   3 100  4.82  1.63      5    4.79  1.48   2   9     7
## political_social      4 100  2.80  1.63      2    2.60  1.48   1   7     6
## political_economic    5 100  3.23  1.66      3    3.14  1.48   1   7     6
##                     skew kurtosis   se
## age                 0.91    -0.09 1.19
## income             -0.41    -0.91 0.23
## ses                 0.15    -0.72 0.16
## political_social    0.72    -0.35 0.16
## political_economic  0.41    -0.85 0.17
## frequency for categorical demos 
freq_tables <- list()

for (col in names(categorical_demos)) {
  if (is.character(categorical_demos[[col]])) {
    freq_table <- as.data.frame(table(categorical_demos[[col]], useNA = "ifany"))
    freq_table$Percent <- round(freq_table$Freq / sum(freq_table$Freq) * 100, 2)
    freq_table <- freq_table[complete.cases(freq_table), ]
    freq_tables[[col]] <- freq_table
  }
}

# Print the frequency tables
for (i in seq_along(freq_tables)) {
  if (!is.null(freq_tables[[i]])) {
    cat("\nTable of frequencies for", names(freq_tables)[i], ":\n")
    print(freq_tables[[i]])
  }
}
## 
## Table of frequencies for gender :
##                        Var1 Freq Percent
## 1                       Man   48      48
## 2 Nonbinary person or Other    1       1
## 3                     Woman   51      51
## 
## Table of frequencies for race :
##                                            Var1 Freq Percent
## 1                                         Asian    8       8
## 2                                   Asian,White    2       2
## 3                     Black or African American    6       6
## 4 Black or African American,Hispanic/Latino/a/x    1       1
## 5               Black or African American,White    1       1
## 6   Indigenous American or Alaskan Native,White    1       1
## 7                                         White   75      75
## 8                     White,Hispanic/Latino/a/x    6       6
## 
## Table of frequencies for education :
##                                                                                Var1
## 1                                                                                  
## 2                                                    Associate Degree (e.g. AA, AS)
## 3                                                   Bachelor's Degree (e.g. BA, BS)
## 4                                       High school degree or equivalent (e.g. GED)
## 5                                                   Less than a high school diploma
## 6 Postgraduate Degree (e.g. Master's Degree, Professional Degree, Doctorate Degree)
## 7                                                           Some college, no degree
##   Freq Percent
## 1    1       1
## 2   10      10
## 3   35      35
## 4    8       8
## 5    1       1
## 6   13      13
## 7   32      32
## 
## Table of frequencies for political_overall :
##             Var1 Freq Percent
## 1       Democrat   52      52
## 2    Independent   35      35
## 3     Republican   11      11
## 4 Something else    2       2
# Create composite political measures
gjg$polit_comp <- if_else(gjg$political_overall == "Democrat", "Democrat",
                          if_else(gjg$political_overall == "Republican"
                                  | gjg$political_overall == "Independent"
                                  | gjg$political_overall == "Something else", "Not Democrat", "NA"))

5 Relationship between DVs

cont_table <- table(genuine = gjg$genuine, approval = gjg$approval, norm_signal = gjg$norm_signal,
                    dnn = c("Genuine", "Approval", "Norm Signal"), 
                    useNA = "ifany")
prop_table <- prop.table(cont_table)
prop_table
## , , Norm Signal = Generosity
## 
##             Approval
## Genuine      Generosity Justice
##   Generosity       0.06    0.02
##   Justice          0.02    0.13
## 
## , , Norm Signal = Justice
## 
##             Approval
## Genuine      Generosity Justice
##   Generosity       0.50    0.06
##   Justice          0.02    0.19

6 Frequency Plots + Chi-squared Tests

ggplot(data = gjg, aes(x = genuine)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Genuine Frequency Plot")+
      theme(plot.title = element_text(hjust = 0.5))

genuine_chi <- table(gjg$genuine)
chisq.test(genuine_chi)
## 
##  Chi-squared test for given probabilities
## 
## data:  genuine_chi
## X-squared = 7.84, df = 1, p-value = 0.00511
ggplot(data = gjg, aes(x = approval)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Approval Frequency Plot")+
      theme(plot.title = element_text(hjust = 0.5))

approval_chi <- table(gjg$approval)
chisq.test(approval_chi)
## 
##  Chi-squared test for given probabilities
## 
## data:  approval_chi
## X-squared = 4, df = 1, p-value = 0.0455
ggplot(data = gjg, aes(x = norm_signal)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Norm Signaling Frequency Plot")+
    theme(plot.title = element_text(hjust = 0.5))

norm_chi <- table(gjg$norm_signal)
chisq.test(norm_chi)
## 
##  Chi-squared test for given probabilities
## 
## data:  norm_chi
## X-squared = 29.16, df = 1, p-value = 6.664e-08

7 Frequency Plots by political affiliation

# genuine

genuine_plot_overall <- ggplot(data = gjg, aes(x = genuine)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC", "#7CCCB0"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Genuine Frequency by Political Orientation") +
  facet_wrap(~ political_overall) + 
  theme(plot.title = element_text(hjust = 0.5))
genuine_plot_overall

genuine_plot_consolidated <- ggplot(data = gjg, aes(x = genuine)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Genuine Frequency by Political Orientation") +
  facet_wrap(~ polit_comp) +
  theme(plot.title = element_text(hjust = 0.5))
genuine_plot_consolidated

genuine_polit_chi <- table(gjg$genuine, gjg$political_overall)
chisq.test(genuine_polit_chi)
## 
##  Pearson's Chi-squared test
## 
## data:  genuine_polit_chi
## X-squared = 3.5834, df = 3, p-value = 0.3101
genuine_polit_comp_chi <- table(gjg$genuine, gjg$polit_comp)
chisq.test(genuine_polit_comp_chi)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  genuine_polit_comp_chi
## X-squared = 1.3439, df = 1, p-value = 0.2463
# approval

approval_plot_overall <- ggplot(data = gjg, aes(x = approval)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC", "#7CCCB0"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Approval Frequency by Political Orientation") +
  facet_wrap(~ political_overall) +
    theme(plot.title = element_text(hjust = 0.5))
approval_plot_overall

approval_plot_consolidated <- ggplot(data = gjg, aes(x = approval)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Approval Frequency by Political Orientation") +
  facet_wrap(~ polit_comp) +
    theme(plot.title = element_text(hjust = 0.5))
approval_plot_consolidated

approval_polit_chi <- table(gjg$approval, gjg$political_overall)
chisq.test(approval_polit_chi)
## 
##  Pearson's Chi-squared test
## 
## data:  approval_polit_chi
## X-squared = 5.0477, df = 3, p-value = 0.1683
approval_polit_comp_chi <- table(gjg$approval, gjg$polit_comp)
chisq.test(approval_polit_comp_chi)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  approval_polit_comp_chi
## X-squared = 2.2853, df = 1, p-value = 0.1306
# norm signaling

norm_plot_overall <- ggplot(data = gjg, aes(x = norm_signal)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC", "#D193DC"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Norm Signaling Frequency by Political Orientation") +
  facet_wrap(~ political_overall) +
    theme(plot.title = element_text(hjust = 0.5))
norm_plot_overall

norm_plot_consolidated <- ggplot(data = gjg, aes(x = norm_signal)) +
  geom_bar(fill = c("#7CCCB0", "#D193DC", "#7CCCB0", "#D193DC"), color = "black") +
  labs(x = "Variable", y = "Frequency", title = "Norm Signaling Frequency by Political Orientation") +
  facet_wrap(~ polit_comp) +
    theme(plot.title = element_text(hjust = 0.5))
norm_plot_consolidated

norm_polit_chi <- table(gjg$norm_signal, gjg$political_overall)
chisq.test(norm_polit_chi)
## 
##  Pearson's Chi-squared test
## 
## data:  norm_polit_chi
## X-squared = 0.85945, df = 3, p-value = 0.8352
norm_polit_comp_chi <- table(gjg$norm_signal, gjg$polit_comp)
chisq.test(norm_polit_comp_chi)
## 
##  Pearson's Chi-squared test with Yates' continuity correction
## 
## data:  norm_polit_comp_chi
## X-squared = 0.065967, df = 1, p-value = 0.7973
gjg$approval
##   [1] "Generosity" "Justice"    "Generosity" "Generosity" "Justice"   
##   [6] "Generosity" "Generosity" "Generosity" "Justice"    "Generosity"
##  [11] "Generosity" "Generosity" "Generosity" "Justice"    "Generosity"
##  [16] "Generosity" "Generosity" "Justice"    "Generosity" "Justice"   
##  [21] "Generosity" "Justice"    "Justice"    "Justice"    "Generosity"
##  [26] "Generosity" "Justice"    "Generosity" "Generosity" "Generosity"
##  [31] "Generosity" "Generosity" "Generosity" "Generosity" "Generosity"
##  [36] "Justice"    "Justice"    "Generosity" "Generosity" "Generosity"
##  [41] "Generosity" "Justice"    "Justice"    "Generosity" "Generosity"
##  [46] "Justice"    "Justice"    "Generosity" "Generosity" "Justice"   
##  [51] "Generosity" "Justice"    "Justice"    "Justice"    "Generosity"
##  [56] "Generosity" "Generosity" "Generosity" "Justice"    "Generosity"
##  [61] "Generosity" "Justice"    "Justice"    "Generosity" "Justice"   
##  [66] "Generosity" "Generosity" "Justice"    "Generosity" "Generosity"
##  [71] "Generosity" "Generosity" "Justice"    "Justice"    "Justice"   
##  [76] "Generosity" "Generosity" "Justice"    "Generosity" "Justice"   
##  [81] "Justice"    "Generosity" "Justice"    "Generosity" "Generosity"
##  [86] "Justice"    "Justice"    "Generosity" "Justice"    "Justice"   
##  [91] "Generosity" "Generosity" "Generosity" "Justice"    "Justice"   
##  [96] "Justice"    "Generosity" "Generosity" "Generosity" "Justice"
gjg <- gjg %>% mutate(approval_dif = ifelse(approval == "Justice", -1, 1))

gjg$political_social
##   [1] 4 2 6 2 5 3 2 1 4 2 7 4 4 1 6 1 4 1 5 1 6 4 1 2 1 6 6 4 4 3 2 4 3 3 1 3 1
##  [38] 3 1 1 3 3 1 2 5 2 1 3 1 2 2 4 2 1 2 1 3 1 4 6 4 2 2 2 1 2 2 3 1 2 4 2 6 1
##  [75] 2 1 3 4 4 2 3 3 2 7 4 2 2 4 1 6 4 1 1 2 1 4 2 1 3 4
gjg$political_economic
##   [1] 4 2 6 6 3 3 4 1 4 5 7 4 4 1 6 1 4 1 5 1 6 4 2 4 1 6 6 4 4 3 2 4 6 4 1 3 2
##  [38] 4 2 1 5 5 1 2 3 3 1 3 2 4 3 6 2 1 3 4 3 2 5 6 4 2 2 6 1 2 1 2 2 6 4 3 6 2
##  [75] 2 3 3 4 4 2 3 2 2 7 2 2 2 4 2 5 4 1 3 2 1 2 5 1 3 4
gjg$approval_dif
##   [1]  1 -1  1  1 -1  1  1  1 -1  1  1  1  1 -1  1  1  1 -1  1 -1  1 -1 -1 -1  1
##  [26]  1 -1  1  1  1  1  1  1  1  1 -1 -1  1  1  1  1 -1 -1  1  1 -1 -1  1  1 -1
##  [51]  1 -1 -1 -1  1  1  1  1 -1  1  1 -1 -1  1 -1  1  1 -1  1  1  1  1 -1 -1 -1
##  [76]  1  1 -1  1 -1 -1  1 -1  1  1 -1 -1  1 -1 -1  1  1  1 -1 -1 -1  1  1  1 -1
grouped_data <- gjg %>% 
  dplyr::group_by(political_social) %>% 
  dplyr::summarize(sum_approval_dif = sum(approval_dif))
grouped_data$sum_approval_dif
## [1] 2 0 7 6 1 2 2
# Create a bar plot of the summed approval_dif for each group
ggplot(grouped_data, aes(x = political_social, y = sum_approval_dif)) +
 geom_line() +
  labs(x = "Political and social scores", y = "Sum of approval difference")

grouped_data <- gjg %>% 
  dplyr::group_by(political_economic) %>% 
  dplyr::summarize(sum_approval_dif = sum(approval_dif))
grouped_data$sum_approval_dif
## [1]  0 -7  8 10  1  6  2
# Create a bar plot of the summed approval_dif for each group
ggplot(grouped_data, aes(x = political_economic, y = sum_approval_dif)) +
 geom_line() +
  labs(x = "Political and social scores", y = "Sum of approval difference")

# stacked plots

## genuine
genuine_plot_overall <- ggplot(data = gjg, aes(x = genuine, group = political_overall, fill = political_overall)) +
  geom_bar(position = "fill") +
  labs(x = "Variable", y = "Proportion", title = "Genuine Proportion by Political Orientation") +
    scale_fill_brewer(palette = "Set2") +
      theme(plot.title = element_text(hjust = 0.5), legend.title = element_blank())
genuine_plot_overall

genuine_plot_consolidated <- ggplot(data = gjg, aes(x = polit_comp, group = genuine, fill = genuine)) +
  geom_bar(position = "fill") +
  labs(x = "Variable", y = "Proportion", title = "Genuine Proportion by Political Orientation") +
      scale_fill_brewer(palette = "Set2") +
      theme(plot.title = element_text(hjust = 0.5), legend.title = element_blank())
genuine_plot_consolidated

# approval

approval_plot_overall <- ggplot(data = gjg, aes(x = approval, group = political_overall, fill = political_overall)) +
  geom_bar(position = "fill") +
  labs(x = "Variable", y = "Proportion", title = "Approval Proportion by Political Orientation") +
      scale_fill_brewer(palette = "Set2") +
      theme(plot.title = element_text(hjust = 0.5), legend.title = element_blank())
approval_plot_overall

approval_plot_consolidated <- ggplot(data = gjg, aes(x = approval, group = polit_comp, fill = polit_comp)) +
  geom_bar(position = "fill") +
  labs(x = "Variable", y = "Proportion", title = "Approval Proportion by Political Orientation") +
        scale_fill_brewer(palette = "Set2") +
      theme(plot.title = element_text(hjust = 0.5), legend.title = element_blank())
approval_plot_consolidated

# norm signaling

norm_plot_overall <- ggplot(data = gjg, aes(x = norm_signal, group = political_overall, fill = political_overall)) +
  geom_bar(position = "fill") +
  labs(x = "Variable", y = "Propotion", title = "Norm Signaling Proportion by Political Orientation") +
      scale_fill_brewer(palette = "Set2") +
      theme(plot.title = element_text(hjust = 0.5), legend.title = element_blank())
norm_plot_overall

norm_plot_consolidated <- ggplot(data = gjg, aes(x = norm_signal, group = polit_comp, fill = polit_comp)) +
  geom_bar(position = "fill") +
  labs(x = "Variable", y = "Proportion", title = "Norm Signaling Proportion by Political Orientation") +
      scale_fill_brewer(palette = "Set2") +
      theme(plot.title = element_text(hjust = 0.5), legend.title = element_blank())
norm_plot_consolidated