add support for fragment-level heatmap plotting in ExtendableHeatmap

Issue #48 new
Thomas Gilgenast created an issue

one possibility is to use this class:

from lib5c.plotters.extendable import ExtendableHeatmap
from lib5c.util.bed import check_intersect


class FragmentHeatmap(ExtendableHeatmap):
    def __init__(self, array, primermap, grange_x, grange_y=None,
                 colorscale=None, colormap='obs', norm=None):
        super(FragmentHeatmap, self).__init__(
            array, grange_x, grange_y=grange_y,
            colorscale=colorscale, colormap=colormap, norm=norm)
        self.primermap = primermap
        self['root'].clear()
        self['root'].autoscale(False)
        self['root'].set_xlim((self.grange_x['start'],
                               self.grange_x['end']))
        self['root'].set_ylim((self.grange_y['end'],
                               self.grange_y['start']))
        self.idx_x, self.primermap_x = zip(*[
            (i, self.primermap[i])
            for i in range(len(self.primermap))
            if check_intersect(self.primermap[i], self.grange_x)
        ])
        self.idx_y, self.primermap_y = zip(*[
            (i, self.primermap[i])
            for i in range(len(self.primermap))
            if check_intersect(self.primermap[i], self.grange_y)
        ])
        edges_x = [self.primermap_x[i]['start']
                   for i in range(len(self.primermap_x))] + \
            [self.primermap_x[-1]['end']]
        edges_y = [self.primermap_y[i]['start']
                   for i in range(len(self.primermap_y))] + \
            [self.primermap_y[-1]['end']]
        self['root'].pcolorfast(
            edges_x, edges_y,
            self.array[self.idx_y[0]:self.idx_y[-1]+1,
                       self.idx_x[0]:self.idx_x[-1]+1],
            cmap=self.cmap,
            vmin=self.vmin,
            vmax=self.vmax
        )
        self['root'].get_xaxis().set_ticks([])
        self['root'].get_yaxis().set_ticks([])

caveats/limitations:

  1. unlike the normal BaseExtendableHeatmap implementation, this one includes some slicing logic internally
  2. unlike the normal BaseExtendableHeatmap implementation, the heatmap axes are actually in units of genomic coordinates, not pixels, so functions like DomainExtendableHeatmap.outline_domain() which always call BaseExtendableHeatmap.transform_feature() internally will not work (we need to add logic that checks to see if the heatmap axes are in genomic coordinates or pixel coordinates, and only use transform_feature() if the axes are in pixel coordinates
  3. since the grid we are passing to matplotlib.axes.Axes.pcolorfast() only includes the endpoints of fragments that are actually present in the primermap, "gaps" between fragments are simply filled in from the left/above (to address this we could add logic to detect and fill gaps in the primermap and expand the array by adding rows/columns of np.nan)

despite these limitations, this approach already seems to be useful in the wild and represents a not-uncommon use case for 5C analysis specifically - we have been missing the ability to align fragment-level data with genomic coordinates for a long time now

Comments (1)

  1. Log in to comment