Skip to contents

{vlightr} (read, “vector-highlighter”) makes it easy to identify elements of interest in a vector printed to the console. It implements a <vlightr_highlight> vector superclass which enhances the format() and print() methods of generic vectors, allowing you to specify a custom conditional formatting method for (almost) any vector type.

Installation

⚠️ This package is still under construction. ⚠️

You can install the development version of vlightr from GitHub with:

# install.packages("devtools")
devtools::install_github("EthanSansom/vlightr")

Features

library(vlightr)
library(dplyr, warn.conflicts = FALSE)

Want to identify an element of a vector? Highlight it with highlight().

x <- c(1, 8, 12, 4, 2)
maximum_hl <- vlightr::highlight(x, .t = ~ .x == max(.x))
print(maximum_hl)
#> <highlight<double>[5]>
#> [1] 1  8  12 4  2

Highlighted elements change as the highlighted vector changes, so you won’t lose them.

# `hl()` is shorthand for `highlight()`
sort(maximum_hl + vlightr::hl(10))
#> <highlight<double>[5]>
#> [1] 11 12 14 18 22

Highlighted vectors can be used as tibble::tibble() columns too.

iris |>
  as_tibble() |>
  mutate(
    species = vlightr::highlight_mult(
      Species,
      "setosa" ~ vlightr::color("purple"),
      "versicolor" ~ vlightr::color("violet"),
      "virginica" ~ vlightr::color("pink")
    )
  ) |>
  group_by(species) |>
  summarize(
    avg_petal_length = vlightr::highlight(mean(Petal.Length), ~ .x == max(.x)),
    avg_sepal_width = vlightr::highlight(mean(Sepal.Width), ~ .x == max(.x))
  ) |>
  ungroup()
#> # A tibble: 3 × 3
#>      species avg_petal_length avg_sepal_width
#>    <hl<fct>>        <hl<dbl>>       <hl<dbl>>
#> 1     setosa            1.462           3.428
#> 2 versicolor            4.260           2.770
#> 3  virginica            5.552           2.974

Are you (or your boss) having a hard time finding that row you’re looking for? Use templight() to temporarily highlight a vector by index.

mtcars |>
  as_tibble(rownames = "make") |>
  mutate(across(everything(), ~ vlightr::templight(.x, make == "Datsun 710"))) |>
  select(make, mpg, disp, vs) |>
  head(5)
#> # A tibble: 5 × 4
#>                make        mpg       disp         vs
#>          <vlghtr_t> <vlghtr_t> <vlghtr_t> <vlghtr_t>
#> 1         Mazda RX4       21.0        160          0
#> 2     Mazda RX4 Wag       21.0        160          0
#> 3        Datsun 710       22.8        108          1
#> 4    Hornet 4 Drive       21.4        258          1
#> 5 Hornet Sportabout       18.7        360          0

You can apply multiple conditional formats to a vector using highlight_mult(). The left-hand-side is you a test function or a literal value that you want to match and the right-hand-side is your formatter function.

indicator <- vlightr::highlight_mult(
    c(1, 0, 1, 0, 0, NA, 5),
    is.na ~ vlightr::color("red"),
    0 ~ vlightr::label("No"),
    1 ~ vlightr::label("Yes"),
    !(.x %in% c(NA, 0, 1)) ~ paste(.x, "[?]")
)
print(indicator)
#> <highlight<double>[7]>
#> [1] 1 [Yes] 0 [No]  1 [Yes] 0 [No]  0 [No]  NA      5 [?]

Simplify the code above using highligh_case(), which provides a dplyr::case_when() style interface and conditionally formats elements using at most one formatter.

indicator <- vlightr::highlight_case(
    c(1, 0, 1, 0, 0, NA, 5),
    is.na ~ vlightr::color("red"),
    0 ~ vlightr::label("No"),
    1 ~ vlightr::label("Yes"),
    vlightr::true ~ paste(.x, "[?]") # Provide a default formatter
)
print(indicator)
#> <highlight_case<double>[7]>
#> [1] 1 [Yes] 0 [No]  1 [Yes] 0 [No]  0 [No]  NA      5 [?]

If you want to re-use a highlight, make a highlighter() and friends.

indicator_highlighter <- vlightr::highlighter_case(
    is.na ~ vlightr::color("red"),
    0 ~ vlightr::label("No"),
    1 ~ vlightr::label("Yes"),
    vlightr::true ~ paste(.x, "[?]")
)
indicator_highlighter(c(0, 1, NA, -9))
#> <highlight_case<double>[4]>
#> [1] 0 [No]  1 [Yes] NA      -9 [?]

Inspiration

The development of {vlightr} relied heavily on the following pacakges:

This package is also heavily inspired by the ivs package, which (also powered by vctrs) implements generic right-open intervals defined by a pair of parallel start and end vectors.

As a testament to the genericity of the <ivs_iv>, here is an ill-advised but perfectly legal interval vector.

library(ivs)

# Prepare highlighted numeric start and end vectors
starts <- vlightr::highlight(-3:2, ~ .x %% 2 == 0, ~ label("Even"))
ends <- vlightr::highlight(c(-2, -1, 2, 5, 7, 8), ~ .x > 0, ~ paste0("+", .x))

# Make an iv() with highlighted `starts` and `ends`
iv(starts, ends)
#> <iv<highlight<double>>[6]>
#> [1] [-3, -2 [Even])        [-2 [Even], -1)        [-1, +2 [Even])
#> [4] [0 [Even], +5)         [+1, +7)               [+2 [Even], +8 [Even])

The interval vector can be manipulated as you’d expect.

iv_groups(iv(starts, ends))
#> <iv<highlight<double>>[1]>
#> [1] [-3, +8 [Even])

And the interval vector can itself be highlighted.

vlightr::highlight(
  iv(starts, ends), 
  ~ (iv_end(.x) - iv_start(.x)) > hl(1),
  vlightr::color("goldenrod")
)
#> <highlight<iv<highlight<double>>>[6]>
#> [1] [-3, -2 [Even])        [-2 [Even], -1)        [-1, +2 [Even])
#> [4] [0 [Even], +5)         [+1, +7)               [+2 [Even], +8 [Even])