# Campaign Finance Visualization Script
# This script creates downloadable high-quality plots for campaign finance data

# Load necessary packages
if (!require("ggplot2")) install.packages("ggplot2")
## Loading required package: ggplot2
if (!require("dplyr")) install.packages("dplyr")
## Loading required package: dplyr
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
if (!require("viridis")) install.packages("viridis")
## Loading required package: viridis
## Loading required package: viridisLite
if (!require("scales")) install.packages("scales")
## Loading required package: scales
## 
## Attaching package: 'scales'
## The following object is masked from 'package:viridis':
## 
##     viridis_pal
if (!require("gridExtra")) install.packages("gridExtra")
## Loading required package: gridExtra
## 
## Attaching package: 'gridExtra'
## The following object is masked from 'package:dplyr':
## 
##     combine
library(ggplot2)     # For creating plots
library(dplyr)       # For data manipulation
library(viridis)     # For better color palettes
library(scales)      # For scale formatting
library(gridExtra)   # For arranging multiple plots

# Function to create and check directory with error handling
create_dir_safely <- function(dir_name) {
  tryCatch({
    # Check if directory exists, if not try to create it
    if (!dir.exists(dir_name)) {
      dir.create(dir_name, showWarnings = TRUE, recursive = TRUE)
      cat(paste("Created directory:", dir_name, "\n"))
    } else {
      cat(paste("Directory already exists:", dir_name, "\n"))
    }
    
    # Test write permissions
    test_file <- file.path(dir_name, "test_write.txt")
    writeLines("test", test_file)
    unlink(test_file)
    cat("Directory is writable.\n")
    return(TRUE)
  }, error = function(e) {
    cat(paste("ERROR: Cannot write to directory", dir_name, "\n"))
    cat(paste("Error message:", e$message, "\n"))
    cat("Using current working directory instead.\n")
    return(FALSE)
  })
}

# Try to create plots directory, fall back to current directory if needed
plot_dir <- "campaign_finance_plots"
if (!create_dir_safely(plot_dir)) {
  plot_dir <- getwd()
  cat(paste("Using current working directory for outputs:", plot_dir, "\n"))
}
## Directory already exists: campaign_finance_plots 
## Directory is writable.
# Function for safely saving plots with error handling
safe_save <- function(filename, plot, width, height, dpi = 300) {
  full_path <- file.path(plot_dir, filename)
  tryCatch({
    ggsave(full_path, plot, width = width, height = height, dpi = dpi)
    cat(paste("Successfully saved:", full_path, "\n"))
  }, error = function(e) {
    cat(paste("WARNING: Failed to save", full_path, "\n"))
    cat(paste("Error message:", e$message, "\n"))
  })
}

# Set global theme for all plots
custom_theme <- theme_minimal(base_size = 14) +
  theme(
    plot.title = element_text(face = "bold", size = 16, hjust = 0.5),
    plot.subtitle = element_text(size = 13, color = "gray30", hjust = 0.5),
    axis.title = element_text(face = "bold", size = 14),
    axis.text = element_text(size = 12),
    legend.title = element_text(face = "bold", size = 13),
    legend.text = element_text(size = 12),
    panel.grid.major = element_line(color = "gray90"),
    panel.grid.minor = element_line(color = "gray95"),
    plot.background = element_rect(fill = "white", color = NA),
    legend.background = element_rect(fill = "white", color = NA),
    plot.margin = margin(20, 20, 20, 20)
  )

theme_set(custom_theme)

# Create or load sample data
# For demonstration, we'll create simulated data
set.seed(123)
n <- 500
campaign_data <- data.frame(
  receipts = rlnorm(n, meanlog = 10, sdlog = 1),
  individual_contributions = rlnorm(n, meanlog = 9.5, sdlog = 1.2),
  disbursements = rlnorm(n, meanlog = 9.8, sdlog = 0.9),
  party = factor(sample(c("Democrat", "Republican"), n, replace = TRUE)),
  incumbency = factor(sample(c("Incumbent", "Challenger", "Open Seat"), n, replace = TRUE))
)

# Log transform variables for better visualization
campaign_data$log_receipts <- log(campaign_data$receipts + 1)  # Add 1 to handle zeros
campaign_data$log_individual_contributions <- log(campaign_data$individual_contributions + 1)
campaign_data$log_disbursements <- log(campaign_data$disbursements + 1)

# Calculate summary statistics
finance_summary <- campaign_data %>%
  group_by(party, incumbency) %>%
  summarize(
    mean_receipts = mean(receipts, na.rm = TRUE),
    median_receipts = median(receipts, na.rm = TRUE),
    mean_individual_contributions = mean(individual_contributions, na.rm = TRUE),
    median_individual_contributions = median(individual_contributions, na.rm = TRUE),
    mean_disbursements = mean(disbursements, na.rm = TRUE),
    median_disbursements = median(disbursements, na.rm = TRUE),
    count = n()
  )
## `summarise()` has grouped output by 'party'. You can override using the
## `.groups` argument.
# Define consistent colors for parties
party_colors <- c("Democrat" = "#3366FF", "Republican" = "#FF3333")
# 1. Boxplot of receipts by party and incumbency
plot_receipts_boxplot <- function() {
  p <- ggplot(campaign_data, aes(x = incumbency, y = receipts, fill = party)) +
    geom_boxplot(alpha = 0.8, outlier.shape = 21, outlier.size = 3) +
    scale_fill_manual(values = party_colors) +
    scale_y_continuous(labels = dollar_format(scale = 1e-3, suffix = "K")) +
    labs(title = "Campaign Receipts by Party and Incumbency Status",
         subtitle = "Dollar amounts in thousands",
         x = "Incumbency Status", 
         y = "Total Receipts ($)",
         fill = "Party") +
    theme(axis.text.x = element_text(angle = 0, hjust = 0.5))
  
  # Save the plot
  safe_save("receipts_boxplot.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}

# 2. Boxplot of log receipts 
plot_log_receipts_boxplot <- function() {
  p <- ggplot(campaign_data, aes(x = incumbency, y = log_receipts, fill = party)) +
    geom_boxplot(alpha = 0.8, outlier.shape = 21, outlier.size = 3) +
    scale_fill_manual(values = party_colors) +
    labs(title = "Log-Transformed Campaign Receipts",
         subtitle = "Natural logarithm of receipts",
         x = "Incumbency Status", 
         y = "Log(Total Receipts)",
         fill = "Party") +
    theme(axis.text.x = element_text(angle = 0, hjust = 0.5))
  
  # Save the plot
  safe_save("log_receipts_boxplot.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}

# 3. Boxplot of individual contributions
plot_contributions_boxplot <- function() {
  p <- ggplot(campaign_data, aes(x = incumbency, y = individual_contributions, fill = party)) +
    geom_boxplot(alpha = 0.8, outlier.shape = 21, outlier.size = 3) +
    scale_fill_manual(values = party_colors) +
    scale_y_continuous(labels = dollar_format(scale = 1e-3, suffix = "K")) +
    labs(title = "Individual Contributions by Party and Incumbency Status",
         subtitle = "Dollar amounts in thousands",
         x = "Incumbency Status", 
         y = "Individual Contributions ($)",
         fill = "Party") +
    theme(axis.text.x = element_text(angle = 0, hjust = 0.5))
  
  # Save the plot
  safe_save("contributions_boxplot.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}

# 4. Boxplot of disbursements
plot_disbursements_boxplot <- function() {
  p <- ggplot(campaign_data, aes(x = incumbency, y = disbursements, fill = party)) +
    geom_boxplot(alpha = 0.8, outlier.shape = 21, outlier.size = 3) +
    scale_fill_manual(values = party_colors) +
    scale_y_continuous(labels = dollar_format(scale = 1e-3, suffix = "K")) +
    labs(title = "Campaign Disbursements by Party and Incumbency Status",
         subtitle = "Dollar amounts in thousands",
         x = "Incumbency Status", 
         y = "Total Disbursements ($)",
         fill = "Party") +
    theme(axis.text.x = element_text(angle = 0, hjust = 0.5))
  
  # Save the plot
  safe_save("disbursements_boxplot.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}
# 1. Bar chart of mean receipts
plot_mean_receipts_bar <- function() {
  p <- ggplot(finance_summary, aes(x = incumbency, y = mean_receipts, fill = party)) +
    geom_col(position = "dodge", alpha = 0.9) +
    geom_text(aes(label = paste0("$", round(mean_receipts/1000, 1), "K")),
              position = position_dodge(width = 0.9),
              vjust = -0.5, size = 4) +
    scale_fill_manual(values = party_colors) +
    scale_y_continuous(labels = dollar_format(scale = 1e-3, suffix = "K")) +
    labs(title = "Mean Campaign Receipts by Party and Incumbency Status",
         subtitle = "Dollar amounts in thousands",
         x = "Incumbency Status", 
         y = "Mean Total Receipts ($)",
         fill = "Party") +
    theme(axis.text.x = element_text(angle = 0, hjust = 0.5))
  
  # Save the plot
  safe_save("mean_receipts_bar.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}

# 2. Bar chart of mean individual contributions
plot_mean_contributions_bar <- function() {
  p <- ggplot(finance_summary, aes(x = incumbency, y = mean_individual_contributions, fill = party)) +
    geom_col(position = "dodge", alpha = 0.9) +
    geom_text(aes(label = paste0("$", round(mean_individual_contributions/1000, 1), "K")),
              position = position_dodge(width = 0.9),
              vjust = -0.5, size = 4) +
    scale_fill_manual(values = party_colors) +
    scale_y_continuous(labels = dollar_format(scale = 1e-3, suffix = "K")) +
    labs(title = "Mean Individual Contributions by Party and Incumbency Status",
         subtitle = "Dollar amounts in thousands",
         x = "Incumbency Status", 
         y = "Mean Individual Contributions ($)",
         fill = "Party") +
    theme(axis.text.x = element_text(angle = 0, hjust = 0.5))
  
  # Save the plot
  safe_save("mean_contributions_bar.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}

# 3. Bar chart of mean disbursements
plot_mean_disbursements_bar <- function() {
  p <- ggplot(finance_summary, aes(x = incumbency, y = mean_disbursements, fill = party)) +
    geom_col(position = "dodge", alpha = 0.9) +
    geom_text(aes(label = paste0("$", round(mean_disbursements/1000, 1), "K")),
              position = position_dodge(width = 0.9),
              vjust = -0.5, size = 4) +
    scale_fill_manual(values = party_colors) +
    scale_y_continuous(labels = dollar_format(scale = 1e-3, suffix = "K")) +
    labs(title = "Mean Campaign Disbursements by Party and Incumbency Status",
         subtitle = "Dollar amounts in thousands",
         x = "Incumbency Status", 
         y = "Mean Total Disbursements ($)",
         fill = "Party") +
    theme(axis.text.x = element_text(angle = 0, hjust = 0.5))
  
  # Save the plot
  safe_save("mean_disbursements_bar.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}
# 1. Density plot of log receipts by party
plot_log_receipts_density <- function() {
  p <- ggplot(campaign_data, aes(x = log_receipts, fill = party)) +
    geom_density(alpha = 0.6, adjust = 1.5) +
    scale_fill_manual(values = party_colors) +
    labs(title = "Distribution of Log Receipts by Party",
         subtitle = "Natural logarithm of campaign receipts",
         x = "Log(Total Receipts)", 
         y = "Density",
         fill = "Party") +
    theme(legend.position = "top")
  
  # Save the plot
  safe_save("log_receipts_density.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}

# 2. Density plot of log individual contributions by party
plot_log_contributions_density <- function() {
  p <- ggplot(campaign_data, aes(x = log_individual_contributions, fill = party)) +
    geom_density(alpha = 0.6, adjust = 1.5) +
    scale_fill_manual(values = party_colors) +
    labs(title = "Distribution of Log Individual Contributions by Party",
         subtitle = "Natural logarithm of individual contributions",
         x = "Log(Individual Contributions)", 
         y = "Density",
         fill = "Party") +
    theme(legend.position = "top")
  
  # Save the plot
  safe_save("log_contributions_density.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}

# 3. Density plot of log disbursements by party
plot_log_disbursements_density <- function() {
  p <- ggplot(campaign_data, aes(x = log_disbursements, fill = party)) +
    geom_density(alpha = 0.6, adjust = 1.5) +
    scale_fill_manual(values = party_colors) +
    labs(title = "Distribution of Log Disbursements by Party",
         subtitle = "Natural logarithm of campaign disbursements",
         x = "Log(Total Disbursements)", 
         y = "Density",
         fill = "Party") +
    theme(legend.position = "top")
  
  # Save the plot
  safe_save("log_disbursements_density.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}

# 4. Faceted density plots by incumbency status
plot_faceted_density <- function() {
  p <- ggplot(campaign_data, aes(x = log_receipts, fill = party)) +
    geom_density(alpha = 0.6, adjust = 1.5) +
    facet_wrap(~ incumbency, ncol = 1) +
    scale_fill_manual(values = party_colors) +
    labs(title = "Distribution of Log Receipts by Party and Incumbency Status",
         subtitle = "Natural logarithm of campaign receipts",
         x = "Log(Total Receipts)", 
         y = "Density",
         fill = "Party") +
    theme(legend.position = "top")
  
  # Save the plot
  safe_save("faceted_density.png", p, width = 10, height = 12, dpi = 300)
  
  return(p)
}
# Add a scatter plot comparing receipts vs disbursements
plot_receipts_vs_disbursements <- function() {
  p <- ggplot(campaign_data, aes(x = log_receipts, y = log_disbursements, color = party, shape = incumbency)) +
    geom_point(alpha = 0.7, size = 3) +
    geom_smooth(aes(group = party), method = "lm", se = TRUE, alpha = 0.2) +
    scale_color_manual(values = party_colors) +
    labs(title = "Campaign Receipts vs. Disbursements",
         subtitle = "Log-transformed values",
         x = "Log(Total Receipts)", 
         y = "Log(Total Disbursements)",
         color = "Party",
         shape = "Incumbency Status") +
    theme(legend.position = "right")
  
  # Save the plot
  safe_save("receipts_vs_disbursements.png", p, width = 10, height = 7, dpi = 300)
  
  return(p)
}
# Function to create and save a comprehensive PDF report with error handling
create_pdf_report <- function() {
  pdf_file <- file.path(plot_dir, "campaign_finance_report.pdf")
  
  tryCatch({
    pdf(pdf_file, width = 11, height = 8.5)
    
    # Title page
    plot.new()
    title <- "Campaign Finance Analysis by Party and Incumbency Status"
    subtitle <- paste("Generated:", format(Sys.time(), "%B %d, %Y"))
    text(0.5, 0.6, title, cex = 2, font = 2)
    text(0.5, 0.5, subtitle, cex = 1.2)
    
    # Print boxplots - storing and then printing plots to avoid potential issues
    p1 <- plot_receipts_boxplot()
    p2 <- plot_log_receipts_boxplot()
    grid.arrange(p1, p2, ncol = 1, top = "Boxplots of Campaign Receipts")
    
    p3 <- plot_contributions_boxplot()
    p4 <- plot_disbursements_boxplot()
    grid.arrange(p3, p4, ncol = 1, top = "Boxplots of Contributions and Disbursements")
    
    # Print bar charts
    p5 <- plot_mean_receipts_bar()
    p6 <- plot_mean_contributions_bar()
    p7 <- plot_mean_disbursements_bar()
    grid.arrange(p5, p6, p7, ncol = 1, top = "Mean Campaign Finance Values by Category")
    
    # Print density plots
    p8 <- plot_log_receipts_density()
    p9 <- plot_log_contributions_density()
    p10 <- plot_log_disbursements_density()
    grid.arrange(p8, p9, p10, ncol = 1, top = "Distributions of Campaign Finance Variables")
    
    p11 <- plot_faceted_density()
    p12 <- plot_receipts_vs_disbursements()
    print(p11)
    print(p12)
    
    dev.off()
    cat(paste("Comprehensive report saved to", pdf_file, "\n"))
  }, error = function(e) {
    # If PDF creation fails, make sure the device is closed
    if (dev.cur() > 1) dev.off()
    cat(paste("WARNING: Failed to create PDF report:", e$message, "\n"))
    cat("Individual PNG files should still be available.\n")
  })
}
# Function to save all plots individually as PNG only
save_all_plots_individually <- function() {
  cat("\nGenerating and saving all plots as PNG files...\n")
  
  # Generate all plots and save them
  plot_receipts_boxplot()
  plot_log_receipts_boxplot()
  plot_contributions_boxplot()
  plot_disbursements_boxplot()
  plot_mean_receipts_bar()
  plot_mean_contributions_bar()
  plot_mean_disbursements_bar()
  plot_log_receipts_density()
  plot_log_contributions_density()
  plot_log_disbursements_density()
  plot_faceted_density()
  plot_receipts_vs_disbursements()
  
  cat("\nAll plots have been generated and saved as PNG files.\n")
}
# Display system information
cat("System information:\n")
## System information:
cat(paste("R version:", R.version.string, "\n"))
## R version: R version 4.4.3 (2025-02-28 ucrt)
cat(paste("Operating system:", Sys.info()["sysname"], Sys.info()["release"], "\n"))
## Operating system: Windows 10 x64
cat(paste("Working directory:", getwd(), "\n\n"))
## Working directory: C:/Users/lemmi/Downloads
# Save individual plots as PNG files
save_all_plots_individually()
## 
## Generating and saving all plots as PNG files...
## Successfully saved: campaign_finance_plots/receipts_boxplot.png
## Successfully saved: campaign_finance_plots/log_receipts_boxplot.png
## Successfully saved: campaign_finance_plots/contributions_boxplot.png
## Successfully saved: campaign_finance_plots/disbursements_boxplot.png
## Successfully saved: campaign_finance_plots/mean_receipts_bar.png
## Successfully saved: campaign_finance_plots/mean_contributions_bar.png
## Successfully saved: campaign_finance_plots/mean_disbursements_bar.png
## Successfully saved: campaign_finance_plots/log_receipts_density.png
## Successfully saved: campaign_finance_plots/log_contributions_density.png
## Successfully saved: campaign_finance_plots/log_disbursements_density.png
## Successfully saved: campaign_finance_plots/faceted_density.png
## `geom_smooth()` using formula = 'y ~ x'
## Warning: The following aesthetics were dropped during statistical transformation: shape.
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
##   the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
##   variable into a factor?
## Successfully saved: campaign_finance_plots/receipts_vs_disbursements.png 
## 
## All plots have been generated and saved as PNG files.
# Try to create the combined PDF report
cat("\nAttempting to create comprehensive PDF report...\n")
## 
## Attempting to create comprehensive PDF report...
create_pdf_report()
## Successfully saved: campaign_finance_plots/receipts_boxplot.png
## Successfully saved: campaign_finance_plots/log_receipts_boxplot.png
## Successfully saved: campaign_finance_plots/contributions_boxplot.png
## Successfully saved: campaign_finance_plots/disbursements_boxplot.png
## Successfully saved: campaign_finance_plots/mean_receipts_bar.png
## Successfully saved: campaign_finance_plots/mean_contributions_bar.png
## Successfully saved: campaign_finance_plots/mean_disbursements_bar.png
## Successfully saved: campaign_finance_plots/log_receipts_density.png
## Successfully saved: campaign_finance_plots/log_contributions_density.png
## Successfully saved: campaign_finance_plots/log_disbursements_density.png
## Successfully saved: campaign_finance_plots/faceted_density.png
## `geom_smooth()` using formula = 'y ~ x'
## Warning: The following aesthetics were dropped during statistical transformation: shape.
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
##   the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
##   variable into a factor?
## Successfully saved: campaign_finance_plots/receipts_vs_disbursements.png
## `geom_smooth()` using formula = 'y ~ x'
## Warning: The following aesthetics were dropped during statistical transformation: shape.
## ℹ This can happen when ggplot fails to infer the correct grouping structure in
##   the data.
## ℹ Did you forget to specify a `group` aesthetic or to convert a numerical
##   variable into a factor?
## Comprehensive report saved to campaign_finance_plots/campaign_finance_report.pdf
cat("\nScript execution completed.\n")
## 
## Script execution completed.