Making annotations on axis of heatmaps

I would like to make a heatmap with some additional annotation on the axis similar to the figure shown below. On the right vertical axis, there are brackets and annotations to denote the rows to a specific label.

Would something like this be possible in matplotlib?

enter image description here

1 answer

  • answered 2018-10-12 09:12 SpghttCd

    In the following, I define a function which creates a curly brace patch based on lower left corner, width and height as input.
    This can then be used in a loop together with lists of the width and position of the bands and their names.

    Please note: as a first shot, this approach still has some drawbacks:

    • the base form is completely stretched, that means that the rounding of the braces changes with the height (and the width of course, which is constant here). That could be optimized in a next step.
    • as soon as you use ggplot-style (plt.style.use('ggplot')), it doesn't show up anymore. I thought it's because of some patches used by ggplo-style and their z-order, but up to now, I was not able to solve that issue.

    Code:

    def CurlyBrace(ll_corner=(0, 0), width=1, height=1):
        import matplotlib.path as mpath
        import matplotlib.patches as mpatches
        import numpy as np
        Path = mpath.Path
        verts = np.array([(0, 0), (.5, 0), (.5, .2), (.5, .3), (.5, .5), (1, .5), (.5, .5), (.5, .7), (.5, .8), (.5, 1), (0, 1)])
        verts[:, 0] *= width
        verts[:, 1] *= height
        verts[:, 0] += ll_corner[0]
        verts[:, 1] += ll_corner[1]
    
        cb_patch = mpatches.PathPatch(
            Path(verts,
                 [Path.MOVETO, Path.CURVE3, Path.CURVE3, Path.LINETO, Path.CURVE3, Path.CURVE3, Path.CURVE3, Path.CURVE3, Path.LINETO, Path.CURVE3, Path.CURVE3]),
            fc="none", clip_on=False, transform=ax.transData)
        return cb_patch
    
    
    import imageio
    
    im = imageio.imread(pic_dir + 'sample_heatmap.png')
    fig, ax = plt.subplots()
    ax.imshow(im)
    
    
    bands = np.array([0, 175, 320, 448, 585, 610, 815])
    bnames = ['H3K4me3', 'H3K9me3', 'H3K27me3', 'H3K36me3', 'CTCF', 'H3K4me1']
    for y, h, bn in zip(bands, np.diff(bands), bnames):
        cb = CurlyBrace([990, y+h*0.025], 30, h*.95)
        ax.add_patch(cb)
        ax.text(1030, y+h/2, bn, va='center')
    
    plt.tight_layout(rect=[0.05, 0, 0.85, 1])
    

    Result:

    enter image description here