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()