highlight() creates a vector with a conditional format()
and print() method. The function takes an input vector .x, a test
function .t, and a formatter function .f. When the result of
highlight(.x, .t, .f) is printed, elements of .x for which .t returns
TRUE are transformed by .f before they are printed.
.t and .f may be equal length lists of functions. Elements of .x for
which .t[[i]] returns true are transformed using .f[[i]]. Conditional
formats are applied to the highlighted vector in the order that they are
applied to .t and .f.
highlight_mult() and highlight_case() allow these pairs of functions to
be supplied as two-sided formulas .t ~ .f using dplyr::case_when()
style syntax.
hl() and highlight() are synonyms, as are hl_mult() and
highlight_mult(), hl_case() and highlight_case().
Usage
highlight(
.x = logical(),
.t = getOption("vlightr.default_test"),
.f = getOption("vlightr.default_formatter")
)
hl(
.x = logical(),
.t = getOption("vlightr.default_test"),
.f = getOption("vlightr.default_formatter")
)
highlight_mult(.x, ...)
hl_mult(.x, ...)
highlight_case(.x, ...)
hl_case(.x, ...)Arguments
- .x
[vector]A vector to highlight. Conceptually, a vector is a collection of objects of size 1.
.xis considered a vector if:.xis not a data.frame.xis not a bare list.xis otherwise a vector, as defined byvctrs::obj_is_vector()
Atomic vector types
"logical","integer","double","complex","character", and"raw"meet these criteria. As do many common vector classes such asPOSIXct,lubridate::interval, orivs::iv.By default
.xis an empty logical vector.- .t
[function / list]Vectorized test functions that indicate which elements of
.xto conditionally format..tmay be:A named function, e.g.
is.naAn anonymous function, e.g.
\(x) 0 <= x & x <= 1A purrr-style lambda, e.g.
~ nchar(.x) > 0,~ .h == 1,~ TRUEA list of functions or lambdas, e.g.
list(~ .x < mean(.x), is.finite)
Each function in
.twill receive.xas it's input and must return a logical vector the same length as.xor of length 1 (in which case the result will be recycled to the length of.x).By default
.tis the functionfalse()which returnsFALSEfor any input. You can modify this default by setting thevlightr.default_testinoptions().- .f
[function / list]Vectorized character manipulation functions used to format
.x..fmay be:A named function, e.g. cli::style_bold
An anonymous function, e.g.
\(words) gsub("hi", "hey", words)A purrr-style lambda, e.g.
~ paste0(.h, "!"),~ "fizz"A list of functions or lambdas, e.g.
list(~ cli::col_red(.x), toupper)
Each formatter function in
.fwill receive a character vector (of variable length) as it's only argument. A formatter must return a character vector the same length as it's input or of length 1 (in which case the result is recycled to the length of the input character).ANSI string vectors (class
cli_ansi_string) are also supported (see cli::ansi-styles for details).By default
.fis the function[cli::bg_br_yellow()]which changes the background color of it's input text to bright yellow. You can modify this default by setting thevlightr.default_formatterinoptions().- ...
[formula / vlightr_highlighter]For
highlighter_mult()andhighlighter_case(), a two sided formula with a test on the left-hand-side and a formatter on the right-hand-side. This argument replaces the.tand.farguments ofhighlight(). The ith dot..iis roughly equivalent to.t[[i]] ~ .f[[i]].The left-hand-side and right-hand-side of the formula may be:
A named function, e.g.
is.numeric, cli::style_boldAn anonymous function, e.g.
\(x) is.nan(x),\(x) ifelse(x == "", "empty", x)A purrr-style lambda expression, e.g.
paste0(.h, "?"),"fizzbuzz"
Additionally, the left-hand-side of the formula may be a scalar atomic object, supplied by name e.g.
1,NaN,"Hello". This is a shorthand for a test of equality. For example:10corresponds to.x == 10,"Word"to.x == "Word"NaNcorresponds tois.nan(.x)NAcorresponds tois.na(.x),NA_int_tois.na(.x) & is.integer(.x)
A one-sided formula (e.g.
~ tolower) may also be supplied, in which case every element of.xis formatted using the right-hand-side function (e.g.tolower).Finally, a highlighter, e.g.
highlighter(is.na, color("red")), may be supplied instead of a formula. Every test (e.g..t) and formatter (e.g..f) associated with the highlighter is inserted as a test and formatter of the returned vector.Examples of arguments to
...include:Color
NAvalues red:is.na ~ color("red")Add an exclamation mark:
toupper(.x) == .x ~ paste0(.x, "!")Label the number 1 as "Yes":
1 ~ "Yes"Color the background yellow by default:
~ cli::cli_bg_yellow(.x)
In the case of
highlight_case(), elements of.xcan be conditionally formatted at most once. Each element of.xis formatted using the formatter corresponding to the first test which returnsTRUEfor that element.
Value
A vector of class vlightr_highlight. For highlight_case(), the a
vector of class vlightr_highlight/vlightr_highlight_case.
Details
The highlighter_mult() and highlight_case() formula syntax can conflict
with dplyr::across() in-lined formulas and other purrr-style-lambdas. In
particular, when the following is executed:
The formula is.na(.x) ~ color("red") will be replaced with
is.na(y) ~ color("red") by dplyr::across(). When the expression is.na(col)
is converted to a test function by highlight_mult(), the object col will
not exist in the environment of the test function, causing an error (or worse,
a difficult to diagnose bug) when the test function is called.
To avoid this behavior, vlightr allows the use of .h in it's
purrr-style-lambdas. Replacing is.na(.x) with is.na(.h), as in the
following snippet, will work as expected:
All purrr-style-lambdas used by vlightr accept the symbols .x, .h, and .
as aliases for their first argument.
See also
templight() for conditionally formatting elements of a vector .x
by location. Replaces the test .t with a vector of positions .at.
is_highlightable() for testing whether an object can be highlighted.
un_highlight() for converting a vector highlight(.x) back to .x.
tests(), formatters(), highlight_functions() for setting and
getting the values of .t (i.e. tests) and .f (i.e. formatters) of a
highlighted vector.
color() and friends for generating formatter functions for use in .f.
Examples
# Emphasize NA values when `x_hl` is printed
x <- c(1, 0, NA, 1, 0)
x_hl <- highlight(x, is.na, ~paste("[", .x, "]"))
print(x)
#> [1] 1 0 NA 1 0
print(x_hl)
#> <highlight<double>[5]>
#> [1] 1 0 [ NA ] 1 0
# Track the maximum of `values`
values <- highlight(c(1, 5, 7, 3), ~ .x == max(.x), wrap("[", "]"))
print(values)
#> <highlight<double>[4]>
#> [1] 1 5 [7] 3
print(sort(values))
#> <highlight<double>[4]>
#> [1] 1 3 5 [7]
print(hl(-1) * values)
#> <highlight<double>[4]>
#> [1] [-1] -5 -7 -3
# Add labels to an indicator variable
indicator <- highlight_mult(
c(0, 1, NA, 5),
0 ~ label("No"),
1 ~ label("Yes"),
is.na ~ color("red"),
!(.x %in% c(0, 1, NA)) ~ label("?")
)
print(indicator)
#> <highlight<double>[4]>
#> [1] 0 [No] 1 [Yes] NA 5 [?]
# Simplify using `dplyr::case_when()` style case matching.
# Elements are conditionally formatted using the first case
# where the left-hand-side returns `TRUE`.
indicator <- highlight_case(
c(0, 1, NA, 5),
0 ~ label("No"),
1 ~ label("Yes"),
is.na ~ color("red"),
true ~ label("?") # `true()` is a function which returns `TRUE`
)
print(indicator)
#> <highlight_case<double>[4]>
#> [1] 0 [No] 1 [Yes] NA 5 [?]
# Make a `highlighter()` to add the formatting of `indicator`
# to other vectors.
indicator_highlighter <- as_highlighter(indicator)
indicator_highlighter(c(1, 0, 1, NA, -9))
#> <highlight_case<double>[5]>
#> [1] 1 [Yes] 0 [No] 1 [Yes] NA -9 [?]
# A highlighter can be supplied to `highlight_mult()` or
# `highlight_case()`. This is an easy way to append new
# options to an existing highlighter.
highlight_case(
c(1, 2, 0, NA, -9),
2 ~ label("Maybe"),
indicator_highlighter
)
#> <highlight_case<double>[5]>
#> [1] 1 [Yes] 2 [Maybe] 0 [No] NA -9 [?]
# Apply multiple formats to the same element
highlight_mult(
1:6,
.x %% 2 == 0 ~ wrap("<", ">"),
.x >= 3 ~ wrap("[", "]")
)
#> <highlight<integer>[6]>
#> [1] 1 <2> [3] [<4>] [5] [<6>]
# Apply a formatter to every element of `.x` by
# supplying a one-sided formula.
upper_letters <- highlight_mult(letters[1:10], ~ toupper)
print(upper_letters)
#> <highlight<character>[10]>
#> [1] "A" "B" "C" "D" "E" "F" "G" "H" "I" "J"
# Note that highlighting does not alter the underlying data
un_highlight(upper_letters)
#> [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
# A one-sided formula supplied to `highlight_case()` will
# format all elements, even if they have already been formatted,
# over-riding the default matching behavior.
highlight_case(
c(1, 1, 0),
0 ~ "No",
1 ~ "Yes",
~ toupper # `true ~ toupper` wouldn't format any elements
)
#> <highlight_case<double>[3]>
#> [1] YES YES NO
# By default no formatting is applied to a highlighted vector.
highlight(1:5) # No conditional formatting
#> <highlight<integer>[5]>
#> [1] 1 2 3 4 5
# The default formatter `.f` colors the background of the
# formatted vector yellow. If you are reading this is in
# an environment which doesn't support ANSI coloring, you
# may not see the yellow background.
highlight(1:5, ~ .x > 3) # Yellow background
#> <highlight<integer>[5]>
#> [1] 1 2 3 4 5
# Change the default test or formatter using `options()`
opts <- options() # Save previous options
options(vlightr.default_formatter = \(x) paste("{", x, "}"))
highlight(-2:2, ~ .x < 0)
#> <highlight<integer>[5]>
#> [1] { -2 } { -1 } 0 1 2
options(vlightr.default_test = \(x) x > 0)
highlight(-2:2)
#> <highlight<integer>[5]>
#> [1] -2 -1 0 { 1 } { 2 }
options(opts) # Reset previous options