Title: | Addressing Annoyances and Irritations |
---|---|
Description: | Visualisation hacks, tabular data helpers, fonts, caching, tidy data functions. It is an swiss army knife, jack of all trades. |
Authors: | Robert Challen [aut, cre] |
Maintainer: | Robert Challen <[email protected]> |
License: | MIT + file LICENSE |
Version: | 0.0.0.9024 |
Built: | 2025-01-09 03:57:21 UTC |
Source: | https://github.com/terminological/ggrrr |
Pick a locally installed font family that matches requested
.substitute_fonts(family, quiet = TRUE)
.substitute_fonts(family, quiet = TRUE)
family |
the font family requested |
quiet |
do not print warnings. |
try({ .substitute_fonts(c("Roboto","Arial","Kings","Unmatched")) })
try({ .substitute_fonts(c("Roboto","Arial","Kings","Unmatched")) })
A checked list is a sub class of list access operator that throws an error if you attempt to access a value that does not exist (rather than returning NULL) the point of this is to throw errors early if the data changes.
## S3 method for class 'checked_list' x$y
## S3 method for class 'checked_list' x$y
x |
the list |
y |
the item |
the value of the list item or an error if it does not exist
Reuse tidy-select syntax outside of a tidy-select function
as_vars(tidyselect, data = NULL)
as_vars(tidyselect, data = NULL)
tidyselect |
a tidyselect syntax which will be evaluated in context by looking for a call in the call stack that includes a dataframe as the first argument |
data |
(optional) a specific dataframe with which to evaluate the tidyselect |
a list of symbols resulting from the evaluation of the tidyselect in the context of the current call stack (or a provided data frame)
Convert a rendered_plot object to a character
## S3 method for class 'rendered_plot' as.character(x, ...)
## S3 method for class 'rendered_plot' as.character(x, ...)
x |
the rendered_plot |
... |
not used |
a named vector
Convert a rendered_table object to a character
## S3 method for class 'rendered_table' as.character(x, ...)
## S3 method for class 'rendered_table' as.character(x, ...)
x |
the rendered_table |
... |
not used |
a named vector
hux = iris %>% hux_default_layout() tmp = hux %>% hux_save_as(tempfile()) as.character(tmp)
hux = iris %>% hux_default_layout() tmp = hux %>% hux_save_as(tempfile()) as.character(tmp)
Converts a square display table format to a long format suitable for applying as a sequence of formatting operations in a google doc or as a ggplot. Currently only plain dataframes and huxtables are supported but flextables look very doable. Only a limited subset of formatting features is implemented at present as supported by roogledocs. The output format is a simple dataframe with the following columns:
as.long_format_table(table, ...)
as.long_format_table(table, ...)
table |
the input table (e.g. a huxtable) |
... |
passed onto subclass methods |
- Character: label - non blank text (a single space is OK but not an empty string) - Integer: row - must be an integer, 1-based from top left - Integer: col - must be an integer, 1-based from top left - Integer: rowSpan - must be an integer, minimum value 1 - Integer: colSpan - must be an integer, minimum value 1 - Character: fontName - font name as seen in font drop down of google docs e.g "Roboto","Arial","Times New Roman", unrecognised values will be displayed as Arial - Character: fontFace - one of "bold", "bold.italic", "italic", "plain" - Numeric: fontSize - in points - Character: fillColour - as a hex string e.g. "#aaaaaa". N.b. British English spelling (sorry) - Numeric: leftBorderWeight - border weight in points - minimum size that appears in google docs is 0.5 - Numeric: rightBorderWeight - Numeric: topBorderWeight - Numeric: bottomBorderWeight - Character: alignment - one of "START","CENTER","END" - Character: valignment - one of "TOP","MIDDLE","BOTTOM"
It also has an attribute 'colWidths' which is a vector the same length as the width of the table containing the relative widths of the columns. The overall table width is decided on rendering.
So not supported at the moment are border line types, border colours, control of padding, row height control, alignment on a decimal point, complex content / markup in cells.
a format that is considered valid for roogledocs::RoogleDocs$updateTable()
TODO: testing this empty input (must specify .class) struct_list - identity simple struct - wrapped list of struct_lists is flattened list of structs is wrapped nested plain lists / struct_lists are flattened
as.struct_list(x, .class = NULL)
as.struct_list(x, .class = NULL)
x |
a list |
.class |
the type of structures in the list |
a structured list
Bind_rows works until there are factors with a set of different levels then it throws a wobbly. This handles that particular situation by combining factor levels.
bind_rows_with_factors(...)
bind_rows_with_factors(...)
... |
a list of dataframes |
the union of those dataframes. Factor levels are combined with a superset of all levels
library(tidyverse) bind_rows_with_factors(iris, ggplot2::diamonds %>% dplyr::rename(Species = cut)) %>% dplyr::pull(Species) %>% levels()
library(tidyverse) bind_rows_with_factors(iris, ggplot2::diamonds %>% dplyr::rename(Species = cut)) %>% dplyr::pull(Species) %>% levels()
A scales breaks generator for log1p scales
breaks_log1p(n = 5, base = 10)
breaks_log1p(n = 5, base = 10)
n |
the number of breaks |
base |
the base for the breaks |
a function for ggplot scale breaks
library(tidyverse) ggplot2::ggplot(diamonds, ggplot2::aes(x=price))+ ggplot2::geom_density()+ ggplot2::scale_x_continuous(trans="log1p", breaks=ggrrr::breaks_log1p())
library(tidyverse) ggplot2::ggplot(diamonds, ggplot2::aes(x=price))+ ggplot2::geom_density()+ ggplot2::scale_x_continuous(trans="log1p", breaks=ggrrr::breaks_log1p())
Clear data from the passthrough cache for complex or long running operations
cache_clear( .cache = getOption("cache.dir", default = rappdirs::user_cache_dir("ggrrr")), .prefix = ".*", interactive = TRUE )
cache_clear( .cache = getOption("cache.dir", default = rappdirs::user_cache_dir("ggrrr")), .prefix = ".*", interactive = TRUE )
.cache |
the location of the cache as a directory. May get its value from options("ggrrr.cache.dir") or the default value of rappdirs::user_cache_dir("ggrrr") |
.prefix |
a regular expression matching the prefix of the cached item, so that do selective clean up operations. defaults to everything. |
interactive |
suppress 'are you sure?' warning with a FALSE value (defaults to TRUE) |
nothing. called for side effects
cache_clear(.prefix="example", .cache=tempdir(), interactive=FALSE)
cache_clear(.prefix="example", .cache=tempdir(), interactive=FALSE)
Staleness is determined by the number of days from 2am on the current day in the current time-zone. A item cached for only one day becomes stale at 2am the day after it is cached. The time is configurable and option(cache.time_day_starts = 0) would be midnight. Automated analysis using caches and updated data should ensure that analysis does not cross this time point otherwise it may end up using old data.
cache_delete_stale( .cache = getOption("cache.dir", default = rappdirs::user_cache_dir("ggrrr")), .prefix = ".*", .stale = getOption("cache.stale", default = Inf) )
cache_delete_stale( .cache = getOption("cache.dir", default = rappdirs::user_cache_dir("ggrrr")), .prefix = ".*", .stale = getOption("cache.stale", default = Inf) )
.cache |
the location of the cache as a directory. May get its value from options("cache.dir") or the default value of rappdirs::user_cache_dir("ggrrr") |
.prefix |
a name of the operation so that you can namespace the cached files and do selective clean up operations on them |
.stale |
the length of time in days to keep cached data before considering it as stale. |
nothing. called for side effects.
This function copies a remote file to a local cache once and makes sure it is reused.
cache_download( url, ..., .nocache = getOption("cache.disable", default = FALSE), .cache = getOption("cache.download.dir", default = rappdirs::user_cache_dir("ggrrr-download")), .stale = getOption("cache.stale", default = Inf), .extn = NULL )
cache_download( url, ..., .nocache = getOption("cache.disable", default = FALSE), .cache = getOption("cache.download.dir", default = rappdirs::user_cache_dir("ggrrr-download")), .stale = getOption("cache.stale", default = Inf), .extn = NULL )
url |
the url to download |
... |
passed to 'utils::download.file()' |
.nocache |
if set to TRUE all caching is disabled |
.cache |
the location of the downloaded files |
.stale |
how long to leave this file before replacing it. |
.extn |
the file name extension |
the path to the downloaded file
executes expr and saves the output as an RDS file indexed by has of code in expr and the hash of input variables (which should contain any variable inputs)
cached( .expr, ..., .nocache = getOption("cache.disable", default = FALSE), .cache = getOption("cache.dir", default = rappdirs::user_cache_dir("ggrrr")), .prefix = getOption("cache.item.prefix", default = "cached"), .stale = getOption("cache.stale", default = Inf) )
cached( .expr, ..., .nocache = getOption("cache.disable", default = FALSE), .cache = getOption("cache.dir", default = rappdirs::user_cache_dir("ggrrr")), .prefix = getOption("cache.item.prefix", default = "cached"), .stale = getOption("cache.stale", default = Inf) )
.expr |
the code the output of which requires caching. Other than a return value this should not create side effects or change global variables. |
... |
inputs that the code in expr depends on and changes in which require the code re-running, Could be Sys.Date() |
.nocache |
an option to defeat the caching which can be set globally as options("cache.disable"=TRUE) |
.cache |
the location of the cache as a directory. May get its value from options("cache.dir") or the default value of rappdirs::user_cache_dir("ggrrr") |
.prefix |
a name of the operation so that you can namespace the cached files and do selective clean up operations on them |
.stale |
the length of time in days to keep cached data before considering it as stale. can also be set by options("cache.stale") |
the output of .expr which will usually be a value
colName = "Petal.Width" { iris[[colName]] } %>% cached(iris, colName, .prefix="example", .cache=tempdir())
colName = "Petal.Width" { iris[[colName]] } %>% cached(iris, colName, .prefix="example", .cache=tempdir())
This checks to see if a font exists. If missing it will try and install from 'google fonts' or 'brick.io'. If nothing can be done it will suggest alternatives from 'fonts_available()'. In all cases this will make the font available to 'systemfonts' (for 'ragg' and 'svg' devices), and 'extrafonts' (for 'pdf' etc). Webfonts are automatically downloaded into the users font directory and from there will be picked up by 'cairo' devices in theory, and system pdf/svg viewers. In practice this is a bit hit and miss.
check_font(family)
check_font(family)
family |
a font family name or names |
the font family name if it can be located or an alternative if not.
check_font(c("Roboto","Arial","Kings","EB Garamond")) extrafont::fonts() fonts_available(c("Roboto","Arial","Kings","EB Garamond")) plot = ggplot2::ggplot(ggplot2::diamonds, ggplot2::aes(x=carat,y=price,color = color))+ ggplot2::theme_minimal(base_family="Roboto")+ ggplot2::geom_point()+ ggplot2::annotate("label",x=2,y=10000,label="Hello \u2014 world", family="Kings")+ ggplot2::labs(tag = "A")+ ggplot2::xlab("Carat\u2082")+ ggplot2::ylab("price\u2265") if (FALSE) { # font but no unicode support tmp = tempfile(fileext = ".pdf") pdf(tmp) plot dev.off() utils::browseURL(tmp) # font and unicode support tmp = tempfile(fileext = ".pdf") cairo_pdf(tmp) plot dev.off() utils::browseURL(tmp) # font and unicode support tmp = tempfile(fileext = ".png") png(tmp) plot dev.off() utils::browseURL(tmp) # font and unicode support tmp = tempfile(fileext = ".png") ragg::agg_png(tmp) plot dev.off() utils::browseURL(tmp) # font and unicode support tmp = tempfile(fileext = ".svg") svglite::svglite(tmp) plot dev.off() utils::browseURL(tmp) # Does not work - "family 'Roboto' not included in postscript() device" # however: names(grDevices::postscriptFonts()) includes Roboto tmp = tempfile(fileext = ".eps") postscript(tmp) plot dev.off() utils::browseURL(tmp) # This does work but rasterises output at low fidelity tmp = tempfile(fileext = ".eps") cairo_ps(tmp) plot dev.off() utils::browseURL(tmp) # This fully works tmp = tempfile(fileext = ".ps") Cairo::CairoPS(tmp) plot dev.off() utils::browseURL(tmp) }
check_font(c("Roboto","Arial","Kings","EB Garamond")) extrafont::fonts() fonts_available(c("Roboto","Arial","Kings","EB Garamond")) plot = ggplot2::ggplot(ggplot2::diamonds, ggplot2::aes(x=carat,y=price,color = color))+ ggplot2::theme_minimal(base_family="Roboto")+ ggplot2::geom_point()+ ggplot2::annotate("label",x=2,y=10000,label="Hello \u2014 world", family="Kings")+ ggplot2::labs(tag = "A")+ ggplot2::xlab("Carat\u2082")+ ggplot2::ylab("price\u2265") if (FALSE) { # font but no unicode support tmp = tempfile(fileext = ".pdf") pdf(tmp) plot dev.off() utils::browseURL(tmp) # font and unicode support tmp = tempfile(fileext = ".pdf") cairo_pdf(tmp) plot dev.off() utils::browseURL(tmp) # font and unicode support tmp = tempfile(fileext = ".png") png(tmp) plot dev.off() utils::browseURL(tmp) # font and unicode support tmp = tempfile(fileext = ".png") ragg::agg_png(tmp) plot dev.off() utils::browseURL(tmp) # font and unicode support tmp = tempfile(fileext = ".svg") svglite::svglite(tmp) plot dev.off() utils::browseURL(tmp) # Does not work - "family 'Roboto' not included in postscript() device" # however: names(grDevices::postscriptFonts()) includes Roboto tmp = tempfile(fileext = ".eps") postscript(tmp) plot dev.off() utils::browseURL(tmp) # This does work but rasterises output at low fidelity tmp = tempfile(fileext = ".eps") cairo_ps(tmp) plot dev.off() utils::browseURL(tmp) # This fully works tmp = tempfile(fileext = ".ps") Cairo::CairoPS(tmp) plot dev.off() utils::browseURL(tmp) }
Pulls out a code snippet based on a start and end tags as comments within the code
code_snip( type, filename, startMatches = "START", endMatches = "END", includeStart = FALSE, includeEnd = FALSE, sep = "\n...\n" )
code_snip( type, filename, startMatches = "START", endMatches = "END", includeStart = FALSE, includeEnd = FALSE, sep = "\n...\n" )
type |
the code type |
filename |
the source code file |
startMatches |
a regex that matched start lines |
endMatches |
a regex that matches end lines |
includeStart |
is the regex inclusive of the start line or not |
includeEnd |
is the regex inclusive of the end line or not |
sep |
a seperator |
a text string of the selected code
Pulls out a code snippet based on a vector of start and end lines.
code_snip_by_line(type, filename, starts = 1, ends = Inf, sep = "\n...\n")
code_snip_by_line(type, filename, starts = 1, ends = Inf, sep = "\n...\n")
type |
The code type (as understood by the minted latex plugin) |
filename |
The source code filename |
starts |
a vector of start indices ( as line numbers ) |
ends |
a vector of end indices ( as line numbers ) |
sep |
a seperator |
a formatted string based on the file
Make sure packages available on CRAN are installed
cran(cran_deps)
cran(cran_deps)
cran_deps |
a vector of package names |
nothing
# cran("tidyverse")
# cran("tidyverse")
where the periodicity of the time series is expressed as numbers of days, weeks, months quarters, or years.
cut_date(dates, full_seq = dates, factor = FALSE, ...)
cut_date(dates, full_seq = dates, factor = FALSE, ...)
dates |
a set of dates |
full_seq |
a full sequence of allowable dates as created by 'full_seq_dates()'. Alternatively a vector of dates will some regular periodicity, that will be used as an input for 'full_seq_dates()', if missing this will be derived from the data itself. |
factor |
return the result as an ordered factor with the date ranges as a label. if false this returns a date vector where the date is |
... |
if full_seq is not give, or a plain vector of dates, other options for 'full_seq_dates()' can be set here. E.g. ('fmt="%d/%m/%Y", period="1 week") |
a set of dates, representing the start (or end) of the period the date falls into, where the period is defined by 'full_seq' - which is usually defined by 'full_seq_dates()'
# dates = as.Date(c("2020-01-01","2020-02-01","2020-01-15","2020-02-03",NA)) # fs = full_seq_dates(dates, "2 days") # dates - cut_date(dates, fs) # cut_date(dates,fs,TRUE) # A weekly set of dates: # dates2 = Sys.Date() + floor(stats::runif(50,max=10))*7 # in this specific situation the final date is not truncated because the # input data is seen as an exact match for the whole output period. # cut_date(dates2, fmt = "%d/%b", factor = TRUE) # if the input dates don't line up with the output dates # there may be incomplete coverage of the first and last category. # where the cutting results in short periods. In this # instance the first and last periods are truncated to prevent them # being counted as complete when they are in fact potentially missing a few days worth of data: # cut_date(dates2, fmt = "%d/%b", factor = TRUE, period = "-2 weeks", anchor="sun")
# dates = as.Date(c("2020-01-01","2020-02-01","2020-01-15","2020-02-03",NA)) # fs = full_seq_dates(dates, "2 days") # dates - cut_date(dates, fs) # cut_date(dates,fs,TRUE) # A weekly set of dates: # dates2 = Sys.Date() + floor(stats::runif(50,max=10))*7 # in this specific situation the final date is not truncated because the # input data is seen as an exact match for the whole output period. # cut_date(dates2, fmt = "%d/%b", factor = TRUE) # if the input dates don't line up with the output dates # there may be incomplete coverage of the first and last category. # where the cutting results in short periods. In this # instance the first and last periods are truncated to prevent them # being counted as complete when they are in fact potentially missing a few days worth of data: # cut_date(dates2, fmt = "%d/%b", factor = TRUE, period = "-2 weeks", anchor="sun")
Deals with some annoying issues classifying integer data sets, such as ages, into groups. where you want to specify just the change over points as integers and clearly label the resulting ordered factor.
cut_integer( x, cut_points, glue = "{label}", lower_limit = -Inf, upper_limit = Inf, ... )
cut_integer( x, cut_points, glue = "{label}", lower_limit = -Inf, upper_limit = Inf, ... )
x |
a vector of integer valued numbers, e.g. ages, counts |
cut_points |
a vector of integer valued cut points which define the lower boundaries of conditions |
glue |
a glue spec that may be used to generate a label. It can use {low}, {high}, {next_low}, or {label} as values. |
lower_limit |
the minimum value we should include (this is inclusive for the bottom category) (default -Inf) |
upper_limit |
the maximum value we should include (this is also inclusive for the top category) (default Inf) |
... |
not used |
an ordered factor of the integer
cut_integer(stats::rbinom(20,20,0.5), c(5,10,15)) cut_integer(floor(stats::runif(100,-10,10)), cut_points = c(2,3,4,6), lower_limit=0, upper_limit=10)
cut_integer(stats::rbinom(20,20,0.5), c(5,10,15)) cut_integer(floor(stats::runif(100,-10,10)), cut_points = c(2,3,4,6), lower_limit=0, upper_limit=10)
where the periodicity of the time series is expressed as numbers of days, weeks, months quarters, or years.
cut_time( timepoints, full_seq = timepoints, unit = attr(timepoints, "unit"), day_zero = attr(timepoints, "day_zero"), factor = FALSE, ... )
cut_time( timepoints, full_seq = timepoints, unit = attr(timepoints, "unit"), day_zero = attr(timepoints, "day_zero"), factor = FALSE, ... )
timepoints |
a set of times (defined by count of periods from a zero day - see 'date_to_time()') |
full_seq |
a full sequence of allowable dates as created by 'full_seq_dates()'. Alternatively a vector of dates will some regular periodicity, that will be used as an input for 'full_seq_dates()', if missing this will be derived from the data itself. |
unit |
the unit of the timepoints in terms of "1 week" |
day_zero |
the origin of the timepoints |
factor |
return the result as an ordered factor with the date ranges as a label. if false this returns a date vector where the date is |
... |
if full_seq is not give, or a plain vector of dates, other options for 'full_seq_dates()' can be set here. E.g. ('fmt="%d/%m/%Y", period="1 week") |
a set of dates, representing the start (or end) of the period the date falls into, where the period is defined by 'full_seq' - which is usually defined by 'full_seq_dates()'
#dates = as.Date(c("2020-01-01","2020-02-01","2020-01-15","2020-02-03",NA)) #fs = full_seq_dates(dates, "2 days") #dates - cut_date(dates, fs) #cut_date(dates,fs,TRUE) # A weekly set of dates: # dates2 = Sys.Date() + floor(stats::runif(50,max=10))*7 #times2 = date_to_time(dates2) # in this specific situation the final date is not truncated because the # input data is seen as an exact match for the whole output period. #cut_time(times2, fmt = "%d/%b", factor = TRUE) # if the input dates don't line up with the output dates # there may be incomplete coverage of the first and last category. # where the cutting results in short periods. In this instance # the first and last periods are truncated to prevent them # being counted as complete when they are in fact potentially missing a few days worth of data: #cut_time(times2, fmt = "%d/%b", factor = TRUE, period = "-2 weeks", anchor="sun") #times2 - cut_time(times2, fmt = "%d/%b", factor = FALSE, period = "-2 weeks", anchor="sun")
#dates = as.Date(c("2020-01-01","2020-02-01","2020-01-15","2020-02-03",NA)) #fs = full_seq_dates(dates, "2 days") #dates - cut_date(dates, fs) #cut_date(dates,fs,TRUE) # A weekly set of dates: # dates2 = Sys.Date() + floor(stats::runif(50,max=10))*7 #times2 = date_to_time(dates2) # in this specific situation the final date is not truncated because the # input data is seen as an exact match for the whole output period. #cut_time(times2, fmt = "%d/%b", factor = TRUE) # if the input dates don't line up with the output dates # there may be incomplete coverage of the first and last category. # where the cutting results in short periods. In this instance # the first and last periods are truncated to prevent them # being counted as complete when they are in fact potentially missing a few days worth of data: #cut_time(times2, fmt = "%d/%b", factor = TRUE, period = "-2 weeks", anchor="sun") #times2 - cut_time(times2, fmt = "%d/%b", factor = FALSE, period = "-2 weeks", anchor="sun")
This function encapsulates a excel output file as a destination for data tables. With the output of this function you can add extra data to the supplement as a new sheet, or you can write the spreadsheet to disk. When each data table is written either the table can be written silently or returned so that it is included in a knitr document. This is controlled by 'option("hide.supplementary.tables"=TRUE)'.
data_supplement( ..., filename = "supplementary-material.xlsx", out = ggrrr::outputter(...), nameGlue = "Supplementary Table {index}" )
data_supplement( ..., filename = "supplementary-material.xlsx", out = ggrrr::outputter(...), nameGlue = "Supplementary Table {index}" )
... |
output location options will be passed to outputter(...) to define the location of the file |
filename |
the xlsx filename |
out |
an outputter (defaults to a default outputter ) |
nameGlue |
What will the tables be named |
a list of 2 functions. $add_table(hux, caption, footnote, index), which takes a huxtable, caption, and index a writes the huxtable into a supplementary. $write() which writes the collection of tables to the excel file.
Using a day_zero and a unit specification or a full sequence of dates (see 'full_seq_dates()')
date_to_time( dates, unit = .day_interval(dates), day_zero = getOption("day_zero", "2019-12-29") )
date_to_time( dates, unit = .day_interval(dates), day_zero = getOption("day_zero", "2019-12-29") )
dates |
a vector of dates to convert |
unit |
a specification of the unit of the resulting time series. Will be determined from periodicity of dates if not specified |
day_zero |
the origin of the conversion. Defaults to the beginning of the COVID pandemic |
a sequence of numeric time points as the number of periods since day zero
# DEPRECATED # times = date_to_time(as.Date("2019-12-29")+0:100, "1 week") # dates = time_to_date(times)
# DEPRECATED # times = date_to_time(as.Date("2019-12-29")+0:100, "1 week") # dates = time_to_date(times)
Internal function for drawing watermark on ggplots
## S3 method for class 'watermark' drawDetails(x, recording)
## S3 method for class 'watermark' drawDetails(x, recording)
x |
A grid grob. |
recording |
A logical value indicating whether a grob is being added to the display list or redrawn from the display list. |
a grid object
Widths are based on dataframe or huxtable content ignoring rowspans and potential for wrapping.
fit_col_widths(table)
fit_col_widths(table)
table |
a table to get column content widths for. |
a vector of column widths
library(tidyverse) iris %>% fit_col_widths()
library(tidyverse) iris %>% fit_col_widths()
Which fonts are available on this system without hitting webfonts.
fonts_available(family)
fonts_available(family)
family |
a font family name or names |
the font family name if it can be located or an empty list otherwise
fonts_available(c("Arial","sdfdsfsd"))
fonts_available(c("Arial","sdfdsfsd"))
Convert a vector of observation dates to a ordered sequence of every day in the time series
full_seq_dates(dates, period = "1 day", anchor = "start", fmt = "%d %b")
full_seq_dates(dates, period = "1 day", anchor = "start", fmt = "%d %b")
dates |
a vector of dates, possibly including NA values |
period |
the gap between observations as a number or, a negative number means the resulting sequence defines a end of time periods, a positive defines the beginning. may be an integer number of days, or a text string like '2 weeks', '-1 month', etc. |
anchor |
defines the day of week the periods start or end. either "start", "end", a day of the week, or a date |
fmt |
a strptime formatting string for date range labels. |
a vector of dates for complete between the minimum and maximum of dates, on the day of week of the anchoring date
# full_seq_dates(c("2020-01-01","2020-02-01","2020-01-15","2020-02-01",NA), "2 days")
# full_seq_dates(c("2020-01-01","2020-02-01","2020-01-15","2020-02-01",NA), "2 days")
Generate a full regular timepoint sequence
full_seq_times( timepoints, period = unit, unit = attr(timepoints, "unit"), day_zero = attr(timepoints, "day_zero"), ... )
full_seq_times( timepoints, period = unit, unit = attr(timepoints, "unit"), day_zero = attr(timepoints, "day_zero"), ... )
timepoints |
a set of timepoints relating to data |
period |
the desired interval between time points, e.g. "1 day". negative periods define the intervals as closed on the left |
unit |
the unit of the timepoints in terms of "1 week" |
day_zero |
the origin of the timepoints |
... |
passed to 'full_seq_dates()', paricularly anchor, and fmt, to define the day of week of the new sequence and the format of the labels. |
a complete set of timepoints on the same scale as the original but with potentially different frequency. This will probably involve non integer times
# DEPRECATED # times = date_to_time(as.Date("2019-12-29")+0:100, "1 week") # tmp = full_seq_times(times)
# DEPRECATED # times = date_to_time(as.Date("2019-12-29")+0:100, "1 week") # tmp = full_seq_times(times)
This function examines a dataframe and returns a list of the columns with sub-lists as all the options for factors. This provides programmatic access (and autocomplete) to the values available in a dataframe, and throws and early error if we try and access data by a variable that does not exist.
get_value_sets(df)
get_value_sets(df)
df |
a dataframe to examine |
a list of lists with the column name and the factor levels as list, as a 'checked list'.
Resolves any missing fonts in a ggplot and tries to resolve them against webfont providers (Brick and Google Fonts) locally cacheing them. This function is the default for 'gg_save_as'
gg_find_webfonts(plot)
gg_find_webfonts(plot)
plot |
a ggplot |
a list of css webfont specifications
This is useful if you want to combine a formatted table with a plot in a multi-panel patchwork.
gg_formatted_table( longFormatTable, colWidths = NULL, tableWidthInches = 5.9, font = "Roboto", ... )
gg_formatted_table( longFormatTable, colWidths = NULL, tableWidthInches = 5.9, font = "Roboto", ... )
longFormatTable |
a table - usually converted using as.long_format_table() |
colWidths |
(optional) the relative widths of the columns. |
tableWidthInches |
the maximum desired width of the plot. Text will be scaled to fit this width. |
font |
the default font family |
... |
passed to as.long_format_table if and only if the input is not already in that format. |
a ggplot object containing the table as a ggplot.
Hide the legend of a plot
gg_hide_legend()
gg_hide_legend()
a theme
Hide the x axis of a plot
gg_hide_X_axis()
gg_hide_X_axis()
a theme
Hide the y axis of a plot
gg_hide_Y_axis()
gg_hide_Y_axis()
a theme
Labels like geom_text are in a random unit size which is only mysteriously connected to the size of text on axes
gg_label_size(pts)
gg_label_size(pts)
pts |
label size in points |
a ggplot size aesthetic for labels
Make a plot narrower
gg_narrow(ang = 90)
gg_narrow(ang = 90)
ang |
the angle for the x labels |
a theme
This is a set of styles with a focus on making plots compact, and minimally fussy, and ensuring fonts are consistent between axes and labels. It sets default sizes for line widths and point sizes. It also switched the default png renderer in knitr to 'ragg::ragg_png' to allow for modern font support.
gg_pedantic( lineSize = 0.25, fontSize = 8, font = "Roboto", size = lineSize * 2, ... )
gg_pedantic( lineSize = 0.25, fontSize = 8, font = "Roboto", size = lineSize * 2, ... )
lineSize |
the default line and shape size in ggplot units |
fontSize |
the base font size |
font |
the default font name. |
size |
the size of points (the default size aesthetic) |
... |
passed to 'ggplot2::theme' |
nothing
Make the legend smaller
gg_resize_legend(pointSize = 0.75, textSize = 6, spaceLegend = 0.75)
gg_resize_legend(pointSize = 0.75, textSize = 6, spaceLegend = 0.75)
pointSize |
- the ggplot size of lines or points |
textSize |
- the size in pts of the text |
spaceLegend |
- degree of spacing between items in the scale (defines overall size) |
a theme
Saves a ggplot object to disk at a set physical size. Allows specific maximum dimensions with an optional target aspect ratio to fit into specific configurations for publication. e.g. a half page plot or a third of a 2 column page. Allows output in pdf for journal publication or png for inclusion in documents, and makes sure that the outputs are near identical.
gg_save_as(...)
gg_save_as(...)
... |
Arguments passed on to
|
For maximum cross platform reproducibility we are using the combination of 'systemfonts' for font management, 'svglite' to render the canonical output 'rsvg' to convert that to pdf, and 'ragg' to for bitmap formats. In some situations 'rsvg' fails in which case we fall back to rendering in a headless chrome instance. This rather complicated pipeline ensures modern webfont support, and editable SVG or PDF.
the output is an sensible default object that can be displayed given the context it is called in, for example if knitting an RMarkdown document a link to the png file for embedding, if latex a link to the pdf file.
try({ .gg_pedantic(fontSize = 6) p = ggplot2::ggplot(mtcars, ggplot2::aes(mpg, wt, colour=as.factor(cyl))) + ggplot2::geom_point() # p %>% .gg_save_as(filename="~/tmp/plot_example",maxWidth=4,maxHeight=4) p %>% .gg_save_as(filename=tempfile(),maxWidth=2,maxHeight=1.5) plot = ggplot2::ggplot(ggplot2::diamonds, ggplot2::aes(x=carat,y=price,color = color))+ ggplot2::geom_point()+ ggplot2::annotate("label",x=2,y=10000,label="Hello \u2014 world", family="Kings")+ ggplot2::labs(tag = "A")+ ggplot2::xlab("Carat\u2082")+ ggplot2::ylab("price\u2265") # plot %>% .gg_save_as(filename="~/tmp/plot_example_2") res = plot %>% .gg_save_as(filename=tempfile(), formats=c("png","eps")) as.character(res) res })
try({ .gg_pedantic(fontSize = 6) p = ggplot2::ggplot(mtcars, ggplot2::aes(mpg, wt, colour=as.factor(cyl))) + ggplot2::geom_point() # p %>% .gg_save_as(filename="~/tmp/plot_example",maxWidth=4,maxHeight=4) p %>% .gg_save_as(filename=tempfile(),maxWidth=2,maxHeight=1.5) plot = ggplot2::ggplot(ggplot2::diamonds, ggplot2::aes(x=carat,y=price,color = color))+ ggplot2::geom_point()+ ggplot2::annotate("label",x=2,y=10000,label="Hello \u2014 world", family="Kings")+ ggplot2::labs(tag = "A")+ ggplot2::xlab("Carat\u2082")+ ggplot2::ylab("price\u2265") # plot %>% .gg_save_as(filename="~/tmp/plot_example_2") res = plot %>% .gg_save_as(filename=tempfile(), formats=c("png","eps")) as.character(res) res })
Set the default sizes of lines, points and fonts in ggplot geoms, and text labels in ggplot axes to get a single consistent look and feel.
gg_set_size_defaults( lineSize = 0.5, fontSizePts = 4 + lineSize * 8, font = "Roboto", size = lineSize * 2 )
gg_set_size_defaults( lineSize = 0.5, fontSizePts = 4 + lineSize * 8, font = "Roboto", size = lineSize * 2 )
lineSize |
the width of lines |
fontSizePts |
the size of labels and other on plot text in pts. |
font |
the font family name |
size |
the size of points (the default size aesthetic) |
nothing
library(tidyverse) gg_set_size_defaults(lineSize = 0.25)
library(tidyverse) gg_set_size_defaults(lineSize = 0.25)
Also sets horizontal and vertical alignment correctly, and does top and bottom axes.
gg_set_X_angle(ang = 60)
gg_set_X_angle(ang = 60)
ang |
the angle for the x labels |
a theme
A simple table as a ggplot patchwork object, no customisation allowed
gg_simple_table(df, pts = 8, font = "sans", unwrapped = FALSE)
gg_simple_table(df, pts = 8, font = "sans", unwrapped = FALSE)
df |
the dataframe with the table data. Column names will become headings |
pts |
text size in points |
font |
the font family |
unwrapped |
- set this to TRUE if you want to add to a patchwork and use patchwork::wrap_plots(p,list(table)) |
A gtable object (i.e. a grob) optionally wrapped as a patchwork plot.
if (FALSE) { gg_simple_table(tibble::tibble(x=c(1,2,3),y=c(5,4,3)),pts=10) }
if (FALSE) { gg_simple_table(tibble::tibble(x=c(1,2,3),y=c(5,4,3)),pts=10) }
A ggplot theme with minimal fluff and with the defaults set small.
gg_tiny_theme(baseSize = 8, font = "Roboto")
gg_tiny_theme(baseSize = 8, font = "Roboto")
baseSize |
the size of the base font. |
font |
the font family name |
a ggplot theme
if (interactive()) { ggplot2::ggplot(ggplot2::diamonds, ggplot2::aes(x=carat,y=price,color=color))+ ggplot2::geom_point()+ gg_tiny_theme() }
if (interactive()) { ggplot2::ggplot(ggplot2::diamonds, ggplot2::aes(x=carat,y=price,color=color))+ ggplot2::geom_point()+ gg_tiny_theme() }
Add in a watermark to plots
gg_watermark( lab = "DRAFT", disable = getOption("ggrrr.disable.watermark", default = FALSE) )
gg_watermark( lab = "DRAFT", disable = getOption("ggrrr.disable.watermark", default = FALSE) )
lab |
the watermark label (DRAFT) |
disable |
- global option to disable all watermarks options("ggrrr.disable.watermark"=TRUE) |
a watermark layer
Drop in replacement for 'here' ('here' pkg)
here(..., projRoot = .locate_project())
here(..., projRoot = .locate_project())
... |
the relative path within the project |
projRoot |
the project root - defaults to '.locate_project()' |
a path
try(.here("vignettes"))
try(.here("vignettes"))
If html2pdfr is installed it will use that by default, if not it will fall back to a headless chrome instance.
html_pdf_converter(html, filename, maxWidth, maxHeight)
html_pdf_converter(html, filename, maxWidth, maxHeight)
html |
the html fragment |
filename |
the pdf filename |
maxWidth |
the maximum page width in inches |
maxHeight |
the maximum page height in inches |
nothing called for side effects
Calculate a sensible column and table width for a huxtable based on its content.
hux_auto_widths(hux, target = "html", including_headers = FALSE)
hux_auto_widths(hux, target = "html", including_headers = FALSE)
hux |
the huxtable |
target |
the expected output (could be "docx"/"odt", "xlsx") which are the only options that matter |
including_headers |
Should we try and fit the header contents as well (TRUE) or let those wrap (FALSE). |
the huxtable with the width options set.
Sometimes vanilla bind_rows gets confused.
hux_bind_rows(...)
hux_bind_rows(...)
... |
a list of huxtables |
a single huxtable
The main aim is to get something that works with google docs when you copy and paste.
hux_default_layout( hux, defaultFontSize = 8, defaultFont = "Roboto", headerRows = 1 )
hux_default_layout( hux, defaultFontSize = 8, defaultFont = "Roboto", headerRows = 1 )
hux |
a huxtable object |
defaultFontSize |
default size of font in points (8) |
defaultFont |
the font family name |
headerRows |
the number of rows that are headers |
the formatted huxtable.
library(tidyverse) hux = iris %>% hux_default_layout()
library(tidyverse) hux = iris %>% hux_default_layout()
Insert row at start maintaining format
hux_insert_start(hux, ..., fill = "", colspan = 1)
hux_insert_start(hux, ..., fill = "", colspan = 1)
hux |
a huxtable |
... |
stuff to insert into cells |
fill |
padding for empty cells. |
colspan |
how far to span first inserted cell? |
a huxtable with row inserted at start in the same format
Converts row spanning columns into column spanning header rows making a table narrower but longer. The column that is being moved is retained to allow for the appearance of indentation.
hux_nest_group(t, col = 1)
hux_nest_group(t, col = 1)
t |
the huxtable |
col |
the column index you want to nest into the row above |
a narrower huxtable
depending on the context return the correct format for a document. The basic output here is to use HTML as an output if possible and convert it to an image or a PDF that can then be included into a latex document for example.
hux_save_as(...)
hux_save_as(...)
... |
Arguments passed on to
|
the output depends on if the function is called in a knitr session. It maybe the HTML or a link to the pdf output for example.
try({ hux = iris %>% huxtable::as_hux() %>% huxtable::theme_mondrian(font="Roboto") out = .hux_save_as(hux, tempfile()) # browseURL(out$html) out2 = .hux_save_as(hux, tempfile(), formats=c("pdf","png")) as.character(out2) # The resulting pdf has fonts embedded & is multipage. })
try({ hux = iris %>% huxtable::as_hux() %>% huxtable::theme_mondrian(font="Roboto") out = .hux_save_as(hux, tempfile()) # browseURL(out$html) out2 = .hux_save_as(hux, tempfile(), formats=c("pdf","png")) as.character(out2) # The resulting pdf has fonts embedded & is multipage. })
Set the font family and size in a huxtable globally
hux_set_font(hux, defaultFontSize = 8, defaultFont = "Roboto")
hux_set_font(hux, defaultFontSize = 8, defaultFont = "Roboto")
hux |
a huxtable table |
defaultFontSize |
the desired font size |
defaultFont |
the desired font |
the altered huxtable
A sprintf alternative that handles NA values gracefully (ish)
hux_sprintf(fmt, ..., na.text = "—")
hux_sprintf(fmt, ..., na.text = "—")
fmt |
sprintf format string |
... |
sprintf inputs |
na.text |
an string to replace NA values with. |
a string value
The assumption here is that the input data is a long format tidy dataframe with both rows and columns specified by values of the 'rowGroupVars' and 'colGroupVars' columns. The long format (sparse) table is translated into a nested tree of rows (using 'rowGroupVars') and a nested tree of columns (from 'colGroupVars'). Individual data items are placed in the cell intersecting these two trees. If there are multiple matches an additional layer of grouping is added to the columns.
hux_tidy( tidyDf, rowGroupVars, colGroupVars, missing = "—", na = "—", displayRedundantColumnNames = FALSE, ... )
hux_tidy( tidyDf, rowGroupVars, colGroupVars, missing = "—", na = "—", displayRedundantColumnNames = FALSE, ... )
tidyDf |
A dataframe with row groupings (as a set of columns) and column groupings (as a set of columns) and data, where the data is in a tidy format with a row per "cell" or cell group. |
rowGroupVars |
A dplyr::vars(...) column specification which will define how rows are grouped |
colGroupVars |
A dplyr::vars(...) column specification with defines how columns will be grouped |
missing |
If there is no content for a given rowGroup / colGroup combination then this character will be used as a placeholder |
na |
If there are NA contents then this character will be used. |
displayRedundantColumnNames |
if there is one column per column group the name of that column may be irrelevant (e.g. if there is a 'col_name', 'value' fully tidy format) and 'col_name' is in the 'colGroupVars' list then the name of the column 'value' is redundant and not displayed by default. However sometimes you want to display this if you have named it as something specific e.g. including the units. If there is more than one column per 'colGroup' the column titles are needed and kept. |
... |
passed to 'hux_default_layout()' |
a huxtable table
Useful if you need to include a formatted table in a figure with a plot
hux_to_ggplot(hux, width = 5.9)
hux_to_ggplot(hux, width = 5.9)
hux |
the huxtable |
width |
the desired ggplot width |
a ggplot object of the right width
Create a new data frame including duplicate rows where the rows fulfil a potentially overlapping set of conditions specified as named predicates (as formulae)
intersecting_group_by(.data, ..., .colname)
intersecting_group_by(.data, ..., .colname)
.data |
a data frame |
... |
a set of predicates specified like case_whens syntax, such as mpg < 5 ~ "gas guzzlers" |
.colname |
the name of the new group |
a new dataframe containing the overlapping groups which may create duplicates of individual rows.
library(tidyverse) iris %>% dplyr::group_by(Species) %>% intersecting_group_by( Sepal.Length > mean(Sepal.Length) ~ "Long", Sepal.Width > mean(Sepal.Width) ~ "Wide" )
library(tidyverse) iris %>% dplyr::group_by(Species) %>% intersecting_group_by( Sepal.Length > mean(Sepal.Length) ~ "Long", Sepal.Width > mean(Sepal.Width) ~ "Wide" )
Knit a rendered_plot object
## S3 method for class 'rendered_plot' knit_print(x, options, ...)
## S3 method for class 'rendered_plot' knit_print(x, options, ...)
x |
the rendered_plot |
options |
the chunk options |
... |
not used |
nothing - used for side effects
Knit a rendered_table object
## S3 method for class 'rendered_table' knit_print(x, ...)
## S3 method for class 'rendered_table' knit_print(x, ...)
x |
the rendered_table |
... |
not used |
nothing - used for side effects
used in a knitr preamble to direct the output to a subdirectory of the project — title: "Analysis 1" output: html_document knit: ggrrr::knit_versioned("output/analysis-1") —
knit_versioned( directory = NULL, ..., datedFile = !datedSubdirectory, datedSubdirectory = FALSE )
knit_versioned( directory = NULL, ..., datedFile = !datedSubdirectory, datedSubdirectory = FALSE )
directory |
the root of the output - can be an absolute path or a relative path interpreted as relative to the root of the project. |
... |
ignored |
datedFile |
do you want the filename to have the date appended (defaults TRUE)? |
datedSubdirectory |
do you want the files to be placed in a dated subdirectory (defaults FALSE)? |
This can only work when deployed as a library and hence no standalone version of it exists, because the fully qualified packagename has to be used.
nothing. called for side effects
Perform logit scaling with right axis formatting. To not be used directly but with ggplot (e.g. ggplot2::scale_y_continuous(trans = "logit")
logit_trans(n = 5, ...)
logit_trans(n = 5, ...)
n |
number of breas |
... |
not used |
A scales object
tibble::tibble(pvalue = c(0.001, 0.05, 0.1), fold_change = 1:3) %>% ggplot2::ggplot(ggplot2::aes(fold_change , pvalue)) + ggplot2::geom_point() + ggplot2::scale_y_continuous(trans = "logit")
tibble::tibble(pvalue = c(0.001, 0.05, 0.1), fold_change = 1:3) %>% ggplot2::ggplot(ggplot2::aes(fold_change , pvalue)) + ggplot2::geom_point() + ggplot2::scale_y_continuous(trans = "logit")
The map functions transform their input by applying a function to each element of a list or atomic vector and returning an object of the same length as the input.
map()
always returns a list. See the modify()
family for
versions that return an object of the same type as the input.
map_lgl()
, map_int()
, map_dbl()
and map_chr()
return an
atomic vector of the indicated type (or die trying). For these functions,
.f
must return a length-1 vector of the appropriate type.
map_vec()
simplifies to the common type of the output. It works with
most types of simple vectors like Date, POSIXct, factors, etc.
walk()
calls .f
for its side-effect and returns
the input .x
.
map_struct(.x, .f, ..., .progress = FALSE)
map_struct(.x, .f, ..., .progress = FALSE)
.x |
A list or atomic vector. |
.f |
A function, specified in one of the following ways:
|
... |
Additional arguments passed on to the mapped function. We now generally recommend against using # Instead of x |> map(f, 1, 2, collapse = ",") # do: x |> map(\(x) f(x, 1, 2, collapse = ",")) This makes it easier to understand which arguments belong to which function and will tend to yield better error messages. |
.progress |
Whether to show a progress bar. Use |
a 'struct_list'
These functions are variants of map()
that iterate over two arguments at
a time.
map2_struct(.x, .y, .f, ..., .progress = FALSE)
map2_struct(.x, .y, .f, ..., .progress = FALSE)
.x , .y
|
A pair of vectors, usually the same length. If not, a vector of length 1 will be recycled to the length of the other. |
.f |
A function, specified in one of the following ways:
|
... |
Additional arguments passed on to the mapped function. We now generally recommend against using # Instead of x |> map(f, 1, 2, collapse = ",") # do: x |> map(\(x) f(x, 1, 2, collapse = ",")) This makes it easier to understand which arguments belong to which function and will tend to yield better error messages. |
.progress |
Whether to show a progress bar. Use |
a 'struct_list'
Use a locally checked out version if available.
non_cran(name, github, force = FALSE, subdir = "", ...)
non_cran(name, github, force = FALSE, subdir = "", ...)
name |
the name of the package |
github |
something like "github-repo/project-name" |
force |
will only update a loaded package if TRUE (defaults to FALSE) |
subdir |
if the package is in a subdirectory of the github repo |
... |
passed to devtools::install_github |
nothing
# non_cran("patchwork", "thomasp85/patchwork")
# non_cran("patchwork", "thomasp85/patchwork")
You want to use a function if it is installed but don't want it to be installed as part of your package and you don't want to reference it as part of the Imports or Suggests fields in a package DESCRIPTION.
optional_fn( pkg, name, alt = function(...) { stop("function `", pkg, "::", name, "(...)` not available") } )
optional_fn( pkg, name, alt = function(...) { stop("function `", pkg, "::", name, "(...)` not available") } )
pkg |
the package name |
name |
the function you wish to use |
alt |
a function that can be used instead |
the function you want if available or the alternative
fn = .optional_fn("openssl", "md5", digest::digest) as.character(fn(as.raw(c(1,2,3))))
fn = .optional_fn("openssl", "md5", digest::digest) as.character(fn(as.raw(c(1,2,3))))
This function generates a function that resolves a file path fragment to a specific file location, accounting for a versioning strategy involving the current date. The defaults create a naming strategy that places an file in the "output" sub-directory of the current project with a filename suffix including the date.
outputter( directory = .here("output"), ..., datedFile = !datedSubdirectory, datedSubdirectory = FALSE )
outputter( directory = .here("output"), ..., datedFile = !datedSubdirectory, datedSubdirectory = FALSE )
directory |
the root of the output |
... |
not used must be empty |
datedFile |
do you want the filename to have the date appended? |
datedSubdirectory |
do you want the files to be placed in a dated subdirectory? |
a function that takes a filename and boolean delete parameter. When called with a filename component this function will return the absolute path of a file which is versioned with date. If the file exists and delete=TRUE it is deleted. (allowing for libraries that refuse to overwrite existing files)
out = outputter("~/output",datedSubdirectory=TRUE) out("file.png")
out = outputter("~/output",datedSubdirectory=TRUE) out("file.png")
display a 0-1 scale as 0-100
percent_trans()
percent_trans()
'r lifecycle::badge(stage = "deprecated")'
A scales object
These functions are variants of map()
that iterate over multiple arguments
simultaneously. They are parallel in the sense that each input is processed
in parallel with the others, not in the sense of multicore computing, i.e.
they share the same notion of "parallel" as base::pmax()
and base::pmin()
.
pmap_struct(.l, .f, ..., .progress = FALSE)
pmap_struct(.l, .f, ..., .progress = FALSE)
.l |
A list of vectors. The length of Vectors of length 1 will be recycled to any length; all other elements must be have the same length. A data frame is an important special case of |
.f |
A function, specified in one of the following ways:
|
... |
Additional arguments passed on to the mapped function. We now generally recommend against using # Instead of x |> map(f, 1, 2, collapse = ",") # do: x |> map(\(x) f(x, 1, 2, collapse = ",")) This makes it easier to understand which arguments belong to which function and will tend to yield better error messages. |
.progress |
Whether to show a progress bar. Use |
a 'struct_list'
'r lifecycle::badge("deprecated")'
pmixnorm(q, means, sds, weights = rep(1, length(means)), na.rm = FALSE)
pmixnorm(q, means, sds, weights = rep(1, length(means)), na.rm = FALSE)
q |
vector of quantiles. |
means |
a vector of normal distribution means |
sds |
a vector of normal distribution sds |
weights |
a vector of weights |
na.rm |
remove distributions which have NA for mean or sd |
the pdf of the mixture distribution.
pmixnorm(q=c(2,20), means=c(10,13,14), sds=c(1,1,2), weights=c(2,2,3))
pmixnorm(q=c(2,20), means=c(10,13,14), sds=c(1,1,2), weights=c(2,2,3))
Print a rendered_plot object
## S3 method for class 'rendered_plot' print(x, ...)
## S3 method for class 'rendered_plot' print(x, ...)
x |
the rendered_plot |
... |
not used |
nothing - used for side effects
Print a rendered_table object
## S3 method for class 'rendered_table' print(x, ...)
## S3 method for class 'rendered_table' print(x, ...)
x |
the rendered_table |
... |
not used |
nothing - used for side effects
'r lifecycle::badge("deprecated")'
qmixnorm(p, means, sds, weights = rep(1, length(means)), na.rm = FALSE)
qmixnorm(p, means, sds, weights = rep(1, length(means)), na.rm = FALSE)
p |
vector of probabilities. |
means |
a vector of normal distribution means |
sds |
a vector of normal distribution sds |
weights |
a vector of weights |
na.rm |
remove distributions with NA values for mean or sd |
the value of the yth quantile
qmixnorm(p=c(0.025,0.5,0.975), means=c(10,13,14), sds=c(1,1,2))
qmixnorm(p=c(0.025,0.5,0.975), means=c(10,13,14), sds=c(1,1,2))
This repopulates 'systemfonts' from the webfont cache and then 'extrafont' from 'systemfonts'. This does a full rebuild and will be slow (depending a bit )
rebuild_fonts()
rebuild_fonts()
nothing
This wipes a lot of cached font data.
reset_fonts( confirm = utils::askYesNo(msg = "Are you sure?", default = FALSE), web = FALSE, fonts = FALSE )
reset_fonts( confirm = utils::askYesNo(msg = "Are you sure?", default = FALSE), web = FALSE, fonts = FALSE )
confirm |
set to TRUE to automatically confirm |
web |
also clear webfont cache? (default FALSE) |
fonts |
also clear any downloaded fonts or converted afm files? (default FALSE) |
nothing
Applies an expression to each row and assignes it to a new column. Per-row failures are handled with default values (NAs) or can be intercepted by the user with a tryCatch(...) expression. There are many other ways to do a similar thing in 'dplyr' and 'purrr' but they are all more complicated than I expect them to be.
rowwise_mutate(.data, ..., .onerror = function(e, ...) NA)
rowwise_mutate(.data, ..., .onerror = function(e, ...) NA)
.data |
a dataframe. grouping is ingnored |
... |
a named list of expressions similar to mutate but where the expressions to be evaluated are evaluated in only in the context of the current row - and are not vectorised. This does not support [dplyr::accross] syntax. |
.onerror |
a function that is called for |
a dataframe the same length as input with additional or altered columns
# calculations are scoped only to current row. Hence max(x) == x always: iris %>% rowwise_mutate( widths = Sepal.Width+max(Petal.Width), lengths = Sepal.Length+max(Petal.Length), tmp = tibble::tibble(a=1, b=2)) %>% dplyr::glimpse() # This is different to standard dplyr behaviour when the additional tibble # column is considered. standard dplyr rowwise does something unexpected: iris %>% dplyr::rowwise() %>% dplyr::mutate( widths = Sepal.Width+max(Petal.Width), lengths = Sepal.Length+max(Petal.Length), tmp = tibble::tibble(a=1, b=2)) %>% dplyr::glimpse() # As expressions are not vectorised we can use normal if ... else ... statements # and errors can be handled and default values provided. suppressWarnings( iris %>% rowwise_mutate( tmp = if (Petal.Width > 2.0) stop("error message: ",Petal.Width) else Petal.Width, .onerror = function(e) -Petal.Width ) %>% dplyr::glimpse() ) # The default values # are evaluated in the same context as the original expression, but only are # defaults for all the columns so makes most sense when a default value is given suppressWarnings( iris %>% rowwise_mutate( tmp = if (Petal.Width > 2.0) stop("too wide petals: ",Petal.Width) else Petal.Width, tmp2 = if (Sepal.Width > 4) stop("too wide sepals: ",Sepal.Width) else Sepal.Width, .onerror = function(e) Inf ) %>% dplyr::glimpse() )
# calculations are scoped only to current row. Hence max(x) == x always: iris %>% rowwise_mutate( widths = Sepal.Width+max(Petal.Width), lengths = Sepal.Length+max(Petal.Length), tmp = tibble::tibble(a=1, b=2)) %>% dplyr::glimpse() # This is different to standard dplyr behaviour when the additional tibble # column is considered. standard dplyr rowwise does something unexpected: iris %>% dplyr::rowwise() %>% dplyr::mutate( widths = Sepal.Width+max(Petal.Width), lengths = Sepal.Length+max(Petal.Length), tmp = tibble::tibble(a=1, b=2)) %>% dplyr::glimpse() # As expressions are not vectorised we can use normal if ... else ... statements # and errors can be handled and default values provided. suppressWarnings( iris %>% rowwise_mutate( tmp = if (Petal.Width > 2.0) stop("error message: ",Petal.Width) else Petal.Width, .onerror = function(e) -Petal.Width ) %>% dplyr::glimpse() ) # The default values # are evaluated in the same context as the original expression, but only are # defaults for all the columns so makes most sense when a default value is given suppressWarnings( iris %>% rowwise_mutate( tmp = if (Petal.Width > 2.0) stop("too wide petals: ",Petal.Width) else Petal.Width, tmp2 = if (Sepal.Width > 4) stop("too wide sepals: ",Sepal.Width) else Sepal.Width, .onerror = function(e) Inf ) %>% dplyr::glimpse() )
This is intended to combine with 'scale_fill_subtype' when we want to divide major groupings differently to minor groups
scale_colour_subtype( subclasses, class_colour = "black", subclass_colour = "grey50", na.value = "grey50", aesthetics = "color", ... )
scale_colour_subtype( subclasses, class_colour = "black", subclass_colour = "grey50", na.value = "grey50", aesthetics = "color", ... )
subclasses |
a vector containing the count of the subcategories, e.g. c(2,3,4) defines 3 major categories and a total of 9 sub-categories |
class_colour |
the colour for major group divisions |
subclass_colour |
the colour for sub group divisions |
na.value |
missing value colour |
aesthetics |
this only really makes sense for color scales. |
... |
passed on to ggplot2::discrete_scale() |
a ggplot scale
library(tidyverse) # prep some data: data = ggplot2::diamonds %>% dplyr::mutate(color_cut = sprintf("%s (%s)",color,cut)) %>% dplyr::group_by(color,cut,color_cut) %>% dplyr::count() %>% dplyr::ungroup() %>% dplyr::mutate(color_cut = ordered(color_cut)) # work out the number of subgroups for each group: subgroups = data %>% dplyr::select(color,cut) %>% dplyr::distinct() %>% dplyr::group_by(color) %>% dplyr::count() %>% dplyr::pull(n) # plot as a horizontal stacked bar chart using color brewer as the main # colour axis. N.b. having enough different colours here is important ggplot2::ggplot(data, ggplot2::aes(y=1,x=n, fill=color_cut, color=color_cut))+ ggplot2::geom_bar(stat="identity",orientation = "y")+ ggrrr::scale_fill_subtype(.palette = scales::brewer_pal, palette="Accent", subclasses = subgroups)+ ggrrr::scale_colour_subtype(subclasses=subgroups)+ ggrrr::gg_hide_Y_axis()+ ggrrr::gg_narrow()
library(tidyverse) # prep some data: data = ggplot2::diamonds %>% dplyr::mutate(color_cut = sprintf("%s (%s)",color,cut)) %>% dplyr::group_by(color,cut,color_cut) %>% dplyr::count() %>% dplyr::ungroup() %>% dplyr::mutate(color_cut = ordered(color_cut)) # work out the number of subgroups for each group: subgroups = data %>% dplyr::select(color,cut) %>% dplyr::distinct() %>% dplyr::group_by(color) %>% dplyr::count() %>% dplyr::pull(n) # plot as a horizontal stacked bar chart using color brewer as the main # colour axis. N.b. having enough different colours here is important ggplot2::ggplot(data, ggplot2::aes(y=1,x=n, fill=color_cut, color=color_cut))+ ggplot2::geom_bar(stat="identity",orientation = "y")+ ggrrr::scale_fill_subtype(.palette = scales::brewer_pal, palette="Accent", subclasses = subgroups)+ ggrrr::scale_colour_subtype(subclasses=subgroups)+ ggrrr::gg_hide_Y_axis()+ ggrrr::gg_narrow()
If you have a categorical variable defining colour or fill and it has a natural grouping you can use this to have a colour scale involving major colors defining the major groupings, and these are progressively lightened for each of the subcategories.
scale_fill_subtype( .palette, subclasses, ..., undefined = "#606060", lighten = NA, na.value = "grey50", aesthetics = "fill" )
scale_fill_subtype( .palette, subclasses, ..., undefined = "#606060", lighten = NA, na.value = "grey50", aesthetics = "fill" )
.palette |
the palette for the major groupings, either as a function e.g. 'scales::viridis_pal', or as a manual set of colors e.g. 'c("#FF0000","#00FF00","#0000FF")'. if a function can be either discrete or continuous palette. |
subclasses |
a vector containing the count of the subcategories, e.g. c(2,3,4) defines 3 major categories and a total of 9 sub-categories |
... |
additional options to be passed to the major palette function, e.g. 'option="magma"', or to 'ggplot2::discrete_scale()', e.g. 'alpha=0.5' |
undefined |
If the number of sub-categories in the data is longer than defined in 'subclasses', the extra categories are assumed to be an set of "other" categories, which will be coloured using this base colour |
lighten |
The factor by which to lighten the colour at each step of the subgrouping. If left blank this will calculate a fraction based on the number of levels of the subgroup. Otherwise if, e.g. 0.5 the first sub category will be the full saturation, the second 0.5 saturation, the third 0.25 saturation, the fourth 0.125 and so on. |
na.value |
what colour for NA values. |
aesthetics |
this is a fill scale by default but can be used for colour by setting this to "color" or both as c("fill","color") |
a ggplot scale
library(tidyverse) # prep some data: data = ggplot2::diamonds %>% dplyr::mutate(color_cut = sprintf("%s (%s)",color,cut)) %>% dplyr::group_by(color,cut,color_cut) %>% dplyr::count() %>% dplyr::ungroup() %>% dplyr::mutate(color_cut = ordered(color_cut)) # work out the number of subgroups for each group: subgroups = data %>% dplyr::select(color,cut) %>% dplyr::distinct() %>% dplyr::group_by(color) %>% dplyr::count() %>% dplyr::pull(n) # plot as a horizontal stacked bar chart using color brewer as the main # colour axis. N.b. having enough different colours here is important ggplot2::ggplot(data, ggplot2::aes(y=1,x=n, fill=color_cut, color=color_cut))+ ggplot2::geom_bar(stat="identity",orientation = "y")+ scale_fill_subtype(.palette = scales::brewer_pal, palette="Accent", subclasses = subgroups)+ scale_colour_subtype(subclasses=subgroups)+ gg_hide_Y_axis()+ gg_narrow()
library(tidyverse) # prep some data: data = ggplot2::diamonds %>% dplyr::mutate(color_cut = sprintf("%s (%s)",color,cut)) %>% dplyr::group_by(color,cut,color_cut) %>% dplyr::count() %>% dplyr::ungroup() %>% dplyr::mutate(color_cut = ordered(color_cut)) # work out the number of subgroups for each group: subgroups = data %>% dplyr::select(color,cut) %>% dplyr::distinct() %>% dplyr::group_by(color) %>% dplyr::count() %>% dplyr::pull(n) # plot as a horizontal stacked bar chart using color brewer as the main # colour axis. N.b. having enough different colours here is important ggplot2::ggplot(data, ggplot2::aes(y=1,x=n, fill=color_cut, color=color_cut))+ ggplot2::geom_bar(stat="identity",orientation = "y")+ scale_fill_subtype(.palette = scales::brewer_pal, palette="Accent", subclasses = subgroups)+ scale_colour_subtype(subclasses=subgroups)+ gg_hide_Y_axis()+ gg_narrow()
A log1p x scale
scale_x_log1p(..., n = 5, base = 10, sf = 2)
scale_x_log1p(..., n = 5, base = 10, sf = 2)
... |
Other arguments passed on to |
n |
the number of major breaks |
base |
the base for the logarithm |
sf |
significant figures |
a ggplot scale
A logit x scale
scale_x_logit(..., n = 5, sf = 2)
scale_x_logit(..., n = 5, sf = 2)
... |
Other arguments passed on to |
n |
the number of major breaks |
sf |
significant figures |
a ggplot scale
A percentage x scale
scale_x_percent(..., sf = 2)
scale_x_percent(..., sf = 2)
... |
Other arguments passed on to |
sf |
significant figures |
a ggplot scale
A log1p y scale
scale_y_log1p(..., n = 5, base = 10, sf = 2)
scale_y_log1p(..., n = 5, base = 10, sf = 2)
... |
Other arguments passed on to |
n |
the number of major breaks |
base |
the base for the logarithm |
sf |
significant figures |
a ggplot scale
A logit y scale
scale_y_logit(..., n = 5, sf = 2)
scale_y_logit(..., n = 5, sf = 2)
... |
Other arguments passed on to |
n |
the number of major breaks |
sf |
significant figures |
a ggplot scale
tibble::tibble(pvalue = c(0.001, 0.05, 0.1), fold_change = 1:3) %>% ggplot2::ggplot(ggplot2::aes(fold_change , pvalue)) + ggplot2::geom_point() + scale_y_logit(n=8)
tibble::tibble(pvalue = c(0.001, 0.05, 0.1), fold_change = 1:3) %>% ggplot2::ggplot(ggplot2::aes(fold_change , pvalue)) + ggplot2::geom_point() + scale_y_logit(n=8)
A percentage y scale
scale_y_percent(..., sf = 2)
scale_y_percent(..., sf = 2)
... |
Other arguments passed on to |
sf |
significant figures |
a ggplot scale
tibble::tibble(pvalue = c(0.001, 0.05, 0.1), fold_change = 1:3) %>% ggplot2::ggplot(ggplot2::aes(fold_change , pvalue)) + ggplot2::geom_point() + scale_y_percent()
tibble::tibble(pvalue = c(0.001, 0.05, 0.1), fold_change = 1:3) %>% ggplot2::ggplot(ggplot2::aes(fold_change , pvalue)) + ggplot2::geom_point() + scale_y_percent()
A variant of sprintf that work well with inputs that are in the format of a list. Good examples of which are the quantile functions
sprintf_list(format, params, na.replace = "―")
sprintf_list(format, params, na.replace = "―")
format |
the format string |
params |
the inputs as a list (rather than as a set of individual numbers) |
na.replace |
a value to replace NA values with. |
the formatted string
# generate a mixture confidence interval from a set of distributions sprintf_list("%1.2f [%1.2f\u2013%1.2f]", qmixnorm(p=c(0.5,0.025,0.975), means=c(10,13,14), sds=c(1,1,2)))
# generate a mixture confidence interval from a set of distributions sprintf_list("%1.2f [%1.2f\u2013%1.2f]", qmixnorm(p=c(0.5,0.025,0.975), means=c(10,13,14), sds=c(1,1,2)))
The width and height of images to fit scientific publication standards.
std_size
std_size
A list with width and height in inches
Unlike 'purrr::list_flatten' this is recursive for one reason which is that a 'struct_list' must only contain 'structs'.
struct_flatten(x)
struct_flatten(x)
x |
a potentially nested list of 'struct_lists'. |
a flat 'struct_list' of 'structs'
These functions allow generic list behaviour.
## S3 method for class 'struct_list' c(...) ## S3 method for class 'struct_list' rep(x, ...) ## S3 method for class 'struct_list' x$y ## S3 method for class 'struct_list' x[...] ## S3 replacement method for class 'struct_list' x[...] <- value ## S3 method for class 'struct_list' x[[...]] ## S3 replacement method for class 'struct_list' x[[...]] <- value
## S3 method for class 'struct_list' c(...) ## S3 method for class 'struct_list' rep(x, ...) ## S3 method for class 'struct_list' x$y ## S3 method for class 'struct_list' x[...] ## S3 replacement method for class 'struct_list' x[...] <- value ## S3 method for class 'struct_list' x[[...]] ## S3 replacement method for class 'struct_list' x[[...]] <- value
... |
generic support |
x |
a 'struct_list' |
y |
item to retrieve |
value |
the value |
a 'struct_list' with all the items
c(struct_list)
: Repeat a 'struct_list'
rep(struct_list)
: Repeat a 'struct_list'
$
: Subset a 'struct_list'
[
: Subset a 'struct_list'
`[`(struct_list) <- value
: Assign a subset to a 'struct_list'
[[
: get a value from a 'struct_list'
`[[`(struct_list) <- value
: set a single value in a 'struct_list'
x = struct(a=1,b=2,c=1:3,.class="test") y = struct(a=4,b=5,c=1:3,.class="test") z= tibble::tibble(a= 1:10, b=rep(c(x,y),5)) z$b c(x,y) c(rep(x,5),y) class(c(rep(x,5),rep(y,5))[[1]]) as.struct_list(list(x,y)) #' x = struct(a=1,b=2,c=1:3,.class="test") class(rep(c(x,y),5)[[1]]) == "test" class(rep(x,5)) a = (rep(c(x,y),5)) a[[1]] = y a
x = struct(a=1,b=2,c=1:3,.class="test") y = struct(a=4,b=5,c=1:3,.class="test") z= tibble::tibble(a= 1:10, b=rep(c(x,y),5)) z$b c(x,y) c(rep(x,5),y) class(c(rep(x,5),rep(y,5))[[1]]) as.struct_list(list(x,y)) #' x = struct(a=1,b=2,c=1:3,.class="test") class(rep(c(x,y),5)[[1]]) == "test" class(rep(x,5)) a = (rep(c(x,y),5)) a[[1]] = y a
Summarise and include a total row, or a row including the summary for the whole group, into a factor list. This looks and feels like a natural summarisation step, but applies the summarisation both to the subgroups and to the data ungrouped by one level. The additional group result is included as a new row. allows for a natural grouped and ungrouped summarisation
summarise_with_totals( .data, ..., .groups = NULL, .total = "Total", .total_first = FALSE )
summarise_with_totals( .data, ..., .groups = NULL, .total = "Total", .total_first = FALSE )
.data |
a dataframe |
... |
the summarisation specification |
.groups |
what to do with the grouping after summarisation (same as dplyr::summarise) |
.total |
name of the total row which will be added into a factor list. |
.total_first |
should the total be before or after the groups |
a summarised dataframe with the additional totals or group row
library(tidyverse) diamonds %>% dplyr::group_by(color,cut) %>% summarise_with_totals( mpg = sprintf("%1.1f \u00B1 %1.1f", mean(price), stats::sd(price)), .total = "Overall" )
library(tidyverse) diamonds %>% dplyr::group_by(color,cut) %>% summarise_with_totals( mpg = sprintf("%1.1f \u00B1 %1.1f", mean(price), stats::sd(price)), .total = "Overall" )
Convert a set of timepoints to dates
time_to_date( timepoints, unit = attr(timepoints, "unit"), day_zero = getOption("day_zero", "2019-12-29") )
time_to_date( timepoints, unit = attr(timepoints, "unit"), day_zero = getOption("day_zero", "2019-12-29") )
timepoints |
a set of numeric time points |
unit |
the period / unit of the time points, which will be extracted from timepoints if possible |
day_zero |
the zero day of the time series, will be extracted from timepoints if possible |
a vector of dates
# DEPRECATED # times = date_to_time(as.Date("2019-12-29")+0:100, "1 week") # dates = time_to_date(times)
# DEPRECATED # times = date_to_time(as.Date("2019-12-29")+0:100, "1 week") # dates = time_to_date(times)
reboot a library reloading from a local development copy if it exists locally alternatively get the most up to date github package.
unstable(pkg = "ggrrr", org = "terminological")
unstable(pkg = "ggrrr", org = "terminological")
pkg |
the package to load the unstable version of |
org |
the github organisation |
nothing
# ggrrr::unstable()
# ggrrr::unstable()