Skip to contents

Position Text

By default, the values are positioned on the “inside-end” of the filled bars:

data <- data.frame(
  Group = c("Red Group 1","Red Group 2","Red Group 3","Red Group 4","Red Group 5",
            "Blue Group 1","Blue Group 2","Blue Group 3","Blue Group 4","Blue Group 5",
            "Green Group 1","Green Group 2","Green Group 3","Green Group 4","Green Group 5"),
  Pct1 = c(.27, .82, .44, .68, .78, 
           .74, .66, .33, .23, .20, 
           .50, .55, .40, .70, .60),
  Pct2 = c(.33, .17, .87, .54, .37,
           .84, .72, .61, .48, .77,
           .21, .39, .60, .55, .81)
)
reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     number_fmt = scales::percent)
  )
)

However, you can change the location of the values with text_position. The available options are “inside-end” (default), “outside-base”, “outside-end”, “inside-base”, “center”, “above”, or “none”. Below is an example of “outside-base” which is the way the old version of data_bars() displayed the values.

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     text_position = "outside-base", 
                     number_fmt = scales::percent)
  )
)

Values positioned inside the base of the filled bars with “inside-base”:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     text_position = "inside-base", 
                     number_fmt = scales::percent)
  )
)

Values positioned inside the end of the filled bars with “outside-end”:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data,
                     text_position = "inside-end",
                     number_fmt = scales::percent)
  )
)

Values positioned inside the center of the filled bars with “center”:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data,
                     text_position = "center", 
                     number_fmt = scales::percent)
  )
)

Values positioned above the filled bars with “above”:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data,
                     text_position = "above", 
                     number_fmt = scales::percent)
  )
)

Lastly, values can be hidden with “none”:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     text_position = "none")
  )
)

Force Text Outside

If the values are difficult to see inside the bars since they are small relative to other values in the column, you can “force” them to show outside of the data bars by providing a range of values within force_outside:

reactable(
  data,
  pagination = FALSE,
  defaultSortOrder = "desc",
  defaultSorted = "Pct2",
  defaultColDef = colDef(
    cell = data_bars(data, 
                     number_fmt = scales::percent,
                     force_outside = c(0,0.4))
  )
)

Change Color of Text

The default text color for the values is black, but it can be changed with text_color:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     text_color = "red", 
                     number_fmt = scales::percent)
  )
)

When dark color palettes are used and text are placed inside the filled bars, the text will automatically show as white in dark-colored bars and black in light-colored bars in order to improve visibility as shown below:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     fill_color = viridis(5), 
                     text_position = "inside-end",
                     number_fmt = scales::percent)
  )
)

Note: This feature can be turned off by setting brighten_text = FALSE.

The color of the labels that appear within dark-filled bars can be changed with brighten_text_color if you prefer to use another color other than the default white:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     fill_color = viridis(5),
                     text_position = "inside-end", 
                     brighten_text_color = "gold", 
                     number_fmt = scales::percent)
  )
)

Aligning Data Bars

By default, the filled bars are aligned from left-to-right, but can be aligned from right-to-left by setting align_bars = "right":

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     align_bars = "right", 
                     number_fmt = scales::percent)
  )
)

The same text positions outlined in the section above can be applied to right-aligned data bars. You can also mix and match alignments.

reactable(
  data,
  pagination = FALSE,
  columns = list(
    Pct1 = colDef(
      cell = data_bars(data, 
                       align_bars = "right", 
                       text_position = "inside-end", 
                       number_fmt = scales::percent)
      ),
    Pct2 = colDef(
      cell = data_bars(data, 
                       align_bars = "left",
                       text_position = "inside-end",
                       number_fmt = scales::percent)
      )
  )
)

Adding a Box Shadow

Box shadows can be added to the bars to create a “3-D” effect via box_shadow.

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     box_shadow = TRUE, 
                     number_fmt = scales::percent)
  )
)

Round Edges

The edges of the bars can be rounded by setting round_edges to TRUE.

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     round_edges = TRUE, 
                     number_fmt = scales::percent)
  )
)

Set a Maximum Width

By default, the width of the filled data bars is equal to the maximum value within that particular column. In most cases, this is what we want to display, but sometimes it’s better to extend the range. For example, in the percentages below, if we want to extend the width to show the values out of 100%, we could do so by setting the max_value to 1:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     fill_color = viridis(5), 
                     background = "lightgrey",
                     text_position = "inside-end", 
                     max_value = 1, 
                     number_fmt = scales::percent)
  )
)

Now when you look at the 82% value above, there is 18% empty space filled by the background showing that the value is out of 100% and not 82%.

Adjusting the Vertical Height of the Bars

The default height of the data bars is set to 19px but can be adjusted within bar_height.

To increase the height of the bars, provide a numeric value greater than 19:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     bar_height = 35, 
                     number_fmt = scales::percent)
  )
)

To decrease the height of the bars, provide a numeric value less than 19:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data,
                     bar_height = 3, 
                     text_position = "outside-end", 
                     background = "transparent", 
                     number_fmt = scales::percent)
  )
)

Color Reference

You can now conditionally assign colors to rows based on values within another column with the fill_color_ref argument. This allows you to assign colors to groups such as shown below:

data %>%
  mutate(color_pal = case_when(
    str_detect(Group, "Red") ~ "#FF3B28",
    str_detect(Group, "Blue") ~ "#006FEF",
    str_detect(Group, "Green") ~ "#3ABC0E",
    TRUE ~ "darkgrey"
  )) %>%
reactable(.,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(.,
                     fill_color_ref = "color_pal", 
                     text_position = "inside-end",
                     background = "lightgrey", 
                     max_value = 1, 
                     number_fmt = scales::percent)
  ),
  columns = list(color_pal = colDef(show = FALSE) ## hide the color_pal column
  )
) 

Or you can conditionally assign colors based on values:

data %>%
  mutate(color_pal = case_when(
    Pct1 >= .7 ~ "#FF3B28",
    TRUE ~ "darkgrey"
  )) %>%
  select(-Pct2) %>% 
reactable(.,
  pagination = FALSE,
  defaultSorted = "Pct1",
  defaultSortOrder = "desc",
  defaultColDef = colDef(
    cell = data_bars(., 
                     fill_color_ref = "color_pal", 
                     text_position = "inside-end", 
                     background = "lightgrey", 
                     max_value = 1, 
                     number_fmt = scales::percent)
  ),
  columns = list(color_pal = colDef(show = FALSE)
  )
) 

Gradient Colors

data_bars_gradient() is now depreciated and has been replaced with the gradient argument within data_bars(). Set fill_gradient = TRUE to change any multi-color palette to a left-to-right gradient to be used as the fill for the bars:

reactable(
  data,
  pagination = FALSE,
  defaultColDef = colDef(
    cell = data_bars(data, 
                     fill_color = c("#1efffd", "#1e20ff"), 
                     fill_gradient = TRUE, 
                     background = "lightgrey", 
                     max_value = 1, 
                     number_fmt = scales::percent)
  )
)

Positive and Negative Values

data_bars_pos_neg() is also now depreciated and has been replaced with the default setting of data_bars() which automatically detects if there are negative values within a column and adjusts the bars to go in opposite directions rather than one.

If two colors are provided, the first color will be applied to the negative-filled bars and the second color will be applied to the positive-filled bars

data %>% 
  mutate(Change = Pct1 - Pct2) %>% 
  select(Group, Change) %>% 
reactable(.,
  pagination = FALSE,
  columns = list(
    Change = colDef(
      cell = data_bars(., 
                       fill_color = c("lightblue","orange"),
                       number_fmt = scales::percent))
  )
)

The labels can be positioned in the same fashion that is used for the positive-valued data bars in the examples above:

data %>% 
  mutate(Change = Pct1 - Pct2) %>% 
  select(Group, Change) %>% 
reactable(.,
  pagination = FALSE,
  defaultSorted = "Change",
  defaultSortOrder = "asc",
  columns = list(
    Change = colDef(
      cell = data_bars(., 
                       fill_color = c("lightblue","orange"),
                       text_position = "inside-end", 
                       number_fmt = scales::percent))
  )
)

Add Icons to Bars

Now within the data_bars() formatter, you can directly add icons to your tables!

First let’s start with a dataset that shows fake data from some of the leading social media websites. We will later use the names of the sites within the Logo column to apply the icons from the Font Awesome icon library. Please note that the names of the sites are all lower-case to match the icon names within Font Awesome.

data <- data.frame(
  Company = c("facebook", "twitter", "linkedin", "reddit", "youtube", "instagram", "pinterest", "snapchat"),
  Primary = c("#4267B2", "#1DA1F2", "#0E76A8", "#FF4500", "#FF0000", "#833AB4", "#E60023", "#FFFC00"),
  Values = c(75, 120, 90, 100, 80, 70, 60, 40)
)
reactable(
  data,
  defaultSorted = "Values",
  defaultSortOrder = "desc",
  columns = list(
    Values = colDef(
      cell = data_bars(data, 
                       fill_color = "black",
                       fill_opacity = 0.8, 
                       text_position = "inside-end"))
  )
)

To add the logos of each company to the end of the data bars, use icon_ref to reference the column (Company) containing the names of the companies:

reactable(
  data,
  defaultSorted = "Values",
  defaultSortOrder = "desc",
  columns = list(
    Values = colDef(
      cell = data_bars(data, 
                       icon_ref = "Company", 
                       fill_color = "black", 
                       fill_opacity = 0.8, 
                       text_position = "inside-end"))
  )
)
## This version of bslib is designed to work with shiny version 1.6.0 or higher.

By default, the color of the icon is inherited from the color of the filled data bar, but they can be changed either through icon_color or with icon_color_ref which we will be using below in order to apply each company’s primary color to icons:

reactable(
  data,
  defaultSorted = "Values",
  defaultSortOrder = "desc",
  columns = list(
    Values = colDef(
      cell = data_bars(data,
                       icon_ref = "Company", 
                       icon_color_ref = "Primary",
                       fill_color = "black", 
                       fill_opacity = 0.8, 
                       text_position = "inside-end"))
  )
)

An alternative would be to use fill_color_ref instead, which applies each company’s primary color to the fill of the data bars and then the icons inherit that color as well:

reactable(
  data,
  defaultSorted = "Values",
  defaultSortOrder = "desc",
  columns = list(
    Values = colDef(
      cell = data_bars(data, 
                       icon_ref = "Company",
                       fill_color_ref = "Primary",
                       text_position = "inside-end"))
  )
)

The size of the icons can also be adjusted with icon_size:

reactable(
  data,
  defaultSorted = "Values",
  defaultSortOrder = "desc",
  columns = list(
    Values = colDef(
      cell = data_bars(data, 
                       icon_ref = "Company", 
                       icon_size = 35, 
                       fill_color_ref = "Primary",
                       text_position = "inside-end", 
                       background = "transparent")
    ),
    Company = colDef(show = FALSE), 
    Primary = colDef(show = FALSE)
  )
) 

Add Images to Bars

Similarly, you can now assign images to your data bars!

First let’s load the dataset from nflfastR that was used in the Embed Images example (this dataset is limited to just the 2018-2019 seasons):

## load multiple seasons
seasons <- 2018:2019
pbp <- map_df(seasons, function(x) {
  readRDS(url(
    paste0(
      "https://raw.githubusercontent.com/guga31bb/nflfastR-data/master/data/play_by_play_",
      x,
      ".rds"
    )
  ))
})
## figures with QB stats
qbs <- pbp %>%
  filter(week <= 17,!is.na(epa)) %>%
  group_by(id, name) %>%
  summarize(
    epa = mean(qb_epa),
    cpoe = mean(cpoe, na.rm = T),
    n_dropbacks = sum(pass),
    n_plays = n(),
    team = last(posteam)
  ) %>%
  ungroup() %>%
  filter(n_dropbacks > 100 & n_plays > 1000)
## `summarise()` has grouped output by 'id'. You can override using the `.groups` argument.
## join team logos to dataset
qbs <- qbs %>%
  left_join(teams_colors_logos, by = c('team' = 'team_abbr')) %>% 
  select(name, team_logo_espn, team_color, cpoe, epa)

The URL’s for the team logos contained within the team_logo_espn column can be referenced using img_ref to overlay on top of the data bars. The images can also be re-sized using img_height and img_width. The default image size is 20px by 20px.

reactable(
  qbs,
  defaultPageSize = 20,
  columns = list(
    team_logo_espn = colDef(show = FALSE), ## hide column containing team logos
    team_color = colDef(show = FALSE), ## hide column containing team colors
    name = colDef(maxWidth = 120),
    cpoe = colDef(
      cell = data_bars(qbs, 
                       fill_color_ref = "team_color",
                       fill_opacity = 0.3,
                       brighten_text = FALSE, 
                       text_position = "inside-end",
                       number_fmt = scales::percent, 
                       img_ref = "team_logo_espn", 
                       img_height = 30, 
                       img_width = 30)
    ),
    epa = colDef(
      cell = data_bars(qbs, 
                       fill_color_ref = "team_color",
                       fill_opacity = 0.3, 
                       brighten_text = FALSE,
                       text_position = "inside-end",
                       number_fmt = scales::number_format(accuracy = 0.01),
                       img_ref = "team_logo_espn",
                       img_height = 30, 
                       img_width = 30)
    )
  )
)