Source code for pycaps.plot.pubfig


import numpy as np

import matplotlib
from matplotlib import transforms
if matplotlib.__version__ == '1.0.0':
    import gridspec
else:
    import matplotlib.gridspec as gridspec

import pylab

import string


[docs]def get_multiplier(fig=None): """ Get a multipler for the size of text objects, a function of the diagonal length on the figure. Args: fig (matplotlib.figure.Figure): The figure to use. Defaults to none, meaning to use the current figure. Returns: The size multiplier for the figure. """ if fig is None: fig = pylab.gcf() base_diag = np.hypot(6, 12) size_x, size_y = fig.get_size_inches() fig_diag = np.hypot(size_x, size_y) return fig_diag / base_diag
def _make_colorbar(colorbar, scal_map, multiplier, left=False): default_left = {True: 0.025, False: 0.9}[left] try: bar_label, format, ticks = colorbar['text'], colorbar['format'], colorbar['ticks'] except KeyError: raise ValueError("Colorbar dictionary must contain at least 'text', 'format', and 'ticks' keys.") tick_labels = colorbar.get('labels', ticks) left = colorbar.get('left', default_left) bottom = colorbar.get('bottom', 0.1125) top = colorbar.get('top', 0.825 + 0.1125) label_offset = colorbar.get('textoffset', 4.0) cax = pylab.axes((left, bottom, 0.020, top - bottom)) bar = pylab.colorbar(scal_map, cax=cax) if scal_map else pylab.colorbar(cax=cax) bar.ax.text(label_offset, 0.5, bar_label, rotation=90, transform=bar.ax.transAxes, size=12 * multiplier, va='center') bar.set_ticks(ticks) bar.set_ticklabels([ format % t for t in tick_labels]) bar.ax.tick_params(labelsize=12 * multiplier) return def _get_gs_indices(idx, layout, spans, n_missing, hanging): rows, columns = layout gs_rowspan, gs_colspan = spans hang_size = 0 if hanging in ['top', 'bottom']: hang_size = columns - n_missing elif hanging in ['left', 'right']: hang_size = rows - n_missing if hanging == 'left': if idx < rows - n_missing: gs_idx = 0 gs_jdy = idx * gs_rowspan + n_missing else: gs_idx = ((idx - hang_size) % (columns - 1) + 1) * gs_colspan gs_jdy = ((idx - hang_size) / (columns - 1)) * gs_rowspan elif hanging == 'right': if idx >= (columns - 1) * rows: gs_idx = columns * gs_colspan - 1 gs_jdy = (idx - (columns - 1) * rows) * gs_rowspan + n_missing else: gs_idx = idx % (columns - 1) * gs_colspan gs_jdy = idx / (columns - 1) * gs_rowspan elif hanging == 'top': if idx < columns - n_missing: gs_idx = idx * gs_colspan + n_missing gs_jdy = 0 else: idx = (idx - hang_size) gs_idx = (idx % columns) * gs_colspan gs_jdy = (idx / columns) * gs_rowspan + 1 elif hanging == 'bottom': if idx >= (rows - 1) * columns: gs_idx = (idx - (rows - 1) * columns) * gs_colspan + n_missing gs_jdy = rows * gs_rowspan - 1 else: gs_idx = (idx % columns) * gs_colspan gs_jdy = (idx / columns) * gs_rowspan else: gs_idx = (idx % columns) * gs_colspan gs_jdy = (idx / columns) * gs_rowspan return gs_idx, gs_jdy
[docs]def get_subplot_position(gs): """ Get a subplot's position in the figure layout. Args: gs (gridspec): A matplotlib gridspec object, perhaps obtained from the `gs_parent` keyword argument to your subpanel function. Returns: A tuple containing the row and column of the subplot. Rows and columns are zero-based. """ return gs.get_position(pylab.gcf(), return_all=True)[1:3]
[docs]def publication_figure(subfigures, layout, corner='ul', colorbar=None, hanging='bottom', dpi=300): """ Make publication figures out of many panels, automatically adding the subfigure letter and generating a figure colorbar. Args: subfigures (list): A list of functions, each of which plots a panel of the figure. Each function should take **kwargs as arguments. layout (tuple): A tuple specifying how the panels are arranged (e.g. (2, 4) for a figure with 2 rows and 4 columns) corner (str): The corner in which to put the figure letter. Acceptable values are 'ul' for the upper-left corner, 'lr' for the lower-right corner, etc. colorbar (dict): A dictionary specifying how to create the figure colorbar. hanging (str): If the number of panels does not fit into the layout (e.g. 3 panels in a 2 :math:`\\times` 2 layout), this specifies where to have the incomplete row/column. Acceptable values are 'left', 'bottom', 'right', and 'top'. dpi (float): Set the figure dpi to be at least this amount. If it's already more than `dpi`, don't mess with it. """ rows, columns = layout n_missing = rows * columns - len(subfigures) if n_missing == 0: hanging = 'bottom' gs_rowspan, gs_colspan = 1, 1 if hanging in ['top', 'bottom']: gs_colspan = 2 elif hanging in ['left', 'right']: gs_rowspan = 2 multiplier = get_multiplier() bbox = {'ec': 'k', 'fc': 'w', 'pad': 5, 'lw': multiplier} loc = {'ul': (0.0, 1.0), 'ur': (1.0, 1.0)} align = {'ul': ('left', 'top'), 'ur': ('right', 'top')} pad_signs = {'l': 1, 'r': -1, 'u': -1} matplotlib.rcdefaults() for rc in ['axes.linewidth', 'xtick.major.size', 'ytick.major.size']: matplotlib.rcParams[rc] *= multiplier pylab.gcf().dpi = max(dpi, pylab.gcf().dpi) grid_spec = gridspec.GridSpec(rows * gs_rowspan, columns * gs_colspan) scal_map = None if type(colorbar) in [list, tuple]: left_colorbar, colorbar = colorbar else: left_colorbar = None for idx, sf in enumerate(subfigures): gs_idx, gs_jdy = _get_gs_indices(idx, layout, (gs_rowspan, gs_colspan), n_missing, hanging) gs = grid_spec[gs_jdy:(gs_jdy + gs_rowspan), gs_idx:(gs_idx + gs_colspan)] sp = pylab.subplot(gs) n_axes = len(pylab.gcf().axes) c_levels = None if type(colorbar) is dict and 'ticks' in colorbar: c_levels = colorbar['ticks'] scm = sf(multiplier=multiplier, gs_parent=gs, c_levels=c_levels) if scm: scal_map = scm if len(pylab.gcf().axes) > n_axes + 1: pylab.sca(sp) sp.xaxis.set_visible(False) sp.yaxis.set_visible(False) sp.set_frame_on(False) if layout != (1, 1): offset = transforms.ScaledTranslation(pad_signs[corner[1]] * bbox['pad'] / 72., pad_signs[corner[0]] * bbox['pad'] / 72., pylab.gcf().dpi_scale_trans) text_transform = pylab.gca().transAxes + offset text_x, text_y = loc[corner] h_align, v_align = align[corner] pylab.text(text_x, text_y, "(%s)" % string.ascii_lowercase[idx], transform=text_transform, bbox=bbox, ha=h_align, va=v_align, fontsize=16 * multiplier, fontweight='bold', zorder=10000) if idx == 0 and left_colorbar: _make_colorbar(left_colorbar, scal_map, multiplier, left=True) if colorbar: _make_colorbar(colorbar, scal_map, multiplier) return
if __name__ == "__main__": import numpy as np def subplot_factory(): def do_subplot(**kwargs): xs, ys = np.random.rand(2, 50) pylab.plot(xs, ys, 'ko') return return do_subplot subplots = [ subplot_factory() for idx in xrange(11) ] for hang in ['top', 'bottom', 'left', 'right']: print hang pylab.figure() publication_figure(subplots, layout=(3, 4), corner='ur', hanging=hang) pylab.savefig("pubfig_test_%s.png" % hang) pylab.close()