Created
April 15, 2026 23:40
-
-
Save acbass49/6d5ec139e45b281970b990553b1be098 to your computer and use it in GitHub Desktop.
2025 General Conference Stats Update
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| library(tidyverse) | |
| library(stringr) | |
| library(scales) | |
| library(ggtext) | |
| library(patchwork) | |
| library(showtext) | |
| font_add("Cairo_bold", "~/Library/Fonts/Cairo-Bold.ttf") | |
| font_add("Cairo", "~/Library/Fonts/Cairo-Regular.ttf") | |
| showtext::showtext_auto(enable = TRUE) | |
| df <- read.csv("./data/membership.csv") | |
| # dataset: https://docs.google.com/spreadsheets/d/1ghU8_9CcaW337iUCMoiFDvPV1SMAQCecu2ZfWrx1y9w/edit?gid=0#gid=0 | |
| data <- df[20:(nrow(df)-1), c("Year","Missionaries", "Converts", "Members", "New.Children.of.Record")] |> | |
| mutate(across(everything(), \(x) str_remove_all(x, pattern = fixed(",")))) |> | |
| mutate(across(everything(), as.numeric)) | |
| # 2024 actuals (released April 2025 General Conference) | |
| yr_2024 <- data.frame( | |
| Year = 2024, | |
| Missionaries = 74127, | |
| Converts = 308682, | |
| Members = 17509781, | |
| New.Children.of.Record = 91617 | |
| ) | |
| # 2025 actuals (released April 2026 General Conference) | |
| yr_2025 <- data.frame( | |
| Year = 2025, | |
| Missionaries = 78596, # full-time teaching missionaries | |
| Converts = 385490, | |
| Members = 17887212, | |
| New.Children.of.Record = 91835 | |
| ) | |
| data <- bind_rows(data, yr_2024, yr_2025) |> | |
| arrange(desc(Year)) | |
| # ── Chart 1: Missionaries (p1) + Convert Baptisms (p2) ────────────────────── | |
| (p1 <- data |> | |
| filter(Year >= 1977, !is.na(Missionaries)) |> | |
| ggplot(aes(x = Year, y = Missionaries)) + | |
| geom_line(linewidth = 1.5, color = "grey") + | |
| labs( | |
| title = "<span style='color:grey'>Missionaries</span> Increase", | |
| subtitle = "The missionary count has almost tripled since 1980", | |
| x = "Year", | |
| y = "Missionary Count" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.title = element_text(size = 40), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_markdown(size = 50, family = "Cairo_bold", hjust = 0.5), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| plot.subtitle = element_text(hjust = 0.5, face = "italic", size = 40, family = "Cairo"), | |
| panel.grid = element_line(color = "grey95"), | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(hjust = 1, size = 33, face = "italic") | |
| ) + | |
| scale_x_continuous(breaks = seq(1975, 2025, 5)) + | |
| scale_y_continuous( | |
| breaks = seq(0, 500000, 25000), | |
| labels = scales::comma_format(), | |
| limits = c(0, 100000) | |
| ) + | |
| geom_vline(xintercept = 2012) + | |
| geom_text(aes(x = 2008, y = 20000, label = "Age Change ->"), size = 8, family = "Cairo") + | |
| geom_vline(xintercept = 2020) + | |
| geom_text(aes(x = 2016.5, y = 20000, label = "COVID-19 ->"), size = 8, family = "Cairo") + | |
| geom_vline(xintercept = 2025, linetype = "dashed") + | |
| geom_text(aes(x = 2018, y = 95000, label = "Women's Age Change (18) ->"), size = 8, family = "Cairo") | |
| ) | |
| (p2 <- data |> | |
| filter(Year >= 1977) |> | |
| ggplot(aes(x = Year, y = Converts)) + | |
| geom_line(linewidth = 1.5, color = "#097969") + | |
| labs( | |
| title = "<span style='color:#097969'>Convert Baptisms</span> Surge in 2025", | |
| subtitle = "385,490 baptisms — a new high", | |
| x = "Year", | |
| y = "Convert Baptisms", | |
| caption = "@mormon_metrics | Source: General Conference" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.title = element_text(size = 40), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_markdown(size = 50, family = "Cairo_bold", hjust = 0.5), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| plot.subtitle = element_text(hjust = 0.5, face = "italic", size = 40, family = "Cairo"), | |
| panel.grid = element_line(color = "grey95"), | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(hjust = 1, size = 33) | |
| ) + | |
| scale_x_continuous(breaks = seq(1975, 2025, 5)) + | |
| scale_y_continuous( | |
| breaks = seq(0, 500000, 100000), | |
| labels = scales::comma_format(), | |
| limits = c(0, 400000) | |
| ) + | |
| geom_vline(xintercept = 2012) + | |
| geom_text(aes(x = 2008, y = 50000, label = "Age Change ->"), size = 8, family = "Cairo") + | |
| geom_vline(xintercept = 2020) + | |
| geom_text(aes(x = 2016.5, y = 50000, label = "COVID-19 ->"), size = 8, family = "Cairo") + | |
| geom_vline(xintercept = 2025, linetype = "dashed") + | |
| geom_text(aes(x = 2018, y = 95000, label = "Women's Age Change (18) ->"), size = 8, family = "Cairo") | |
| ) | |
| p3 <- p1 / p2 | |
| ggsave("./images/32_conference_stats_2025_1.png", p3, width = 1700, height = 2000, units = "px", dpi = 300) | |
| # ── Chart 2: Converts per missionary ──────────────────────────────────────── | |
| p4 <- data |> | |
| filter(Year >= 1977, !is.na(Missionaries)) |> | |
| mutate(converts_per_missionary = Converts / Missionaries) |> | |
| ggplot(aes(x = Year, y = converts_per_missionary)) + | |
| geom_point(size = 3, alpha = 0.4, color = "goldenrod3") + | |
| geom_smooth(se = FALSE, color = "goldenrod3", method = "lm") + | |
| labs( | |
| title = "Missionaries Today Have Half The Baptisms As The 80s", | |
| subtitle = "From ~8 converts per missionary in the 1980s; 2025 sees an uptick to ~4.9", | |
| x = "Year", | |
| y = "Converts Per Missionary", | |
| caption = "@mormon_metrics | Source: General Conference" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.title = element_text(size = 40), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_text(hjust = 0.5, size = 50, face = "bold", family = "Cairo_bold"), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| plot.subtitle = element_text(hjust = 0.5, face = "italic", size = 40, family = "Cairo"), | |
| panel.grid = element_line(color = "grey95"), | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(hjust = 1, size = 33) | |
| ) + | |
| scale_x_continuous(breaks = seq(1975, 2025, 5)) + | |
| scale_y_continuous(breaks = seq(0, 10, 2), limits = c(0, 10)) + | |
| geom_vline(xintercept = 2012) + | |
| geom_text(aes(x = 2008, y = 1, label = "Age Change ->"), size = 8, family = "Cairo") + | |
| geom_vline(xintercept = 2020) + | |
| geom_text(aes(x = 2016.5, y = 1, label = "COVID-19 ->"), size = 8, family = "Cairo") + | |
| geom_vline(xintercept = 2025, linetype = "dashed") + | |
| geom_text(aes(x = 2019, y = 8, label = "Women's Age Change (18) ->"), size = 8, family = "Cairo") | |
| ggsave("./images/32_conference_stats_2025_2.png", p4, width = 2000, height = 2000, units = "px", dpi = 300) | |
| # ── Chart 3: Total membership + YoY growth + Children of Record ───────────── | |
| p5 <- data |> | |
| filter(Year >= 1973) |> | |
| ggplot(aes(x = Year, y = Members)) + | |
| geom_line(linewidth = 1.5, color = "#FF7F0E") + | |
| geom_text( | |
| data = data |> filter(Year == 2025) |> | |
| mutate(percent_lbl = format(round(Members), big.mark = ",")), | |
| aes(x = Year, y = Members, label = percent_lbl), | |
| family = "Cairo", fontface = "bold", size = 15, | |
| nudge_x = 4.5, show.legend = FALSE, color = "#FF7F0E" | |
| ) + | |
| labs( | |
| title = "Total Church Membership Continues To Grow", | |
| y = "Total Church Membership (Official)", | |
| x = "Year" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.title = element_text(size = 40), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_text(size = 60, face = "bold", family = "Cairo_bold", hjust = 0.5), | |
| plot.subtitle = element_text(hjust = 0.5, face = "italic", size = 45, family = "Cairo"), | |
| legend.title = element_blank(), | |
| legend.background = element_blank(), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| legend.box.background = element_blank(), | |
| legend.key = element_blank(), | |
| legend.position = "top", | |
| panel.grid = element_line(color = "grey95"), | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(size = 33, face = "italic") | |
| ) + | |
| scale_x_continuous(breaks = seq(1970, 2030, 5), limits = c(1970, 2032)) + | |
| scale_y_continuous( | |
| breaks = seq(0, 20000000, 5000000), | |
| limits = c(0, 20000000), | |
| labels = scales::label_number(scale_cut = cut_short_scale()) | |
| ) | |
| p6_1 <- data |> | |
| filter(Year >= 1973) |> | |
| mutate( | |
| members_lead = lead(Members, 1), | |
| perc_change = round((Members - members_lead) / Members * 100, 2) | |
| ) |> | |
| ggplot(aes(x = Year, y = perc_change)) + | |
| geom_point(size = 3, alpha = 0.4, color = "black") + | |
| geom_smooth(se = FALSE, color = "black", method = "lm") + | |
| labs( | |
| title = "YoY Percent Change In Membership Has Dropped Over Time", | |
| subtitle = "2025 shows uptick driven by higher convert baptisms", | |
| y = "YoY Membership Growth % (Official)", | |
| x = "Year" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.title = element_text(size = 40), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_text(size = 60, face = "bold", family = "Cairo_bold", hjust = 0.5), | |
| plot.subtitle = element_text(hjust = 0.5, face = "italic", size = 45, family = "Cairo"), | |
| legend.title = element_blank(), | |
| legend.background = element_blank(), | |
| panel.grid = element_line(color = "grey95"), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| legend.box.background = element_blank(), | |
| legend.key = element_blank(), | |
| legend.position = "top", | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(size = 33) | |
| ) + | |
| scale_x_continuous(breaks = seq(1970, 2030, 5), limits = c(1970, 2030)) + | |
| scale_y_continuous(breaks = seq(1, 10, 1)) | |
| p6 <- data |> | |
| filter(Year >= 1973) |> | |
| ggplot(aes(x = Year, y = New.Children.of.Record)) + | |
| geom_line(linewidth = 1.5, color = "#1D71BA") + | |
| geom_text( | |
| data = data |> filter(Year == 2025) |> | |
| mutate(percent_lbl = format(round(New.Children.of.Record), big.mark = ",")), | |
| aes(x = Year, y = New.Children.of.Record, label = percent_lbl), | |
| family = "Cairo", fontface = "bold", size = 15, | |
| nudge_x = 3.5, show.legend = FALSE, color = "#1D71BA" | |
| ) + | |
| labs( | |
| title = "Children of Record Births Remain Flat in 2025", | |
| caption = "@mormon_metrics | Source: General Conference", | |
| subtitle = "Children of Record Births Have Flatlined Despite 3X Increase In Membership", | |
| y = "Children of Record Births (Official)", | |
| x = "Year" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.title = element_text(size = 40), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_text(size = 60, face = "bold", family = "Cairo_bold", hjust = 0.5), | |
| plot.subtitle = element_text(hjust = 0.5, face = "italic", size = 45, family = "Cairo"), | |
| legend.title = element_blank(), | |
| legend.background = element_blank(), | |
| panel.grid = element_line(color = "grey95"), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| legend.box.background = element_blank(), | |
| legend.key = element_blank(), | |
| legend.position = "top", | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(size = 33) | |
| ) + | |
| scale_x_continuous(breaks = seq(1970, 2030, 5), limits = c(1970, 2030)) + | |
| scale_y_continuous( | |
| breaks = seq(0, 200000, 25000), | |
| limits = c(0, 200000), | |
| labels = scales::label_number(scale_cut = cut_short_scale()) | |
| ) | |
| p7 <- (p5 / p6_1 / p6) | |
| ggsave("./images/32_conference_stats_2025_3.png", p7, width = 2500, height = 3000, units = "px", dpi = 300) | |
| # ── Chart 4: Births per 1000 members ──────────────────────────────────────── | |
| p8_births <- data |> | |
| filter(Year >= 1973) |> | |
| mutate(birth_rate = New.Children.of.Record / (Members / 1000)) |> | |
| ggplot(aes(x = Year, y = birth_rate)) + | |
| geom_line(linewidth = 1.5, color = "#1D71BA") + | |
| geom_text( | |
| data = data |> filter(Year == 2025) |> | |
| mutate( | |
| birth_rate = New.Children.of.Record / (Members / 1000), | |
| percent_lbl = as.character(round(birth_rate, 2)) | |
| ), | |
| aes(x = Year, y = birth_rate, label = percent_lbl), | |
| family = "Cairo", fontface = "bold", size = 15, | |
| nudge_x = 1.5, show.legend = FALSE, color = "#1D71BA" | |
| ) + | |
| labs( | |
| title = "Births Per 1000 Members Has Dropped Over Time", | |
| caption = "@mormon_metrics | Source: General Conference", | |
| subtitle = "Births per 1000 members is only ~1/5 of what it was in 1980", | |
| y = "Births Per 1000 Members (Official)", | |
| x = "Year" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_text(size = 60, face = "bold", family = "Cairo_bold", hjust = 0.5), | |
| plot.subtitle = element_text(hjust = 0.5, face = "italic", size = 45, family = "Cairo"), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| axis.title = element_text(size = 40, face = "bold"), | |
| legend.title = element_blank(), | |
| legend.background = element_blank(), | |
| legend.box.background = element_blank(), | |
| legend.key = element_blank(), | |
| legend.position = "top", | |
| panel.grid = element_line(color = "grey95"), | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(size = 30) | |
| ) + | |
| scale_x_continuous(breaks = seq(1970, 2025, 5)) + | |
| scale_y_continuous(breaks = seq(0, 30, 5), limits = c(0, 30)) | |
| ggsave("./images/32_conference_stats_2025_4.png", p8_births, width = 2500, height = 2000, units = "px", dpi = 300) | |
| # ── Chart 5: Exits per 1000 members ───────────────────────────────────────── | |
| p8_exits <- data |> | |
| filter(Year >= 2000) |> | |
| mutate( | |
| lead_members = lead(Members, 1), | |
| lost = (Converts + New.Children.of.Record) - (Members - lead_members), | |
| lost_rate = lost / (Members / 1000) | |
| ) |> | |
| ggplot(aes(x = Year, y = lost_rate)) + | |
| geom_point(size = 3, alpha = 0.4, color = "#D62728") + | |
| geom_smooth(se = FALSE, color = "#D62728", method = "lm") + | |
| labs( | |
| title = "Exits Per 1000 Members Has Increased Since 2000", | |
| caption = "@mormon_metrics | Source: General Conference", | |
| subtitle = "Exits per 1000 members Has Doubled Since 2000", | |
| y = "Exits Per 1000 Members (Official)", | |
| x = "Year" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_text(size = 60, face = "bold", family = "Cairo_bold", hjust = 0.5), | |
| plot.subtitle = element_text(hjust = 0.5, face = "italic", size = 45, family = "Cairo"), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| axis.title = element_text(size = 40, face = "bold"), | |
| legend.title = element_blank(), | |
| legend.background = element_blank(), | |
| legend.box.background = element_blank(), | |
| legend.key = element_blank(), | |
| legend.position = "top", | |
| panel.grid = element_line(color = "grey95"), | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(size = 30) | |
| ) + | |
| scale_x_continuous(breaks = seq(2000, 2025, 5)) + | |
| scale_y_continuous(breaks = seq(0, 14, 2), limits = c(0, 15)) | |
| ggsave("./images/32_conference_stats_2025_5.png", p8_exits, width = 2000, height = 2000, units = "px", dpi = 300) | |
| # ── Chart 6: Proportion of growth from births vs converts ─────────────────── | |
| prop_data <- data |> | |
| filter(Year >= 1977) |> | |
| mutate( | |
| total_joiners = Converts + New.Children.of.Record, | |
| prop_converts = Converts / total_joiners, | |
| prop_births = New.Children.of.Record / total_joiners | |
| ) | |
| p_prop <- prop_data |> | |
| select(Year, prop_converts, prop_births) |> | |
| pivot_longer(cols = c(prop_converts, prop_births), names_to = "type", values_to = "prop") |> | |
| mutate(type = factor(type, | |
| levels = c("prop_births", "prop_converts"), | |
| labels = c("Children of Record", "Convert Baptisms") | |
| )) |> | |
| ggplot(aes(x = Year, y = prop, fill = type)) + | |
| geom_col(width = 0.8) + | |
| geom_segment( | |
| data = prop_data, | |
| aes(x = Year - 0.4, xend = Year + 0.4, y = 1-prop_births, yend = 1-prop_births), | |
| inherit.aes = FALSE, | |
| linewidth = 2.2, color = "black" | |
| ) + | |
| scale_fill_manual(values = c("Children of Record" = "#1D71BA", "Convert Baptisms" = "#097969")) + | |
| scale_y_continuous(labels = scales::percent_format(accuracy = 1)) + | |
| scale_x_continuous(breaks = seq(1975, 2025, 5)) + | |
| labs( | |
| title = "Church Growth Is Increasingly Convert-Driven", | |
| subtitle = "<span style='color:#097969; font-weight:bold'>Convert Baptisms</span> vs <span style='color:#1D71BA; font-weight:bold'>Children of Record</span> as share of new joiners", | |
| caption = "@mormon_metrics | Source: General Conference", | |
| x = "Year", | |
| y = "Share of New Joiners" | |
| ) + | |
| theme( | |
| axis.ticks = element_blank(), | |
| axis.title = element_text(size = 40), | |
| axis.text = element_text(size = 30), | |
| panel.background = element_blank(), | |
| text = element_text(face = "bold", family = "Cairo"), | |
| plot.title = element_text(hjust = 0.5, size = 60, face = "bold", family = "Cairo_bold"), | |
| plot.background = element_rect(fill = "grey95", color = NA), | |
| plot.subtitle = element_markdown(hjust = 0.5, face = "italic", size = 45, family = "Cairo_bold"), | |
| panel.grid = element_blank(), | |
| panel.grid.major.y = element_line(color = "lightgrey", linetype = "solid"), | |
| plot.caption = element_text(hjust = 1, size = 30), | |
| legend.position = "none" | |
| ) | |
| ggsave("./images/32_conference_stats_2025_6.png", p_prop, width = 2000, height = 2000, units = "px", dpi = 300) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment