Source code for HErmes.plotting.canvases

"""
Provides canvases for multi axes plots
"""

from builtins import object
import os.path
import pylab as p
import tempfile

from HErmes.utils.logger import Logger
try:
    from IPython.core.display import Image
except ImportError:
    try:
        from IPython.display import DisplayObject as Image
    except ImportError:
        Logger.debug("Can not import IPython!")
[docs] def Image(x): x
# golden cut values from .layout import FIGSIZE_A4_SQUARE, FIGSIZE_A4, FIGSIZE_A4_LANDSCAPE ##########################################
[docs]class YStackedCanvas(object): """ A canvas for plotting multiple axes """ def __init__(self, subplot_yheights=(.2,.2,.5),\ padding=(0.15, 0.05, 0.0, 0.1 ),\ space_between_plots=0,\ figsize="auto", figure_factory=None): """ Create a new canvas with multiple axes on top of each other. The height of the individual axes can be specified. In most cases, the defaults should be reasonable. Keyword Args: subplot_yheights (iterable): The normalized heights of the individual subplots. Sorted from bottom to top padding (left, right, top, bottom): The padding around the figure figsize (width, height) or str: The size of the figure (in inches). Keyword "auto" means the plot figures it out by itself. space_between_plots (float): Distance between the subplots figure_factory (func): Factory function must return matplotlib.Figure """ assert sum(subplot_yheights) <= 1., "subplot_yheights must be in relative heights" assert len(padding) == 4, "Needs 4 values for padding (left, right, top, bottom)" self.axes = None if figure_factory is None: if figsize == "auto": # FIXME: something more clever should happen here self.figure = p.figure(figsize=FIGSIZE_A4_SQUARE) else: self.figure = p.figure(figsize=figsize) else: self.figure = figure_factory() # self.create_top_stacked_axes(heights=axeslayout) left, right, top, bot = padding width = 1. - left - right height = 1. - top - bot # calculate absolute heights and stack the axes # from bottom to top heights = [height * h for h in subplot_yheights] heights.reverse() Logger.debug("Using heights {0}".format(heights.__repr__())) abs_bot = 0 + bot axes = [p.axes([left, abs_bot, width, heights[0]])] abs_bot = bot + heights[0] for h in heights[1:]: Logger.warn("Creating axes with {}".format(left, abs_bot, width, h)) theaxis = p.axes([left, abs_bot, width, h], sharex=axes[0]) p.setp(theaxis.get_xticklabels(), visible=False) p.setp(theaxis.get_xticklines(), visible=False) #theaxis.xaxis.minorTicks = [] #theaxis.xaxis.majorTicks = [] axes.append(theaxis) abs_bot += h + space_between_plots self.axes = axes self.png_filename = None for subplot in self.axes: self.figure.add_axes(subplot) self.figure.subplots_adjust(hspace=0) self.savekwargs = dict() # def create_top_stacked_axes(self, heights=(1.)): # """ # Create several axes for subplot on top of each other # # Args: # heights (iterable): relative height e.g. # heights = [.2,.1,.6] will give axes using this amount of # space # """ # # cfg = get_config_item("canvas") # left = cfg["leftpadding"] # right = cfg["rightpadding"] # bot = cfg["bottompadding"] # top = cfg["toppadding"] # width = 1. - left - right # height = 1. - top - bot # # heights = [height*h for h in heights] # heights.reverse() # Logger.debug("Using heights {0}".format(heights.__repr__())) # abs_bot = 0 + bot # axes = [p.axes([left, abs_bot,width,heights[0]])] # restheights = heights[1:] # abs_bot = bot + heights[0] # for h in restheights: # theaxes = p.axes([left,abs_bot,width,h]) # p.setp(theaxes.get_xticklabels(), visible=False) # axes.append(theaxes) # abs_bot += h # # self.axes = axes
[docs] def limit_yrange(self, ymin=None, ymax=None): """ Walk through all axes and adjust ymin and ymax Keyword Args: ymin (float): min ymin value """ for ax in self.axes: if ymin is not None: ax.set_ylim(ymin=ymin) if ymax is not None: ax.set_ylim(ymax=ymax)
[docs] def limit_xrange(self, xmin=None, xmax=None): """ Walk through all axes and set xlims Keyword Args: xmin (float): left x edge of axes xmax (float): right x edge of axes Returns: None """ for ax in self.axes: if xmin is not None: ax.set_xlim(xmin=xmin) if xmax is not None: ax.set_xlim(xmax=xmax)
[docs] def eliminate_lower_yticks(self): """ Eliminate the lowest y tick on each axes. The bottom axes keeps its lowest y-tick. """ for ax in self.axes[1:]: ax.yaxis.get_major_ticks()[0].label1.set_visible(False) ax.yaxis.get_major_ticks()[-1].label1.set_visible(False)
[docs] def select_axes(self, axes): """ Set the scope on a certain axes Args: axes (int): 0 lowest, -1 highest, increasing y-order Returns: matplotlib.axes.axes: The axes instance """ #print (axes) ax = self.axes[axes] p.sca(ax) return ax
[docs] def global_legend(self, *args, **kwargs): """ A combined legend for all axes Args: all args will be passed to pylab.legend Keyword Args: all kwargs will be passed to pylab.legend """ handles, labels = self.select_axes(-1).get_legend_handles_labels() if args: args = [i[1] for i in args] self.legend = p.legend(*args, **kwargs)
#else: # self.legend = p.legend([i[0] for i in legitems], # [i[1] for i in legitems],**kwargs) # bbox_to_anchor=self.leg_bbox, # bbox_transform=self.figure.transFigure, # mode="expand", borderaxespad=0, # loc="lower left", # **kwargs)
[docs] def save(self, path, name, formats=("pdf", "png"), **kwargs): """ Calls pylab.savefig for all endings Args: path (str): path to savefile name (str): filename to save formats (tuple): for each name in endings, a file is save Keyword Args: all keyword args will be passed to pylab.savefig Returns: str: The full path to the the saved file """ ending = name.split(".")[-1] if ending in formats: name = name.replace("." + ending, "") for theformat in formats: filename = os.path.join(path, name + '.' + theformat) self.figure.savefig(filename, format=theformat, **kwargs) if theformat == "png": self.png_filename = filename return self.png_filename
[docs] def show(self): """ Use the IPython.core.Image to show the plot Returns: IPython.core.Image: the plot """ with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as f: self.figure.savefig(f, format="png") return Image(f.name)