# Load packages
suppressPackageStartupMessages({
 library(tidyverse)
 library(haven)
 library(knitr)
 library(kableExtra)
})

# Load data
file_path <- "C:/Users/JH/Kitces.com/DV - Research/Anonymized Data and Codebooks - All Projects/AdvisorTech Studies/2025/tech 25.dta"
df <- haven::read_dta(file_path)

# Prepare clean data
df_clean <- df %>%
 filter(!is.na(fpprsuse)) %>%
 mutate(
 # Current use
 curr_emoney  = (fpprssw1 == 9 | fpprssw2 == 9),
 curr_moneyguide  = (fpprssw1 == 15 | fpprssw2 == 15),
 curr_rightcapital = (fpprssw1 == 23 | fpprssw2 == 23),
# Future 
 future = case_when(
 fpfutsw == 9 ~ "eMoney",
 fpfutsw == 15 ~ "MoneyGuide",
 fpfutsw == 23 ~ "RightCapital",
 TRUE ~ "Other/missing"
 ),
 
 # Convert fpprsuse to numeric
 fpprsuse_num = as.numeric(fpprsuse)
 )
total_sample <- nrow(df_clean) 

# Summary table 
summary_table <- tibble(
 Category = c(
"Total respondents who answered the financial planning software question",
 "Respondants who do not use any financial planning software",
 "Respondants who use at least one financial planning software",
 "Total users of eMoney",
 "Total users of MoneyGuidePro",
 "Total users of RightCapital"
 ),
 
 Count = c(
 total_sample,
 sum(df_clean$fpprsuse_num == 0, na.rm = TRUE),
 sum(df_clean$fpprsuse_num == 1, na.rm = TRUE), 
 sum(df_clean$curr_emoney, na.rm = TRUE),
 sum(df_clean$curr_moneyguide, na.rm = TRUE),
 sum(df_clean$curr_rightcapital, na.rm = TRUE)
 )
) %>%
 mutate(
 Percent = round(Count / total_sample * 100, 1),
 Percent = paste0(Percent, "%")
 )

# Display table
kable(summary_table,
 caption = "Financial Planning Software Usage Overview",
 col.names = c("Category", "Count", "Percent of Respondents"),
 align = c("l", "r", "r"),
 digits = 1) %>%
 kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
 full_width = FALSE,
 position = "left") %>%
 row_spec(0, bold = TRUE, background = "#f0f8ff")
Financial Planning Software Usage Overview
Category Count Percent of Respondents
Total respondents who answered the financial planning software question 699 100%
Respondants who do not use any financial planning software 35 5%
Respondants who use at least one financial planning software 664 95%
Total users of eMoney 214 30.6%
Total users of MoneyGuidePro 133 19%
Total users of RightCapital 178 25.5%
# Commentary
knitr::asis_output(
 "The majority of the 699 advisors who answered the financial planning software use question report using at least one tool. eMoney remains the most widely adopted platform (30.6% use it primary or secondary), followed by RightCapital (25.5%) and MoneyGuidePro (19.0%)."
)

The majority of the 699 advisors who answered the financial planning software use question report using at least one tool. eMoney remains the most widely adopted platform (30.6% use it primary or secondary), followed by RightCapital (25.5%) and MoneyGuidePro (19.0%).

# Table 2 Switching from current to future
matrix_data <- tibble(
 From = c("eMoney", "MoneyGuide", "RightCapital"),
 `To eMoney` = c(
 mean(df_clean$curr_emoney & df_clean$future == "eMoney", na.rm = TRUE) * 100,
 mean(df_clean$curr_moneyguide & df_clean$future == "eMoney", na.rm = TRUE) * 100,
 mean(df_clean$curr_rightcapital & df_clean$future == "eMoney", na.rm = TRUE) * 100
 ),
 `To MoneyGuide` = c(
 mean(df_clean$curr_emoney & df_clean$future == "MoneyGuide", na.rm = TRUE) * 100,
 mean(df_clean$curr_moneyguide & df_clean$future == "MoneyGuide", na.rm = TRUE) * 100,
 mean(df_clean$curr_rightcapital & df_clean$future == "MoneyGuide", na.rm = TRUE) * 100
 ),
 `To RightCapital` = c(
 mean(df_clean$curr_emoney & df_clean$future == "RightCapital", na.rm = TRUE) * 100,
 mean(df_clean$curr_moneyguide & df_clean$future == "RightCapital", na.rm = TRUE) * 100,
 mean(df_clean$curr_rightcapital & df_clean$future == "RightCapital", na.rm = TRUE) * 100
 )
) %>%
 mutate(across(where(is.numeric), ~ round(., 1)))

# Create display version
matrix_display <- tibble(
 From = matrix_data$From,
 
 `To eMoney` = c(
 sum(df_clean$curr_emoney & df_clean$future == "eMoney", na.rm = TRUE),
 sum(df_clean$curr_moneyguide & df_clean$future == "eMoney", na.rm = TRUE),
 sum(df_clean$curr_rightcapital & df_clean$future == "eMoney", na.rm = TRUE)
 ),
 `To MoneyGuide` = c(
 sum(df_clean$curr_emoney & df_clean$future == "MoneyGuide", na.rm = TRUE),
 sum(df_clean$curr_moneyguide & df_clean$future == "MoneyGuide", na.rm = TRUE),
 sum(df_clean$curr_rightcapital & df_clean$future == "MoneyGuide", na.rm = TRUE)
 ),
 `To RightCapital` = c(
 sum(df_clean$curr_emoney & df_clean$future == "RightCapital", na.rm = TRUE),
 sum(df_clean$curr_moneyguide & df_clean$future == "RightCapital", na.rm = TRUE),
 sum(df_clean$curr_rightcapital & df_clean$future == "RightCapital", na.rm = TRUE)
 )
) %>%
 mutate(
 `To eMoney` = paste0(round(matrix_data$`To eMoney`, 1), "% (", `To eMoney`, ")"),
 `To MoneyGuide` = paste0(round(matrix_data$`To MoneyGuide`, 1), "% (", `To MoneyGuide`, ")"),
 `To RightCapital` = paste0(round(matrix_data$`To RightCapital`, 1), "% (", `To RightCapital`, ")")
 )
kable(matrix_display,
 caption = "Planned Switches to Future Financial Planning Software (Next 12 Months)",
 align = c("l", "c", "c", "c")) %>%
 kable_styling(bootstrap_options = c("striped", "hover", "condensed", "responsive"),
 full_width = FALSE,
 position = "left") %>%
 row_spec(0, bold = TRUE, background = "#f0f8ff") %>%
footnote(general = paste( "Percentages and counts are based on all advisors who answered the financial planning software use question (N =", total_sample, "). ", "Table shows planned switches among the three main platforms only; a small proportion plan to switch to other software or have no reported future sofatware use." ), general_title = "Note: ")
Planned Switches to Future Financial Planning Software (Next 12 Months)
From To eMoney To MoneyGuide To RightCapital
eMoney 28.9% (202) 0.7% (4) 0.7% (4)
MoneyGuide 0.6% (3) 17.8% (124) 0.6% (3)
RightCapital 0.4% (2) 0.2% (1) 24.3% (168)
Note:
Percentages and counts are based on all advisors who answered the financial planning software use question (N = 699 ). Table shows planned switches among the three main platforms only; a small proportion plan to switch to other software or have no reported future sofatware use.
knitr::asis_output("Among all advisors, the large majority who currently use eMoney plan to retain it as their primary software in the next 12 months. the case for MoneyGuidePro and RightCapital is similar. Planned switches away from current tools appear limited overall, suggesting relatively stable preferences across the three platforms..")

Among all advisors, the large majority who currently use eMoney plan to retain it as their primary software in the next 12 months. the case for MoneyGuidePro and RightCapital is similar. Planned switches away from current tools appear limited overall, suggesting relatively stable preferences across the three platforms..

# Generating plots
matrix_long <- matrix_data %>%  
pivot_longer(
cols = starts_with("To "),
names_to = "To",
values_to = "Percentage"
) %>%
mutate(
To = str_remove(To, "To "),
From = factor(From, levels = c("eMoney", "MoneyGuide", "RightCapital")),
To  = factor(To,   levels = c("eMoney", "MoneyGuide", "RightCapital"))
)
# Heatmap
ggplot(matrix_long, aes(x = To, y = From, fill = Percentage)) +
geom_tile(color = "grey80", linewidth = 0.4) +
geom_text(aes(label = paste0(Percentage, "%")), 
color = "black", size = 2.2, fontface = "bold") +
scale_fill_gradient(low = "#f0f8ff", high = "#00bfff",
limits = c(0, 30),
breaks = seq(0, 30, by = 10)) +
labs(
title = "Planned Switches to Future Financial Planning Software (Next 12 Months)",
x = "Planned Future Financial Planning Software",
y = "Current Financial Planning Software",
fill = "%"
) +
theme_minimal(base_size = 10) +
theme(
plot.title = element_text(face = "bold", size = 10, hjust = 0.5),
plot.subtitle = element_text(size = 10, hjust = 0.5, color = "grey50"),
axis.title = element_text(size = 10, face = "bold"),
axis.text = element_text(size = 9),
legend.text = element_text(size = 9),
legend.title = element_text(size = 9),
panel.grid = element_line(color = "grey92", linewidth = 0.3),
plot.margin = margin(t = 10, r = 20, b = 10, l = 10)
)

knitr::asis_output("The heatmap illustrates high retention rates for the three platforms among their respective current users, with limited cross-provider switching intent in the next 12 months.")

The heatmap illustrates high retention rates for the three platforms among their respective current users, with limited cross-provider switching intent in the next 12 months.

# Bar chart
ggplot(matrix_long, aes(x = To, y = Percentage, fill = From)) +
geom_col(position = position_dodge(width = 0.9), width = 0.8) +
geom_text(aes(label = paste0(Percentage, "%")),
position = position_dodge(0.9),
vjust = -0.4, size = 2.8, fontface = "bold") +
scale_fill_brewer(palette = "Set2", name = "") +
labs(
title = "Planned Switches to Future Financial Planning Software (Next 12 Months)",
x = "Future Financial Planning Software",
y = "Percentage of all advisors (%)"
) +
theme_minimal(base_size = 10) +
theme(
plot.title = element_text(face = "bold", hjust = 0.5),
plot.subtitle = element_text(hjust = 0.5, color = "grey50"),
legend.position = "bottom",
axis.text.x = element_text(angle = 0, vjust = 0.5)
)

knitr::asis_output("The bar graph illustrates high retention rates for the three platforms among their respective current users, with limited cross-provider switching intent in the next 12 months.")

The bar graph illustrates high retention rates for the three platforms among their respective current users, with limited cross-provider switching intent in the next 12 months.