How to style cells in a gt table based on their content.

I am having a rough time trying to style cells in a gt table. I think it's because I am misunderstanding a concept.

Here's an example of what I mean, starting with a tibble...

  my_data <- tibble(person = c('pablo','spots','harry'), 
                    outcome_1 = c('good','bad','good'),
                    outcome_2 = c('good','good','bad'))

What I would to do is to fill the background of all cells in the outcome_1 or outcome_2 column that contain 'bad' with red.

So to do that we just add a tab_style consisting of 2 arguments:
style -- a list of styles to apply
locations -- a thing that somehow identifies where the styles are to be applied

Here's what I tried... but it doesn't work. I am expecting the cells with 'bad' to be colored red and have bold text but instead, they're unstyled.

  my_data |> 
    gt() |>
    
    tab_style(
      
      style = list(
        cell_fill(color = 'red'),
        cell_text(weight = 'bold')),
      
      locations = cells_body(
        columns = starts_with('outcome'),
        rows = contains('bad')
      )
    )

Here's what it yields...
image

I used cells_body because I want to apply the styles to cells. The examples in the docs for cells_body typically specify columns and rows.

OK, so columns = starts_with('outcome') allows me limit the locations to the outcome columns, right?

Then, it's a matter of selecting WHICH rows in those columns?

I used rows = contains('bad') because the docs say I can use tidyselect selection helpers and that seems plausible.

Obviously, I am missing something. What's going on?

I think contains wants to work at the variable name level rather than the contents of the variable.
I can acheive the result in this way , explicitly setting the rules on each column

my_data |> 
  gt() |>
  tab_style(
    
    style = list(
      cell_fill(color = 'red'),
      cell_text(weight = 'bold')),
    locations = list(cells_body(
      columns = outcome_1,
      rows = str_detect(outcome_1,"bad")
    ),
    cells_body(
      columns = outcome_2,
      rows = str_detect(outcome_2,"bad")
    ))
  )

I can generalise this, and map over the outcome_1/2 names


(nms_ <- names(my_data))
(nms_ <- nms_[startsWith(nms_,"outcome")])


my_data |> 
  gt() |>
  tab_style(
    style = list(
      cell_fill(color = 'red'),
      cell_text(weight = 'bold')),
    locations = map( nms_ ,
                     \(x){cells_body(
                       columns = x,
                       rows = str_detect(!!sym(x),"bad")
                     )})
  )
1 Like

Thank you, this solves my problem!

I do wish there were a simpler solution. Having to use !!sym() is particularly unpleasant. I am glad it works today for my problem, but I won't be able to remember it.

It's jarring how dense and technical the documentation is for help('!!')-- with many deep rabbit-hole concepts like "defused expressions", "data-masking", "inject()", "symbolized column names", "with", "quosures", "{{". Come on, gt, I just want to make a nice table!

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.