How to load your dataset

If you would like to clean your dataset by yourselves, please refer to the data cleaning file. If you would like to start with the simplified dataset, you may use the code below.

# Load your dataset
df_us <- read.csv("us_core.csv")
#df_global <- read.csv("global_core.csv")

Replication of Figure 1: Regular and Undemocratic Behavior Bias

# Estimate the regression
ols_us <- lm_robust(dem ~ treatment + left_right + treatment:left_right, clusters=id, data = df_us)
tidy(ols_us)

Predict the dependent variable based on the regression

  • First, create a dataset with all unique combinations of the two explanatory variables
df_pred <- df_us %>% 
  data_grid(treatment, left_right)

df_pred
  • Second, predict the dependent variable based on the regression into this dataset
df_fit <- predict(ols_us, newdata = df_pred, interval = "confidence")
df_fit <- data.frame(df_fit)
colnames(df_fit) <- c("dem_pred", "conf.low", "conf.high")
  

df_pred <- bind_cols(df_pred, df_fit)
df_pred

Plot it

  • Split the data based on whether the treatment was democratic or undemocratic
# Subset data for plotting
df_plot_dem <- df_pred %>% 
  filter(treatment %in% c("Regular Right Wing", "Regular Left Wing"))

df_plot_undem <- df_pred %>% 
  filter(treatment %in% c("Undemocratic Right Wing", "Undemocratic Left Wing"))
  • A simple plot of “regular behavior”
df_plot_dem %>%
  ggplot(aes(x = left_right, y = dem_pred, color = treatment)) +
              geom_line(aes(color = treatment)) +
              scale_color_manual(values = c("Regular Left Wing" = "blue",
                                            "Regular Right Wing" = "red")) +
              geom_point(aes(color = treatment), size = 2)

  • A simple plot of “undemocratic behavior”
df_plot_undem %>%
  ggplot(aes(x = left_right, y = dem_pred, color = treatment)) +
              geom_line(aes(color = treatment)) +
              scale_color_manual(values = c("Undemocratic Left Wing" = "blue",
                                            "Undemocratic Right Wing" = "red")) +
              geom_point(aes(color = treatment), size = 2)

Make the plots look similar to the paper

  1. Regular behavior
df_plot_dem %>%
  ggplot(aes(x = left_right, y = dem_pred, color = treatment)) +
  geom_line(aes(color = treatment)) +
  geom_point(aes(color = treatment), size = 2) + 
  geom_errorbar(aes(ymin=conf.low, ymax=conf.high, col=treatment), width=0.1) +
  scale_color_manual(values = c("Regular Left Wing" = "blue", "Regular Right Wing" = "red")) +            
  scale_x_continuous(name = "Left-right", limits=c(0, 12), breaks=seq(0, 12, 2)) +                        
  scale_y_continuous(name = "Perception", limits=c(1, 5), breaks=seq(1, 5, 1)) +
  theme_bw() + 
  theme(legend.position = c(0.05, 0.9),
    legend.justification = c(0, 1),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 0),
    legend.key.size = unit(8, "mm"),
    legend.background = element_blank())
## Warning: A numeric `legend.position` argument in `theme()` was deprecated in ggplot2
## 3.5.0.
## ℹ Please use the `legend.position.inside` argument of `theme()` instead.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.

  1. Undemocratic behavior
df_plot_undem %>%
  ggplot(aes(x = left_right, y = dem_pred, color = treatment)) +
  geom_line(aes(color = treatment)) +
  geom_point(aes(color = treatment), size = 2) + 
  geom_errorbar(aes(ymin=conf.low, ymax=conf.high, col=treatment), width=0.1) +
  scale_color_manual(values = c("Undemocratic Left Wing" = "blue", "Undemocratic Right Wing" = "red")) +            
  scale_x_continuous(name = "Left-right", limits=c(0, 12), breaks=seq(0, 12, 2)) +                        
  scale_y_continuous(name = "Perception", limits=c(1, 5), breaks=seq(1, 5, 1)) +
  theme_bw() + 
  theme(legend.position = c(0.05, 0.9),
    legend.justification = c(0, 1),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 0),
    legend.key.size = unit(8, "mm"),
    legend.background = element_blank())

Suggestion I: Code that does not rely on the assumption that the relationship between X and Y is linear

df_means <- df_us %>% 
  group_by(left_right, treatment) %>%
  do(lm_robust(dem ~ 1, data = ., clusters=id) %>% tidy)

df_means
  1. Regular behavior
df_plot_dem <- df_means %>%
   filter(treatment %in% c("Regular Right Wing", "Regular Left Wing"))
  
df_plot_dem %>%
  ggplot(aes(x = left_right, y = estimate, color = treatment)) +
  geom_line(aes(color = treatment), linetype="dashed") +
  geom_point(aes(color = treatment), size = 2) + 
  geom_errorbar(aes(ymin=conf.low, ymax=conf.high, col=treatment), width=0.1) +
  scale_color_manual(values = c("Regular Left Wing" = "blue", "Regular Right Wing" = "red")) +            
  scale_x_continuous(name = "Left-right", limits=c(0, 12), breaks=seq(0, 12, 2)) +                        
  scale_y_continuous(name = "Perception", limits=c(1, 5), breaks=seq(1, 5, 1)) +
  theme_bw() + 
  theme(legend.position = c(0.05, 0.9),
    legend.justification = c(0, 1),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 0),
    legend.key.size = unit(8, "mm"),
    legend.background = element_blank())

  1. Undemocratic behavior
df_plot_undem <- df_means %>%
  filter(treatment %in% c("Undemocratic Right Wing", "Undemocratic Left Wing"))
  
df_plot_undem %>%
  ggplot(aes(x = left_right, y = estimate, color = treatment)) +
  geom_line(aes(color = treatment), linetype="dashed") +
  geom_point(aes(color = treatment), size = 2) + 
  geom_errorbar(aes(ymin=conf.low, ymax=conf.high, col=treatment), width=0.1) +
  scale_color_manual(values = c("Undemocratic Left Wing" = "blue", "Undemocratic Right Wing" = "red")) +            
  scale_x_continuous(name = "Left-right", limits=c(0, 12), breaks=seq(0, 12, 2)) +                        
  scale_y_continuous(name = "Perception", limits=c(1, 5), breaks=seq(1, 5, 1)) +
  theme_bw() + 
  theme(legend.position = c(0.05, 0.9),
    legend.justification = c(0, 1),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 0),
    legend.key.size = unit(8, "mm"),
    legend.background = element_blank())

Suggestion II: Evens simpler code that does not rely on the assumption that the relationship between X and Y is linear

df_means <- df_us %>% 
  group_by(left_right, treatment) %>%
  summarize(
    mean = mean(dem, na.rm=TRUE)
  )
## `summarise()` has grouped output by 'left_right'. You can override using the
## `.groups` argument.
df_means
  1. Regular behavior
df_plot_dem <- df_means %>%
   filter(treatment %in% c("Regular Right Wing", "Regular Left Wing"))
  
df_plot_dem %>%
  ggplot(aes(x = left_right, y = mean, color = treatment)) +
  geom_line(aes(color = treatment), linetype="dashed") +
  geom_point(aes(color = treatment), size = 2) + 
  scale_color_manual(values = c("Regular Left Wing" = "blue", "Regular Right Wing" = "red")) +            
  scale_x_continuous(name = "Left-right", limits=c(0, 12), breaks=seq(0, 12, 2)) +                        
  scale_y_continuous(name = "Perception", limits=c(1, 5), breaks=seq(1, 5, 1)) +
  theme_bw() + 
  theme(legend.position = c(0.05, 0.9),
    legend.justification = c(0, 1),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 0),
    legend.key.size = unit(8, "mm"),
    legend.background = element_blank())

df_diff_regular <- df_means %>%
   filter(treatment %in% c("Regular Right Wing", "Regular Left Wing"))

df_diff_regular
df_diff_regular <- df_diff_regular %>% 
  pivot_wider(names_from = treatment, values_from = mean) %>%
  mutate(
    diff = `Regular Left Wing` - `Regular Right Wing`
  )

df_diff_regular
df_diff_regular %>%
  ggplot(aes(x = left_right, y = diff)) +
  geom_hline(yintercept=0, col="grey50") +
  geom_line(linetype="dashed") +
  geom_point(size = 2) + 
  scale_x_continuous(name = "Left-right", limits=c(0, 12), breaks=seq(0, 12, 2)) +                        
  scale_y_continuous(name = "Difference in Perception", limits=c(-2, 2)) +
  theme_bw() + 
  theme(legend.position = c(0.05, 0.9),
    legend.justification = c(0, 1),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 0),
    legend.key.size = unit(8, "mm"),
    legend.background = element_blank())

  1. Undemocratic behavior
df_plot_undem <- df_means %>%
  filter(treatment %in% c("Undemocratic Right Wing", "Undemocratic Left Wing"))
  
df_plot_undem %>%
  ggplot(aes(x = left_right, y = mean, color = treatment)) +
  geom_line(aes(color = treatment), linetype="dashed") +
  geom_point(aes(color = treatment), size = 2) +
  scale_color_manual(values = c("Undemocratic Left Wing" = "blue", "Undemocratic Right Wing" = "red")) +            
  scale_x_continuous(name = "Left-right", limits=c(0, 12), breaks=seq(0, 12, 2)) +                        
  scale_y_continuous(name = "Perception", limits=c(1, 5), breaks=seq(1, 5, 1)) +
  theme_bw() + 
  theme(legend.position = c(0.05, 0.9),
    legend.justification = c(0, 1),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 0),
    legend.key.size = unit(8, "mm"),
    legend.background = element_blank())

df_diff_undem <- df_means %>%
  filter(treatment %in% c("Undemocratic Right Wing", "Undemocratic Left Wing"))

df_diff_undem
df_diff_undem <- df_diff_undem %>% 
  pivot_wider(names_from = treatment, values_from = mean) %>%
  mutate(
    diff = `Undemocratic Left Wing` - `Undemocratic Right Wing`
  )

df_diff_undem
df_diff_undem %>%
  ggplot(aes(x = left_right, y = diff)) +
  geom_hline(yintercept=0, col="grey50") +
  geom_line(linetype="dashed") +
  geom_point(size = 2) + 
  scale_x_continuous(name = "Left-right", limits=c(0, 12), breaks=seq(0, 12, 2)) +                        
  scale_y_continuous(name = "Difference in Perception", limits=c(-2, 2)) +
  theme_bw() + 
  theme(legend.position = c(0.05, 0.9),
    legend.justification = c(0, 1),
    legend.text = element_text(size = 10),
    legend.title = element_text(size = 0),
    legend.key.size = unit(8, "mm"),
    legend.background = element_blank())

# Load necessary libraries
library(modelr)
library(estimatr)
library(dplyr)
library(ggplot2)
library(broom)

# Load data (adjust path if needed)
df_us <- read.csv("us_core.csv")

# Fit linear model with interaction between treatment and age
ols_us <- lm_robust(dem ~ treatment + age + treatment:age, clusters = id, data = df_us)

# Show model summary
tidy(ols_us)
# Create prediction grid for treatment and age
df_pred <- df_us %>%
 data_grid(treatment, age)

# Predict fitted values and confidence intervals
df_fit <- predict(ols_us, newdata = df_pred, interval = "confidence")
df_fit <- data.frame(df_fit)
colnames(df_fit) <- c("dem_pred", "conf.low", "conf.high")

# Merge predictions with original grid
df_pred <- bind_cols(df_pred, df_fit)

# Split into democratic behavior and undemocratic behavior groups
df_plot_dem <- df_pred %>%
 filter(treatment %in% c("Regular Right Wing", "Regular Left Wing"))

df_plot_undem <- df_pred %>%
 filter(treatment %in% c("Undemocratic Right Wing", "Undemocratic Left Wing"))

# Plot: Democratic behavior perceptions by age
ggplot(df_plot_dem, aes(x = age, y = dem_pred, color = treatment)) +
 geom_line() +
 geom_point(size = 2) +
 scale_color_manual(values = c("Regular Left Wing" = "blue",
                               "Regular Right Wing" = "red")) +
 labs(title = "Perceived Democracy of Democratic Politicians by Age",
      x = "Age", y = "Predicted Democratic Perception") +
 theme_minimal()

# Plot: Undemocratic behavior perceptions by age
ggplot(df_plot_undem, aes(x = age, y = dem_pred, color = treatment)) +
 geom_line() +
 geom_point(size = 2) +
 scale_color_manual(values = c("Undemocratic Left Wing" = "blue",
                               "Undemocratic Right Wing" = "red")) +
 labs(title = "Perceived Democracy of Undemocratic Politicians by Age",
      x = "Age", y = "Predicted Democratic Perception") +
 theme_minimal()

# Libraries (only if not already loaded)
library(dplyr)
library(ggplot2)
library(modelr)
library(estimatr)
library(broom)

# Load data (adjust path if needed)
df_us <- read.csv("us_core.csv")

# Fit model with interaction between treatment and age
ols_us <- lm_robust(dem ~ treatment + age + treatment:age, clusters = id, data = df_us)

# Prediction grid: treatment and age combinations
df_pred <- df_us %>%
 data_grid(treatment, age)

# Predict values with confidence intervals
df_fit <- predict(ols_us, newdata = df_pred, interval = "confidence")
df_fit <- data.frame(df_fit)
colnames(df_fit) <- c("dem_pred", "conf.low", "conf.high")

# Merge predictions
df_pred <- bind_cols(df_pred, df_fit)

# Split into democratic and undemocratic treatments
df_dem <- df_pred %>% filter(grepl("Regular", treatment))
df_undem <- df_pred %>% filter(grepl("Undemocratic", treatment))

# Clean treatment labels
df_dem <- df_dem %>% mutate(party = ifelse(grepl("Right", treatment), "Right Wing", "Left Wing"))
df_undem <- df_undem %>% mutate(party = ifelse(grepl("Right", treatment), "Right Wing", "Left Wing"))

# Join to compute causal effect: Dem - Undem
df_effect <- left_join(df_dem, df_undem, by = c("age", "party")) %>%
 mutate(effect = dem_pred.x - dem_pred.y)

# ===== Plot 1: Causal effect of undemocratic behavior across age (by party) =====
ggplot(df_effect, aes(x = age, y = effect, color = party)) +
 geom_line(size = 1) +
 geom_hline(yintercept = 0, linetype = "dashed", color = "gray50") +
 labs(title = "Causal Effect of Undemocratic Behavior on Democratic Perception",
      subtitle = "Difference in perception between democratic and undemocratic behavior by age",
      x = "Age",
      y = "Perceived Democracy (Democratic - Undemocratic)",
      color = "Party") +
 theme_minimal()

# ===== Plot 2: Raw perception of undemocratic politicians by age (by party) =====
ggplot(df_undem, aes(x = age, y = dem_pred, color = party)) +
 geom_line(size = 1) +
 labs(title = "Perception of Undemocratic Politicians by Age",
      subtitle = "Younger subjects are more tolerant if perception is higher at younger ages",
      x = "Age",
      y = "Predicted Democratic Perception",
      color = "Party") +
 theme_minimal()