Welcome to the Library Event Attendance and Performance Analysis! This report was designed to provide a clear, data-driven look into our library’s adult event programming. The goal is to help us better understand what makes an event successful, so we can make more informed decisions about future programming.
We began by taking our raw event data and cleaning it up. To focus on the adult audience, we filtered out all events intended for children or youth, as well as any events that were cancelled, had zero attendees, or lacked a valid date or registration count. We also removed any events that started before 9 a.m. This process left us with a clean dataset of our true adult programs.
The core of our analysis is a series of visual heatmaps that show us when people are most likely to register for events. By looking at a simple grid of days and times, we can immediately spot patterns and trends. We created a large, overall heatmap to see a general picture of attendance across all adult programs.
To dig deeper, we also generated subject-specific and room-specific heatmaps. This allows us to answer questions like, “Do our technology workshops perform better on a certain day of the week?” or “Is a room more popular in the morning or evening?” We then supported these visuals with summary tables that highlight the top-performing subjects and rooms based on the number of events and total registrations, giving us a quick reference for our most successful programs and locations.
This analysis provides a new way to look at our event data, offering clear insights into when and where our adult programs are most successful. By leveraging this information, we can strategically plan our future events to better meet the needs of our community and maximize attendance.
Show code
# Load required librarieslibrary(tidyverse)library(janitor)library(lubridate)library(kableExtra)library(viridis)# Load and prepare the dataevent_data <-read_csv("event_data_with_analysis.csv", col_types =cols(), na =c("", "NA", "N/A")) %>%clean_names() %>%mutate(# Parse event dates and timesevent_start_time =ymd_hms(event_start_time),event_date =as.Date(event_start_time),event_year =year(event_date),event_month =month(event_date),event_day_of_week =wday(event_date, label =TRUE),event_hour_decimal =hour(event_start_time) +minute(event_start_time) /60,# Filter out children/youth events and cancelled eventsis_valid_event =!str_detect(tolower(event_title %||%""), "child|kid|family|youth") &!str_detect(tolower(event_subjects %||%""), "child|kid|family|youth") &!str_detect(tolower(event_title %||%""), "cancel") &!is.na(event_date) &!is.na(actual_registrations) & actual_registrations >0&hour(event_start_time) >=9# Remove pre-opening events ) %>%filter(is_valid_event)
Overall Event Registration Heatmap
Show code
# Create overall heatmapoverall_heatmap_data <- event_data %>%group_by(event_day_of_week, event_hour_decimal =floor(event_hour_decimal)) %>%summarise(avg_registrations =mean(actual_registrations, na.rm =TRUE),event_count =n(),.groups ="drop" )ggplot(overall_heatmap_data, aes(x = event_day_of_week, y = event_hour_decimal, fill = avg_registrations)) +geom_tile(color ="white") +scale_fill_viridis_c(name ="Avg Registrations", option ="plasma") +labs(title ="Overall Registration Patterns by Day and Time",x ="Day of Week", y ="Hour of Day") +theme_minimal() +theme(axis.text.x =element_text(angle =45, hjust =1))
Subject-Specific Heatmaps
Show code
# Function to create heatmap for a specific subjectcreate_subject_heatmap <-function(subject) {# Prepare data for the specific subject subject_heatmap_data <- event_data %>%filter(event_subjects == subject) %>%group_by(event_day_of_week, event_hour_decimal =floor(event_hour_decimal)) %>%summarise(avg_registrations =mean(actual_registrations, na.rm =TRUE),event_count =n(),.groups ="drop" )# Create the heatmap p <-ggplot(subject_heatmap_data, aes(x = event_day_of_week, y = event_hour_decimal, fill = avg_registrations)) +geom_tile(color ="white") +scale_fill_viridis_c(name ="Avg Registrations", option ="plasma") +labs(title =paste("Registration Patterns for", subject),x ="Day of Week", y ="Hour of Day") +theme_minimal() +theme(axis.text.x =element_text(angle =45, hjust =1))# Print the plot with a headercat("\n\n###", subject, "Events\n\n")print(p)}# Generate heatmaps for each unique subject# Limit to top 10 subjects to prevent overwhelming outputtop_subjects <- event_data %>%group_by(event_subjects) %>%summarise(total_events =n(),total_registrations =sum(actual_registrations, na.rm =TRUE) ) %>%slice_max(total_events, n =10) %>%pull(event_subjects)# Create heatmaps for top subjectslapply(top_subjects, create_subject_heatmap)
# Function to create heatmap for a specific roomcreate_room_heatmap <-function(room) {# Prepare data for the specific room room_heatmap_data <- event_data %>%filter(event_room_name == room) %>%group_by(event_day_of_week, event_hour_decimal =floor(event_hour_decimal)) %>%summarise(avg_registrations =mean(actual_registrations, na.rm =TRUE),event_count =n(),.groups ="drop" )# Create the heatmap p <-ggplot(room_heatmap_data, aes(x = event_day_of_week, y = event_hour_decimal, fill = avg_registrations)) +geom_tile(color ="white") +scale_fill_viridis_c(name ="Avg Registrations", option ="plasma") +labs(title =paste("Registration Patterns for", room),x ="Day of Week", y ="Hour of Day") +theme_minimal() +theme(axis.text.x =element_text(angle =45, hjust =1))# Print the plot with a headercat("\n\n###", room, "Room\n\n")print(p)}# Generate heatmaps for top roomstop_rooms <- event_data %>%group_by(event_room_name) %>%summarise(total_events =n(),total_registrations =sum(actual_registrations, na.rm =TRUE) ) %>%slice_max(total_events, n =10) %>%pull(event_room_name)# Create heatmaps for top roomslapply(top_rooms, create_room_heatmap)