diff --git a/.Rbuildignore b/.Rbuildignore index 446bfca..61f8e31 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -6,3 +6,4 @@ ^docs$ ^pkgdown$ ^\.github$ +^data-raw$ diff --git a/DESCRIPTION b/DESCRIPTION index 62e1156..04c3806 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -19,12 +19,15 @@ Imports: ggplot2, ggtext, glue, + grid, highcharter, lifecycle, methods, + patchwork, rlang, scales, tidyr, + tidyselect, vctrs URL: https://github.com/ASNDataAnalytics/asn, https://asndataanalytics.github.io/asn/ @@ -32,3 +35,6 @@ BugReports: https://github.com/ASNDataAnalytics/asn/issues Suggests: testthat (>= 3.0.0) Config/testthat/edition: 3 +Depends: + R (>= 4.1.0) +LazyData: true diff --git a/NAMESPACE b/NAMESPACE index bda4714..1c78aca 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -13,6 +13,7 @@ export(asn_secondary) export(asn_secondary_blue) export(asn_spring) export(asn_theme) +export(asn_tilegrid) export(check_all) export(get_labels) export(get_labs) @@ -31,10 +32,14 @@ export(theme_asn_dark) import(dplyr) import(forcats) import(ggplot2) +import(glue) +import(grid) import(highcharter) +import(patchwork) import(rlang) import(scales) import(tidyr) +import(tidyselect) importFrom(grDevices,colorRampPalette) importFrom(lifecycle,deprecated) importFrom(methods,setOldClass) diff --git a/R/asn_tilegrid.R b/R/asn_tilegrid.R new file mode 100644 index 0000000..d468e49 --- /dev/null +++ b/R/asn_tilegrid.R @@ -0,0 +1,537 @@ +#' Create a U.S. Tilegrid Choropleth Map in ggplot2 in style of The Economist +#' @import dplyr +#' @import ggplot2 +#' @import glue +#' @import patchwork +#' @import grid +#' @param data A data frame, comprising a column with 2-letter USPS state abbreviations and a column with a +#' numeric variable to be visualized in a tilegrid choropleth map. +#' @param data_source Source of the numeric data visualized in the choropleth. +#' @param plot_title Plot title. +#' @param state_column Column containing 2-letter USPS state abbreviations. +#' @param numeric_column Column containing numeric data being visualized in choropleth. +#' @param plot_panel_color Background color for plot. +#' @param palette Vector of hex colors mapping numeric column to choropleth map fill color. +#' @param breaks Numeric vector of breaks corresponding to colors in the color palette mapping to the numeric column. +#' @param zero_color Optional hex color to indicate states with a 0 numeric value. +#' @param na_color Optional hex color to indicate states with missing values. +#' +#' @returns ggplot2 object +#' +#' @export +#' @examples +#' asn_tilegrid( +#' data = neph_per_100K_df, +#' data_source = "AMA PPD and U.S. Census Bureau.", +#' plot_title = "Ratio of Nephrologists per 100K Adult Population", +#' state_column = "MailState", +#' numeric_column = neph_per_100k, +#' plot_panel_color = "#ffffff", +#' palette = c("#f0f8ff", "#a0bdd8", "#5081b2", "#00468b"), +#' breaks = c(2.21, 3.1, 4, 5.6), +#' zero_color = NULL, +#' na_color = "#EEECE6" +#' ) +asn_tilegrid <- function( + data = df, + data_source = "Source", + plot_title = "Plot Title", + state_column = "state_column_name", + numeric_column = n, + plot_panel_color = "#ffffff", + palette = c("#FCC8B4", "#FAAA90", "#F58469", "#EF1B26"), # Ascending Order + breaks = c(1, 2, 6, 11), # Ascending Order + zero_color = NULL, + na_color = NULL +) { + ## 01 Ensure Palette Length and Breaks Are Same Length ---- + + pal <- palette + + pal_length <- length(pal) + + breaks_length <- length(breaks) + + if (pal_length != breaks_length) { + stop("The palette and break lengths must be the same.") + } + + if (pal_length > 5) { + stop("The maximum number of bins and colors is 5.") + } + + ## 02 Build Tile Grid Choropleth ---- + + ## 02.01 If NA ---- + + if (is.null(zero_color) & !is.null(na_color)) { + choropleth <- + grid_df |> + dplyr::left_join( + data, + by = c("State" = {{ state_column }}) + ) |> + dplyr::mutate( + fill_color = dplyr::case_when( + is.na({{ numeric_column }}) ~ na_color, + dplyr::between({{ numeric_column }}, 0, breaks[1]) ~ pal[1], + dplyr::between({{ numeric_column }}, breaks[1], breaks[2]) ~ pal[2], + dplyr::between({{ numeric_column }}, breaks[2], breaks[3]) ~ pal[3], + dplyr::between({{ numeric_column }}, breaks[3], breaks[4]) ~ pal[4] + ) + ) |> + dplyr::mutate( + text_color = dplyr::if_else( + fill_color == pal[4], + "#ffffff", + "#000000" + ) + ) |> + ggplot2::ggplot( + ggplot2::aes( + x = x, + y = y + ) + ) + + ggplot2::geom_tile( + ggplot2::aes( + fill = fill_color + ), + color = "#000", + linewidth = 0.2 + ) + + ggplot2::scale_fill_identity() + + ggplot2::theme_void() + + ggplot2::coord_equal() + + ggplot2::geom_text( + ggplot2::aes( + label = State, + color = text_color + ), + family = "Gotham", + size = 3.4 + ) + + ggplot2::scale_color_identity() + + ggplot2::labs( + caption = glue::glue("Source: {data_source}") + ) + + ggplot2::theme( + plot.caption = ggplot2::element_text( + hjust = 0.06, + family = "Gotham", + color = "#5c5c5c" + ), + plot.caption.position = "plot", + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + } else if (!is.null(zero_color) & is.null(na_color)) { + ## 02.02 If Zero ---- + + choropleth <- + grid_df |> + dplyr::left_join( + data, + by = c("State" = {{ state_column }}) + ) |> + dplyr::mutate( + fill_color = dplyr::case_when( + {{ numeric_column }} == 0 ~ zero_color, + dplyr::between({{ numeric_column }}, 0.01, breaks[1]) ~ pal[1], + dplyr::between({{ numeric_column }}, breaks[1], breaks[2]) ~ pal[2], + dplyr::between({{ numeric_column }}, breaks[2], breaks[3]) ~ pal[3], + dplyr::between({{ numeric_column }}, breaks[3], breaks[4]) ~ pal[4] + ) + ) |> + dplyr::mutate( + text_color = dplyr::if_else( + fill_color == pal[4], + "#ffffff", + "#000000" + ) + ) |> + ggplot2::ggplot( + ggplot2::aes( + x = x, + y = y + ) + ) + + ggplot2::geom_tile( + ggplot2::aes( + fill = fill_color + ), + color = "#000", + linewidth = 0.2 + ) + + ggplot2::scale_fill_identity() + + ggplot2::theme_void() + + ggplot2::coord_equal() + + ggplot2::geom_text( + ggplot2::aes( + label = State, + color = text_color + ), + family = "Gotham", + size = 3.4 + ) + + ggplot2::scale_color_identity() + + ggplot2::labs( + caption = glue::glue("Source: {data_source}") + ) + + ggplot2::theme( + plot.caption = ggplot2::element_text( + hjust = 0.06, + family = "Gotham", + color = "#5c5c5c" + ), + plot.caption.position = "plot", + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + } else if (is.null(na_color) & is.null(zero_color)) { + ## 02.03 If Neither NA nor Zero + + choropleth <- + grid_df |> + dplyr::left_join( + data, + by = c("State" = {{ state_column }}) + ) |> + dplyr::mutate( + fill_color = dplyr::case_when( + dplyr::between({{ numeric_column }}, 0, breaks[1]) ~ pal[1], + dplyr::between({{ numeric_column }}, breaks[1], breaks[2]) ~ pal[2], + dplyr::between({{ numeric_column }}, breaks[2], breaks[3]) ~ pal[3], + dplyr::between({{ numeric_column }}, breaks[3], breaks[4]) ~ pal[4] + ) + ) |> + dplyr::mutate( + text_color = dplyr::if_else( + fill_color == pal[4], + "#ffffff", + "#000000" + ) + ) |> + ggplot2::ggplot( + ggplot2::aes( + x = x, + y = y + ) + ) + + ggplot2::geom_tile( + ggplot2::aes( + fill = fill_color + ), + color = "#000", + linewidth = 0.2 + ) + + ggplot2::scale_fill_identity() + + ggplot2::theme_void() + + ggplot2::coord_equal() + + ggplot2::geom_text( + ggplot2::aes( + label = State, + color = text_color + ), + family = "Gotham", + size = 3.4 + ) + + ggplot2::scale_color_identity() + + ggplot2::labs( + caption = glue::glue("Source: {data_source}") + ) + + ggplot2::theme( + plot.caption = ggplot2::element_text( + hjust = 0.06, + family = "Gotham", + color = "#5c5c5c" + ), + plot.caption.position = "plot", + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + } + + ## 03 Build guide_legend() Scales ---- + + scale_df <- + data.frame( + x = seq(10, 40, 10), + y = rep(0.1, 4), + fill_color = pal + ) + + top_legend <- + ggplot2::ggplot( + scale_df, + ggplot2::aes( + x = x, + y = y + ) + ) + + ggplot2::geom_tile( + color = "#000000", + ggplot2::aes( + fill = fill_color + ), + linewidth = 0.4 + ) + + ggplot2::scale_fill_identity() + + ggplot2::theme_void( + base_family = "Gotham" + ) + + ggplot2::scale_x_continuous( + breaks = seq( + 15, + 45, + 10 + ), + labels = breaks |> + as.character() + ) + + ggplot2::theme( + axis.text.x.bottom = ggplot2::element_text( + vjust = 0.5, + size = 10 + ), + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + + ## 04 Determine if Zero or NA Color Guide Needed + + if (is.null(zero_color) & !is.null(na_color)) { + zero_na_df <- + data.frame( + x = 1, + y = 0.1, + fill_color = na_color + ) + + zero_na_legend <- + ggplot2::ggplot( + zero_na_df, + ggplot2::aes( + x = x, + y = y + ) + ) + + ggplot2::geom_tile( + color = "#000000", + ggplot2::aes( + fill = fill_color + ), + linewidth = 0.4 + ) + + ggplot2::scale_fill_identity() + + ggplot2::theme_void( + base_family = "Gotham" + ) + + ggplot2::scale_x_continuous( + breaks = 1, + labels = "NA" + ) + + ggplot2::theme( + axis.text.x.bottom = ggplot2::element_text( + vjust = 0.5, + size = 10 + ), + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + + ggplot2::coord_fixed(ratio = 1) + } else if (!is.null(zero_color) & is.null(na_color)) { + zero_na_df <- + data.frame( + x = 1, + y = 0.1, + fill_color = zero_color + ) + + zero_na_legend <- + ggplot2::ggplot( + zero_na_df, + ggplot2::aes( + x = x, + y = y + ) + ) + + ggplot2::geom_tile( + color = "#000000", + ggplot2::aes( + fill = fill_color + ), + linewidth = 0.4 + ) + + ggplot2::scale_fill_identity() + + ggplot2::theme_void( + base_family = "Gotham" + ) + + ggplot2::scale_x_continuous( + breaks = 1, + labels = "0" + ) + + ggplot2::theme( + axis.text.x.bottom = ggplot2::element_text( + vjust = 0.5, + size = 10 + ), + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + + ggplot2::coord_fixed(ratio = 1) + } + + zero_na_df <- + data.frame( + x = 1, + y = 0.1, + fill_color = na_color + ) + + zero_na_legend <- + ggplot2::ggplot( + zero_na_df, + ggplot2::aes( + x = x, + y = y + ) + ) + + ggplot2::geom_tile( + color = "#000000", + ggplot2::aes( + fill = fill_color + ), + linewidth = 0.4 + ) + + ggplot2::scale_fill_identity() + + ggplot2::theme_void( + base_family = "Gotham" + ) + + ggplot2::scale_x_continuous( + breaks = 1, + labels = "NA" + ) + + ggplot2::theme( + axis.text.x.bottom = ggplot2::element_text( + vjust = 0.5, + size = 10 + ), + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + + ggplot2::coord_fixed(ratio = 1) + + ## 04 Assemble Plot ---- + + ## 04.01 No Zero Color or NA Color + + if (is.null(zero_color) & is.null(na_color)) { + ((patchwork::plot_spacer() + + ggplot2::theme( + plot.margin = grid::unit(c(0, 0, 0, 30), "pt") + ) + + top_legend + + patchwork::plot_spacer()) + + patchwork::plot_layout(widths = c(2, 5, 2), nrow = 1)) / + choropleth + + patchwork::plot_layout( + heights = c(0.05, 1) + ) + + patchwork::plot_annotation( + title = plot_title + ) & + ggplot2::theme( + plot.title = ggtext::element_textbox_simple( + size = 11, + family = "Gotham", + hjust = 0.25, + margin = ggplot2::margin(0, 0, 5, 0, unit = "pt") + ), + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + } else { + ## 04.02 Add Zero or NA Color Legend + + ((patchwork::plot_spacer() + + zero_na_legend + + ggplot2::theme( + plot.margin = grid::unit(c(0, 0, 0, 30), "pt") + ) + + top_legend + + patchwork::plot_spacer()) + + patchwork::plot_layout(widths = c(0.3, 1, 5, 1.4), nrow = 1)) / + choropleth + + patchwork::plot_layout( + heights = c(0.05, 1) + ) + + patchwork::plot_annotation( + title = plot_title + ) & + ggplot2::theme( + plot.title = ggtext::element_textbox_simple( + size = 11, + family = "Gotham", + hjust = 0.25, + margin = ggplot2::margin(0, 0, 5, 0, unit = "pt") + ), + plot.background = ggplot2::element_rect( + color = plot_panel_color, + fill = plot_panel_color + ), + panel.background = ggplot2::element_rect( + fill = plot_panel_color, + color = plot_panel_color + ) + ) + } +} diff --git a/R/check_all.R b/R/check_all.R index 05a262e..28dd665 100644 --- a/R/check_all.R +++ b/R/check_all.R @@ -1,8 +1,8 @@ #' Count number of unique responses to 'Select All'/'Check All' survey questions #' @import dplyr #' @import rlang -#' @import forcats #' @import tidyr +#' @import tidyselect #' @param data A data frame, typically results from a Qualtrics survey, where responses to #' 'Select All'/'Check All' questions are recorded in consecutive columns named using the #' format: `Question-Number_Response-Option-Number`. For example, if Question 2 @@ -19,167 +19,74 @@ #' @export #' #' @examples -#' -#' # Toy Dataset -#' mouse_cheese_df <- -#' dplyr::tribble( -#' ~Q1, ~Q2_1, ~Q2_2, ~Q2_3, ~Q2_4, ~Q2_TEXT, -#' "Country", NA, NA, NA, "Colby", "Brie", -#' "City", NA, "Gruyere", NA, NA, "", -#' "City", NA, NA, "Swiss", NA, "Parmesan", -#' "City", NA, NA, NA, NA, "", -#' "Country", "Cheddar", NA, NA, "Colby", "", -#' "City", "Cheddar", NA, NA, "Colby", "", -#' "Country", "Cheddar", "Gruyere", NA, "Colby", "", -#' "City", NA, "Gruyere", NA, NA, "", -#' "City", NA, "Gruyere", NA, NA, "", -#' "City", NA, NA, "Swiss", NA, "Mozzarella", -#' "Country", "Cheddar", NA, NA, "Colby", "" -#' ) |> -#' dplyr::mutate( -#' dplyr::across(dplyr::everything(), as.factor) -#' ) #' # Grouped Results #' check_all( -#' data = mouse_cheese_df, -#' group_var = Q1, -#' column_prefix = "Q2", -#' free_text_var_suffix = "_TEXT" +#' data = board_prep_df, +#' group_var = q6, +#' column_prefix = "q65", +#' free_text_var_suffix = "_6_text" #' ) #' #' # Ungrouped Results #' check_all( -#' data = mouse_cheese_df, -#' column_prefix = "Q2", -#' free_text_var_suffix = "_TEXT" +#' data = board_prep_df, +#' column_prefix = "q65", +#' free_text_var_suffix = "_6_text" #' ) + check_all <- function( - data, - group_var = NULL, - column_prefix, - free_text_var_suffix = "_TEXT" + data, + group_var = NULL, + column_prefix, + free_text_var_suffix = "_TEXT" ) { - group_var_expr <- rlang::enquo(group_var) - free_text_column <- paste0(column_prefix, free_text_var_suffix) - - num_col <- data |> - dplyr::select( - dplyr::all_of( - dplyr::contains(column_prefix) - ) - ) |> - # Omit Free Text Responses - dplyr::select( - !free_text_column - ) |> - ncol() - - if(rlang::quo_is_null(group_var_expr)) { - - ret <- data |> - dplyr::select( - dplyr::all_of( - dplyr::contains(column_prefix) - ) - ) |> - # Omit Free Text Responses - dplyr::select( - !free_text_column - ) |> - dplyr::rowwise() |> - dplyr::mutate( - all_miss = sum( - is.na( - dplyr::c_across( - dplyr::all_of(dplyr::contains(column_prefix)) - ) - ) - ) - ) |> - dplyr::ungroup() |> - dplyr::filter(all_miss < num_col) |> - dplyr::reframe( - dplyr::across( - dplyr::all_of( - dplyr::contains(column_prefix) - ), - forcats::fct_count - ) - ) |> + has_free_text <- free_text_column %in% names(data) + # Select relevant columns + if (rlang::quo_is_null(group_var_expr)) { + if (has_free_text) { + data_filtered <- + data |> + dplyr::select(tidyselect::contains(column_prefix)) |> + dplyr::select(!tidyselect::all_of(free_text_column)) + } else { + data_filtered <- + data |> + dplyr::select(tidyselect::contains(column_prefix)) + } + } else { + if (has_free_text) { + data_filtered <- + data |> + dplyr::select(!!group_var_expr, tidyselect::contains(column_prefix)) |> + dplyr::select(!tidyselect::all_of(free_text_column)) + } else { + data_filtered <- + data |> + dplyr::select(!!group_var_expr, tidyselect::contains(column_prefix)) + } + } + # Pivot and count + if (rlang::quo_is_null(group_var_expr)) { + data_filtered |> tidyr::pivot_longer( - names_to = column_prefix, - values_to = "Number", - cols = dplyr::everything() + cols = everything(), + names_to = "question", + values_to = "value" ) |> - dplyr::select(-column_prefix) |> - dplyr::mutate( - column_prefix = Number$f, - N = Number$n - ) |> - dplyr::select( - Variable = column_prefix, - N - ) |> - tidyr::drop_na() |> - dplyr::distinct() - - + dplyr::filter(!is.na(value)) |> + dplyr::count(value, name = "N") |> + dplyr::rename(Variable = value) } else { - - ret <- data |> - dplyr::select( - !! group_var_expr, - dplyr::all_of( - dplyr::contains(column_prefix) - ) - ) |> - # Omit Free Text Responses - dplyr::select( - !free_text_column - ) |> - dplyr::rowwise() |> - dplyr::mutate( - all_miss = sum( - is.na( - dplyr::c_across( - dplyr::all_of(contains(column_prefix)) - ) - ) - ) - ) |> - dplyr::ungroup() |> - dplyr::filter(all_miss < num_col) |> - dplyr::group_by(!! group_var_expr) |> - dplyr::reframe( - dplyr::across( - dplyr::all_of( - dplyr::contains(column_prefix) - ), - forcats::fct_count - ) - ) |> - dplyr::ungroup() |> + data_filtered |> tidyr::pivot_longer( - names_to = column_prefix, - values_to = "Number", - cols = - !! group_var_expr - ) |> - dplyr::select(-column_prefix) |> - dplyr::mutate( - column_prefix = Number$f, - N = Number$n + cols = -!!group_var_expr, + names_to = "question", + values_to = "value" ) |> - dplyr::select( - !! group_var_expr, - Variable = column_prefix, - N - ) |> - tidyr::drop_na() |> - dplyr::distinct() + dplyr::filter(!is.na(value)) |> + dplyr::count(!!group_var_expr, value, name = "N") |> + dplyr::rename(Variable = value) } - - ret - } diff --git a/R/data.R b/R/data.R new file mode 100644 index 0000000..c629633 --- /dev/null +++ b/R/data.R @@ -0,0 +1,53 @@ +#' Board Prep Resources +#' +#' Resources used by nephrology fellows in preparation for initial board certication in +#' nephrology. This is a synthesized data set generated based on proportions of actual responses to +#' measures in the 2025 ASN Nephrology Fellow Survey. +#' +#' @format A data frame with 8 columns +#' 1. `q6`: Repondent medical school location, either "United States" or "Other country". +#' 2. `q65_1`: ASN Kidney Self-Assessment Program (KSAP) selected as a used resource ( = "No"). +#' 3. `q65_2`: ASN Nephrology Self-Assessment Program (NephSAP) selected as a used resource ( = "No"). +#' 4. `q65_3`: ASN Board Review Course & Update selected as a used resource ( = "No"). +#' 5. `q65_4`: Oakstone/Brigham Intensive Review of Nephrology Course ( = "No"). +#' 6. `q65_5`: Other board review course ( = "No"). +#' 7. `q65_6`: Other resource(s) (please specify) ( = "No"). +#' 8. `q65_6_text`: Free text response describing other resource(s) used. +#' +#' @source +#' +#' @examples +#' board_prep_df +#' +"board_prep_df" + +#' Nephrologists per 100K U.S. Population by State +#' +#' Ratio of practicing nephrologists per 100K adult population per state and District of +#' Columbia in 2023. Nephrologist counts aggregated from the American Medical Assosciation +#' Physician Professional Database. U.S. adult population extracted from the U.S. Census Bureau. +#' +#' @format A data frame with 2 columns: +#' 1. `MailState`: USPS codes for U.S. states and the District of Columbia. +#' 2. `neph_per_100k`: Ratio of practicing nephrologists per 100K adult population in state/DC. +#' @source +#' +#' @examples +#' neph_per_100K_df +#' +"neph_per_100K_df" + +#' Grid Data Frame for asn_tilegrid() +#' +#' Data frame of The Economist's 8 x 11 rectangular tile grid for the asn_tilegrid() function, adapted from the tilegrid +#' choropleth designed by The Economist Data Team. +#' +#' @format A data frame with 6 columns: +#' 1. `State`: USPS codes for U.S. states and the District of Columbia. +#' 2. `x`: Corresponding x coordinate for tilegrid. +#' 3. `y`: Corresponding y coordinate for tilegrid. +#' @source +#' @examples +#' grid_df +#' +"grid_df" diff --git a/_pkgdown.yml b/_pkgdown.yml index 3db95db..5d9d2ba 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -1,4 +1,6 @@ url: https://asndataanalytics.github.io/asn/ template: bootstrap: 5 + light-switch: true + bootswatch: litera diff --git a/data-raw/DATASET.R b/data-raw/DATASET.R new file mode 100644 index 0000000..be600f0 --- /dev/null +++ b/data-raw/DATASET.R @@ -0,0 +1,208 @@ +## 1. Synthesized Survey Data Based on the 2025 ASN Nephrology Fellow Survey + +set.seed(20260116) + +board_prep_df <- + data.frame( + q6 = sample( + c("United States", "Other country"), + size = 400, + prob = c(0.42, 0.58), + replace = TRUE + ), + q65_1 = sample( + c("ASN Kidney Self-Assessment Program (KSAP)", NA_character_), + size = 400, + prob = c(0.484, 1 - 0.484), + replace = TRUE + ), + q65_2 = sample( + c("ASN Nephrology Self-Assessment Program (NephSAP)", NA_character_), + size = 400, + prob = c(0.274, 1 - 0.274), + replace = TRUE + ), + q65_3 = sample( + c("ASN Board Review Course & Update", NA_character_), + size = 400, + prob = c(0.381, 1 - 0.381), + replace = TRUE + ), + q65_4 = sample( + c( + "Oakstone/Brigham Intensive Review of Nephrology Course", + NA_character_ + ), + size = 400, + prob = c(0.0442, 1 - 0.0442), + replace = TRUE + ), + q65_5 = sample( + c("Other board review course", NA_character_), + size = 400, + prob = c(0.0324, 1 - 0.0324), + replace = TRUE + ), + q65_6 = sample( + c("Other resource(s) (please specify)", NA_character_), + size = 400, + prob = c(0.0324, 1 - 0.0324), + replace = TRUE + ), + q65_6_text = c( + rep(NA_character_, 235), + "Textbooks", + rep(NA_character_, 14), + "Washington Manual Nephrology Subspecialty Consult", + rep(NA_character_, 50), + "Board Vitals for Nephrology", + rep(NA_character_, 56), + "Institution Materials", + rep(NA_character_, 5), + "Brcu", + rep(NA_character_, 23), + "uptodate", + rep(NA_character_, 10), + "Comprehensive" + ) + ) + +usethis::use_data(board_prep_df, overwrite = TRUE) + +## 2. Ratio of Nephrologists per 100K U.S. Population by State + +neph_per_100K_df <- + tibble::tribble( + ~MailState , ~neph_per_100k , + "ND" , 2.66143841875072 , + "VT" , 2.6205935490236 , + "OK" , 2.04238213609549 , + "MI" , 2.81652259426326 , + "NM" , 2.6400598916444 , + "IA" , 1.58463143647772 , + "AZ" , 2.94392085027928 , + "WV" , 2.76758759555943 , + "WI" , 2.36071566781695 , + "NV" , 2.86215340333372 , + "KY" , 2.61504264826907 , + "OH" , 2.78246831834212 , + "GA" , 2.97349199669716 , + "FL" , 2.65882344312135 , + "TX" , 3.05585577141808 , + "MO" , 2.88335863923513 , + "VA" , 2.75911495377338 , + "MD" , 3.50647942709917 , + "IN" , 2.60169464796528 , + "DE" , 3.08754244164786 , + "IL" , 3.24309128613802 , + "AR" , 2.0524762800529 , + "DC" , 5.52868807141901 , + "UT" , 1.59734109505574 , + "NJ" , 3.79545402692342 , + "SD" , 3.48468101556672 , + "PA" , 3.37232607765983 , + "NY" , 3.94176183682454 , + "NH" , 1.92554694447792 , + "WA" , 2.21449552773719 , + "TN" , 2.79786645895306 , + "WY" , 1.1964441679329 , + "SC" , 2.43140559371769 , + "MA" , 4.00477289682913 , + "ME" , 2.28629239107603 , + "CT" , 3.95276120957787 , + "AL" , 2.75515844798994 , + "KS" , 2.1345078773505 , + "NE" , 1.91159958628961 , + "CA" , 2.85723812270986 , + "AK" , 1.08620385330817 , + "LA" , 3.33473479377281 , + "MT" , 1.50269335685785 , + "NC" , 2.72948112563802 , + "MN" , 2.69422400091221 , + "OR" , 2.32741128625208 , + "RI" , 3.53443674219184 , + "MS" , 2.44634020709629 , + "HI" , 2.84448243254587 , + "ID" , 1.42051075478839 , + "CO" , 2.18594457969623 + ) + +usethis::use_data(neph_per_100K_df, overwrite = TRUE) + +## 3. Grid Data Frame for asn_tilegrid() + +# fmt: skip + +grid_df <- + tibble::tribble( + ~State, ~x, ~y, + "AL", 7, 7, + "AK", 1, 1, + "AZ", 2, 6, + "AR", 5, 6, + "CA", 1, 5, + "CO", 3, 5, + "CT", 10, 4, + "DC", 9, 6, + "DE", 10, 5, + "FL", 9, 8, + "GA", 8, 7, + "HI", 1, 8, + "ID", 2, 3, + "IL", 6, 3, + "IN", 6, 4, + "IA", 5, 4, + "KS", 4, 6, + "KY", 6, 5, + "LA", 5, 7, + "ME", 11, 1, + "MD", 9, 5, + "MA", 10, 3, + "MI", 7, 3, + "MN", 5, 3, + "MS", 6, 7, + "MO", 5, 5, + "MT", 3, 3, + "NE", 4, 5, + "NV", 2, 4, + "NH", 11, 2, + "NJ", 9, 4, + "NM", 3, 6, + "NY", 9, 3, + "NC", 7, 6, + "ND", 4, 3, + "OH", 7, 4, + "OK", 4, 7, + "OR", 1, 4, + "PA", 8, 4, + "RI", 11, 4, + "SC", 8, 6, + "SD", 4, 4, + "TN", 6, 6, + "TX", 4, 8, + "UT", 2, 5, + "VT", 10, 2, + "VA", 8, 5, + "WA", 1, 3, + "WV", 7, 5, + "WI", 6, 2, + "WY", 3, 4 + ) |> + dplyr::mutate( + y = dplyr::case_when( + y == 1 ~ 12, + y == 2 ~ 11, + y == 3 ~ 10, + y == 4 ~ 9, + y == 5 ~ 8, + y == 6 ~ 7, + y == 7 ~ 6, + y == 8 ~ 5, + y == 9 ~ 4, + y == 10 ~ 3, + y == 11 ~ 2, + y == 12 ~ 1 + ) + ) + +usethis::use_data(grid_df, overwrite = TRUE) diff --git a/data/board_prep_df.rda b/data/board_prep_df.rda new file mode 100644 index 0000000..854d156 Binary files /dev/null and b/data/board_prep_df.rda differ diff --git a/data/grid_df.rda b/data/grid_df.rda new file mode 100644 index 0000000..2f566d1 Binary files /dev/null and b/data/grid_df.rda differ diff --git a/data/neph_per_100K_df.rda b/data/neph_per_100K_df.rda new file mode 100644 index 0000000..0b412a3 Binary files /dev/null and b/data/neph_per_100K_df.rda differ diff --git a/man/asn_tilegrid.Rd b/man/asn_tilegrid.Rd new file mode 100644 index 0000000..c3e8697 --- /dev/null +++ b/man/asn_tilegrid.Rd @@ -0,0 +1,61 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/asn_tilegrid.R +\name{asn_tilegrid} +\alias{asn_tilegrid} +\title{Create a U.S. Tilegrid Choropleth Map in ggplot2 in style of The Economist} +\usage{ +asn_tilegrid( + data = df, + data_source = "Source", + plot_title = "Plot Title", + state_column = "state_column_name", + numeric_column = n, + plot_panel_color = "#ffffff", + palette = c("#FCC8B4", "#FAAA90", "#F58469", "#EF1B26"), + breaks = c(1, 2, 6, 11), + zero_color = NULL, + na_color = NULL +) +} +\arguments{ +\item{data}{A data frame, comprising a column with 2-letter USPS state abbreviations and a column with a +numeric variable to be visualized in a tilegrid choropleth map.} + +\item{data_source}{Source of the numeric data visualized in the choropleth.} + +\item{plot_title}{Plot title.} + +\item{state_column}{Column containing 2-letter USPS state abbreviations.} + +\item{numeric_column}{Column containing numeric data being visualized in choropleth.} + +\item{plot_panel_color}{Background color for plot.} + +\item{palette}{Vector of hex colors mapping numeric column to choropleth map fill color.} + +\item{breaks}{Numeric vector of breaks corresponding to colors in the color palette mapping to the numeric column.} + +\item{zero_color}{Optional hex color to indicate states with a 0 numeric value.} + +\item{na_color}{Optional hex color to indicate states with missing values.} +} +\value{ +ggplot2 object +} +\description{ +Create a U.S. Tilegrid Choropleth Map in ggplot2 in style of The Economist +} +\examples{ +asn_tilegrid( + data = neph_per_100K_df, + data_source = "AMA PPD and U.S. Census Bureau.", + plot_title = "Ratio of Nephrologists per 100K Adult Population", + state_column = "MailState", + numeric_column = neph_per_100k, + plot_panel_color = "#ffffff", + palette = c("#f0f8ff", "#a0bdd8", "#5081b2", "#00468b"), + breaks = c(2.21, 3.1, 4, 5.6), + zero_color = NULL, + na_color = "#EEECE6" +) +} diff --git a/man/board_prep_df.Rd b/man/board_prep_df.Rd new file mode 100644 index 0000000..97313cc --- /dev/null +++ b/man/board_prep_df.Rd @@ -0,0 +1,35 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{board_prep_df} +\alias{board_prep_df} +\title{Board Prep Resources} +\format{ +A data frame with 8 columns +\enumerate{ +\item \code{q6}: Repondent medical school location, either "United States" or "Other country". +\item \code{q65_1}: ASN Kidney Self-Assessment Program (KSAP) selected as a used resource (\if{html}{\out{}} = "No"). +\item \code{q65_2}: ASN Nephrology Self-Assessment Program (NephSAP) selected as a used resource (\if{html}{\out{}} = "No"). +\item \code{q65_3}: ASN Board Review Course & Update selected as a used resource (\if{html}{\out{}} = "No"). +\item \code{q65_4}: Oakstone/Brigham Intensive Review of Nephrology Course (\if{html}{\out{}} = "No"). +\item \code{q65_5}: Other board review course (\if{html}{\out{}} = "No"). +\item \code{q65_6}: Other resource(s) (please specify) (\if{html}{\out{}} = "No"). +\item \code{q65_6_text}: Free text response describing other resource(s) used. +} +} +\source{ +\url{https://data.asn-online.org/posts/2025_fellow_survey/} +} +\usage{ +board_prep_df +} +\description{ +Resources used by nephrology fellows in preparation for initial board certication in +nephrology. This is a synthesized data set generated based on proportions of actual responses to +measures in the 2025 ASN Nephrology Fellow Survey. +} +\examples{ +board_prep_df + +} +\keyword{datasets} diff --git a/man/check_all.Rd b/man/check_all.Rd index 9194ff2..d2dde43 100644 --- a/man/check_all.Rd +++ b/man/check_all.Rd @@ -35,38 +35,18 @@ A data frame. Count number of unique responses to 'Select All'/'Check All' survey questions } \examples{ - -# Toy Dataset -mouse_cheese_df <- - dplyr::tribble( - ~Q1, ~Q2_1, ~Q2_2, ~Q2_3, ~Q2_4, ~Q2_TEXT, - "Country", NA, NA, NA, "Colby", "Brie", - "City", NA, "Gruyere", NA, NA, "", - "City", NA, NA, "Swiss", NA, "Parmesan", - "City", NA, NA, NA, NA, "", - "Country", "Cheddar", NA, NA, "Colby", "", - "City", "Cheddar", NA, NA, "Colby", "", - "Country", "Cheddar", "Gruyere", NA, "Colby", "", - "City", NA, "Gruyere", NA, NA, "", - "City", NA, "Gruyere", NA, NA, "", - "City", NA, NA, "Swiss", NA, "Mozzarella", - "Country", "Cheddar", NA, NA, "Colby", "" - ) |> - dplyr::mutate( - dplyr::across(dplyr::everything(), as.factor) - ) # Grouped Results check_all( - data = mouse_cheese_df, - group_var = Q1, - column_prefix = "Q2", - free_text_var_suffix = "_TEXT" + data = board_prep_df, + group_var = q6, + column_prefix = "q65", + free_text_var_suffix = "_6_text" ) # Ungrouped Results check_all( - data = mouse_cheese_df, - column_prefix = "Q2", - free_text_var_suffix = "_TEXT" + data = board_prep_df, + column_prefix = "q65", + free_text_var_suffix = "_6_text" ) } diff --git a/man/grid_df.Rd b/man/grid_df.Rd new file mode 100644 index 0000000..c3e2dd6 --- /dev/null +++ b/man/grid_df.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{grid_df} +\alias{grid_df} +\title{Grid Data Frame for asn_tilegrid()} +\format{ +A data frame with 6 columns: +\enumerate{ +\item \code{State}: USPS codes for U.S. states and the District of Columbia. +\item \code{x}: Corresponding x coordinate for tilegrid. +\item \code{y}: Corresponding y coordinate for tilegrid. +} +} +\source{ +\url{https://github.com/kpivert/economist_choropleth} +} +\usage{ +grid_df +} +\description{ +Data frame of The Economist's 8 x 11 rectangular tile grid for the asn_tilegrid() function, adapted from the tilegrid +choropleth designed by The Economist Data Team. +} +\examples{ +grid_df + +} +\keyword{datasets} diff --git a/man/neph_per_100K_df.Rd b/man/neph_per_100K_df.Rd new file mode 100644 index 0000000..6100266 --- /dev/null +++ b/man/neph_per_100K_df.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/data.R +\docType{data} +\name{neph_per_100K_df} +\alias{neph_per_100K_df} +\title{Nephrologists per 100K U.S. Population by State} +\format{ +A data frame with 2 columns: +\enumerate{ +\item \code{MailState}: USPS codes for U.S. states and the District of Columbia. +\item \code{neph_per_100k}: Ratio of practicing nephrologists per 100K adult population in state/DC. +} +} +\source{ +\url{https://www.census.gov/data/datasets/time-series/demo/popest/2020s-counties-detail.html} +} +\usage{ +neph_per_100K_df +} +\description{ +Ratio of practicing nephrologists per 100K adult population per state and District of +Columbia in 2023. Nephrologist counts aggregated from the American Medical Assosciation +Physician Professional Database. U.S. adult population extracted from the U.S. Census Bureau. +} +\examples{ +neph_per_100K_df + +} +\keyword{datasets}