Skip to content

TickBar #6658

@droumis

Description

@droumis

Is your feature request related to a problem? Please describe.

When the number of columns or rows of a heatmap are large, it becomes unmanageable to rely on normal text ticks per entry to interpret an explicit or implicit semantic grouping. In addition to group text labels, a colored bar that group the ticks based on a particular groupby column would be helpful.

Example from scanpy groupby:

Image

Describe the solution you'd like

An operation to add an adjoined TickBar.. what I'm calling a single row/column heatmap that encodes a specified groupby feature.

Describe alternatives you've considered

This is conceptually aligned with the planned effort to expand hierarchical ticks to heatmap categorical axes... trying to encode index grouping in an easily parsable way.

Additional context

Minimal example of how to currently achieve this in HoloViews:

import numpy as np
import pandas as pd
import holoviews as hv
from holoviews import opts
hv.extension('bokeh')

categories = {
    'Gene_A': 'Group1',
    'Gene_B': 'Group1', 
    'Gene_C': 'Group1',
    'Gene_D': 'Group2',
    'Gene_E': 'Group2',
    'Gene_F': 'Group3',
    'Gene_G': 'Group3',
    'Gene_H': 'Group3',
    'Gene_I': 'Group4',
    'Gene_J': 'Group4'
}

genes = list(categories.keys())
samples = [f'Sample_{i}' for i in range(1, 11)]

gene_groups = pd.Series(categories)
group_base_values = {'Group1': 0, 'Group2': 2, 'Group3': -1, 'Group4': 1}
base_values = gene_groups.map(group_base_values).values

expression_matrix = base_values[:, np.newaxis] + np.random.randn(len(genes), len(samples)) * 0.5

index = pd.MultiIndex.from_product([genes, samples], names=['Gene', 'Sample'])
df = pd.DataFrame({'Expression': expression_matrix.ravel()}, index=index).reset_index()

main_heatmap = hv.HeatMap(df, kdims=['Sample', 'Gene'], vdims=['Expression'])

group_to_num = {'Group1': 0, 'Group2': 1, 'Group3': 2, 'Group4': 3}
gene_series = pd.Series(genes)
group_series = gene_series.map(categories)

category_df = pd.DataFrame({
    'Gene': genes,
    'Category': ' ',
    'Group_Name': group_series,
    'Group_Num': group_series.map(group_to_num)
})

category_heatmap = hv.HeatMap(
    category_df, 
    kdims=['Category', 'Gene'], 
    vdims=['Group_Num', 'Group_Name']
)

styled_category = category_heatmap.opts(
    cmap='Category10',
    width=50,
    height=400,
    colorbar=False,
    xaxis=None,
    yaxis=None,
    tools=['hover'],
)

styled_main = main_heatmap.opts(
    cmap='RdBu_r',
    width=600,
    height=400,
    xlabel='Samples',
    tools=['hover'],
    xrotation=90,
)

styled_main + styled_category
Image

Metadata

Metadata

Assignees

Labels

No labels
No labels

Projects

Status

No status

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions