Overview
A high-level overview of the functions and styling customization options available in {reactablefmtr}.
Titles and Sources
A title, subtitle, and source can be added to any reactable table
using add_title()
, add_subtitle()
, and
add_source()
respectively. There are several built-in
formatters available, such as the ability to change the font size, font
color, font style, and margin.
library(palmerpenguins)
reactable(penguins) %>%
add_title(
title = 'Palmer Penguins'
) %>%
add_subtitle(
subtitle = 'Palmer Archipelago (Antarctica) penguin data',
font_size = 20,
font_color = '#666666',
margin = reactablefmtr::margin(t=10,r=0,b=15,l=0)
) %>%
add_source(
source = 'Authors: Allison Marie Horst, Alison Presmanes Hill, and Kristen B Gorman',
font_style = 'italic',
font_weight = 'bold'
)
Palmer Penguins
Palmer Archipelago (Antarctica) penguin data
Authors: Allison Marie Horst, Alison Presmanes Hill, and Kristen B Gorman
Inserting images and icons
You can also parse HTML with reactablefmtr::html()
. This
allows for the ability to add images and clickable links within the
title and source as shown below:
reactable(penguins) %>%
add_title(
title = reactablefmtr::html("Palmer Penguins <img src='https://raw.githubusercontent.com/allisonhorst/palmerpenguins/master/man/figures/lter_penguins.png' alt='Palmer Penguins' width='200' height='110'>")
) %>%
add_subtitle(
subtitle = 'Palmer Archipelago (Antarctica) penguin data',
font_size = 20,
font_color = '#666666',
margin = reactablefmtr::margin(t=10,r=0,b=15,l=0)
) %>%
add_source(
source = reactablefmtr::html("<i class='fas fa-book'></i> Authors: Allison Marie Horst, Alison Presmanes Hill, and Kristen B Gorman <br> <i class='fas fa-palette'></i> Artwork by @allison_horst "),
font_style = 'italic',
font_weight = 'bold'
) %>%
add_source(
source = html("<i class='fas fa-link'></i> Link to package: <a href='https://allisonhorst.github.io/palmerpenguins/'>{palmerpenguins}</a>"),
font_style = 'italic',
font_weight = 'bold'
)
Palmer Penguins
Palmer Archipelago (Antarctica) penguin data
Authors: Allison Marie Horst, Alison Presmanes Hill, and Kristen B Gorman
Artwork by @allison_horst
Link to package: {palmerpenguins}
Themes
There are over 20 themes available within {reactablefmtr} that can be
applied simply within reactable::theme
.
There are additional styling options within each theme that allows you to change the font color and font size of both the body of the table and the header, as shown below in the NY Times-inspired table:
Another important feature within each theme is the ability to
vertically center the values within each row. By default, {reactable}
tables display the values towards the top of each cell. To center the
values, include centered = TRUE
within the theme
options:
FiveThirtyEight
penguins %>%
reactable(theme = fivethirtyeight())
Bubble grids
Bubble grid charts can easily be created with the
bubble_grid()
function:
penguins %>%
group_by(species, sex) %>%
summarize(across(where(is.numeric), mean, na.rm = TRUE)) %>%
select(-year) %>%
reactable(
defaultColDef = colDef(
align = 'center',
cell = bubble_grid(
data = .,
number_fmt = scales::comma
)
)
)
Adjust size of bubbles
Adjust the size of the bubbles using min_value
and/or
max_value
:
# load bee colony stressor dataset from tidy tuesday
stressor <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2022/2022-01-11/stressor.csv')
stressor %>%
filter(year == 2020 & state %in% c('United States','California','Georgia','Texas','Idaho')) %>%
group_by(state, stressor) %>%
summarize(stress_pct = mean(stress_pct, na.rm = TRUE)) %>%
pivot_wider(names_from = stressor, values_from = stress_pct) %>%
select(c(State = state, Diseases = Disesases, Pesticides, `Other pests/parasites`, Other, Unknown)) %>%
reactable(
theme = no_lines(centered = TRUE),
defaultColDef = colDef(align = 'center'),
columns = list(
Diseases = colDef(
cell = bubble_grid(
data = .,
colors = '#084C61',
number_fmt = scales::number,
min_value = 0,
max_value = 15
)
),
Pesticides = colDef(
cell = bubble_grid(
data = .,
colors = '#DB504A',
number_fmt = scales::number,
min_value = 0,
max_value = 15
)
),
`Other pests/parasites` = colDef(
cell = bubble_grid(
data = .,
colors = '#E3B505',
number_fmt = scales::number,
min_value = 0,
max_value = 15
)
),
Other = colDef(
cell = bubble_grid(
data = .,
colors = '#4F6D7A',
number_fmt = scales::number,
min_value = 0,
max_value = 15
)
),
Unknown = colDef(
cell = bubble_grid(
data = .,
colors = '#56A3A6',
number_fmt = scales::number,
min_value = 0,
max_value = 15
)
)
)
) %>%
add_title(
title = reactablefmtr::html("Bee Colony Health Stressors <img src='https://svgsilh.com/svg/30649.svg' alt='Bee' width='40' height='40'>"),
margin = reactablefmtr::margin(t=0,r=0,b=3,l=0)
) %>%
add_subtitle(
subtitle = '% of colonies affected by stressors during 2020',
font_weight = 'normal',
font_size = 20,
margin = reactablefmtr::margin(t=0,r=0,b=6,l=0)
) %>%
add_source(
source = 'Data: USDA, #TidyTuesday Week 2, 2022',
margin = reactablefmtr::margin(t=7,r=0,b=0,l=0),
font_style = "italic"
)
Bee Colony Health Stressors
% of colonies affected by stressors during 2020
Data: USDA, #TidyTuesday Week 2, 2022
Note that the animation on sort disappears when the bubbles are all the same color in each column. This is because, by default, the color of the bubble is the only element set to animate on sort, which is set by
animation = background 1s ease'
. If you still want to see some sort of animation, you could set the animation property to ‘all 1s ease’ as shown below:
If you’re interested in learning more about animation options, please see the CSS transition property documentation here.
Bubble squares
In addition to bubble circles, you can also create bubble squares by
setting the shape
parameter to ‘squares’:
penguins %>%
group_by(species, sex) %>%
summarize(across(where(is.numeric), mean, na.rm = TRUE)) %>%
select(-year) %>%
reactable(
theme = no_lines(centered = TRUE),
defaultColDef = colDef(align = 'center'),
columns = list(
bill_length_mm = colDef(
cell = bubble_grid(
data = .,
shape = 'squares',
colors = c('#f2f0f7','#cbc9e2','#9e9ac8','#756bb1','#54278f'),
box_shadow = TRUE,
number_fmt = scales::number_format(accuracy = 0.1),
min_value = 30,
animation = 'all 1s ease'
)
),
bill_depth_mm = colDef(
cell = bubble_grid(
data = .,
shape = 'squares',
colors = c('#feedde','#fdbe85','#fd8d3c','#e6550d','#a63603'),
box_shadow = TRUE,
number_fmt = scales::number_format(accuracy = 0.1),
min_value = 13,
max_value = 21,
animation = 'all 1s ease'
)
),
flipper_length_mm = colDef(
cell = bubble_grid(
data = .,
shape = 'squares',
colors = c('#f1eef6','#bdc9e1','#74a9cf','#2b8cbe','#045a8d'),
box_shadow = TRUE,
number_fmt = scales::number_format(accuracy = 0.1),
min_value = 120,
animation = 'all 1s ease'
)
),
body_mass_g = colDef(
cell = bubble_grid(
data = .,
shape = 'squares',
colors = c('#edf8e9','#bae4b3','#74c476','#31a354','#006d2c'),
opacity = 0.8,
box_shadow = TRUE,
number_fmt = scales::comma,
min_value = 2000,
animation = 'all 1s ease'
)
)
)
)
Bar charts
There are many ways to customize the appearance of the bar charts
within data_bars()
:
penguins %>%
group_by(species, island, sex) %>%
summarize(across(where(is.numeric), mean, na.rm = TRUE)) %>%
select(-year) %>%
reactable(
theme = clean(),
pagination = FALSE,
columns = list(
bill_length_mm = colDef(
cell = data_bars(
data = .,
fill_color = viridis::mako(5),
background = '#F1F1F1',
min_value = 35,
max_value = 55,
text_position = 'outside-end',
number_fmt = scales::comma
)
),
bill_depth_mm = colDef(
cell = data_bars(
data = .,
fill_color = c('#FFF2D9','#FFE1A6','#FFCB66','#FFB627'),
fill_gradient = TRUE,
background = 'transparent',
number_fmt = scales::comma_format(accuracy = 0.1)
)
),
flipper_length_mm = colDef(
cell = data_bars(
data = .,
fill_color = 'black',
fill_opacity = 0.8,
round_edges = TRUE,
text_position = 'center',
number_fmt = scales::comma
)
),
body_mass_g = colDef(
cell = data_bars(
data = .,
fill_color = 'white',
background = 'darkgrey',
border_style = 'solid',
border_width = '1px',
border_color = 'forestgreen',
box_shadow = TRUE,
text_position = 'inside-base',
number_fmt = scales::comma
)
)
)
)
Conditional fill
Conditionally assign colors to bars by assigning the colors within a
new column using dplyr::case_when()
and then referencing
that column to be used as the fill of the bars with
fill_color_ref
:
survey <- data.frame(
response = c('Agree','Disagree','Neutral'),
percentage = c(0.64, 0.29, 0.07)
)
survey %>%
mutate(response_colors = case_when(
response == 'Agree' ~ '#127852',
response == 'Disagree' ~ '#C40233',
TRUE ~ '#A5A0A1'
)) %>%
reactable(
theme = clean(centered = TRUE),
columns = list(
response_colors = colDef(show = FALSE),
response = colDef(maxWidth = 110),
percentage = colDef(
align = 'left',
cell = data_bars(
data = .,
fill_color_ref = 'response_colors',
number_fmt = scales::percent,
max_value = 1,
bar_height = 50,
text_size = '1.3em'
)
)
)
)
Fill by another column
Alternatively, you can use fill_by
to apply a bar chart
to a column containing text:
survey %>%
mutate(response_colors = case_when(
response == 'Agree' ~ '#127852',
response == 'Disagree' ~ '#C40233',
TRUE ~ '#8C8687'
),
response = paste0(response, " (", percentage*100, "%)")) %>%
reactable(
theme = void(centered = TRUE),
columns = list(
response = colDef(
name = '',
cell = data_bars(
data = .,
fill_by = 'percentage',
fill_color_ref = 'response_colors',
text_position = 'outside-end',
max_value = 1,
bar_height = 50,
text_color_ref = 'response_colors',
text_size = '1.5em',
bold_text = TRUE
)
),
response_colors = colDef(show = FALSE),
percentage = colDef(show = FALSE)
)
) %>%
add_title('Survey Responses')
Survey Responses
Add icons to bars
If you would like to add an icon to the data bars, you can do so by
providing the name of the icon within the icon
parameter.
Note that the color of the icon will automatically be inherited by the color of the data bar unless provided explicity within the
icon_color
parameter.
cars <- mtcars %>%
rownames_to_column(var = 'model') %>%
select(c(model,mpg,hp))
reactable(cars,
theme = nytimes(centered = TRUE),
compact = TRUE,
defaultSortOrder = 'desc',
defaultSorted = 'hp',
pagination = FALSE,
columns = list(
hp = colDef(
minWidth = 150,
cell = data_bars(
data = cars,
text_position = 'none',
box_shadow = TRUE,
round_edges = TRUE,
fill_color = rev(MetBrewer::met.brewer('Troy')),
bias = 1.5,
icon = 'horse-head',
background = 'transparent',
bar_height = 4,
max_value = 400
)
),
mpg = colDef(
minWidth = 150,
cell = data_bars(
data = cars,
text_position = 'none',
box_shadow = TRUE,
round_edges = TRUE,
fill_color = MetBrewer::met.brewer('VanGogh3'),
bias = 1.5,
icon = 'leaf',
background = 'transparent',
bar_height = 4
)
)
)
)
Adding images to bars
To add an external web image to the data bars, you can do so by
providing a link to the image within the img
parameter:
cars <- mtcars %>%
rownames_to_column(var = 'model') %>%
select(c(model,mpg,cyl,drat,wt,hp,qsec)) %>%
mutate(rank = rank(qsec)) %>%
relocate(rank, .before = 'model')
reactable(cars,
theme = nytimes(centered = TRUE, font_color = '#666666'),
compact = TRUE,
defaultSortOrder = 'asc',
defaultSorted = 'qsec',
pagination = FALSE,
showSortIcon = FALSE,
columns = list(
model = colDef(
minWidth = 100,
style = cell_style(
data = cars,
font_color = '#222222',
font_weight = 'bold'
)),
mpg = colDef(maxWidth = 60),
cyl = colDef(maxWidth = 60),
hp = colDef(maxWidth = 60),
drat = colDef(maxWidth = 60),
wt = colDef(maxWidth = 60),
rank = colDef(
maxWidth = 45,
format = colFormat(digits = 0)
),
qsec = colDef(
name = '1/4 mile time',
align = 'left',
minWidth = 200,
format = colFormat(digits = 0),
cell = data_bars(
data = cars,
fill_color = c('#FAFAFA','#E7E7E7','#D3D3D3','#BFBFBF'),
fill_gradient = TRUE,
bold_text = TRUE,
background = 'transparent',
text_position = 'inside-base',
text_color = '#222222',
number_fmt = scales::number_format(accuracy = 0.1, suffix = 's'),
bar_height = 12,
min_value = 13,
max_value = 25,
img = 'https://www.pngkit.com/png/detail/54-544889_45-top-view-of-car-clipart-images-racecar.png',
img_height = 20,
img_width = 25
)
)
)
) %>%
add_title(
title = reactablefmtr::html("Fastest cars in the mtcars dataset <i class='fas fa-flag-checkered'></i>"),
font_color = 'black',
text_shadow = '1px 1px 2px red',
margin = margin(t=0,r=0,b=5,l=0)
)
Fastest cars in the mtcars dataset
Display positive and negative values
Data bars are able to display both positive and negative values automatically:
cars <- mtcars %>%
rownames_to_column(var = 'model') %>%
select(c(model,wt,mpg,hp)) %>%
mutate(wt = wt-mean(wt),
mpg = mpg-mean(mpg),
hp = hp-mean(hp))
reactable(cars,
theme = nytimes(centered = TRUE),
compact = TRUE,
defaultSortOrder = 'desc',
defaultSorted = 'mpg',
pagination = FALSE,
columns = list(
wt = colDef(
name = 'WT VS AVG',
minWidth = 150,
align = 'center',
cell = data_bars(
data = cars,
text_position = 'outside-end',
fill_color = viridis::mako(5),
number_fmt = scales::number_format(accuracy = 0.01)
)
),
hp = colDef(
name = 'HP VS AVG',
minWidth = 150,
align = 'center',
cell = data_bars(
data = cars,
text_position = 'outside-end',
fill_color = c('#C40233','#127852'),
number_fmt = scales::comma
)
),
mpg = colDef(
name = 'MPG VS AVG',
minWidth = 150,
align = 'center',
cell = data_bars(
data = cars,
text_position = 'none',
box_shadow = TRUE,
fill_color = MetBrewer::met.brewer('VanGogh3'),
number_fmt = scales::comma
)
)
)
)
Dot plots
You can create dot plot charts by assigning a ‘circle’ icon to the data bars and making the data bars transparent:
midwest %>%
group_by(state, county) %>%
summarize(perchsd = mean(perchsd/100, na.rm = TRUE),
percollege = mean(percollege/100, na.rm = TRUE)) %>%
filter(state == 'IL') %>%
reactable(
theme = clean(),
defaultSorted = 'county',
defaultPageSize = 25,
paginationType = 'jump',
columns = list(
state = colDef(maxWidth = 80),
county = colDef(maxWidth = 120),
perchsd = colDef(
name = '% with a High School Diploma',
align = 'left',
minWidth = 250,
cell = data_bars(
data = .,
fill_color = '#EEEEEE',
number_fmt = scales::percent,
text_position = 'outside-end',
max_value = 1,
icon = 'circle',
icon_color = 'firebrick',
icon_size = 15,
text_color = 'firebrick',
round_edges = TRUE
)
),
percollege = colDef(
name = '% with a College Education',
align = 'left',
minWidth = 250,
cell = data_bars(
data = .,
fill_color = '#EEEEEE',
number_fmt = scales::percent,
text_position = 'outside-end',
max_value = 1,
icon = 'circle',
icon_color = '#226ab2',
icon_size = 15,
text_color = '#226ab2',
round_edges = TRUE
)
)
)
)
Lollipop charts
You can create lollipop charts by following a similar method used to create the dot plot charts above, but by adding color to the data bars and reducing the height of the bars:
midwest %>%
group_by(state, county) %>%
summarize(perchsd = mean(perchsd/100, na.rm = TRUE),
percollege = mean(percollege/100, na.rm = TRUE)) %>%
filter(state == 'IL') %>%
reactable(
theme = clean(),
defaultSorted = 'county',
defaultPageSize = 25,
paginationType = 'jump',
columns = list(
state = colDef(maxWidth = 80),
county = colDef(maxWidth = 120),
perchsd = colDef(
name = '% with a High School Diploma',
align = 'left',
minWidth = 250,
cell = data_bars(
data = .,
fill_color = 'firebrick',
background = '#FFFFFF',
bar_height = 7,
number_fmt = scales::percent,
text_position = 'outside-end',
max_value = 1,
icon = 'circle',
icon_color = 'firebrick',
icon_size = 15,
text_color = 'firebrick',
round_edges = TRUE
)
),
percollege = colDef(
name = '% with a College Education',
align = 'left',
minWidth = 250,
cell = data_bars(
data = .,
fill_color = '#226ab2',
background = '#FFFFFF',
bar_height = 7,
number_fmt = scales::percent,
text_position = 'outside-end',
max_value = 1,
icon = 'circle',
icon_color = '#226ab2',
icon_size = 15,
text_color = '#226ab2',
round_edges = TRUE
)
)
)
)
Heatmaps
Heatmaps can be created by using the color_scales()
function and hiding the text by setting show_text
to FALSE.
Additionally, you can set tooltip
to TRUE so that you can
still see the values when a user hovers over each cell:
sanmarcos_sales <- txhousing %>%
filter(city == 'San Marcos' & year > 2004 & year < 2015) %>%
group_by(year, month) %>%
summarize(sales = mean(sales, na.rm = TRUE)) %>%
mutate(month = month.abb[month]) %>%
pivot_wider(names_from = 'month', values_from = 'sales') %>%
ungroup() %>%
mutate(year = as.character(year),
total = rowSums(across(where(is.numeric))))
sanmarcos_legend <- txhousing %>%
filter(city == 'San Marcos' & year > 2004 & year < 2015) %>%
group_by(year, month) %>%
summarize(sales = mean(sales, na.rm = TRUE)) %>%
mutate(month = month.abb[month])
reactable(
sanmarcos_sales,
pagination = FALSE,
showSortIcon = FALSE,
theme = void(
centered = TRUE,
cell_padding = 0,
header_font_color = 'black',
font_color = 'black'
),
defaultColDef = colDef(
maxWidth = 50,
align = 'center',
cell = tooltip(),
style = color_scales(
data = sanmarcos_sales,
span = 2:13,
colors = c('#002347','#003366','#003F7D','#FF8E00','#FD7702','#FF5003'),
bias = 1.4,
opacity = 0.9,
show_text = FALSE
)
),
columns = list(
total = colDef(
maxWidth = 225,
cell = data_bars(
data = sanmarcos_sales,
fill_color = c('#002347','#003366','#003F7D','#FF8E00','#FD7702','#FF5003'),
bias = 1.4,
fill_opacity = 0.9,
background = 'transparent',
bar_height = 40,
text_position = 'center'
),
style = list(borderLeft = "2px solid #999999")
)
)
) %>%
add_title(
title = html("San Marcos Housing Sales <i class='fas fa-home'></i>"),
align = 'center',
margin = reactablefmtr::margin(t=10,r=0,b=2,l=0)
) %>%
add_subtitle(
subtitle = 'Hover over cells to see values',
font_style = 'italic',
font_color = '#777777',
font_size = 18,
align = 'center',
margin = reactablefmtr::margin(t=0,r=0,b=10,l=0)
) %>%
add_legend(
data = sanmarcos_legend,
align = 'left',
title = '# of Sales (Jan - Dec)',
col_name = 'sales',
colors = c('#002347','#003366','#003F7D','#FF8E00','#FD7702','#FF5003'),
bias = 1.4,
bins = 6
)
San Marcos Housing Sales
Hover over cells to see values
- 6
- 14
- 19
- 26
- 34
- 63
Nested tables
{reactablefmtr} styling supports nested {reactable} tables that expand on click:
data <- MASS::Cars93[1:30, c('Type','Make','Model','MPG.city','MPG.highway')]
averages <- data %>%
group_by(Type) %>%
summarize(
MPG.city = mean(MPG.city),
MPG.highway = mean(MPG.highway)
)
reactable(
averages,
theme = clean(centered = TRUE),
columns = list(
Type = colDef(maxWidth = 250),
MPG.city = colDef(
maxWidth = 200,
style = color_scales(
data = data,
colors = viridis::mako(5)),
format = colFormat(digits = 1)),
MPG.highway = colDef(
maxWidth = 200,
cell = data_bars(
data = data,
fill_color = viridis::mako(5),
number_fmt = scales::comma))
),
onClick = "expand",
details = function(index) {
data_sub <- data[data$Type == averages$Type[index], ]
reactable(
data_sub,
theme = clean(centered = TRUE),
columns = list(
Type = colDef(show = FALSE),
Make = colDef(maxWidth = 175),
Model = colDef(maxWidth = 120),
MPG.city = colDef(
maxWidth = 200,
style = color_scales(data, viridis::mako(5)),
format = colFormat(digits = 1)),
MPG.highway = colDef(
maxWidth = 200,
cell = data_bars(data, fill_color = viridis::mako(5), number_fmt = scales::comma))
)
)
}
)