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.
.x
is considered a vector if:.x
is not a data.frame.x
is not a bare list.x
is 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
.x
is an empty logical vector.- .t
[function / list]
Vectorized test functions that indicate which elements of
.x
to conditionally format..t
may be:A named function, e.g.
is.na
An anonymous function, e.g.
\(x) 0 <= x & x <= 1
A purrr-style lambda, e.g.
~ nchar(.x) > 0
,~ .h == 1
,~ TRUE
A list of functions or lambdas, e.g.
list(~ .x < mean(.x), is.finite)
Each function in
.t
will receive.x
as it's input and must return a logical vector the same length as.x
or of length 1 (in which case the result will be recycled to the length of.x
).By default
.t
is the functionfalse()
which returnsFALSE
for any input. You can modify this default by setting thevlightr.default_test
inoptions()
.- .f
[function / list]
Vectorized character manipulation functions used to format
.x
..f
may 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
.f
will 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
.f
is 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_formatter
inoptions()
.- ...
[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.t
and.f
arguments ofhighlight()
. The ith dot..i
is 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:10
corresponds to.x == 10
,"Word"
to.x == "Word"
NaN
corresponds tois.nan(.x)
NA
corresponds 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.x
is 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
NA
values 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.x
can be conditionally formatted at most once. Each element of.x
is formatted using the formatter corresponding to the first test which returnsTRUE
for 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