Skip to content

Commit

Permalink
Merge pull request #1704 from rstudio/unit-conversion-helper
Browse files Browse the repository at this point in the history
Unit conversion helper
  • Loading branch information
rich-iannone authored Jun 14, 2024
2 parents e97c62e + 0965e59 commit b2fd5f2
Show file tree
Hide file tree
Showing 48 changed files with 1,395 additions and 32 deletions.
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ export(info_icons)
export(info_locales)
export(info_paletteer)
export(info_time_style)
export(info_unit_conversions)
export(local_image)
export(matches)
export(md)
Expand Down Expand Up @@ -218,6 +219,7 @@ export(text_case_match)
export(text_case_when)
export(text_replace)
export(text_transform)
export(unit_conversion)
export(vars)
export(vec_fmt_bytes)
export(vec_fmt_currency)
Expand Down
123 changes: 121 additions & 2 deletions R/helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,125 @@ currency <- function(
currency_list
}

#' Get a conversion factor across two measurement units of a given class
#'
#' @description
#'
#' The `unit_conversion()` helper function gives us a conversion factor for
#' transforming a value from one form of measurement units to a target form.
#' For example if you have a length value that is expressed in miles you could
#' transform that value to one in kilometers through multiplication of the value
#' by the conversion factor (in this case `1.60934`).
#'
#' For `unit_conversion()` to understand the source and destination units, you
#' need to provide a keyword value for the `from` and `to` arguments. To aid as
#' a reference for this, call [info_unit_conversions()] to display an
#' information table that contains all of the keywords for every conversion
#' type.
#'
#' @param from *Units for the input value*
#'
#' `scalar<character>` // **required**
#'
#' The keyword representing the units for the value that requires unit
#' conversion. In the case where the value has units of miles, the necessary
#' input is `"length.mile"`.
#'
#' @param to *Desired units for the value*
#'
#' `scalar<character>` // **required**
#'
#' The keyword representing the target units for the value with units defined
#' in `from`. In the case where input value has units of miles and we would
#' rather want the value to be expressed as kilometers, the `to` value should
#' be `"length.kilometer"`.
#'
#' @return A single numerical value.
#'
#' @section Examples:
#'
#' Let's use a portion of the [`towny`] dataset and create a table showing
#' population, density, and land area for 10 municipalities. The `land_area_km2`
#' values are in units of square kilometers, however, we'd rather the values
#' were in square miles. We can convert the numeric values while formatting the
#' values with [`fmt_number()`] by using `unit_conversion()` in the `scale_by`
#' argument since the return value of that is a conversion factor (which is
#' applied to each value by multiplication). The same is done for converting the
#' 'people per square kilometer' values in `density_2021` to 'people per square
#' mile', however, the units to convert are in the denominator so the inverse
#' of the conversion factor must be used.
#'
#' ```r
#' towny |>
#' dplyr::arrange(desc(density_2021)) |>
#' dplyr::slice_head(n = 10) |>
#' dplyr::select(name, population_2021, density_2021, land_area_km2) |>
#' gt(rowname_col = "name") |>
#' fmt_integer(columns = population_2021) |>
#' fmt_number(
#' columns = land_area_km2,
#' decimals = 1,
#' scale_by = unit_conversion(
#' from = "area.square_kilometer",
#' to = "area.square_mile"
#' )
#' ) |>
#' fmt_number(
#' columns = density_2021,
#' decimals = 1,
#' scale_by = 1 / unit_conversion(
#' from = "area.square_kilometer",
#' to = "area.square_mile"
#' )
#' ) |>
#' cols_label(
#' land_area_km2 = "Land Area,<br>sq. mi",
#' population_2021 = "Population",
#' density_2021 = "Density,<br>ppl / sq. mi",
#' .fn = md
#' )
#' ```
#'
#' \if{html}{\out{
#' `r man_get_image_tag(file = "man_unit_conversion_1.png")`
#' }}
#'
#' @family helper functions
#' @section Function ID:
#' 8-7
#'
#' @section Function Introduced:
#' *In Development*
#'
#' @export
unit_conversion <- function(from, to) {

force(from)
force(to)

if (!(from %in% conversion_factors[["from"]])) {
cli::cli_abort("The unit supplied in {.arg from} is not known.")
}
if (!(to %in% conversion_factors[["to"]])) {
cli::cli_abort("The unit supplied in {.arg to} is not known.")
}

if (from == to) {
return(1.0)
}

row_conversion <-
dplyr::filter(conversion_factors, from == {{ from }}, to == {{ to }})

# In the case where units are valid and available in the internal dataset,
# they may be across categories; such pairings do not allow for a conversion
# to take place
if (nrow(row_conversion) < 1) {
cli::cli_abort("The conversion specified cannot be performed.")
}

row_conversion[["conv_factor"]]
}

#' Supply nanoplot options to `cols_nanoplot()`
#'
Expand Down Expand Up @@ -778,7 +897,7 @@ currency <- function(
#'
#' @family helper functions
#' @section Function ID:
#' 8-7
#' 8-8
#'
#' @section Function Introduced:
#' `v0.10.0` (October 7, 2023)
Expand Down Expand Up @@ -984,7 +1103,7 @@ nanoplot_options <- function(
#'
#' @family helper functions
#' @section Function ID:
#' 8-8
#' 8-9
#'
#' @section Function Introduced:
#' `v0.2.0.5` (March 31, 2020)
Expand Down
38 changes: 38 additions & 0 deletions R/info_tables.R
Original file line number Diff line number Diff line change
Expand Up @@ -824,3 +824,41 @@ info_flags <- function() {
info_icons <- function() {
readRDS(system_file("gt_tables/info_icons.rds"))
}

#' View a table with all units that can be converted by `unit_conversion()`
#'
#' @description
#'
#' [unit_conversion()] can be used to yield conversion factors across compatible
#' pairs of units. This is useful for expressing values in different units and
#' the conversion can be performed via the `scale_by` argument available in
#' several formatting functions. When calling [unit_conversion()], one must
#' supply two string-based keywords to specify the value's current units and the
#' desired units. All of these keywords are provided in the table shown by
#' calling `info_unit_conversions()`.
#'
#' @return An object of class `gt_tbl`.
#'
#' @section Examples:
#'
#' Get a table of info on all the available keywords for unit conversions.
#'
#' ```r
#' info_unit_conversions()
#' ```
#'
#' \if{html}{\out{
#' `r man_get_image_tag(file = "man_info_unit_conversions_1.png")`
#' }}
#'
#' @family information functions
#' @section Function ID:
#' 11-9
#'
#' @section Function Introduced:
#' *In Development*
#'
#' @export
info_unit_conversions <- function() {
readRDS(system_file("gt_tables/info_conversions.rds"))
}
Binary file modified R/sysdata.rda
Binary file not shown.
3 changes: 3 additions & 0 deletions data-raw/X01-currencies.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ currencies <-
file = "data-raw/x_currencies.csv",
col_types = "ccccc"
)

# Drop spec() attribute
currencies <- currencies[]
3 changes: 3 additions & 0 deletions data-raw/X02-currency_symbols.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ currency_symbols <-
file = "data-raw/x_currency_symbols.csv",
col_types = "cc"
)

# Drop spec() attribute
currency_symbols <- currency_symbols[]
3 changes: 3 additions & 0 deletions data-raw/X07-fractions.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ fractions <-
file = "data-raw/fractions.csv",
col_types = "ccccccccc"
)

# Drop spec() attribute
fractions <- fractions[]
3 changes: 3 additions & 0 deletions data-raw/X10-spelled_num.R
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,6 @@ spelled_num <-
zh = col_character()
)
)

# Drop spec() attribute
spelled_num <- spelled_num[]
3 changes: 3 additions & 0 deletions data-raw/X12-country_names.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ country_names <-
col_types = cols(.default = col_character()),
na = ""
)

# Drop spec() attribute
country_names <- country_names[]
3 changes: 3 additions & 0 deletions data-raw/X13-country_names_additional.R
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ country_names_additional <-
col_types = cols(.default = col_character()),
na = ""
)

# Drop spec() attribute
country_names_additional <- country_names_additional[]
3 changes: 3 additions & 0 deletions data-raw/X14-tf_words.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,6 @@ tf_words <-
file = "data-raw/tf_words.csv",
col_types = cols(.default = col_character())
)

# Drop spec() attribute
tf_words <- tf_words[]
15 changes: 15 additions & 0 deletions data-raw/X15-conversion_factors.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
library(tidyverse)

conversion_factors <-
readr::read_csv(
file = "data-raw/conversion_factors.csv",
col_types = cols(
type = col_character(),
from = col_character(),
to = col_character(),
conv_factor = col_double()
)
)

# Drop spec() attribute
conversion_factors <- conversion_factors[]
Loading

0 comments on commit b2fd5f2

Please sign in to comment.