Skip to contents
# Example datasets
go_mf <- gprofiler_data |> 
  filter(source == "GO:MF")
go_mf
#> # A tibble: 22 × 25
#>    source term_name  term_id highlighted  p_value `−log10(pval)` ENSG00000184983
#>    <chr>  <chr>      <chr>   <lgl>          <dbl>          <dbl> <chr>          
#>  1 GO:MF  ion chann… GO:000… TRUE        4.07e-10           9.39 NA             
#>  2 GO:MF  channel i… GO:001… FALSE       4.73e-10           9.33 NA             
#>  3 GO:MF  potassium… GO:001… FALSE       5.05e- 8           7.30 NA             
#>  4 GO:MF  NADH dehy… GO:000… TRUE        8.38e- 8           7.08 TAS NAS        
#>  5 GO:MF  NADH dehy… GO:005… FALSE       9.51e- 8           7.02 TAS NAS        
#>  6 GO:MF  NADH dehy… GO:000… FALSE       1.21e- 7           6.92 TAS NAS        
#>  7 GO:MF  NAD(P)H d… GO:000… FALSE       1.36e- 7           6.87 TAS NAS        
#>  8 GO:MF  oxidoredu… GO:001… FALSE       4.64e- 7           6.33 TAS NAS        
#>  9 GO:MF  oxidoredu… GO:001… FALSE       9.85e- 7           6.01 TAS NAS        
#> 10 GO:MF  ion chann… GO:009… FALSE       1.18e- 6           5.93 NA             
#> # ℹ 12 more rows
#> # ℹ 18 more variables: ENSG00000198888 <chr>, ENSG00000119013 <chr>,
#> #   ENSG00000212907 <chr>, ENSG00000109390 <chr>, ENSG00000105974 <chr>,
#> #   ENSG00000134240 <chr>, ENSG00000136869 <chr>, ENSG00000196632 <chr>,
#> #   ENSG00000119782 <chr>, ENSG00000101680 <chr>, ENSG00000168610 <chr>,
#> #   ENSG00000126562 <chr>, ENSG00000054148 <chr>, ENSG00000160439 <chr>,
#> #   ENSG00000171497 <chr>, ENSG00000126787 <chr>, ENSG00000256060 <chr>, …
.rotated-header {
  transform: rotate(90deg);
  white-space: nowrap;
  border-top: none !important;
}
.filtered-indicator {
    display: inline-block;
    box-sizing: border-box;
    width: 10px;
    height: 100%;
    overflow: hidden;
    border: 1px solid lightgrey !important;
    font-size: 5px;
}

.filtered-indicator.filtered {
    background-color: darkgray;
}

.evidence-code {
    display: inline-block;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    overflow: hidden;
    border: 1px solid lightgrey;
    font-size: 5px;
}

.no-padding {
  padding: 0 !important;
}

.customHeaderLabel {
    font-size: 8px;
    top: -80px;
    float: left;
    border-left: 1px solid lightgrey;
    border-right: 1px solid lightgrey;
    background-color: #f5f7f7;
    padding: 5px 0;
    writing-mode: tb-rl;
    writing-mode: vertical-lr;
}
table <- go_mf |> 
  select(-source) |> 
  relocate(term_id) |> 
  aggrid(checkboxSelection = T,suppressRowClickSelection = T) |> 
  ag_col_width(term_name,maxWidth = 380) |> 
  ag_col_group(1:2,headerName = "GO: MF") |> 
  ag_col_group(3:5,headerName = "Stats") |> 
  # custom pvalue cellrender
  ag_col_def(p_value,cellRenderer = JS('
function exponentToSup(params) {
  let formatted = params.value.toExponential(3).toString().replace(/e(.*)/, "<sup>$1</sup>");

  return formatted; 
}'))

add sparkline bar

# see more <https://www.ag-grid.com/javascript-data-grid/sparklines-bar-customisation/>
bar_formatter <- function(values,palette = "viridis") {
  cols <- scales::col_numeric(palette, domain = NULL)(values)
  names(cols) <- scales::number_format(accuracy = 0.001)(values)
  cols_dict = jsonlite::toJSON(as.list(cols),auto_unbox = T)

  formatter_code <- htmlwidgets::JS(sprintf('function formatter(params) {
  const cols_dict = %s;
  const { yValue } = params;
  const col = cols_dict[yValue.toFixed(3)];
  return {fill: col}
}',cols_dict))
  formatter_code
}
table <- table |> 
  ag_col_render("−log10(pval)",
    cellRenderer = "agSparklineCellRenderer",
    cellRendererParams = list(
      sparklineOptions = list(
        type = "bar",
        valueAxisDomain = range(go_mf$`−log10(pval)`),
        formatter = bar_formatter(go_mf$`−log10(pval)`)
      )
    ),
    minWidth = 200
  )
#> Warning: By default htmlwidgets set auto_unbox = TRUE so the 1 length atomic elements
#> are not send as array. So default set `valueGetter` to convert Number to Array.

highlighted columns

table <- table |> 
  ag_col_def(highlighted,cellRenderer = JS('
(params) => {
  const a = params.value ? "filtered-indicator filtered" : "filtered-indicator";
  return `<span class = "${a}"></span>`;
}'),
  width = 10,
  suppressSizeToFit = TRUE,
  cellClass = 'no-padding',sortable = F,menuTabs = FALSE)
get_gene_color_code <- function(go_mf) {
  levels <- dplyr::select(go_mf,starts_with("ENSG")) |> 
    as.matrix() |> as.character() |> unique()
  gene_colors <- scales::col_factor("Set1",domain = NULL,na.color = "white")(levels)
  names(gene_colors) <- levels
  gene_cell_render_code <- JS(sprintf('
  (params) => {
    const gene_colors = %s;
    return `<span class = "evidence-code" style = "background-color: ${gene_colors[params.value]}"></span>`;
  }',jsonlite::toJSON(as.list(gene_colors),auto_unbox = T)))
}

# custom tootip
# copy from https://www.ag-grid.com/javascript-data-grid/component-tooltip/

tooltipComponent <- JS(r"(
class CustomTooltip {
    init(params) {
        const eGui = this.eGui = document.createElement('div');
        const color = params.color || '#4b4646';
        console.log(params.value);
        eGui.classList.add('custom-tooltip');
        eGui.style['background-color'] = color;
        eGui.style['color'] = "white";
        eGui.innerHTML = `
            <div style = "padding: 2px 6px;text-align: center;">
                <span>${params.value}</span><br/>
                ${params.column.colId}
            </div>
        `;
    }

    getGui() {
        return this.eGui;
    }
}
)")

table |> 
  ag_col_def(columns = starts_with("ENSG") ,
             # headerClass = "rotated-header",
             sortable = F,
             menuTabs = F,
             suppressSpanHeaderHeight = F,
             headerClass = "customHeaderLabel",
             width = 20,
             cellClass = 'no-padding',
             cellRenderer = get_gene_color_code(go_mf),
    tooltipValueGetter = JS('(params) => { return params.value;}'),
    tooltipComponent = tooltipComponent
  ) |> 
  # set aggrid options
  ag_gridOptions(headerHeight = 32,groupHeaderHeight = 95,
    getContextMenuItems = JS('() => []'),
    tooltipShowDelay = 0) |> 
  ag_size_columns(skipHeader = T)
#> Warning in RColorBrewer::brewer.pal(n, pal): n too large, allowed maximum for palette Set1 is 9
#> Returning the palette you asked for with that many colors