glin / reactable

Interactive data tables for R
https://glin.github.io/reactable
Other
612 stars 79 forks source link

Images in aggregated cells #330

Closed grsarah closed 11 months ago

grsarah commented 12 months ago

Hi!

I am trying to aggregate a row with an image in each cell, but when I apply the aggregate function the images disappear. Ids there a way to have them visible in the aggregated cells? my code is below if that's helpful :)

columns = list(

     ROUND = colDef(
       name = "Round",

       cell = function(value) {
         image <- img(src = paste0('Logos/',value, ".png"), style = "height: 15; width: 15; max-height:38px; max-wodth = 38px;")
         tagList(
           div(image),
           value
         )
       }
      ),
glin commented 11 months ago

Hi, there seems to be missing code here and I don't see the aggregate function. But as a quick guess, you may need to use the aggregated cell renderer which customizes display of aggregated cells, rather than the aggregate function that converts a list of raw cell values to an aggregate value. If you have a more complete example, I might be able to give a better answer.

grsarah commented 11 months ago

Thanks @glin , I have attached the full code below. I am hoping to be able to display the image in the 'logo' column when the table is grouped by the 'round' name. Currently when I group by round, the image only displays when I open the drop down arrow. Any help would be greatly appreciated :)

drill.sum %>% reactable( groupBy = "ROUND", sortable = FALSE, pagination = FALSE, bordered = FALSE, outlined = FALSE, striped = TRUE, fullWidth = TRUE, highlight = FALSE, compact = FALSE,

   columns = list(

     ROUND = colDef(
       name = "Round",
       align = "right"),

     LOGO = colDef(
       name = "",
       minWidth = 25,
       align = "left",
      cell = function(value) {
        image <- img(src = paste0('Logos/',value, ".png"), style = "height: 15; width: 15; max-height:38px; max-width = 38px;")
        tagList(
          div(image))
       }),

     CLASSIFICATION = colDef(
       name = "Classification")

)

glin commented 11 months ago

So I still can't run that code without drill.sum (I wasn't able to find this if it's a standard dataset), but I think I understand the issue now. When you group rows together, a new aggregate row is created for each group, and that row is empty unless you specify how the values should be aggregated. Since you want to show an image as the aggregate value, you'll have to create a custom aggregate function as there's no built-in function for aggregating images.

If the images in each group can differ, you'll also have to figure out which image to show to represent the group. Here's a quick example I made based on the Embed Images example in the docs. It uses the first Animal value of each group as the aggregate image.

Currently, aggregate functions can only be written in JavaScript, so the cell render function needs to be translated to JavaScript. But it's not too radically different vs. the R version. With JavaScript, you'd create an HTML string for the image and use colDef(html = TRUE) to enable raw HTML rendering.

library(reactable)
library(htmltools)

data <- data.frame(
  Group = c(1, 1, 2, 2, 3),
  Animal = c("beaver", "beaver", "cow", "wolf", "goat"),
  Body = c(1.35, 1.35, 465, 36.33, 27.66),
  Brain = c(8.1, 8.1, 423, 119.5, 115)
)

reactable(
  data,
  groupBy = "Group",
  columns = list(
    Animal = colDef(
      cell = function(value) {
        image <- img(src = sprintf("https://glin.github.io/reactable/articles/cookbook/images/%s.png", value),
                     style = "height: 24px;", alt = value)
        image
      },
      aggregate = JS('function(values) {
        // Use the first value in the group for the image
        const value = values[0]
        const src = "https://glin.github.io/reactable/articles/cookbook/images/" + value + ".png"
        return `<img src="${src}" style="height: 24px;" alt="${value}">`
      }'),
      html = TRUE
    ),
    Body = colDef(name = "Body (kg)"),
    Brain = colDef(name = "Brain (g)")
  )
)
grsarah commented 11 months ago

Thanks so much for you help @glin, that has solved the problem!