diff --git a/.Rbuildignore b/.Rbuildignore index 03e9f13..eeb3025 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -4,7 +4,7 @@ ^\.vscode$ ^app\.R$ ^CODEOWNERS$ -^cpma-explorer\.Rproj$ +^tpma-explorer\.Rproj$ ^dev$ ^LICENSE\.md$ ^README\.md$ diff --git a/DESCRIPTION b/DESCRIPTION index 224e9cc..f6d8c0b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,13 +1,13 @@ -Package: cpma.explorer -Title: Explore CPMA Data -Version: 0.0.0.9000 +Package: tpma.explorer +Title: Explore TPMA Data +Version: 0.1.0.9000 Authors@R: person("Matt", "Dray", , "matt.dray@nhs.net", role = c("aut", "cre")) Description: A Shiny-app-in-a-package to explore data related to - categories of potentially mitigaable activity (CPMAs). + Types of Potentially Mitigatable Activity (TPMAs). License: MIT + file LICENSE -URL: https://github.com/The-Strategy-Unit/cpma-explorer -BugReports: https://github.com/The-Strategy-Unit/cpma-explorer/issues +URL: https://github.com/The-Strategy-Unit/tpma-explorer +BugReports: https://github.com/The-Strategy-Unit/tpma-explorer/issues Depends: R (>= 4.1.0) Imports: @@ -19,10 +19,9 @@ Imports: jsonlite, purrr, rlang, - shiny, - stringr + shiny Remotes: The-Strategy-Unit/azkit Encoding: UTF-8 Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 diff --git a/NAMESPACE b/NAMESPACE index 7076e99..b73ca71 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,5 +1,6 @@ # Generated by roxygen2: do not edit by hand +export(plot_rates) export(run_app) importFrom(rlang,.data) importFrom(rlang,.env) diff --git a/R/add_external_resources.R b/R/add_external_resources.R index 0b1778c..5003741 100644 --- a/R/add_external_resources.R +++ b/R/add_external_resources.R @@ -1,6 +1,7 @@ #' Add External Resources to the Application #' This function is internally used to add external resources inside the Shiny #' application. +#' @noRd add_external_resources <- function() { shiny::addResourcePath( "www", @@ -12,9 +13,9 @@ add_external_resources <- function() { } #' Access Files in the Current App -#' @param ... character vectors, specifying subdirectory and file(s) +#' @param ... Character vectors, specifying subdirectory and file(s) #' within your package. The default, none, returns the root of the app. #' @noRd app_sys <- function(...) { - system.file(..., package = "cpma.explorer") + system.file(..., package = "tpma.explorer") } diff --git a/R/app_server.R b/R/app_server.R index 3d91550..20c96db 100644 --- a/R/app_server.R +++ b/R/app_server.R @@ -1,58 +1,33 @@ -#' The application server-side -#' @param input,output,session Internal parameters for {shiny}. +#' Server-Side Application +#' @param input,output,session Internal parameters for 'shiny'. #' @noRd app_server <- function(input, output, session) { - # Data ---- - container <- azkit::get_container(Sys.getenv("AZ_CONTAINER_INPUTS")) - rates <- azkit::read_azure_parquet(container, "rates", "dev") - - # Reactives ---- - - selected_provider <- shiny::reactive(input$provider_select) - selected_strategy <- shiny::reactive(input$strategy_select) - - rates_prepared <- shiny::reactive({ - rates |> - dplyr::filter( - .data$provider == selected_provider(), - .data$strategy == selected_strategy() - ) |> - dplyr::arrange(.data$fyear) - }) |> - shiny::bindEvent(selected_provider(), selected_strategy()) - - # Observers ---- - - shiny::observe({ - providers <- jsonlite::read_json( - app_sys("app", "data", "datasets.json"), - simplify_vector = TRUE - ) - provider_choices <- purrr::set_names(names(providers), providers) - shiny::updateSelectInput( - session, - "provider_select", - choices = provider_choices - ) - }) - - shiny::observe({ - strategies <- jsonlite::read_json( - app_sys("app", "data", "mitigators.json"), - simplify_vector = TRUE - ) - strategy_choices <- purrr::set_names(names(strategies), strategies) - shiny::updateSelectInput( - session, - "strategy_select", - choices = strategy_choices - ) - }) - - # Outputs ---- - - output$rates_plot <- shiny::renderPlot({ - rates_prepared() |> plot_rates() - }) + rates_data <- azkit::read_azure_parquet(container, "rates", "dev") + + providers_lookup <- jsonlite::read_json( + app_sys("app", "data", "datasets.json"), + simplify_vector = TRUE + ) + + strategies_lookup <- jsonlite::read_json( + app_sys("app", "data", "mitigators.json"), + simplify_vector = TRUE + ) + + selected_provider <- mod_select_provider_server( + "mod_select_provider", + providers_lookup + ) + selected_strategy <- mod_select_strategy_server( + "mod_select_strategy", + strategies_lookup + ) + + mod_plot_trend_server( + "mod_plot_trend", + rates_data, + selected_provider, + selected_strategy + ) } diff --git a/R/app_ui.R b/R/app_ui.R index 24e582f..150f528 100644 --- a/R/app_ui.R +++ b/R/app_ui.R @@ -1,20 +1,12 @@ -#' The application User-Interface -#' @param request Internal parameter for shiny. +#' Application User Interface +#' @param request Internal parameter for 'shiny'. #' @noRd app_ui <- function(request) { bslib::page_sidebar( - title = "CPMA Explorer", + title = "TPMA Explorer", sidebar = bslib::sidebar( - shiny::selectInput( - "provider_select", - "Choose a provider:", - choices = NULL - ), - shiny::selectInput( - "strategy_select", - "Choose a strategy:", - choices = NULL - ) + mod_select_provider_ui("mod_select_provider"), + mod_select_strategy_ui("mod_select_strategy"), ), bslib::card( @@ -30,9 +22,7 @@ app_ui <- function(request) { bslib::card( bslib::card_header("Trend in rates"), - bslib::card_body( - shiny::plotOutput("rates_plot") - ), + bslib::card_body(mod_plot_trend_ui("mod_plot_trend")), full_screen = TRUE ) ) diff --git a/R/fct_plot.R b/R/fct_plot.R index 38fec15..8004f23 100644 --- a/R/fct_plot.R +++ b/R/fct_plot.R @@ -6,23 +6,19 @@ #' financial year in the form `"2023/24"`. #' @param rate_col Character. Name of the column in `rates_df` containing the #' rate value (the type of which is dependent on the strategy). +#' @return A ggplot2 object. +#' @export plot_rates <- function(rates_df, fyear_col = "fyear", rate_col = "rate") { - x_breaks <- rates_df[[fyear_col]] - x_labels <- enstring_fyear(x_breaks) - rates_df |> - ggplot2::ggplot(ggplot2::aes( - x = .data[[fyear_col]], - y = .data[[rate_col]] - )) + + ggplot2::ggplot( + ggplot2::aes( + x = .data[[fyear_col]], + y = .data[[rate_col]] + ) + ) + ggplot2::geom_line() + ggplot2::labs( x = "Financial year", y = "Rate" - ) + - ggplot2::scale_x_continuous( - breaks = x_breaks, - labels = x_labels, - guide = ggplot2::guide_axis(angle = 45) ) } diff --git a/R/fct_utils.R b/R/fct_utils.R deleted file mode 100644 index 5d36b15..0000000 --- a/R/fct_utils.R +++ /dev/null @@ -1,8 +0,0 @@ -#' Convert a Financial Year to Character -#' @param year Integer. Expressed in the form `202526`. To be converted to the -#' form `"2025/26"`. -enstring_fyear <- function(year) { - yyyy <- stringr::str_sub(year, 1, 4) - yy <- stringr::str_sub(year, -2) - paste0(yyyy, "/", yy) -} diff --git a/R/mod_plot_trend.R b/R/mod_plot_trend.R new file mode 100644 index 0000000..66d9cf5 --- /dev/null +++ b/R/mod_plot_trend.R @@ -0,0 +1,46 @@ +#' Plot Trend UI +#' @param id,input,output,session Internal parameters for `shiny`. +#' @noRd +mod_plot_trend_ui <- function(id) { + ns <- shiny::NS(id) + shiny::plotOutput(ns("rates_plot")) +} + +#' Plot Trend Server +#' @param id Internal parameter for `shiny`. +#' @param rates A data.frame. Annual rate values for combinations of provider +#' and TPMA. +#' @param selected_provider Character. Provider code, e.g. `"RCX"`. +#' @param selected_strategy Character. TPMA variable name, e.g. +#' `"discharged_no_treatment_adult_ambulance"`. +#' @noRd +mod_plot_trend_server <- function( + id, + rates, + selected_provider, + selected_strategy +) { + shiny::moduleServer(id, function(input, output, session) { + rates_prepared <- shiny::reactive({ + shiny::req(rates) + shiny::req(selected_provider()) + shiny::req(selected_strategy()) + + rates |> + dplyr::filter( + .data$provider == selected_provider(), + .data$strategy == selected_strategy() + ) |> + dplyr::arrange(.data$fyear) + }) + + output$rates_plot <- shiny::renderPlot({ + rates <- rates_prepared() + shiny::validate(shiny::need( + nrow(rates) > 0, + "No data available for these selections" + )) + plot_rates(rates) + }) + }) +} diff --git a/R/mod_select_provider.R b/R/mod_select_provider.R new file mode 100644 index 0000000..cb003e1 --- /dev/null +++ b/R/mod_select_provider.R @@ -0,0 +1,31 @@ +#' Select Provider UI +#' @param id,input,output,session Internal parameters for `shiny`. +#' @noRd +mod_select_provider_ui <- function(id) { + ns <- shiny::NS(id) + shiny::selectInput( + ns("provider_select"), + "Choose a provider:", + choices = NULL + ) +} + +#' Select Provider Server +#' @param id Internal parameter for `shiny`. +#' @param providers A named list. Names are provider codes (e.g. `"RCF"`) and +#' their values are the corresponding human-readable names and codes (e.g. +#' `"Airedale NHS Foundation Trust (RCF)"`). +#' @noRd +mod_select_provider_server <- function(id, providers) { + shiny::moduleServer(id, function(input, output, session) { + shiny::observe({ + provider_choices <- purrr::set_names(names(providers), providers) + shiny::updateSelectInput( + session, + "provider_select", + choices = provider_choices + ) + }) + shiny::reactive(input$provider_select) + }) +} diff --git a/R/mod_select_strategy.R b/R/mod_select_strategy.R new file mode 100644 index 0000000..65b85a2 --- /dev/null +++ b/R/mod_select_strategy.R @@ -0,0 +1,33 @@ +#' Select Strategy UI +#' @param id,input,output,session Internal parameters for `shiny`. +#' @noRd +mod_select_strategy_ui <- function(id) { + ns <- shiny::NS(id) + shiny::selectInput( + ns("strategy_select"), + "Choose a strategy:", + choices = NULL + ) +} + +#' Select Strategy Server +#' @param id Internal parameter for `shiny`. +#' @param strategies A named list. Names are TPMA variable names (e.g. +#' `"alcohol_partially_attributable_acute"`) and their values are the +#' corresponding human-readable names and codes (e.g. +#' `"Alcohol Related Admissions (Acute Conditions - Partially Attributable) +#' (IP-AA-001)"`). +#' @noRd +mod_select_strategy_server <- function(id, strategies) { + shiny::moduleServer(id, function(input, output, session) { + shiny::observe({ + strategy_choices <- purrr::set_names(names(strategies), strategies) + shiny::updateSelectInput( + session, + "strategy_select", + choices = strategy_choices + ) + }) + shiny::reactive(input$strategy_select) + }) +} diff --git a/R/cpma-explorer-app.R b/R/tpma-explorer-app.R similarity index 100% rename from R/cpma-explorer-app.R rename to R/tpma-explorer-app.R diff --git a/README.md b/README.md index 90fb884..1485183 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ -# cpma-explorer +# tpma-explorer [![Project Status: Concept – Minimal or no implementation has been done yet, or the repository is only intended to be a limited example, demo, or proof-of-concept.](https://www.repostatus.org/badges/latest/concept.svg)](https://www.repostatus.org/#concept) -An app to explore data for categories of potentially-mitigable activity (CPMAs). +An app to explore data for Types of Potentially-Mitigable Activity (TPMAs). -The app is [deployed to Posit Connect](https://connect.strategyunitwm.nhs.uk/cpma-explorer/) (login and permissions required). +The app is [deployed to Posit Connect](https://connect.strategyunitwm.nhs.uk/tpma-explorer/) (login and permissions required). The app is made with [Shiny](https://shiny.posit.co/) and is an R package following [the nolem approach](https://github.com/StatsRhian/nolem). diff --git a/dev/deploy.R b/dev/deploy.R index a73e769..90d5a0b 100644 --- a/dev/deploy.R +++ b/dev/deploy.R @@ -1,6 +1,6 @@ rsconnect::deployApp( - appName = "cpma-explorer", - appTitle = "CPMA explorer", + appName = "tpma-explorer", + appTitle = "TPMA explorer", server = "connect.strategyunitwm.nhs.uk", appId = 200, appFiles = c( diff --git a/man/add_external_resources.Rd b/man/add_external_resources.Rd deleted file mode 100644 index 597d55f..0000000 --- a/man/add_external_resources.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/add_external_resources.R -\name{add_external_resources} -\alias{add_external_resources} -\title{Add External Resources to the Application -This function is internally used to add external resources inside the Shiny -application.} -\usage{ -add_external_resources() -} -\description{ -Add External Resources to the Application -This function is internally used to add external resources inside the Shiny -application. -} diff --git a/man/cpma.explorer-package.Rd b/man/cpma.explorer-package.Rd deleted file mode 100644 index 35d3d4e..0000000 --- a/man/cpma.explorer-package.Rd +++ /dev/null @@ -1,23 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/cpma-explorer-app.R -\docType{package} -\name{cpma.explorer-package} -\alias{cpma.explorer} -\alias{cpma.explorer-package} -\title{cpma.explorer: Explore CPMA Data} -\description{ -A Shiny-app-in-a-package to explore data related to categories of potentially mitigaable activity (CPMAs). -} -\seealso{ -Useful links: -\itemize{ - \item \url{https://github.com/The-Strategy-Unit/cpma-explorer} - \item Report bugs at \url{https://github.com/The-Strategy-Unit/cpma-explorer/issues} -} - -} -\author{ -\strong{Maintainer}: Matt Dray \email{matt.dray@nhs.net} - -} -\keyword{internal} diff --git a/man/enstring_fyear.Rd b/man/enstring_fyear.Rd deleted file mode 100644 index 3ba131d..0000000 --- a/man/enstring_fyear.Rd +++ /dev/null @@ -1,15 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/fct_utils.R -\name{enstring_fyear} -\alias{enstring_fyear} -\title{Convert a Financial Year to Character} -\usage{ -enstring_fyear(year) -} -\arguments{ -\item{year}{Integer. Expressed in the form \code{202526}. To be converted to the -form \code{"2025/26"}.} -} -\description{ -Convert a Financial Year to Character -} diff --git a/man/plot_rates.Rd b/man/plot_rates.Rd index bdf95d5..05fa127 100644 --- a/man/plot_rates.Rd +++ b/man/plot_rates.Rd @@ -17,6 +17,9 @@ financial year in the form \code{"2023/24"}.} \item{rate_col}{Character. Name of the column in \code{rates_df} containing the rate value (the type of which is dependent on the strategy).} } +\value{ +A ggplot2 object. +} \description{ Plot Trend in Rates } diff --git a/man/tpma.explorer-package.Rd b/man/tpma.explorer-package.Rd new file mode 100644 index 0000000..491f73e --- /dev/null +++ b/man/tpma.explorer-package.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/tpma-explorer-app.R +\docType{package} +\name{tpma.explorer-package} +\alias{tpma.explorer} +\alias{tpma.explorer-package} +\title{tpma.explorer: Explore TPMA Data} +\description{ +A Shiny-app-in-a-package to explore data related to Types of Potentially Mitigatable Activity (TPMAs). +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/The-Strategy-Unit/tpma-explorer} + \item Report bugs at \url{https://github.com/The-Strategy-Unit/tpma-explorer/issues} +} + +} +\author{ +\strong{Maintainer}: Matt Dray \email{matt.dray@nhs.net} + +} +\keyword{internal} diff --git a/cpma-explorer.Rproj b/tpma-explorer.Rproj similarity index 100% rename from cpma-explorer.Rproj rename to tpma-explorer.Rproj