diff --git a/NAMESPACE b/NAMESPACE index 92cd1c2..2aba884 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,7 +4,6 @@ export(convert_md_to_html) export(entable_encounters) export(fetch_strategy_text) export(generate_rates_baseline_data) -export(generate_rates_funnel_data) export(get_all_geo_data) export(get_container) export(get_golem_config) @@ -20,6 +19,7 @@ export(prepare_diagnoses_data) export(prepare_procedures_data) export(run_app) export(theme_rates) +export(uprime_calculations) importFrom(rlang,":=") importFrom(rlang,.data) importFrom(rlang,.env) diff --git a/R/fct_plots.R b/R/fct_plots.R index 251bafe..e209692 100644 --- a/R/fct_plots.R +++ b/R/fct_plots.R @@ -35,32 +35,53 @@ plot_rates_trend <- function( } #' Plot Rates Funnel with Peers -#' @param rates_funnel_data A data.frame. Rates data read in from Azure and -#' processed with [generate_rates_baseline_data] to filter for provider, -#' strategy and year, followed by [generate_rates_funnel_data] to generate -#' values for funnel structure. +#' @param rates_funnel_data A data.frame. Rates data read in from Azure. +#' @param funnel_calculations A list. Output from [uprime_calculations] used to +#' plot U-Prime lines. #' @param y_axis_limits Numeric vector. Min and max values for the y axis. #' @param x_axis_title Character. Title for the x-axis. #' @return A 'ggplot2' object. #' @export -plot_rates_funnel <- function(rates_funnel_data, y_axis_limits, x_axis_title) { - lines_data <- rates_funnel_data |> - dplyr::select( - "denominator", - tidyselect::matches("^(lower|upper)"), - "mean" - ) |> - tidyr::pivot_longer(-"denominator", values_to = "rate") +plot_rates_funnel <- function( + rates_funnel_data, + funnel_calculations, + y_axis_limits, + x_axis_title +) { + cl2_colour <- "black" + cl3_colour <- "black" + cl_line_type <- "dashed" rates_funnel_data |> ggplot2::ggplot(ggplot2::aes(.data$denominator, .data$rate)) + - ggplot2::geom_line( - data = lines_data, - ggplot2::aes(group = .data$name), - linetype = "dashed", - na.rm = TRUE + ggplot2::geom_hline( + yintercept = funnel_calculations$cl, + linetype = cl_line_type + ) + + ggplot2::geom_function( + fun = funnel_calculations$lcl2, + colour = cl2_colour, + linetype = cl_line_type + ) + + ggplot2::geom_function( + fun = funnel_calculations$ucl2, + colour = cl2_colour, + linetype = cl_line_type + ) + + ggplot2::geom_function( + fun = funnel_calculations$lcl3, + colour = cl3_colour, + linetype = cl_line_type ) + - ggplot2::geom_point(ggplot2::aes(colour = .data$is_peer)) + + ggplot2::geom_function( + fun = funnel_calculations$ucl3, + colour = cl3_colour, + linetype = cl_line_type + ) + + ggplot2::geom_point(ggplot2::aes( + colour = .data$is_peer, + alpha = .data$is_peer + )) + ggrepel::geom_text_repel( data = dplyr::filter(rates_funnel_data, !is.na(.data$is_peer)), ggplot2::aes(label = .data$provider, colour = .data$is_peer), @@ -68,7 +89,11 @@ plot_rates_funnel <- function(rates_funnel_data, y_axis_limits, x_axis_title) { ) + ggplot2::scale_colour_manual( values = c("TRUE" = "black", "FALSE" = "red"), - na.value = "lightgrey" + na.value = "black" + ) + + ggplot2::scale_alpha_manual( + values = c("TRUE" = 1, "FALSE" = 1), + na.value = 0.2 ) + ggplot2::theme(legend.position = "none") + ggplot2::scale_x_continuous(labels = scales::comma_format()) + @@ -88,10 +113,21 @@ plot_rates_box <- function(rates_box_data, y_axis_limits) { rates_box_data |> ggplot2::ggplot(ggplot2::aes(x = "", y = .data$rate)) + ggplot2::geom_boxplot(alpha = 0.2, outlier.shape = NA) + - ggbeeswarm::geom_quasirandom(ggplot2::aes(colour = .data$is_peer)) + + ggbeeswarm::geom_quasirandom( + # just show peers/selected provider + data = \(.x) dplyr::filter(.x, !is.na(.data$is_peer)), + ggplot2::aes( + colour = .data$is_peer, + alpha = .data$is_peer + ) + ) + ggplot2::scale_colour_manual( values = c("TRUE" = "black", "FALSE" = "red"), - na.value = "lightgrey" + na.value = "black" + ) + + ggplot2::scale_alpha_manual( + values = c("TRUE" = 1, "FALSE" = 1), + na.value = 0.2 ) + ggplot2::coord_cartesian(ylim = y_axis_limits) + ggplot2::labs(x = "") + diff --git a/R/mod_plot_rates.R b/R/mod_plot_rates.R index 7a29c28..e5f758d 100644 --- a/R/mod_plot_rates.R +++ b/R/mod_plot_rates.R @@ -71,23 +71,28 @@ mod_plot_rates_server <- function( ) }) - rates_funnel_data <- shiny::reactive({ - shiny::req(rates_baseline_data()) - rates_baseline_data() |> generate_rates_funnel_data() + rates_funnel_calculations <- shiny::reactive({ + df <- shiny::req(rates_baseline_data()) + + uprime_calculations(df) }) # Prepare variables ---- y_axis_limits <- shiny::reactive({ - shiny::req(rates_trend_data()) - shiny::req(rates_funnel_data()) - range(c( - rates_trend_data()[["rate"]], - rates_funnel_data()[["rate"]], - rates_funnel_data()[["lower3"]], - rates_funnel_data()[["upper3"]] - )) |> - pmax(0) + td_rate <- shiny::req(rates_trend_data())$rate + + bd <- shiny::req(rates_baseline_data()) + bd$z <- rates_funnel_calculations()$z_i + + fd_rate <- bd |> + dplyr::filter( + .data$denominator >= 0.05 * max(.data$denominator), + abs(.data$z) < 4 + ) |> + dplyr::pull("rate") + + c(0, max(c(td_rate, fd_rate))) }) strategy_config <- shiny::reactive({ @@ -127,7 +132,8 @@ mod_plot_rates_server <- function( ) mod_plot_rates_funnel_server( "mod_plot_rates_funnel", - rates_funnel_data, + rates_baseline_data, + rates_funnel_calculations, y_axis_limits, funnel_x_title ) diff --git a/R/mod_plot_rates_funnel.R b/R/mod_plot_rates_funnel.R index e634a1c..3e28e7f 100644 --- a/R/mod_plot_rates_funnel.R +++ b/R/mod_plot_rates_funnel.R @@ -18,12 +18,15 @@ mod_plot_rates_funnel_ui <- function(id) { #' @param id Internal parameter for `shiny`. #' @param rates A data.frame. Annual rate values for combinations of provider #' and strategy +#' @param funnel_calculations A list. Output from [uprime_calculations] used to +#' plot U-Prime lines. #' @param y_axis_limits Numeric vector. Min and max values for the y axis. #' @param x_axis_title Character. Title for the x-axis. #' @noRd mod_plot_rates_funnel_server <- function( id, rates, + funnel_calculations, y_axis_limits, x_axis_title ) { @@ -39,6 +42,7 @@ mod_plot_rates_funnel_server <- function( plot_rates_funnel( rates, + funnel_calculations(), y_axis_limits(), x_axis_title = x_axis_title() ) diff --git a/R/utils_plot.R b/R/utils_plot.R index 3b847da..20ff78c 100644 --- a/R/utils_plot.R +++ b/R/utils_plot.R @@ -39,27 +39,33 @@ generate_rates_baseline_data <- function( .default = NA # if scheme is neither focal nor a peer ) ) |> - dplyr::filter(!is.na(.data$is_peer)) |> # only focal scheme and peers dplyr::arrange(dplyr::desc(.data$is_peer)) # to plot focal scheme last } -#' Generate Data for the Funnel Plot -#' @param rates_baseline_data A data.frame. Rates data read in from Azure and +#' Generate Function to Calculate U-Prime values +#' @param df A data.frame. Rates data read in from Azure and #' processed [generate_rates_baseline_data]. -#' @return A data.frame. +#' @return A list containing items to produce a U-Prime funnel chart. #' @export -generate_rates_funnel_data <- function(rates_baseline_data) { - rates_baseline_data |> - dplyr::mutate( - mean = rates_baseline_data$national_rate, - sdev_pop_i = sqrt(abs(.data$mean) / .data$denominator), - z = (.data$rate - .data$mean) / .data$sdev_pop_i, - sigz = stats::sd(.data$z, na.rm = TRUE), - cl2 = 2 * .data$sdev_pop_i * .data$sigz, - cl3 = 3 * .data$sdev_pop_i * .data$sigz, - lower2 = .data$mean - .data$cl2, - lower3 = .data$mean - .data$cl3, - upper2 = .data$mean + .data$cl2, - upper3 = .data$mean + .data$cl3 - ) +uprime_calculations <- function(df) { + df <- dplyr::arrange(df, .data$denominator) + + cl <- df$national_rate[[1]] # centre line + stdev <- sqrt(cl / df$denominator) + z_i <- (df$rate - cl) / stdev + mr <- abs(diff(z_i)) # moving range + ulmr <- 3.267 * mean(mr, na.rm = TRUE) # upper-limit of moving range + amr <- mean(mr[mr < ulmr], na.rm = TRUE) # average moving range + sigma_z <- amr / 1.128 + sd_fn <- \(x) sqrt(cl / x) * sigma_z + cl_fn <- \(s) \(x) cl + s * sd_fn(x) + + list( + cl = cl, + z_i = (df$rate - cl) / sd_fn(df$denominator), + lcl3 = cl_fn(-3), # lower control limit + ucl3 = cl_fn(3), # upper control limit + lcl2 = cl_fn(-2), + ucl2 = cl_fn(2) + ) } diff --git a/man/get_all_geo_data.Rd b/man/get_all_geo_data.Rd index a065e87..fcd94d9 100644 --- a/man/get_all_geo_data.Rd +++ b/man/get_all_geo_data.Rd @@ -4,13 +4,9 @@ \alias{get_all_geo_data} \title{Read Inputs Datasets for All Geographies} \usage{ -get_all_geo_data(inputs_container, geographies, data_types) +get_all_geo_data(geographies, data_types) } \arguments{ -\item{inputs_container}{A blob_container/storage_container list. The -object containing the connection to the Azure container hosting the -datasets named by \code{data_types}.} - \item{geographies}{Character. The geography level for which the user wants to select a provider.} diff --git a/man/get_container.Rd b/man/get_container.Rd index c4f263d..fc470c7 100644 --- a/man/get_container.Rd +++ b/man/get_container.Rd @@ -5,21 +5,19 @@ \title{Get Azure Container} \usage{ get_container( - tenant = Sys.getenv("AZ_TENANT_ID"), - app_id = Sys.getenv("AZ_APP_ID"), ep_uri = Sys.getenv("AZ_STORAGE_EP"), container_name = Sys.getenv("AZ_CONTAINER_INPUTS") ) } \arguments{ -\item{tenant}{Character. Tenant ID.} - -\item{app_id}{Character. App ID.} - \item{ep_uri}{Character. Endpoint URI.} \item{container_name}{Character. The name of the blob/storage container that hosts files you want to read.} + +\item{tenant}{Character. Tenant ID.} + +\item{app_id}{Character. App ID.} } \value{ A blob_container/storage_container list. diff --git a/man/plot_rates_funnel.Rd b/man/plot_rates_funnel.Rd index 80495e1..c607446 100644 --- a/man/plot_rates_funnel.Rd +++ b/man/plot_rates_funnel.Rd @@ -4,13 +4,18 @@ \alias{plot_rates_funnel} \title{Plot Rates Funnel with Peers} \usage{ -plot_rates_funnel(rates_funnel_data, y_axis_limits, x_axis_title) +plot_rates_funnel( + rates_funnel_data, + funnel_calculations, + y_axis_limits, + x_axis_title +) } \arguments{ -\item{rates_funnel_data}{A data.frame. Rates data read in from Azure and -processed with \link{generate_rates_baseline_data} to filter for provider, -strategy and year, followed by \link{generate_rates_funnel_data} to generate -values for funnel structure.} +\item{rates_funnel_data}{A data.frame. Rates data read in from Azure.} + +\item{funnel_calculations}{A list. Output from \link{uprime_calculations} used to +plot U-Prime lines.} \item{y_axis_limits}{Numeric vector. Min and max values for the y axis.} diff --git a/man/plot_rates_trend.Rd b/man/plot_rates_trend.Rd index 39415de..d84f96e 100644 --- a/man/plot_rates_trend.Rd +++ b/man/plot_rates_trend.Rd @@ -9,7 +9,8 @@ plot_rates_trend( baseline_year, y_axis_limits, x_axis_title = "Financial year", - y_axis_title + y_axis_title, + y_labels ) } \arguments{ @@ -23,6 +24,8 @@ for a given provider and strategy, and arranged by year.} \item{x_axis_title}{Character. Title for the x-axis.} \item{y_axis_title}{Character. Title for the y-axis.} + +\item{y_labels}{A function. Function to format y-axis labels.} } \value{ A 'ggplot2' object. diff --git a/man/generate_rates_funnel_data.Rd b/man/uprime_calculations.Rd similarity index 52% rename from man/generate_rates_funnel_data.Rd rename to man/uprime_calculations.Rd index da4874e..626d0f9 100644 --- a/man/generate_rates_funnel_data.Rd +++ b/man/uprime_calculations.Rd @@ -1,18 +1,18 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/utils_plot.R -\name{generate_rates_funnel_data} -\alias{generate_rates_funnel_data} -\title{Generate Data for the Funnel Plot} +\name{uprime_calculations} +\alias{uprime_calculations} +\title{Generate Function to Calculate U-Prime values} \usage{ -generate_rates_funnel_data(rates_baseline_data) +uprime_calculations(df) } \arguments{ \item{rates_baseline_data}{A data.frame. Rates data read in from Azure and processed \link{generate_rates_baseline_data}.} } \value{ -A data.frame. +A list containing items to produce a U-Prime funnel chart. } \description{ -Generate Data for the Funnel Plot +Generate Function to Calculate U-Prime values }