Source code for secml.figure.c_figure

"""
.. module:: CFigure
   :synopsis: A figure for making plots.

.. moduleauthor:: Marco Melis <marco.melis@unica.it>
.. moduleauthor:: Ambra Demontis <ambra.demontis@unica.it>

"""
from secml.core import CCreator
from secml.figure._plots import CPlot
from secml.utils import LastInDict
from secml.core.type_utils import is_tuple

import os
import matplotlib as mpl
if os.name == 'posix' and os.environ.get('DISPLAY', '') == '':
    # If no display is available, use file-only backend
    mpl.use('Agg')

import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec


[docs]class CFigure(CCreator): """Creates a Figure. A Figure is a collection of subplots. The last active subplot can be accessed by calling CFigure.sp`, followed by the desired plotting function (plot, scatter, contour, etc.). Each subplot is identified by an index (grid slot) inside an imaginary grid (n_rows, n_columns, grid_slot), counting from left to right, from top to bottom. By default, a subplot is created in a single-row, single-column imaginary grid (1, 1, 1). Parameters ---------- height : scalar, optional Height of the new figure. Default 6. width : scalar, optional Width of the new figure. Default 6. title : str, optional Super title of the new figure. This is not the subplot title. To set a title for active subplot use :meth:`.subtitle`. Default is to not set a super title. linewidth : float, optional Define default linewidth for all subplots. Default 2. fontsize : int, optional Define default fontsize for all subplots. Default 12. markersize : scalar, optional Define default markersize for all subplots. Default 7. Notes ----- Not all `matplotlib` methods and/or parameters are currently available. If needed, directly access the `matplotlib.Axes` active subplot instance through the `CFigure.sp._sp` parameter. Examples -------- >>> from secml.figure import CFigure >>> fig = CFigure(fontsize=14) >>> fig.sp.plot([0, 1], color='red') >>> fig.show() # This will open a new window with the figure """ def __init__(self, height=6, width=6, title="", fontsize=12, linewidth=2, markersize=7): # Instancing figure with desired dimensions self.width = width self.height = height self._fig = plt.figure(figsize=(self.width, self.height)) # Setting default fontsize, linewidth, markersize self._default_params = {'font.size': fontsize, 'lines.linewidth': linewidth, 'lines.markersize': markersize} # Setting figure super title self.title(title) # Setting up the subplots container self._sp_data = LastInDict() # Handle of the subplot grid self._gs = None @property def sp(self): """Return reference to active subplot class. If no subplot is available, creates a new standard subplot in `(1,1,1)` position and returns its reference. """ if self.n_sp == 0: self.subplot(1, 1, 1) return self._sp_data.lastin @property def n_sp(self): """Returns the number of created subplots.""" return len(self._sp_data)
[docs] def get_state(self): raise NotImplementedError
[docs] def set_state(self, state_dict, copy=False): raise NotImplementedError
[docs] def load_state(self, path): raise NotImplementedError
[docs] def save_state(self, path): raise NotImplementedError
[docs] def subplot(self, n_rows=1, n_cols=1, grid_slot=1, **kwargs): """Create a new subplot into specific position. Creates a new subplot placing it in the n_plot position of the n_rows * n_cols imaginary grid. Position is indexed in raster-scan. If subplot is created in a slot occupied by another subplot, old subplot will be used. Parameters ---------- n_rows : int Number of rows of the imaginary grid used for subdividing the figure. Default 1 (one row). n_cols : int Number of columns of the imaginary grid used for subdividing the figure. Default 1 (one column). grid_slot : int or tuple If int, raster scan position of the new subplot. Default 1. If tuple, index of the slot of the grid. Each dimension can be specified as an int or a slice, e.g. in a 3 x 3 subplot grid, grid_slot=(0, slice(1, 3)) will create a subplot at row index 0 that spans between columns index 1 and 2. Examples -------- .. plot:: pyplots/subplot.py :include-source: """ # Create a new grid if shape has changed or this is the first grid if self._gs is None or self._gs.get_geometry()[0] != n_rows or \ self._gs.get_geometry()[1] != n_cols: self._gs = gridspec.GridSpec(n_rows, n_cols) # If grid_slot is not a tuple, assume we want to use a single slot grid_slot = grid_slot-1 if not is_tuple(grid_slot) else grid_slot # Calling matplotlib subplot switcher axes = self._fig.add_subplot(self._gs[grid_slot], **kwargs) # Set default parameters axes.tick_params(labelsize=self._default_params['font.size']) sp_id = hex(id(axes)) # Index of the subplot # Create the subplot if not available or switch lastitem reference if sp_id not in self._sp_data: self._sp_data[sp_id] = CPlot( sp=axes, default_params=self._default_params) else: self._sp_data.lastin_key = sp_id return self.sp
[docs] def get_default_params(self): """Return current defaults for the figure. Returns ------- default_parameters : dict Contain default parameters value set. """ return self._default_params
[docs] @staticmethod def show(block=True): """Show all created figures. Parameters ---------- block : boolean, default True If true, execution is halted until the showed figure(s) are closed. """ plt.show(block=block)
[docs] def close(self, fig=None): """Close current or input figure. Parameters ---------- fig : CFigure or None Handle to figure to close. If None (default), current figure is closed. """ plt.close(self._fig if fig is None else fig)
[docs] def subplots_adjust(self, left=0.125, right=0.9, bottom=0.1, top=0.9, wspace=0.2, hspace=0.2): """Tune the subplot layout. Parameters ---------- left : float, default 0.125 Left side of the subplots. right : float, default 0.9 Right side of the subplots. bottom : float, default 0.1 Bottom of the subplots. top : float, default 0.9 Top of the subplots. wspace : float, default 0.2 Amount of width reserved for blank space between subplots. hspace : float, default 0.2 Amount of height reserved for white space between subplots Examples -------- .. plot:: pyplots/subplots_adjust.py :include-source: """ self._fig.subplots_adjust(left=left, bottom=bottom, right=right, top=top, wspace=wspace, hspace=hspace)
[docs] def tight_layout(self, pad=1.08, h_pad=None, w_pad=None, rect=None): """Adjust space between plot and figure. Parameters ---------- pad : float, default 1.08 Padding between the figure edge and the edges of subplots, as a fraction of the font-size. h_pad, w_pad : float, defaults to pad_inches. padding (height/width) between edges of adjacent subplots. rect : tuple of scalars, default is (0, 0, 1, 1). (left, bottom, right, top) in the normalized figure coordinate that the whole subplots area (including labels) will fit into. """ self._fig.tight_layout(pad=pad, h_pad=h_pad, w_pad=w_pad, rect=rect)
[docs] def title(self, label, **kwargs): """Set the global title for current figure. Parameters ---------- label : str Text to use for the title. **kwargs Same as :meth:`.text` method. """ if 'fontsize' not in kwargs: kwargs['fontsize'] = self.get_default_params()['font.size'] return self._fig.suptitle(label, **kwargs)
[docs] def savefig(self, fname, dpi=None, facecolor='w', edgecolor='w', orientation='portrait', file_format=None, transparent=False, bbox_inches=None, bbox_extra_artists=None, pad_inches=0.1): """Save figure to disk. Parameters ---------- fname : string containing a path to a filename, or a Python file-like object. If file_format is None and fname is a string, the output file_format is deduced from the extension of the filename. If the filename has no extension, the value of the rc parameter savefig.file_format is used. If fname is not a string, remember to specify file_format to ensure that the correct backend is used. dpi : [ None | scalar > 0 ], optional The resolution in dots per inch. If None it will default to the value savefig.dpi in the matplotlibrc file. facecolor, edgecolor : color or str, optional The colors of the figure rectangle. Default 'w' (white). orientation: [ 'landscape' | 'portrait' ], optional not supported on all backends; currently only on postscript output file_format : str, optional One of the file extensions supported by the active backend. Most backends support png, pdf, ps, eps and svg. transparent : bool, optional If True, the axes patches will all be transparent; the figure patch will also be transparent unless facecolor and/or edgecolor are specified via kwargs. This is useful, for example, for displaying a plot on top of a colored background on a web page. The transparency of these patches will be restored to their original values upon exit of this function. bbox_inches : scalar or str, optional Bbox in inches. Only the given portion of the figure is saved. If 'tight', try to figure out the tight bbox of the figure. bbox_extra_artists : list A list of extra artists that will be considered when the tight bbox is calculated. pad_inches : scalar Amount of padding around the figure when bbox_inches is 'tight'. """ self._fig.savefig(fname, dpi=dpi, facecolor=facecolor, edgecolor=edgecolor, orientation=orientation, format=file_format, transparent=transparent, bbox_inches=bbox_inches, pad_inches=pad_inches, bbox_extra_artists=bbox_extra_artists)