GHSD MSD Summary Tables
The MSD Summary Tables are an SI product created on a quarterly basis using the latest OU_IM or PSNU_IM MER Structured dataset (MSD). Two tables are produced, one which summarizes the current achievement for a set of core (main) indicators, and another which summarizes TX_MMD, VLS, and VLC (treatment).
Starting in FY21 Q2, the SI team migrated the production of the
tables from Tableau to R to reduce the manual burden of creating and
copy and pasting the tables into over 50 briefers. The SI team created a
package to automate the data munging required for the tables. The
selfdestructin5
package is the result of these efforts.
Below we review the process for creating the main and treatment tables.
# Load libraries needed for table creation (glitr, glamr and gophr are OHA-SI packages not on CRAN)
library(gagglr)
library(tidyverse)
library(gt)
library(selfdestructin5)
Load helper functions/paths from other SI packages.
# Set up paths
mdb_out <- "../../Sandbox/" #Alter this path to where you'd like saved tables to go
merdata <- si_path("path_msd")
msd_path <- return_latest(folderpath = merdata, pattern = "OU_IM")
load_secrets()
# Load OU_IM table - using FY23 Q3 data from Panorama
ou_im <- read_psd(msd_path)
# With the new updates, you only need to set the meta data one time using the set_metadata() function
# This new approach stores the metadata in a package environment
set_metadata(gophr::get_metadata(msd_path))
With our data loaded and time objects created, we are ready to munge the data. Let’s start with the main table.
# Main Table
# Create the long mdb_df of the main summary indicators
# This will remove mechs with known issues by default. If you want to keep all mechs set `resolve_issues == FALSE`
summary_df <- make_mdb_df(ou_im)
# Create the reshaped df that is gt() ready
summary_tbl <- reshape_mdb_df(summary_df)
# the `agg_type` column flags the operatingunit as either OU, Region-Country or Agency
summary_tbl %>% distinct(agg_type, operatingunit) %>% slice(1:15)
The mdb_tbl
data frame is a wide-shaped data frame that
contains embedded svg icons from the fontawesome
package.
We can pass this to the create_mdb
function to make a table
for a desired operating unit.
# Generate base table for global results
create_mdb(summary_tbl, ou = "Global", type = "main")
# Try a specific country now
create_mdb(summary_tbl, ou = "Zambia", type = "main")
# Or a regional program
create_mdb(summary_tbl, ou = "Asia Region-Indonesia", type = "main")
The steps are similar for creating the treatment table.
# Create the treatment data frame needed for derived indicators
summary_df_tx <- make_mdb_tx_df(ou_im, resolve_issues = F)
summary_tbl_tx <- reshape_mdb_tx_df(summary_df_tx)
create_mdb(summary_tbl_tx, ou = "Global", type = "treatment")
Batching Tables
The reshape functions for the main and treatment indicators return a
single data frame of all operating units in PEPFAR, including a Global
and region-country level. Using the agg_type
column, we can
define a list of operating units over which we can batch create
tables.
# First, define a function to return the distinct levels in each aggregation type
# create batch tables
distinct_agg_type <- function(df, type = "OU"){
df %>%
filter(agg_type == {{type}}) %>%
distinct(operatingunit) %>%
pull()
}
# Write the different types to character objects
ous <- distinct_agg_type(summary_tbl, "OU")
glb <- distinct_agg_type(summary_tbl, "Agency")
rgl <- distinct_agg_type(summary_tbl, "Region-Country")
# Use purr to map across the list and create tables for all entries in each object
purrr::map(ous[2:3], ~create_mdb(summary_tbl, ou = .x, type = "main") %>%
gtsave(., path = mdb_out, filename = glue::glue("{.x}_{pkg_env$meta$curr_pd}_mdb_main.png")))
# TREATMENT
ous_tx <- distinct_agg_type(summary_tbl_tx, "OU")
map(ous[10:12], ~create_mdb(summary_tbl_tx, ou = .x, type = "treatment") %>%
gtsave(., path = mdb_out, filename = glue::glue("{.x}_{pkg_env$meta$curr_pd}_mdb_treatment.png")))
Creating bespoke tables
If there is a core indicator on which you’d like to focus across a
list of operating units, it is possible to use the main or treatment
data frames to create a custom table of OUs by indicator. For example,
say we would like to compare Zambia, Malawi, Mozambique, Tanzania, and
Zimbabwes’s HTS_TST_POS performance. We can filter the
mdb_tbl
data frame by a given indicator.
# Filter existing wide data frame to desired indicator and OUs
mdb_tbl_hts_tst <- summary_tbl %>%
filter(indicator == "TX_CURR", agency == "USAID") %>%
filter(operatingunit %in% c("Malawi", "Zambia", "Tanzania", "Mozambique", "Zimbabwe"))
# Pass resulting data frame to the mdb_main_theme() with a bit of rearranging to get a desired sort order.
mdb_tbl_hts_tst %>%
mutate(operatingunit = fct_reorder(operatingunit, present_targets_achievement, .desc = T)) %>%
arrange(agency, operatingunit) %>%
gt(groupname_col = "agency") %>%
mdb_main_theme() %>%
cols_unhide("operatingunit") %>%
cols_align(
align = "left",
columns = operatingunit
) %>%
cols_hide(indicator2) %>%
tab_header(
title = glue::glue("HTS_TST Comparison Across OUs")
)
You can also create a comparison table of OU achievement by core indicators. With a couple reshapes and filters, you can generate summary table organized in descending order by TX_CURR.
summary_tbl %>%
filter(agency == "USAID", agg_type == "OU") %>%
select(operatingunit, present_targets_achievement, indicator) %>%
pivot_wider(names_from = indicator,
values_from = present_targets_achievement,
names_sort = TRUE) %>%
arrange(desc(TX_CURR)) %>%
gt() %>%
sub_missing(columns = -c("operatingunit"), missing_text = "-") %>%
fmt_percent(columns = -c("operatingunit"), decimals = 0) %>%
cols_label(operatingunit = "") %>%
tab_options(
source_notes.font.size = 8,
table.font.size = 13,
data_row.padding = gt::px(5)
) %>%
tab_header(title = glue::glue("USAID OU PERFORMANCE SUMMARY FOR {pkg_env$meta$curr_pd}"))
If you wish the create tables by implementing partner, you could do something as below.
# Create a custom function to pull IP tables
# Filter the MSD to the partner of focus before passing the data to the reshape_msd_df()
mk_ptr_tbl <- function(df, mech_id) {
ip_mdb <-
df %>%
filter(mech_code == mech_id) %>%
make_mdb_df() %>%
reshape_mdb_df(.)
mech_name <-
df %>%
filter(mech_code == mech_id) %>%
distinct(mech_name) %>%
pull(mech_name)
ip_mdb %>%
create_mdb(ou = "Minoria", type = "main") %>%
tab_header(
title = glue::glue("{mech_name} PERFORMANCE SUMMARY")
) %>%
gtsave(path = "Images", filename = glue::glue("{mech_name}_mdb_main.png"))
}
# Loop over function and create tables for each of the main C&T mechs
mech_list <- c(123456, 789101, 654321)
map(mech_list, ~mk_ptr_tbl(ou_im, .x))