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 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', papertype=None, file_format=None,
transparent=False, bbox_inches=None, bbox_extra_artists=None,
pad_inches=0.1, frameon=None):
"""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
papertype : str, optional
One of 'letter', 'legal', 'executive', 'ledger',
'a0' through 'a10', 'b0' through 'b10'.
Only supported for 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'.
frameon : bool, optional
If True, the figure patch will be colored, if False, the figure
background will be transparent. If not provided, the rcParam
'savefig.frameon' will be used.
"""
self._fig.savefig(fname, dpi=dpi, facecolor=facecolor,
edgecolor=edgecolor, orientation=orientation,
papertype=papertype, format=file_format,
transparent=transparent, frameon=frameon,
bbox_inches=bbox_inches, pad_inches=pad_inches,
bbox_extra_artists=bbox_extra_artists)