modularize the plotting system
plotting functions should modify a target axis (or create new axes as a sane default) and return it
there may be an optional interface to allow plotting functions to set xlabels/ylabels/titles/etc., but manually setting plot attributes from the pyplot API after calling the function should be possible
some research may be done on supporting an API to specify or control the ordering of overlay plots - though most likely this can be done by simply requiring that all plotting functions accept OrderedDicts as well as native dicts, see the current implementation in the expected plotter
there should be a unified API for controlling figure aesthetics, namely to control seaborn themes (including figuring out when to turn off the seaborn styles, e.g. when plotting heatmaps), color cycles and mappings, etc.
plotting functions should support an outfile
kwarg that will save the resulting plot automatically, recapitulating the old behavior
the heatmap plotter in particular should allocate a grid initially (via a function that creates and returns a "heatmap plotting context" to be used for coordinate conversions, etc.) and then accept a sequence of independent plotting commands to draw the desired pieces over each other one at a time - this will remove the current kwarg bloat on the plot_heatmap()
function
zoom windows will become a parameter of the heatmap plotting context creation
Comments (6)
-
reporter -
reporter - changed status to open
-
reporter the new plotting system could also support an i5c-style annotation API, which would allow a plotting context to be created that tracks metadata for different replicates and allows simple mapping of colors to different attributes of the metadata
-
reporter breaking up
plot_heatmap()
is a critical step in the modularization of the plotting systemto do this, we propose leveraging axes_grid
an example code snippet is:
import matplotlib.pyplot as plt from mpl_toolkits.axes_grid1 import make_axes_locatable import numpy as np ax = plt.subplot(111) im = ax.imshow(np.arange(100).reshape((10,10))) divider = make_axes_locatable(ax) def add_trig_things(divider, color): xs = np.arange(0, 10) htrack = divider.append_axes("bottom", size="10%", pad=0.0) vtrack = divider.append_axes("left", size="10%", pad=0.0) htrack.plot(xs, np.sin(xs), c=color) vtrack.plot(np.tan(xs), xs, c=color) add_trig_things(divider, 'b') add_trig_things(divider, 'r') add_trig_things(divider, 'g') add_trig_things(divider, 'purple') plt.savefig('test.png', bbox_inches='tight')
we could capture a reference to the
divider
instance as well as named references to the component axes using a class structure as follows:class Heatmap(object): def __init__(self, array, **kwargs): self.axes = {} self.fig, (self.axes['heatmap'],) = plt.subplots() self.array = array self.im = self.axes['heatmap'].imshow(self.array, **kwargs) self.divider = make_axes_locatable(self.axes['heatmap']) def add_colorbar(self): self.axes['colorbar'] = self.divider.append_axes("right", size="10%", pad=0.1) self.fig.colorbar(self.im, cax=self.axes['colorbar']) def add_horizontal_track(self, name): self.axes[name] = self.divider.append_axes("bottom", size="10%", pad=0.1) return self.axes[name] def add_horizontal_gene_track(self, name='gene_track_h'): self.add_horizontal_track(name) plot_hgene(.., self.axes[name], ...) def save(self, filename): self.fig.savefig(filename, dpi=800, bbox_inches='tight') h = heatmap(counts['Sox2']) h.add_colorbar() h.add_horizontal_track('IS horizontal') h.axes['IS horizontal'].plot(...) h.save('somefile.png') draw_communities(h.axes['heatmap'], ...) outline_clusters(h.axes['heatmap'], ...)
-
reporter as of 0a5b142,
lib5c.plotters.extendable.ExtendableHeatmap
recapitulates all features of the old heatmap plotter (lib5c.plotters.heatmap.plot_heatmap()
) and this design goal, closing this issue -
reporter - changed status to resolved
- Log in to comment
re overlay plots: it would be nice to standardize these
in particular, the current implementation of the expected model overlay plotting contains a lot of typechecking and "fake overloading" (repurposing the same function name to serve two distinct ends) just to allow overlaying of multiple models - it should be refactored into separate functions