Module thunderhopper.plottools
Functions
def setup_fig(rows=1,
cols=1,
size=None,
width=16.0,
height=None,
row_height=3.0,
unit=0.39370078740157477,
with_axes=True,
return_specs=False,
letter_specs={},
uppercase=False,
**kwargs)-
Expand source code
def setup_fig(rows=1, cols=1, size=None, width=16., height=None, row_height=3., unit=1 / 2.54, with_axes=True, return_specs=False, letter_specs={}, uppercase=False, **kwargs): """ Creates a standardized figure, with or without a grid of subplots. Figure size can be specified directly or calculated from other inputs. Size-related parameters are converted from inches to the desired unit. Can optionally return a dictionary of figure size, grid layout, and characters for subplot annotations with specified font properties. Parameters ---------- rows : int, optional Number of subplot rows in the grid. The default is 1. cols : int, optional Number of subplot columns in the grid. The default is 1. size : tuple or list (2,) of floats or ints, optional If specified, sets the figure size (width, height) in the given unit. width : float or int, optional If specified and size is None, sets the figure width in unit. The default is 16.0. height : float or int, optional If specified and size is None, sets the figure height in unit. If both size and height are None, calculated as row_height * rows in unit. The default is None. row_height : float or int, optional If specified and height and size are None, determines the figure height by row_height * rows in unit. Height of rendered subplots will likely be smaller due to padding space taken from figure. The default is 3.0. unit : float, optional Conversion factor to transform size, width, height, and row_height from default inches to the desired unit. The default is 1 / 2.54 for cm. with_axes : bool, optional If True, calls plt.subplots() with rows, cols, figsize, and additional keyword arguments, and returns the figure and axes handles. Else, calls plt.figure() with figsize and additional keyword arguments, and returns the figure handle. The default is True. return_specs : bool, optional If True, also returns a dictionary of figure properties and subplot annotation letters. Contains 'size', 'grid', 'chars', and 'char_specs'. The default is False. letter_specs : dict, optional Text properties to update returned default 'char_specs' dictionary. Ignored if return_specs is False. The default is {}. uppercase : bool, optional If True, returns uppercase strings as letters for subplot annotations, else lowercase. Ignored if return_specs is False. The default is False. **kwargs : dict, optional Additional keyword arguments passed to plt.subplots() if with_axes is True, or to plt.figure() if with_axes is False. Returns ------- fig : matplotlib figure object Handle to the created figure. axes : (array of) matplotlib axes objects Handles to the created subplots in the requested grid layout. Only returned if with_axes is True. params : dict Contains 'size' for the figure size (width, height) in unit, 'grid' for the grid layout (rows, cols), 'chars' for a list of string characters for subplot annotations (as many as axes), and 'char_specs' for a dictionary of text properties to pass to plt.text() when annotating subplots. Only returned if return_specs is True. """ # Input interpretation: if size is None: if height is None: # Equal aspect for single subplot, else scaled by row number: height = width if (rows * cols) == 1 else rows * row_height size = (width * unit, height * unit) else: # Convert units of specified size: size = (size[0] * unit, size[1] * unit) # Expand figure settings: kwargs['figsize'] = size if return_specs: # Fetch letters for subplot annotations: chars = string.ascii_uppercase if uppercase else string.ascii_lowercase chars = list(chars[:rows * cols]) # Default font: char_specs = { 'x': 0, 'y': 1.125, 'c': 'k', 'fontsize': 15, 'weight': 'bold', 'ha': 'center', 'va': 'center' } # Override with user settings: char_specs.update(letter_specs) # Wrap up: specs = { 'size': size, 'grid': (rows, cols), 'chars': chars, 'char_specs': char_specs } # Return options: if with_axes: # Figure with one or multiple subplots: fig, axes = plt.subplots(rows, cols, **kwargs) return (fig, axes, specs) if return_specs else (fig, axes) # Blank figure: fig = plt.figure(**kwargs) return (fig, specs) if return_specs else fig
Creates a standardized figure, with or without a grid of subplots. Figure size can be specified directly or calculated from other inputs. Size-related parameters are converted from inches to the desired unit. Can optionally return a dictionary of figure size, grid layout, and characters for subplot annotations with specified font properties.
Parameters
rows
:int
, optional- Number of subplot rows in the grid. The default is 1.
cols
:int
, optional- Number of subplot columns in the grid. The default is 1.
size
:tuple
orlist (2,)
offloats
orints
, optional- If specified, sets the figure size (width, height) in the given unit.
width
:float
orint
, optional- If specified and size is None, sets the figure width in unit. The default is 16.0.
height
:float
orint
, optional- If specified and size is None, sets the figure height in unit. If both size and height are None, calculated as row_height * rows in unit. The default is None.
row_height
:float
orint
, optional- If specified and height and size are None, determines the figure height by row_height * rows in unit. Height of rendered subplots will likely be smaller due to padding space taken from figure. The default is 3.0.
unit
:float
, optional- Conversion factor to transform size, width, height, and row_height from default inches to the desired unit. The default is 1 / 2.54 for cm.
with_axes
:bool
, optional- If True, calls plt.subplots() with rows, cols, figsize, and additional keyword arguments, and returns the figure and axes handles. Else, calls plt.figure() with figsize and additional keyword arguments, and returns the figure handle. The default is True.
return_specs
:bool
, optional- If True, also returns a dictionary of figure properties and subplot annotation letters. Contains 'size', 'grid', 'chars', and 'char_specs'. The default is False.
letter_specs
:dict
, optional- Text properties to update returned default 'char_specs' dictionary. Ignored if return_specs is False. The default is {}.
uppercase
:bool
, optional- If True, returns uppercase strings as letters for subplot annotations, else lowercase. Ignored if return_specs is False. The default is False.
**kwargs
:dict
, optional- Additional keyword arguments passed to plt.subplots() if with_axes is True, or to plt.figure() if with_axes is False.
Returns
fig
:matplotlib figure object
- Handle to the created figure.
axes
:(array of) matplotlib axes objects
- Handles to the created subplots in the requested grid layout. Only returned if with_axes is True.
params
:dict
- Contains 'size' for the figure size (width, height) in unit, 'grid' for the grid layout (rows, cols), 'chars' for a list of string characters for subplot annotations (as many as axes), and 'char_specs' for a dictionary of text properties to pass to plt.text() when annotating subplots. Only returned if return_specs is True.
def switch_transforms(coords, current, target, bbox=False)
-
Expand source code
def switch_transforms(coords, current, target, bbox=False): """ Converts coordinates from one matplotlib transform to another. Each of matplotlib's transforms maps only from one distinct coordinate system into display coordinates, or back using the inverse transform. To remap coordinates from one non-display coordinate system to another, coordinates must first be converted to display coordinates using the current transform, and then mapped to the desired coordinate system using the inverse of the target transform. Available transforms include: # ax.transAxes (relative axes coordinates) # ax.transData (axes coordinates in data units) -> CHANGES WITH LIMITS! # subfigure.transSubfigure (relative subfigure coordinates) # fig.transFigure (relative figure coordinates) # fig.dpi_scale_trans (figure coordinates in inches) # ax.get_xaxis_transform() (blended relative/data axes coordinates) # ax.get_yaxis_transform() (blended relative/data axes coordinates) # IdentityTransform (display coordinates, no conversion). Parameters ---------- coords : 2D array (m, 2) or array-like (2 * m,) of floats or ints Coordinates to be transformed. Number of elements must be even. If bbox is False, expects pure point coordinates as pairs (x, y). If bbox is True, expects bounding boxes as multiples of 4 (x, y, width, height). current : matplotlib transform Current coordinate system of the provided coordinates. target : matplotlib transform Target coordinate system to convert coordinates to. bbox : bool, optional If True, expects bounding box coordinates (x, y, width, height). Necessary to correctly convert rectangle extents. The default is False. Returns ------- coordinates : 2D array (m, 2) or 1D array (2 * m,) of floats Converted coordinates in the coordinate system specified by target. If bbox is True, output shape is (m, 4) or (4 * m,) instead. """ # Define required transformation: double_transform = current + target.inverted() if not bbox: # Pure point coordinates: return double_transform.transform(coords) # Bounding box coordinates: if not isinstance(coords, np.ndarray): coords = np.array(coords) dims = coords.ndim coords = np.reshape(coords, (-1, 4)) coords[:, 2:] += coords[:, :2] coords = double_transform.transform(coords).reshape(-1, 4) coords[:, 2:] -= coords[:, :2] return coords if dims == 2 else coords.ravel()
Converts coordinates from one matplotlib transform to another. Each of matplotlib's transforms maps only from one distinct coordinate system into display coordinates, or back using the inverse transform. To remap coordinates from one non-display coordinate system to another, coordinates must first be converted to display coordinates using the current transform, and then mapped to the desired coordinate system using the inverse of the target transform.
Available transforms include: # ax.transAxes (relative axes coordinates) # ax.transData (axes coordinates in data units) -> CHANGES WITH LIMITS! # subfigure.transSubfigure (relative subfigure coordinates) # fig.transFigure (relative figure coordinates) # fig.dpi_scale_trans (figure coordinates in inches) # ax.get_xaxis_transform() (blended relative/data axes coordinates) # ax.get_yaxis_transform() (blended relative/data axes coordinates) # IdentityTransform (display coordinates, no conversion).
Parameters
coords
:2D array (m, 2)
orarray-like (2 * m,)
offloats
orints
- Coordinates to be transformed. Number of elements must be even. If bbox is False, expects pure point coordinates as pairs (x, y). If bbox is True, expects bounding boxes as multiples of 4 (x, y, width, height).
current
:matplotlib transform
- Current coordinate system of the provided coordinates.
target
:matplotlib transform
- Target coordinate system to convert coordinates to.
bbox
:bool
, optional- If True, expects bounding box coordinates (x, y, width, height). Necessary to correctly convert rectangle extents. The default is False.
Returns
coordinates
:2D array (m, 2)
or1D array (2 * m,)
offloats
- Converted coordinates in the coordinate system specified by target. If bbox is True, output shape is (m, 4) or (4 * m,) instead.
def update_limits(ax, which, low=None, high=None, axes=None, expand=True)
-
Expand source code
def update_limits(ax, which, low=None, high=None, axes=None, expand=True): """ Decides whether to adjust current axes limits to the specified bounds. Can either contract or expand the limits by choosing the smaller or larger of the current and the given bound. Applies new axes limits to the target subplot as well as any other passed subplot. Best used in combination with a tick locator. Parameters ---------- ax : matplotlib axes object Target subplot whose current axes limits are used as reference. which : str Target axis or axes of the subplot. Options are 'x', 'y', or 'both'. low : float or int, optional If specified, potential new lower bound of the requested target axis. The default is None. high : float or int, optional If specified, potential new upper bound of the requested target axis. The default is None. axes : (1D array or list or tuple of) matplotlib axes object(s), optional If specified, applies the new axes limits to these subplots as well. The default is None. expand : bool, optional If True, expands the current axis limits by taking the smaller lower bound and the larger upper bound. Else, contracts the limits by taking the larger lower bound and smaller upper bound. The default is True. """ # Bundle targets: subplots = [ax] if np.iterable(axes): subplots.extend(axes) elif axes is not None: subplots.append(axes) # Decide between expanding or contracting axes limits: low_func, high_func = (min, max) if expand else (max, min) # Treat x-axis limits: if which == 'x' or which == 'both': limits = ax.get_xlim() if low is not None: low_limit = low_func([limits[0], low]) [ax.set_xlim(left=low_limit) for ax in subplots] if high is not None: high_limit = high_func([limits[1], high]) [ax.set_xlim(right=high_limit) for ax in subplots] # Treat y-axis limits: if which == 'y' or which == 'both': limits = ax.get_ylim() if low is not None: low_limit = low_func([limits[0], low]) [ax.set_ylim(bottom=low_limit) for ax in subplots] if high is not None: high_limit = high_func([limits[1], high]) [ax.set_ylim(top=high_limit) for ax in subplots] return None
Decides whether to adjust current axes limits to the specified bounds. Can either contract or expand the limits by choosing the smaller or larger of the current and the given bound. Applies new axes limits to the target subplot as well as any other passed subplot. Best used in combination with a tick locator.
Parameters
ax
:matplotlib axes object
- Target subplot whose current axes limits are used as reference.
which
:str
- Target axis or axes of the subplot. Options are 'x', 'y', or 'both'.
low
:float
orint
, optional- If specified, potential new lower bound of the requested target axis. The default is None.
high
:float
orint
, optional- If specified, potential new upper bound of the requested target axis. The default is None.
axes
:(1D array
orlist
ortuple of) matplotlib axes object(s)
, optional- If specified, applies the new axes limits to these subplots as well. The default is None.
expand
:bool
, optional- If True, expands the current axis limits by taking the smaller lower bound and the larger upper bound. Else, contracts the limits by taking the larger lower bound and smaller upper bound. The default is True.
def data_limits(data, margins=0.1, axes=None, which=None, log=False)
-
Expand source code
def data_limits(data, margins=0.1, axes=None, which=None, log=False): """ Computes padded lower and upper axes limits to fully encompass data. Limits are calculated as minimum and maximum values of data padded by some proportion of the data range. Same functionality as ax.margin(), but supports individual margins for lower and upper limits. Parameters ---------- data : list of floats or ints (m,) or array of arbitrary shape Plotted data for which to compute limits. Accepts any iterable. Extreme values are always calculated over the flattened data. margins : float or tuple/list of floats (2,), optional Proportion of the data range (maximum - minimum) to use for padding. If scalar, uses the same margin for both lower and upper limits. Two provided values define individual margins for lower and upper limits, respectively. The default is 0.1. axes : matplotlib axes object or list of axes objects, optional If specified, directly applies the calculated limits to the desired axes of the given subplots. The default is None. which : str, optional Target axis or axes of each given subplot to apply the calculated limits. Ignored if axes is None. Options are 'x', 'y', or 'both'. The default is None. log : bool, optional If True, assumes log-scaled data and adjusts padding calculation so that the same margin for lower and upper limits results in visually equal padding on a logarithmic scale. The default is False. Returns ------- limits : tuple of floats (2,) Calculated axes limits to encompass the data with the given margins. """ # Input interpretation: if not isinstance(margins, (list, tuple)): margins = (margins, margins) # Assert iterable: axes = check_list(axes) # Determine extremes and range of data: minimum, maximum = np.min(data), np.max(data) span = maximum - minimum if not log: # Pad extremes by proportion of data range on a linear scale: limits = (minimum - span * margins[0], maximum + span * margins[1]) else: # Pad on a logarithmic scale and convert back to linear scale: limits = (10**(np.log10(minimum) - np.log10(span) * margins[0]), 10**(np.log10(maximum) + np.log10(span) * margins[1])) # Optional application of calculated axes limits: if axes is not None and (which == 'x' or which == 'both'): [ax.set_xlim(limits) for ax in axes] if axes is not None and (which == 'y' or which == 'both'): [ax.set_ylim(limits) for ax in axes] return limits
Computes padded lower and upper axes limits to fully encompass data. Limits are calculated as minimum and maximum values of data padded by some proportion of the data range. Same functionality as ax.margin(), but supports individual margins for lower and upper limits.
Parameters
data
:list
offloats
orints (m,)
orarray
ofarbitrary shape
- Plotted data for which to compute limits. Accepts any iterable. Extreme values are always calculated over the flattened data.
margins
:float
ortuple/list
offloats (2,)
, optional- Proportion of the data range (maximum - minimum) to use for padding. If scalar, uses the same margin for both lower and upper limits. Two provided values define individual margins for lower and upper limits, respectively. The default is 0.1.
axes
:matplotlib axes object
orlist
ofaxes objects
, optional- If specified, directly applies the calculated limits to the desired axes of the given subplots. The default is None.
which
:str
, optional- Target axis or axes of each given subplot to apply the calculated limits. Ignored if axes is None. Options are 'x', 'y', or 'both'. The default is None.
log
:bool
, optional- If True, assumes log-scaled data and adjusts padding calculation so that the same margin for lower and upper limits results in visually equal padding on a logarithmic scale. The default is False.
Returns
limits
:tuple
offloats (2,)
- Calculated axes limits to encompass the data with the given margins.
def log_axes(axes,
which,
scale='log',
base=10,
subs=[2, 3, 4, 5, 6, 7, 8, 9],
linthresh=None,
linscale=None,
x=None,
y=None,
xlim=(None, None),
ylim=(None, None),
zerotol=None)-
Expand source code
def log_axes(axes, which, scale='log', base=10, subs=[2, 3, 4, 5, 6, 7, 8, 9], linthresh=None, linscale=None, x=None, y=None, xlim=(None, None), ylim=(None, None), zerotol=None): """ Logarithmic rescaling of one or both axes of the given target subplots. Can handle log-incompatible (zero or negative) values in the axis data by switching to a symmetric pseudo-logarithmic (symlog) axis scaling. Parameters ---------- axes : matplotlib axes or 1D array-like of matplotlib axes One or several target subplots for logarithmic axis rescaling. which : str Target axis for rescaling. Options are 'x', 'y', or 'both'. scale : str, optional Type of logarithmic scale to apply. Options are 'log' for standard logarithmic scaling, or 'symlog' for symmetric pseudo-logarithmic scaling with a central linear region around zero and two mirrored logarithmic sides. If x or y axis data is given and contains any non- positive values, replaces log with symlog scale. The default is 'log'. base : int, optional Base of the logarithm. The default is 10. subs : 1D array-like of ints, optional Number and position of minor axis ticks within one decade on the log scale (e.g. from 1 to 10). The default is [2, 3, 4, 5, 6, 7, 8, 9], resulting in 8 equally spaced minor ticks for a base-10 logarithm. linthresh : float or int, optional Transition point between the linear region and each logarithmic side of the symlog scale. If x or y axis data is given, set to the minimum absolute non-zero value with respect to zerotol, else falls back to a default value of 1e-3. The default is None. linscale : float, optional Factor for warping each side of the linear region on the symlog scale, in multiples of the visual space occupied by a single decade on the logarithmic sides. If x or y axis data is given, set to 0.25 for a one- sided symlog (one axis limit at 0), or 0.5 for two-sided. The default is None. x : ND array of floats or ints, optional Collection of values to be represented on the x-axis. Triggers switch to symlog scale if any non-positive values are present. Used to infer missing linthresh and linscale inputs. Unspecified axis limits are set to match the range of the data. The default is None. y : ND array of floats or ints, optional Collection of values to be represented on the y-axis. Triggers switch to symlog scale if any non-positive values are present. Used to infer missing linthresh and linscale inputs. Unspecified axis limits are set to match the range of the data. The default is None. xlim : 1D array-like of floats or ints or None (2,), optional Left and right limit of the x-axis. Nones are treated as unspecified limits (can be auto-completed from x). The default is (None, None). ylim : 1D array-like of floats or ints or None (2,), optional Lower and upper limit of the y-axis. Nones are treated as unspecified limits (can be auto-completed from y). The default is (None, None). zerotol : float, optional Maximum allowed distance for snapping one of two axis limits to zero. No snapping is performed if zerotol is not given. The default is None. """ # Initialize helpers for axis rescaling: set_x = lambda ax, **args: ax.set_xscale(**args) set_y = lambda ax, **args: ax.set_yscale(**args) set_scale = {'x': (set_x,), 'y': (set_y,), 'both': (set_x, set_y)}[which] # Initialize helpers for axis limits: set_x = lambda ax, limits: ax.set_xlim(limits) set_y = lambda ax, limits: ax.set_ylim(limits) set_limit = {'x': (set_x,), 'y': (set_y,), 'both': (set_x, set_y)}[which] limits = {'x': [xlim], 'y': [ylim], 'both': [xlim, ylim]}[which] # Prepare general log/symlog scale settings: args = {'value': scale, 'base': base, 'subs': subs} if scale == 'symlog': # Expand with symlog scale-specific settings: args.update({'linthresh': linthresh, 'linscale': linscale}) # Split into axis-specific settings: args = [args.copy() for _ in set_scale] # Consider switch from log to symlog to represent non-positive axis data: for i, data in enumerate({'x': (x,), 'y': (y,), 'both': (x, y)}[which]): # Data-free early exit: if data is None: # Fall back to default settings: if 'linthresh' in args[i] and linthresh is None: args[i]['linthresh'] = 1e-3 if 'linscale' in args[i] and linscale is None: args[i]['linscale'] = 0.5 continue # Determine extent of data on target axis: data_range = np.array([np.min(data), np.max(data)]) # Snap endpoint to zero: if zerotol is not None: distance = data_range.abs() # Choose endpoint closer to zero (if both are within tolerance): data_range[(distance <= zerotol) & (distance == distance.min())] = 0 # Auto-complete user-defined limits: zipped = zip(data_range, limits[i]) limits[i] = [value if lim is None else lim for value, lim in zipped] # All-positive early exit: if limits[i][0] > 0: continue # Allow non-positive values: args[i]['value'] = 'symlog' if linscale is None: # Half linear space of one-sided symlog: linscale = 0.25 if 0 in limits[i] else 0.5 args[i]['linscale'] = linscale if linthresh is None: # Prepare indices of non-zero data points within axis limits: ind = (data >= limits[i][0]) & (data <= limits[i][1]) & (data != 0) # Get minimum distance to zero: thresh = np.abs(data[ind]).min() # Find next-closer integer exponent towards zero: linthresh = round_power(thresh, base, which='floor')[0] args[i]['linthresh'] = linthresh # Apply axis limits and scaling to one or more subplots: for ax in (axes,) if isinstance(axes, plt.Axes) else axes: [func(ax, lims) for func, lims in zip(set_limit, limits)] [func(ax, **kwargs) for func, kwargs in zip(set_scale, args)] return None
Logarithmic rescaling of one or both axes of the given target subplots. Can handle log-incompatible (zero or negative) values in the axis data by switching to a symmetric pseudo-logarithmic (symlog) axis scaling.
Parameters
axes
:matplotlib axes
or1D array-like
ofmatplotlib axes
- One or several target subplots for logarithmic axis rescaling.
which
:str
- Target axis for rescaling. Options are 'x', 'y', or 'both'.
scale
:str
, optional- Type of logarithmic scale to apply. Options are 'log' for standard logarithmic scaling, or 'symlog' for symmetric pseudo-logarithmic scaling with a central linear region around zero and two mirrored logarithmic sides. If x or y axis data is given and contains any non- positive values, replaces log with symlog scale. The default is 'log'.
base
:int
, optional- Base of the logarithm. The default is 10.
subs
:1D array-like
ofints
, optional- Number and position of minor axis ticks within one decade on the log scale (e.g. from 1 to 10). The default is [2, 3, 4, 5, 6, 7, 8, 9], resulting in 8 equally spaced minor ticks for a base-10 logarithm.
linthresh
:float
orint
, optional- Transition point between the linear region and each logarithmic side of the symlog scale. If x or y axis data is given, set to the minimum absolute non-zero value with respect to zerotol, else falls back to a default value of 1e-3. The default is None.
linscale
:float
, optional- Factor for warping each side of the linear region on the symlog scale, in multiples of the visual space occupied by a single decade on the logarithmic sides. If x or y axis data is given, set to 0.25 for a one- sided symlog (one axis limit at 0), or 0.5 for two-sided. The default is None.
x
:ND array
offloats
orints
, optional- Collection of values to be represented on the x-axis. Triggers switch to symlog scale if any non-positive values are present. Used to infer missing linthresh and linscale inputs. Unspecified axis limits are set to match the range of the data. The default is None.
y
:ND array
offloats
orints
, optional- Collection of values to be represented on the y-axis. Triggers switch to symlog scale if any non-positive values are present. Used to infer missing linthresh and linscale inputs. Unspecified axis limits are set to match the range of the data. The default is None.
xlim
:1D array-like
offloats
orints
orNone (2,)
, optional- Left and right limit of the x-axis. Nones are treated as unspecified limits (can be auto-completed from x). The default is (None, None).
ylim
:1D array-like
offloats
orints
orNone (2,)
, optional- Lower and upper limit of the y-axis. Nones are treated as unspecified limits (can be auto-completed from y). The default is (None, None).
zerotol
:float
, optional- Maximum allowed distance for snapping one of two axis limits to zero. No snapping is performed if zerotol is not given. The default is None.
def sync_axes(main_ax, sub_axes, which, hide_labels=True)
-
Expand source code
def sync_axes(main_ax, sub_axes, which, hide_labels=True): """ Synchronizes axes limits and tick locators between the given subplots. Meant to create look of shared axes if actual sharing is not feasible. Limits and locators of reference subplot should be set before calling. Parameters ---------- main_ax : matplotlib axes object Reference subplot that determines the desired limits and locators. If hide_labels is True, main_ax should be the first subplot in line, as it is the only one that retains all axes labels and tick labels. sub_axes : matplotlib axes object or list of axes objects Dependent subplots whose limits and locators are adjusted. which : str Target axis or axes of dependent subplots to synchronize to the reference. Options are 'x', 'y', 'both'. hide_labels : bool, optional If True, removes specified tick labels and axes labels from each dependent subplot but leaves ticks as is. The default is True. """ # Input interpretation: if isinstance(sub_axes, np.ndarray): sub_axes = sub_axes.tolist() else: # Assert iterable: sub_axes = check_list(sub_axes) for sub_ax in sub_axes: # Treat x-axis limits and ticks: if which == 'x' or which == 'both': sub_ax.set_xlim(main_ax.get_xlim()) sub_ax.xaxis.set_major_locator(main_ax.xaxis.get_major_locator()) sub_ax.xaxis.set_minor_locator(main_ax.xaxis.get_minor_locator()) if hide_labels: sub_ax.set_xticklabels([]) sub_ax.set_xlabel('') # Treat y-axis limits and ticks: if which == 'y' or which == 'both': sub_ax.set_ylim(main_ax.get_ylim()) sub_ax.yaxis.set_major_locator(main_ax.yaxis.get_major_locator()) sub_ax.yaxis.set_minor_locator(main_ax.yaxis.get_minor_locator()) if hide_labels: sub_ax.set_yticklabels([]) sub_ax.set_ylabel('') return None
Synchronizes axes limits and tick locators between the given subplots. Meant to create look of shared axes if actual sharing is not feasible. Limits and locators of reference subplot should be set before calling.
Parameters
main_ax
:matplotlib axes object
- Reference subplot that determines the desired limits and locators. If hide_labels is True, main_ax should be the first subplot in line, as it is the only one that retains all axes labels and tick labels.
sub_axes
:matplotlib axes object
orlist
ofaxes objects
- Dependent subplots whose limits and locators are adjusted.
which
:str
- Target axis or axes of dependent subplots to synchronize to the reference. Options are 'x', 'y', 'both'.
hide_labels
:bool
, optional- If True, removes specified tick labels and axes labels from each dependent subplot but leaves ticks as is. The default is True.
def split_axes(ax, side, percent=10, pad=5)
-
Expand source code
def split_axes(ax, side, percent=10, pad=5): """ Divides parent subplot into two or more separate subplots. Meant to create smaller axes objects whose width or height matches the parent (e.g. for colorbars). Repeated calls on the same parent might have undesirable effects, so all splits should be done in one go. For multiple splits, pass any of side, percent, or pad as sequence-likes of equal number of elements. Single-element inputs are repeated to match. Parameters ---------- ax : matplotlib axes object Parent subplot to be divided. side : str or tuple/list/1D array of str (m,) Side of the parent subplot where each new subplot should be split off. Options are 'top', 'bottom', 'left', 'right'. percent : int or tuple/list/1D array of ints, optional Extent of each new subplot relative to the parent subplot as percentage of width (if side is 'left' or 'right') or height (if side is 'top' or 'bottom'). This proportion does not appear as expected in the displayed figure due to internal unit differences! The default is 10. pad : int or tuple/list/1D array of ints, optional Padding between each new subplot and the remainder of the parent subplot as percentage of the parent's width or height (same behavior as the percent argument). The default is 5. Returns ------- matplotlib axes object or list of axes objects New subplot(s) split off from the parent subplot. Extent and padding do not appear as expected in the displayed figure due to internal unit differences but are consistent between each other. """ # Open divider on parent axes: div = make_axes_locatable(ax) # Return single split for single-element inputs: if not any(np.ndim(variable) for variable in [side, percent, pad]): return div.append_axes(side, size=f'{percent}%', pad=f'{pad}%') # Equalize lengths and return multiple splits: vars = zip(equal_sequences(side, percent, pad)) return [div.append_axes(s, f'{per}%', f'{p}%') for s, per, p in vars]
Divides parent subplot into two or more separate subplots. Meant to create smaller axes objects whose width or height matches the parent (e.g. for colorbars). Repeated calls on the same parent might have undesirable effects, so all splits should be done in one go. For multiple splits, pass any of side, percent, or pad as sequence-likes of equal number of elements. Single-element inputs are repeated to match.
Parameters
ax
:matplotlib axes object
- Parent subplot to be divided.
side
:str
ortuple/list/1D array
ofstr (m,)
- Side of the parent subplot where each new subplot should be split off. Options are 'top', 'bottom', 'left', 'right'.
percent
:int
ortuple/list/1D array
ofints
, optional- Extent of each new subplot relative to the parent subplot as percentage of width (if side is 'left' or 'right') or height (if side is 'top' or 'bottom'). This proportion does not appear as expected in the displayed figure due to internal unit differences! The default is 10.
pad
:int
ortuple/list/1D array
ofints
, optional- Padding between each new subplot and the remainder of the parent subplot as percentage of the parent's width or height (same behavior as the percent argument). The default is 5.
Returns
matplotlib axes object
orlist
ofaxes objects
- New subplot(s) split off from the parent subplot. Extent and padding do not appear as expected in the displayed figure due to internal unit differences but are consistent between each other.
def inset_axes(ax, transform, x=None, y=None, width=None, height=None, xn=1, yn=1, **kwargs)
-
Expand source code
def inset_axes(ax, transform, x=None, y=None, width=None, height=None, xn=1, yn=1, **kwargs): """ Adds one or more inset axes to the given parent subplot. Parameters ---------- ax : matplotlib axes Target subplot to insert the inset axes. transform : matplotlib transform Coordinate system of all of x, y, width, and height. Pass ax.transAxes to use relative coordinates or ax.transData to use data coordinates. x : float or int or array-like (m,) of floats or ints, optional Coordinates of the center of the inset axes in x. If not provided, generates xn evenly spaced center coordinates. The default is None. y : float or int or array-like (m,) of floats or ints, optional Coordinates of the center of the inset axes in y. If not provided, generates yn evenly spaced center coordinates. The default is None. width : float or int or array-like (m,) of floats or ints, optional Horizontal extent of the inset axes. If not provided, uses the minimum distance between x-coordinates, or the whole x-axis range in case of a single inset axes. The default is None. height : float or int or array-like (m,) of floats or ints, optional Vertical extent of the inset axes. If not provided, uses the minimum distance between y-ccordinates, or the whole y-axis range in case of a single inset axes. The default is None. xn : int, optional If x is None, the number of center coordinates to create in x. New x is converted to match the given transform. The default is 1. yn : int, optional If y is None, the number of center coordinates to create in y. New y is converted to match the given transform. The default is 1. **kwargs : dict, optional Additional keyword arguments passed to ax.inset_axes(). Returns ------- sub_axes : list of matplotlib axes One or more inset axes in the given parent subplot. """ def complete_inputs(which, coords, extent, n): # Get full axis range in relative or data coordinates: limits = {'x': ax.get_xlim, 'y': ax.get_ylim}[which]() full = limits[1] - limits[0] if transform is ax.transData else 1 if coords is None: # Create equidistant centered relative coordinates: coords = np.linspace(0, 1, n + 1)[:-1] + 1 / n / 2 if transform is ax.transData: # Data coordinates: coords *= full coords += limits[0] if extent is None: # Default to all available space on axis or between coordinates: extent = full if np.size(coords) == 1 else min(np.diff(coords)) return coords, extent # Input interpretation and completion: x, width = complete_inputs('x', x, width, xn) y, height = complete_inputs('y', y, height, yn) # Ensure sequence-likes with equal numbers of elements: x, y, width, height = equal_sequences(x, y, width, height, skip_None=True) # Create axes: sub_axes = [] for x0, y0, w, h in zip(x, y, width, height): extent = (x0 - w / 2, y0 - h / 2, w, h) sub_axes.append(ax.inset_axes(extent, transform=transform, **kwargs)) return sub_axes
Adds one or more inset axes to the given parent subplot.
Parameters
ax
:matplotlib axes
- Target subplot to insert the inset axes.
transform
:matplotlib transform
- Coordinate system of all of x, y, width, and height. Pass ax.transAxes to use relative coordinates or ax.transData to use data coordinates.
x
:float
orint
orarray-like (m,)
offloats
orints
, optional- Coordinates of the center of the inset axes in x. If not provided, generates xn evenly spaced center coordinates. The default is None.
y
:float
orint
orarray-like (m,)
offloats
orints
, optional- Coordinates of the center of the inset axes in y. If not provided, generates yn evenly spaced center coordinates. The default is None.
width
:float
orint
orarray-like (m,)
offloats
orints
, optional- Horizontal extent of the inset axes. If not provided, uses the minimum distance between x-coordinates, or the whole x-axis range in case of a single inset axes. The default is None.
height
:float
orint
orarray-like (m,)
offloats
orints
, optional- Vertical extent of the inset axes. If not provided, uses the minimum distance between y-ccordinates, or the whole y-axis range in case of a single inset axes. The default is None.
xn
:int
, optional- If x is None, the number of center coordinates to create in x. New x is converted to match the given transform. The default is 1.
yn
:int
, optional- If y is None, the number of center coordinates to create in y. New y is converted to match the given transform. The default is 1.
**kwargs
:dict
, optional- Additional keyword arguments passed to ax.inset_axes().
Returns
sub_axes
:list
ofmatplotlib axes
- One or more inset axes in the given parent subplot.
def auto_plotgrid(n_plots,
fig=None,
order='row',
long_axis=0,
grid_min=2,
n_rows=None,
n_cols=None,
plot_size=5,
x=None,
y=None,
**kwargs)-
Expand source code
def auto_plotgrid(n_plots, fig=None, order='row', long_axis=0, grid_min=2, n_rows=None, n_cols=None, plot_size=5, x=None, y=None, **kwargs): """ Mass-produces subplots in an optimized grid layout of given attributes. Grid layout can be constrained to a fixed number of rows or columns, or automatically calculated as a pair of integers whose product matches the requested number of subplots as closely as possible. The aspect of the grid can be controlled by specifying the longer axis. Created subplots are filled into the grid in the specified order (default: row- major). The order of the returned axes matches the order of creation. If no target figure is provided, creates a new figure and scales its size to the grid extent. This function is meant for quick visualization of data with many variables or categories, and returns the created axes in an order that allows for plotting structured data in a single loop. Parameters ---------- n_plots : int Total number of subplots to create. fig : Matplotlib figure object, optional If specified, the target figure to add subplots to. Else, creates a new figure with constrained layout and varying size. Figure size is the number of rows and columns in the grid scaled by plot_size in inches, and clipped to a minimum of 1x1 and a maximum of 20x10 inches. order : str, optional Order of created subplots in grid (determines order of returned axes). Should correspond to the order in which subplots are supposed to be filled later. Options are 'row' for row-major order or 'col' for column-major order. The default is 'row'. long_axis : int, optional The grid axis to extend if n_plots does not fit a square grid. Options are 0 for rows or 1 for columns. If n_plots does not fit a rectangular grid, an additional row or column that is not completely filled is appended to the shorter axis, so that the extent of the longer axis increases by one. Can be overridden by certain values of n_rows and n_cols. The default is 0. grid_min : int, optional If specified without n_rows and n_cols, the minimum number of rows or columns that are allowed in the auto-adjusted grid. During auto- adjustment, first attempts to find a square grid that fits n_plots with side length int(np.sqrt(n_plots). Next, gets all integer numbers in [grid_min, side length] that divide n_plots evenly, and takes the largest one (if any). This gives a rectangular grid with exactly n_plots positions, whose aspect depends on long_axis. As a fallback, expands one side of the square grid to hold at least n_plots axes, which results in overhanging subplots arrangements. Given grid_min is always clipped to [1, side length + 1]. Pass None to disable search for clean rectangular grid shapes. The default is 2. n_rows : int, optional If specified, a fixed number of rows in the grid. The number of columns is calculated as np.ceil(n_plots / n_rows), which may result in over- hanging subplots. If specified together with n_cols, enforces a fixed rectangular grid (likely underfilled, may throw an error if too small). Overrides grid_min and potentially long_axis, too. The default is None. n_cols : int, optional If specified, a fixed number of columns in the grid. The number of rows is calculated as np.ceil(n_plots / n_cols), which may result in over- hanging subplots. If specified together with n_rows, enforces a fixed rectangular grid (likely underfilled, may throw an error if too small). Overrides grid_min and potentially long_axis, too. The default is None. plot_size : float or int or tuple or list (2,) of floats or ints, optional If fig is not specified, sets the size of the created figure by scaling the extent of the finalized grid (so that each row/column is around plot_size inches wide). Add conversion fators to plot_size for other units. Single values specify equal widths for both rows and columns. Two values specify different widths in the format (columns, rows). Mind that the input order is in standard figsize format (width, height) instead of matrix format (rows, columns). Always clipped to a minimum of 1 inch and a maximum of 20 inches width and 10 inches height. The default is 5. x : str, optional If specified, used as x-axis label of the bottom-most subplot in each column. Passing the xlabel keyword argument instead applies the label to all subplots. The default is None. y : str, optional If specified, used as y-axis label of the left-most subplot in each row. Passing the ylabel keyword argument instead applies the label to all subplots. The default is None. **kwargs : dict, optional Additional keyword arguments passed to plt.subplot2grid() and further to plt.add_subplot() to specify additional subplot attributes. If the sharex or sharey keyword arguments are provided, they must be specified as a bool instead of the usual axes object (if True, uses first created subplot as reference whose axes are shared by all other subplots). Returns ------- axes : list of Matplotlib axes objects [n_plots,] Created subplots in the order of their insertion into the grid. If order is 'col', subplots are added column-wise from top to bottom and left to right. Else, subplots are added row-wise from left to right and top to bottom. Can be used to plot data in a structured way without iterating in nested loops (e.g. over 2D arrays of axes objects). Raises ------ ValueError Breaks if long_axis is not 0 or 1, or if n_rows * n_cols < n_plots. """ # Validate inputs: if long_axis not in [0, 1]: raise ValueError('Longer grid axis must be 0 (rows) or 1 (columns).') # Range-check inputs: even_side = int(np.sqrt(n_plots)) if grid_min is None: grid_min = even_side + 1 grid_min = min(max(grid_min, 1), even_side + 1) if n_rows is not None: n_rows = min(max(n_rows, 1), n_plots) if n_cols is not None: n_cols = min(max(n_cols, 1), n_plots) if n_rows is not None and n_cols is not None: if n_rows * n_cols < n_plots: msg = 'A grid with n_rows x n_cols must hold at least n_plots.' raise ValueError(msg) # Manage keywords: keywords = kwargs.copy() switch_keys = [key for key in ['sharex', 'sharey'] if key in kwargs] # Disable shared axes for first created subplot: keywords.update({key: None for key in switch_keys}) # Shape of overall subplot grid: if n_rows is not None and n_cols is not None: # Fixed rectangular grid: grid = [n_rows, n_cols] if n_rows is not None and n_cols is None: # Rectangular grid with fixed number of rows: grid = [n_rows, int(np.ceil(n_plots / n_rows))] elif n_rows is None and n_cols is not None: # Rectangular grid with fixed number of columns: grid = [int(np.ceil(n_plots / n_cols)), n_cols] else: # Initial square grid: even_side = int(np.sqrt(n_plots)) if even_side**2 == n_plots: # Clean square grid: grid = [even_side, even_side] else: # Check for integers that divide n_plots evenly: test_ints = np.arange(even_side, grid_min - 1, -1) factors = test_ints[n_plots % test_ints == 0] if len(factors): # Clean rectangular grid without overhang: grid = [factors[0], n_plots // factors[0]] # Assign larger number of subplots to long side of grid: grid[long_axis], grid[1 - long_axis] = max(grid), min(grid) else: # Overhanging rectangular grid: grid = [even_side, even_side] # Append half-filled row/column to short side of grid: grid[long_axis] = int(np.ceil(n_plots / even_side)) # Get coordinates of each possible subplot in grid: row_coords, col_coords = np.mgrid[:grid[0], :grid[1]] if order == 'col': # Flip grid to flatten in column-major order: row_coords, col_coords = row_coords.T, col_coords.T # Flatten grid coordinates into position vectors (row, col): position = np.vstack([row_coords.ravel(), col_coords.ravel()]).T # Truncate to requested amount: position = position[:n_plots, :] # Manage figure: if fig is None: # Adapt figure size to grid extent: figsize = plot_size * np.array(grid)[::-1] # Range-check calculated size and create figure: figsize = np.where(figsize >= 1, figsize, (1, 1)) figsize = np.where(figsize <= (20, 10), figsize, (20, 10)) fig = plt.figure(constrained_layout=True, figsize=figsize) axes = [] # Fill grid in the specified order: for i, pos in enumerate(position): if i == 1: # Re-enable shared axes for all other subplots: keywords.update({key: axes[0] for key in switch_keys}) # Add subplot to figure: axes.append(plt.subplot2grid(grid, pos, fig=fig, **keywords)) # Manage outer axis labels: if x is not None and i >= n_plots - grid[1]: axes[-1].set_xlabel(x) if y is not None and pos[1] == 0: axes[-1].set_ylabel(y) return axes
Mass-produces subplots in an optimized grid layout of given attributes. Grid layout can be constrained to a fixed number of rows or columns, or automatically calculated as a pair of integers whose product matches the requested number of subplots as closely as possible. The aspect of the grid can be controlled by specifying the longer axis. Created subplots are filled into the grid in the specified order (default: row- major). The order of the returned axes matches the order of creation. If no target figure is provided, creates a new figure and scales its size to the grid extent. This function is meant for quick visualization of data with many variables or categories, and returns the created axes in an order that allows for plotting structured data in a single loop.
Parameters
n_plots
:int
- Total number of subplots to create.
fig
:Matplotlib figure object
, optional- If specified, the target figure to add subplots to. Else, creates a new figure with constrained layout and varying size. Figure size is the number of rows and columns in the grid scaled by plot_size in inches, and clipped to a minimum of 1x1 and a maximum of 20x10 inches.
order
:str
, optional- Order of created subplots in grid (determines order of returned axes). Should correspond to the order in which subplots are supposed to be filled later. Options are 'row' for row-major order or 'col' for column-major order. The default is 'row'.
long_axis
:int
, optional- The grid axis to extend if n_plots does not fit a square grid. Options are 0 for rows or 1 for columns. If n_plots does not fit a rectangular grid, an additional row or column that is not completely filled is appended to the shorter axis, so that the extent of the longer axis increases by one. Can be overridden by certain values of n_rows and n_cols. The default is 0.
grid_min
:int
, optional- If specified without n_rows and n_cols, the minimum number of rows or columns that are allowed in the auto-adjusted grid. During auto- adjustment, first attempts to find a square grid that fits n_plots with side length int(np.sqrt(n_plots). Next, gets all integer numbers in [grid_min, side length] that divide n_plots evenly, and takes the largest one (if any). This gives a rectangular grid with exactly n_plots positions, whose aspect depends on long_axis. As a fallback, expands one side of the square grid to hold at least n_plots axes, which results in overhanging subplots arrangements. Given grid_min is always clipped to [1, side length + 1]. Pass None to disable search for clean rectangular grid shapes. The default is 2.
n_rows
:int
, optional- If specified, a fixed number of rows in the grid. The number of columns is calculated as np.ceil(n_plots / n_rows), which may result in over- hanging subplots. If specified together with n_cols, enforces a fixed rectangular grid (likely underfilled, may throw an error if too small). Overrides grid_min and potentially long_axis, too. The default is None.
n_cols
:int
, optional- If specified, a fixed number of columns in the grid. The number of rows is calculated as np.ceil(n_plots / n_cols), which may result in over- hanging subplots. If specified together with n_rows, enforces a fixed rectangular grid (likely underfilled, may throw an error if too small). Overrides grid_min and potentially long_axis, too. The default is None.
plot_size
:float
orint
ortuple
orlist (2,)
offloats
orints
, optional- If fig is not specified, sets the size of the created figure by scaling the extent of the finalized grid (so that each row/column is around plot_size inches wide). Add conversion fators to plot_size for other units. Single values specify equal widths for both rows and columns. Two values specify different widths in the format (columns, rows). Mind that the input order is in standard figsize format (width, height) instead of matrix format (rows, columns). Always clipped to a minimum of 1 inch and a maximum of 20 inches width and 10 inches height. The default is 5.
x
:str
, optional- If specified, used as x-axis label of the bottom-most subplot in each column. Passing the xlabel keyword argument instead applies the label to all subplots. The default is None.
y
:str
, optional- If specified, used as y-axis label of the left-most subplot in each row. Passing the ylabel keyword argument instead applies the label to all subplots. The default is None.
**kwargs
:dict
, optional- Additional keyword arguments passed to plt.subplot2grid() and further to plt.add_subplot() to specify additional subplot attributes. If the sharex or sharey keyword arguments are provided, they must be specified as a bool instead of the usual axes object (if True, uses first created subplot as reference whose axes are shared by all other subplots).
Returns
axes
:list
ofMatplotlib axes objects [n_plots,]
- Created subplots in the order of their insertion into the grid. If order is 'col', subplots are added column-wise from top to bottom and left to right. Else, subplots are added row-wise from left to right and top to bottom. Can be used to plot data in a structured way without iterating in nested loops (e.g. over 2D arrays of axes objects).
Raises
ValueError
- Breaks if long_axis is not 0 or 1, or if n_rows * n_cols < n_plots.
def remake_cmap(cmap, low=0.0, high=1.0, segments=None, n=1000, reverse=False, resample=True, name=None)
-
Expand source code
def remake_cmap(cmap, low=0., high=1., segments=None, n=1000, reverse=False, resample=True, name=None): """ Truncates colormap or cuts/repeats segments to create a new colormap. Parameters ---------- cmap : matplotlib colormap object or str Underlying colormap. Accepts both a ready colormap object or a name string known to Matplotlib. low : float, optional Lower bound of the new colormap (in [0,1]) relative to the original. If high is not None, low should be < high. Ignored if segments are given. The default is 0.0. high : float, optional Upper bound of the new colormap (in [0,1]) relative to the original. If low is not None, high should be > low. Ignored if segments are given. The default is 1.0. segments : list (m,) of tuples or lists of floats (2,), optional Segments to extract from the original colormap and concatenate into the new colormap. Each segment must have start and end points in [0,1]. Allows for repetitions and re-ordering of segments. Overrides low and high if specified. The default is None. n : int, optional Number of color samples to draw from the original colormap. The default is 1000. reverse : bool, optional If True, reverses the order of colors in the new colormap. The default is False. resample : bool, optional If True, restores original number of color samples specified by n before returning the new colormap. Takes place after reversing. The default is True. name : str, optional If specified, registers the new colormap under this name in Matplotlib. Allows use as standard colormap that is recognized by its name string. Takes place after reversing and resampling. The default is None. Returns ------- new_cmap : matplotlib colormap object Re-structured colormap based on the given cmap. """ # Input interpretation: if isinstance(cmap, str): cmap = plt.colormaps.get_cmap(cmap) # Draw number of colors: colors = cmap(np.linspace(0, 1, n)) if segments is None: # Truncate edges: colors = colors[int(n * low):int(n * high), :] else: # Segment-wise re-structuring: cols = [] for segment in segments: start, end = int(n * segment[0]), int(n * segment[1]) step = 1 if start < end else -1 cols.append(colors[start:end:step, :]) colors = np.vstack(cols) # cols = [colors[int(n * s[0]):int(n * s[1]):, :] for s in segments] # colors = np.vstack(cols) new_cmap = ListedColormap(colors) if reverse: # Reverse order: new_cmap = new_cmap.reversed() if resample: # Restore original resolution: new_cmap = new_cmap.resampled(n) if name is not None: # Add reference by string: new_cmap.name = name plt.colormaps.register(new_cmap) return new_cmap
Truncates colormap or cuts/repeats segments to create a new colormap.
Parameters
cmap
:matplotlib colormap object
orstr
- Underlying colormap. Accepts both a ready colormap object or a name string known to Matplotlib.
low
:float
, optional- Lower bound of the new colormap (in [0,1]) relative to the original. If high is not None, low should be < high. Ignored if segments are given. The default is 0.0.
high
:float
, optional- Upper bound of the new colormap (in [0,1]) relative to the original. If low is not None, high should be > low. Ignored if segments are given. The default is 1.0.
segments
:list (m,)
oftuples
orlists
offloats (2,)
, optional- Segments to extract from the original colormap and concatenate into the new colormap. Each segment must have start and end points in [0,1]. Allows for repetitions and re-ordering of segments. Overrides low and high if specified. The default is None.
n
:int
, optional- Number of color samples to draw from the original colormap. The default is 1000.
reverse
:bool
, optional- If True, reverses the order of colors in the new colormap. The default is False.
resample
:bool
, optional- If True, restores original number of color samples specified by n before returning the new colormap. Takes place after reversing. The default is True.
name
:str
, optional- If specified, registers the new colormap under this name in Matplotlib. Allows use as standard colormap that is recognized by its name string. Takes place after reversing and resampling. The default is None.
Returns
new_cmap
:matplotlib colormap object
- Re-structured colormap based on the given cmap.
def color_range(cmap,
n,
alpha=None,
reverse=False,
alternate=False,
shuffle=False,
n_near=1,
low=None,
high=None,
segments=None)-
Expand source code
def color_range(cmap, n, alpha=None, reverse=False, alternate=False, shuffle=False, n_near=1, low=None, high=None, segments=None): """ Draws given number of colors from the specified colormap. Parameters ---------- cmap : matplotlib colormap object or str Underlying colormap. Accepts both a ready colormap object or a name string known to Matplotlib. n : int Number of colors to draw from the colormap. Drawn colors are equally spaced in cmap and always include the first and last color. alpha : float, optional If specified, returns colors as RGBA tuples (4,) with this alpha value. Adds alpha channel if not present in the colormap. If None, crops alpha channel if present and returns RGB tuples (3,). The default is None. reverse : bool, optional If True, reverses the order of the drawn colors. Takes place before alternating or shuffling. The default is False. alternate : bool, optional If True, alternates drawn colors by reversing front and back at every second index, so that [0, -2, 2, ... , -3, 1, -1]. First and last entry is always preserved. If n is odd, the central entry is also preserved. Prevents shuffling. The default is False. shuffle : bool, optional If True, calls spread_shuffle() on the drawn colors to shuffle them while avoiding to place a entry next to its n_near neighbours to the left and right, respectively. Ignored if alternate is True. The default is False. n_near : int, optional Number of neighbours to avoid when shuffling. Ignored if shuffle is False or alternate is True. The default is 1, which corresponds to the direct neighbours left and right of each entry. low : float, optional If specified, passed to remake_cmap() to truncate the original colormap to a relative lower bound in [0, 1]. Ignored if segments are given. The default is None. high : float, optional If specified, passed to remake_cmap() to truncate the original colormap to a relative upper bound in [0, 1]. Ignored if segments are given. The default is None. segments : list (m,) of tuples or lists of floats (2,), optional If specified, passed to remake_cmap() to reduce the original colormap to a set of relative segments in [0, 1]. Overrides low and high if given. The default is None. Returns ------- colors : list (n,) of tuples of floats (3, or 4, if alpha is not None) Drawn colors from cmap as RGB or RGBA tuples in the desired order. """ # Input interpretation: if isinstance(cmap, str): cmap = plt.colormaps.get_cmap(cmap) if low is not None or high is not None or segments is not None: # Optional colormap re-structuring: cmap = remake_cmap(cmap, low, high, segments) # Draw number of colors: colors = cmap(np.linspace(0, 1, n)) if alpha is None: # Crop alpha channel, if present: colors = colors[:, :3] if colors.shape[1] == 4 else colors elif colors.shape[1] == 4 and alpha < 1 and alpha >= 0: # Set non-default value: colors[:, 3] = alpha elif colors.shape[1] == 3 and alpha >= 0 and alpha <= 1: # Add alpha channel with any value: colors = np.concatenate((colors, alpha * np.ones((n, 1))), axis=1) colors = [tuple(c) for c in colors] if reverse: # Reverse order: colors = colors[::-1] if alternate: # Alternate from ends towards center: for i in range(1, n // 2 + 1, 2): colors[i], colors[-i - 1] = colors[-i - 1], colors[i] elif shuffle: # Shuffle while avoiding neighbours: colors = spread_shuffle(colors, n_near) return colors
Draws given number of colors from the specified colormap.
Parameters
cmap
:matplotlib colormap object
orstr
- Underlying colormap. Accepts both a ready colormap object or a name string known to Matplotlib.
n
:int
- Number of colors to draw from the colormap. Drawn colors are equally spaced in cmap and always include the first and last color.
alpha
:float
, optional- If specified, returns colors as RGBA tuples (4,) with this alpha value. Adds alpha channel if not present in the colormap. If None, crops alpha channel if present and returns RGB tuples (3,). The default is None.
reverse
:bool
, optional- If True, reverses the order of the drawn colors. Takes place before alternating or shuffling. The default is False.
alternate
:bool
, optional- If True, alternates drawn colors by reversing front and back at every second index, so that [0, -2, 2, … , -3, 1, -1]. First and last entry is always preserved. If n is odd, the central entry is also preserved. Prevents shuffling. The default is False.
shuffle
:bool
, optional- If True, calls spread_shuffle() on the drawn colors to shuffle them while avoiding to place a entry next to its n_near neighbours to the left and right, respectively. Ignored if alternate is True. The default is False.
n_near
:int
, optional- Number of neighbours to avoid when shuffling. Ignored if shuffle is False or alternate is True. The default is 1, which corresponds to the direct neighbours left and right of each entry.
low
:float
, optional- If specified, passed to remake_cmap() to truncate the original colormap to a relative lower bound in [0, 1]. Ignored if segments are given. The default is None.
high
:float
, optional- If specified, passed to remake_cmap() to truncate the original colormap to a relative upper bound in [0, 1]. Ignored if segments are given. The default is None.
segments
:list (m,)
oftuples
orlists
offloats (2,)
, optional- If specified, passed to remake_cmap() to reduce the original colormap to a set of relative segments in [0, 1]. Overrides low and high if given. The default is None.
Returns
colors
:list (n,)
oftuples
offloats (3,
or4, if alpha is not None)
- Drawn colors from cmap as RGB or RGBA tuples in the desired order.
def sort_colors(colors, sort_start='min', background=(1, 1, 1))
-
Expand source code
def sort_colors(colors, sort_start='min', background=(1, 1, 1)): """ Sorts a set of RGB(A) colors by minimizing pairwise distances. Distances are computed as Euclidean metric and will thus not match the actual perceived color difference. Provides several options to specify the entry point of the sorting process. Parameters ---------- colors : list (m,) of tuples of floats (3 or 4,) Set of colors in RGB or RGBA format to sort. If RGBA, omits the alpha channel and performs distance computation on a mixture of each color with the given background: color * alpha + background * (1 - alpha). sort_start : str or int or None, optional Determines the entry point of the sorting process. Options are 'min' to start with the "darkest" color (minimum RGB sum), 'max' to start with the "lightest" color (maximum RGB sum), None to choose the first color randomly, or a fixed integer index. The default is 'min'. background : tuple of floats (3,) RGB background color for alpha blending. May not have an alpha channel. The default is (1, 1, 1), corresponding to a white background. Returns ------- sorted_colors : list (m,) of tuples of floats (3 or 4,) Set of colors sorted by pairwise distance minimization. The resulting order of colors strongly depends on the chosen entry point and does not reflect how an observer percieves the (dis)similarity between colors. """ # Ensure RGB(A) array format: color_array = np.array(colors) n = color_array.shape[0] # Manage alpha channel: if color_array.shape[1] == 4: # Ensure simple RGB format: alpha = color_array[:, 3] # Mix colors with background color: color_array = color_array[:, :3] * alpha color_array += np.array(background) * (1 - alpha) # Input interpretation: if sort_start == 'min': # Pseudo-darkest color first: ind = np.argmin(np.sum(color_array, axis=1)) elif sort_start == 'max': # Pseudo-lightest color first: ind = np.argmax(np.sum(color_array, axis=1)) elif sort_start is None: # Random entry point: ind = np.random.default_rng().integers(0, n) else: # Sanitize and use specified start: ind = np.clip(sort_start, -n, n - 1) # Compute pairwise distance matrix: distances = squareform(pdist(color_array, metric='euclidean')) distances[np.diag_indices(n)] = np.nan # Sort by minimal distance: sorted_colors = [colors[ind]] distances[ind, :] = np.nan for _ in range(n - 1): # Find closest remaining neighbor: ind = np.nanargmin(distances[:, ind]) # Log and disable chosen color: sorted_colors.append(colors[ind]) distances[ind, :] = np.nan return sorted_colors
Sorts a set of RGB(A) colors by minimizing pairwise distances. Distances are computed as Euclidean metric and will thus not match the actual perceived color difference. Provides several options to specify the entry point of the sorting process.
Parameters
colors
:list (m,)
oftuples
offloats (3
or4,)
- Set of colors in RGB or RGBA format to sort. If RGBA, omits the alpha channel and performs distance computation on a mixture of each color with the given background: color * alpha + background * (1 - alpha).
sort_start
:str
orint
orNone
, optional- Determines the entry point of the sorting process. Options are 'min' to start with the "darkest" color (minimum RGB sum), 'max' to start with the "lightest" color (maximum RGB sum), None to choose the first color randomly, or a fixed integer index. The default is 'min'.
background
:tuple
offloats (3,)
- RGB background color for alpha blending. May not have an alpha channel. The default is (1, 1, 1), corresponding to a white background.
Returns
sorted_colors
:list (m,)
oftuples
offloats (3
or4,)
- Set of colors sorted by pairwise distance minimization. The resulting order of colors strongly depends on the chosen entry point and does not reflect how an observer percieves the (dis)similarity between colors.
def sort_distinctipy(n, sort_start='min', batch=1, gap=0, clean_end=True, **kwargs)
-
Expand source code
def sort_distinctipy(n, sort_start='min', batch=1, gap=0, clean_end=True, **kwargs): """ Wrapper to distinctipy.get_colors() to create a categorical color set. Generates a number of perceptually distinct colors and sorts them by pairwise RGB distance. Can also create and sort a larger color set and subsample it into batches of successive colors separated by gaps of redundant colors to achieve a grouping effect. Parameters ---------- n : int Number of colors to generate and sort. If not an integer multiple of batch, the number of colors is rounded up to the next multiple. sort_start : str or int or None, optional Determines the entry point of the sorting process. Options are 'min' to start with the "darkest" color (minimum RGB sum), 'max' to start with the "lightest" color (maximum RGB sum), None to choose the first color randomly, or a fixed integer index. The default is 'min'. batch : int, optional Number of colors to group together in the returned color subset. The default is 1. gap : int, optional Number of redundant colors between two batches. Not returned in the final color subset. The default is 0. clean_end : bool, optional If True, generates one additional color, sorts all, and removes the last of the sorted colors. Ensures that the end point of the final color set is based on actual RGB distance to its predecessor and not just the last available color. The default is True. **kwargs : dict, optional Additional keyword arguments passed to distinctipy.get_colors(). Returns ------- color_subset : list (n,) of tuples of floats (3,) Sorted set of perceptually distinct colors in RGB format. If n is not an integer multiple of batch, might return more colors than requested. """ if n % batch: # Ensure greater integer multiple: n = (n // batch + 1) * batch # Expand for later subsampling: total = n + (n // batch - 1) * gap # Generate a number of distinct colors: colors = distinctipy.get_colors(total + clean_end, **kwargs) # Sort colors by pairwise RGB distance: colors = sort_colors(colors, sort_start) if clean_end: colors = colors[:-1] # Full color set early exit: if batch == 1 and gap == 0: return colors # Subsample colors: color_subset = [] for i in range(0, total, batch + gap): color_subset += colors[i : i + batch] return color_subset
Wrapper to distinctipy.get_colors() to create a categorical color set. Generates a number of perceptually distinct colors and sorts them by pairwise RGB distance. Can also create and sort a larger color set and subsample it into batches of successive colors separated by gaps of redundant colors to achieve a grouping effect.
Parameters
n
:int
- Number of colors to generate and sort. If not an integer multiple of batch, the number of colors is rounded up to the next multiple.
sort_start
:str
orint
orNone
, optional- Determines the entry point of the sorting process. Options are 'min' to start with the "darkest" color (minimum RGB sum), 'max' to start with the "lightest" color (maximum RGB sum), None to choose the first color randomly, or a fixed integer index. The default is 'min'.
batch
:int
, optional- Number of colors to group together in the returned color subset. The default is 1.
gap
:int
, optional- Number of redundant colors between two batches. Not returned in the final color subset. The default is 0.
clean_end
:bool
, optional- If True, generates one additional color, sorts all, and removes the last of the sorted colors. Ensures that the end point of the final color set is based on actual RGB distance to its predecessor and not just the last available color. The default is True.
**kwargs
:dict
, optional- Additional keyword arguments passed to distinctipy.get_colors().
Returns
color_subset
:list (n,)
oftuples
offloats (3,)
- Sorted set of perceptually distinct colors in RGB format. If n is not an integer multiple of batch, might return more colors than requested.
def mappable_cmap(cmap, low=0.0, high=1.0)
-
Expand source code
def mappable_cmap(cmap, low=0., high=1.): """ Creates a linear scalar mappable from the specified colormap. Enables colorbars with custom mapping of values to colors, and without reference to actual image or scatter data. Normalization boundaries are the smallest and largest values that will be mapped to colors. Defines the ticklabels on the colorbar. Parameters ---------- cmap : matplotlib colormap object or str Underlying colormap. Accepts both a ready colormap object or a name string known to Matplotlib. low : float, optional Custom lower normalization boundary, corresponding to the first color in the colormap (and the smallest mappable value). The default is 0.0. high : float, optional Custom upper normalization boundary, corresponding to the last color in the colormap (and the largest mappable value). The default is 1.0. Returns ------- mappable : matplotlib ScalarMappable object Scalar mappable object representing the colormap. Can be passed to a colorbar function instead of an actual artist, such as an image. """ # Input interpretation: if isinstance(cmap, str): cmap = plt.colormaps.get_cmap(cmap) # Define mapping of values to colors: mappable = ScalarMappable(Normalize(low, high), cmap) return mappable
Creates a linear scalar mappable from the specified colormap. Enables colorbars with custom mapping of values to colors, and without reference to actual image or scatter data. Normalization boundaries are the smallest and largest values that will be mapped to colors. Defines the ticklabels on the colorbar.
Parameters
cmap
:matplotlib colormap object
orstr
- Underlying colormap. Accepts both a ready colormap object or a name string known to Matplotlib.
low
:float
, optional- Custom lower normalization boundary, corresponding to the first color in the colormap (and the smallest mappable value). The default is 0.0.
high
:float
, optional- Custom upper normalization boundary, corresponding to the last color in the colormap (and the largest mappable value). The default is 1.0.
Returns
mappable
:matplotlib ScalarMappable object
- Scalar mappable object representing the colormap. Can be passed to a colorbar function instead of an actual artist, such as an image.
def proxy_handles(labels, iter_kwargs={}, mode='line', **kwargs)
-
Expand source code
def proxy_handles(labels, iter_kwargs={}, mode='line', **kwargs): """ Creates a collection of custom proxy artists for use in a legend. Call plt.legend(handles=artists) without labels argument to set the proxies as legend entries. Supports Line2D and Patch artist class. Parameters ---------- labels : array-like (m,) of strings, floats or ints Artist-specific legend labels. iter_kwargs : dict of array-likes (m,), optional Artist-specific keyword arguments. Must be compatible with the artist class specified by mode. The default is {}. mode : str, optional The artist class to use for creating the proxies. Options are 'line' for Line2D and 'patch' for Patch objects. The default is 'line'. **kwargs : dict, optional General keyword arguments to apply to all artists. Must be compatible with the artist class specified by mode. Returns ------- artists : list of matplotlib Line2D or Patch objects (m,) Legend proxy artists with the specified properties and labels. """ func = { 'line': Line2D, 'patch': Patch }[mode] if mode == 'line': kwargs.update({'xdata': [], 'ydata': []}) artists = [] for i, label in enumerate(labels): artist_kwargs = {key: value[i] for key, value in iter_kwargs.items()} artists.append(func(label=label, **artist_kwargs, **kwargs)) return artists
Creates a collection of custom proxy artists for use in a legend. Call plt.legend(handles=artists) without labels argument to set the proxies as legend entries. Supports Line2D and Patch artist class.
Parameters
labels
:array-like (m,)
ofstrings, floats
orints
- Artist-specific legend labels.
iter_kwargs
:dict
ofarray-likes (m,)
, optional- Artist-specific keyword arguments. Must be compatible with the artist class specified by mode. The default is {}.
mode
:str
, optional- The artist class to use for creating the proxies. Options are 'line' for Line2D and 'patch' for Patch objects. The default is 'line'.
**kwargs
:dict
, optional- General keyword arguments to apply to all artists. Must be compatible with the artist class specified by mode.
Returns
artists
:list
ofmatplotlib Line2D
orPatch objects (m,)
- Legend proxy artists with the specified properties and labels.
def kill_ax(axes, turn_off=True)
-
Expand source code
def kill_ax(axes, turn_off=True): # TODO docstring axes = check_list(axes) for ax in axes: ax.set_xlabel('') ax.set_ylabel('') ax.set_xticks([], []) ax.set_yticks([], []) ax.tick_params('both', length=0, width=0) ax.spines[:].set(visible=False, lw=0) if turn_off: ax.axis('off') return None
def ax_box(ax)
-
Expand source code
def ax_box(ax): """ Hides all axes, labels, and ticks, but draws the full box of spines. Parameters ---------- ax : matplotlib axes object Target subplot to frame. """ ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) ax.spines[:].set_visible(True) return None
Hides all axes, labels, and ticks, but draws the full box of spines.
Parameters
ax
:matplotlib axes object
- Target subplot to frame.
def ax_cross(ax, **kwargs)
-
Expand source code
def ax_cross(ax, **kwargs): """ Draws horizontal and vertical zero lines in the given subplot. Parameters ---------- ax : matplotlib axes object Target subplot to add the cross of zero lines. **kwargs : dict, optional Keyword arguments passed to axhline() and axvline() for customizing the zero lines. Defaults to {'c': 'k', 'lw': 0.5, 'ls': 'dotted'} if nothing else is provided. """ if not kwargs: kwargs = {'c': 'k', 'lw': 0.5, 'ls': 'dotted'} ax.axhline(0, **kwargs) ax.axvline(0, **kwargs) return None
Draws horizontal and vertical zero lines in the given subplot.
Parameters
ax
:matplotlib axes object
- Target subplot to add the cross of zero lines.
**kwargs
:dict
, optional- Keyword arguments passed to axhline() and axvline() for customizing the zero lines. Defaults to {'c': 'k', 'lw': 0.5, 'ls': 'dotted'} if nothing else is provided.
def quick_hist(ax, data, n_bins=50, bins=None, density=True, width=0.8, **kwargs)
-
Expand source code
def quick_hist(ax, data, n_bins=50, bins=None, density=True, width=0.8, **kwargs): """ Computes a histogram over the data and plots it to the given subplot. Does exactly the same as plt.hist(). Parameters ---------- ax : matplotlib axes object Target subplot to which the bar plot of the histogram is added. Axes limits are set to [edges[0], edges[-1]] and [0, max(hist)*1.05] for x and y, respectively. data : 1D array of floats or ints (m,) Data over which the histogram is computed. n_bins : int, optional Number of bins passed to np.histogram(). Ignored if bins is specified. The default is 50. bins : 1D array or list of floats (n,), optional Bin edges passed to np.histogram(). Overrides n_bins if specified. The default is None. density : bool, optional Density argument passed to np.histogram(). If True, the histogram is normalized to form a probability density. The default is True. width : float, optional Width of the bars in the bar plot relative to width of each bin. Should be in [0, 1]. The default is 0.8. **kwargs : dict, optional Keyword arguments passed to ax.bar() to specify additional properties. The default is {'fc': 'k', 'lw': 0}. Returns ------- hist : 1D array of floats (n,) Histogram counts or density values for each bin. centers : 1D array of floats (n,) Bin centers computed from the bin edges. edges : 1D array of floats (n + 1,) Bin edges corresponding to centers. Returns given bins if specified. """ if not kwargs: kwargs = {'fc': 'k', 'lw': 0} # Compute histogram and bin centers: hist, edges = np.histogram(data, bins=n_bins if bins is None else bins, density=density) bar_widths = edges[1:] - edges[:-1] centers = edges[:-1] + 0.5 * bar_widths # Add barplot and adjust axes limits: ax.bar(centers, hist, width * bar_widths, **kwargs) ax.set_xlim(edges[0], edges[-1]) ax.set_ylim(0, max(hist) * 1.05) return hist, centers, edges
Computes a histogram over the data and plots it to the given subplot. Does exactly the same as plt.hist().
Parameters
ax
:matplotlib axes object
- Target subplot to which the bar plot of the histogram is added. Axes limits are set to [edges[0], edges[-1]] and [0, max(hist)*1.05] for x and y, respectively.
data
:1D array
offloats
orints (m,)
- Data over which the histogram is computed.
n_bins
:int
, optional- Number of bins passed to np.histogram(). Ignored if bins is specified. The default is 50.
bins
:1D array
orlist
offloats (n,)
, optional- Bin edges passed to np.histogram(). Overrides n_bins if specified. The default is None.
density
:bool
, optional- Density argument passed to np.histogram(). If True, the histogram is normalized to form a probability density. The default is True.
width
:float
, optional- Width of the bars in the bar plot relative to width of each bin. Should be in [0, 1]. The default is 0.8.
**kwargs
:dict
, optional- Keyword arguments passed to ax.bar() to specify additional properties. The default is {'fc': 'k', 'lw': 0}.
Returns
hist
:1D array
offloats (n,)
- Histogram counts or density values for each bin.
centers
:1D array
offloats (n,)
- Bin centers computed from the bin edges.
edges
:1D array
offloats (n + 1,)
- Bin edges corresponding to centers. Returns given bins if specified.
def quick_boxplot(ax,
data,
c_line,
c_median=None,
c_out=None,
lw=2.0,
ms=8.0,
mew=1.5,
alpha=1.0,
alpha_out=None,
**kwargs)-
Expand source code
def quick_boxplot(ax, data, c_line, c_median=None, c_out=None, lw=2., ms=8., mew=1.5, alpha=1., alpha_out=None, **kwargs): """ Wrapper for plt.boxplot() to quickly create single-color boxplots. Applies the given line color and width to all parts of a boxplot (box, whiskers, caps) except median and outliers. Accepts any other keyword arguments of plt.boxplot(). Parameters ---------- ax : matplotlib axes object Target subplot in which the boxplots are added. data : 1D (m,) or 2D (m,n) array of floats or ints or list of arrays The data to be represented by boxplots. If 1D, draws a single boxplot. If 2D, draws a boxplot for each column. If list, draws a boxplot for each array in the list. c_line : str Color of the box, whiskers, and caps. Also applied to median lines if c_median is None, and to face and edge of outliers if c_out is None. c_median : str, optional If specified, different color for median lines (else c_line). The default is None. c_out : str or tuple of str (2,), optional If specified, different color for face and edge of outliers (else c_line). A single string sets both at once. The default is None. lw : float or int, optional Width of box, whiskers, caps, and median lines in points. The default is 2.0. ms : float or int, optional Size of outlier markers in points. The default is 8.0. mew : float or int, optional Width of outlier marker edges in points. The default is 1.5. alpha : float, optional Alpha value of box, whiskers, caps, and median lines in [0, 1]. Also applied to outliers if alpha_out is None. The default is 1.0. alpha_out : float, optional If specified, different alpha value of outliers in [0, 1]. The default is None. **kwargs : dict, optional Additional keyword arguments passed to plt.boxplot() to specify properties such as outlier symbols or legend labels. Returns ------- b : dict of lists of Line2D objects Collection of line artists that represent different boxplot components, as returned by plt.boxplot(). """ # Input interpretation: if isinstance(c_out, str): c_out = (c_out, c_out) if not kwargs: kwargs = {'sym': '+'} # Bundle properties: line_props = { 'c': c_line, 'lw': lw, 'alpha': alpha } median_props = { 'c': c_line if c_median is None else c_median, 'lw': lw, 'alpha': alpha } outlier_props = { 'mfc': c_line if c_out is None else c_out[0], 'mec': c_line if c_out is None else c_out[1], 'alpha': alpha if alpha_out is None else alpha_out, 'ms': ms, 'mew': mew } # Create boxplot: b = ax.boxplot(data, boxprops=line_props, whiskerprops=line_props, capprops=line_props, medianprops=median_props, flierprops=outlier_props, **kwargs) return b
Wrapper for plt.boxplot() to quickly create single-color boxplots. Applies the given line color and width to all parts of a boxplot (box, whiskers, caps) except median and outliers. Accepts any other keyword arguments of plt.boxplot().
Parameters
ax
:matplotlib axes object
- Target subplot in which the boxplots are added.
data
:1D (m,)
or2D (m,n) array
offloats
orints
orlist
ofarrays
- The data to be represented by boxplots. If 1D, draws a single boxplot. If 2D, draws a boxplot for each column. If list, draws a boxplot for each array in the list.
c_line
:str
- Color of the box, whiskers, and caps. Also applied to median lines if c_median is None, and to face and edge of outliers if c_out is None.
c_median
:str
, optional- If specified, different color for median lines (else c_line). The default is None.
c_out
:str
ortuple
ofstr (2,)
, optional- If specified, different color for face and edge of outliers (else c_line). A single string sets both at once. The default is None.
lw
:float
orint
, optional- Width of box, whiskers, caps, and median lines in points. The default is 2.0.
ms
:float
orint
, optional- Size of outlier markers in points. The default is 8.0.
mew
:float
orint
, optional- Width of outlier marker edges in points. The default is 1.5.
alpha
:float
, optional- Alpha value of box, whiskers, caps, and median lines in [0, 1]. Also applied to outliers if alpha_out is None. The default is 1.0.
alpha_out
:float
, optional- If specified, different alpha value of outliers in [0, 1]. The default is None.
**kwargs
:dict
, optional- Additional keyword arguments passed to plt.boxplot() to specify properties such as outlier symbols or legend labels.
Returns
b
:dict
oflists
ofLine2D objects
- Collection of line artists that represent different boxplot components, as returned by plt.boxplot().
def cross_plot(array, grid=None, start_row=0, start_col=0, fig=None, labels=None, **kwargs)
-
Expand source code
def cross_plot(array, grid=None, start_row=0, start_col=0, fig=None, labels=None, **kwargs): """ Plots unique pairs of array columns against each other in an axes grid. Subplots are arranged in a triangle shape. Each subplot row corresponds to one of the array columns (excluding the last one). The data from this column is always treated as independent variable and plotted in separate subplots against the data from the following array columns. Self-pairs and duplicate pairings are not included. The subplot triangle can be placed at different positions in a larger grid by specifying the coordinates of its top-left corner. Parameters ---------- array : 2D array of floats or ints (m, n) Data to be plotted against each other column-wise. For n array columns, there are (n**2 - n) / 2 unique pairings and as many subplots in the triangle with n - 1 rows and n - 1 columns. grid : tuple of ints (2,), optional If specified, determines the axes grid in which all created subplots are placed as (rows, columns). If not specified, the grid is set to (n - 1, n - 1), so that the subplot triangle fits exactly into it. The default is None. start_row : int, optional Row coordinate of the subplot triangle's top-left corner. Can be used to shift the triangle in vertical direction. The default is 0. start_col : int, optional Column coordinate of the subplot triangle's top-left corner. Can be used to shift the triangle in horizontal direction. The default is 0. fig : matplotlib figure object, optional If specified, creates subplots in this figure according to the given grid. If not specified, creates a new figure with constrained_layout. The default is None. labels : list of str (n,), optional Column-specific names to be used as x- and y-axis labels for each subplot. If not specified, creates default labels that indicate the corresponding array column as a number in [1, n]. The default is None. **kwargs : dict, optional Additional keyword arguments passed to plt.plot() for each subplot. Defaults to black 'o' markers with white edge and linestyle ''. Returns ------- axes = list of matplotlib axes objects The created subplots in the triangle in row-wise order (left to right, then top to bottom), one for each unique pairing of array columns. All axes have the same limits for both x- and y-axis. handles = list of matplotlib line objects Plot handles corresponding to axes in the same order. Raises ------ ValueError Breaks if the grid space occupied by a subplot triangle with given corner coordinates would exceed the borders of the full grid. """ # Input interpretation: n = array.shape[1] if grid is None: grid = (n - 1, n - 1) if (grid[0] - start_row) < (n - 1) or (grid[1] - start_col) < (n - 1): # Break if required space conflicts with borders of subplot grid: msg = f'Grid {grid} is too small for subplot triangle with starting '\ f'coordinates ({start_row}, {start_col}) and size {n - 1}.' raise ValueError(msg) if not kwargs: kwargs = {'marker': 'o', 'ls': '', 'ms': 5, 'mfc': 'k', 'mec': 'w'} if fig is None: fig = plt.figure(constrained_layout=True) if labels is None: labels = [f'dim$_{i}$' for i in range(1, n + 1)] # Cross-wise comparison: axes, handles = [], [] for i in range(n): # Manage indices of subplots and array columns: for col_ind, j in enumerate(np.arange(n)[i + 1:]): # Create subplot at given position in grid: ax = plt.subplot2grid(grid, (start_row + i, start_col + col_ind)) ax.set_xlabel(labels[i]) ax.set_ylabel(labels[j]) axes.append(ax) # Plot paired data against each other: handle = ax.plot(array[:, i], array[:, j], **kwargs)[0] handles.append(handle) # Define fixed axes limits for all subplots: data_limits(array, margins=0.1, axes=axes, which='both') return axes, handles
Plots unique pairs of array columns against each other in an axes grid. Subplots are arranged in a triangle shape. Each subplot row corresponds to one of the array columns (excluding the last one). The data from this column is always treated as independent variable and plotted in separate subplots against the data from the following array columns. Self-pairs and duplicate pairings are not included. The subplot triangle can be placed at different positions in a larger grid by specifying the coordinates of its top-left corner.
Parameters
array
:2D array
offloats
orints (m, n)
- Data to be plotted against each other column-wise. For n array columns, there are (n**2 - n) / 2 unique pairings and as many subplots in the triangle with n - 1 rows and n - 1 columns.
grid
:tuple
ofints (2,)
, optional- If specified, determines the axes grid in which all created subplots are placed as (rows, columns). If not specified, the grid is set to (n - 1, n - 1), so that the subplot triangle fits exactly into it. The default is None.
start_row
:int
, optional- Row coordinate of the subplot triangle's top-left corner. Can be used to shift the triangle in vertical direction. The default is 0.
start_col
:int
, optional- Column coordinate of the subplot triangle's top-left corner. Can be used to shift the triangle in horizontal direction. The default is 0.
fig
:matplotlib figure object
, optional- If specified, creates subplots in this figure according to the given grid. If not specified, creates a new figure with constrained_layout. The default is None.
labels
:list
ofstr (n,)
, optional- Column-specific names to be used as x- and y-axis labels for each subplot. If not specified, creates default labels that indicate the corresponding array column as a number in [1, n]. The default is None.
**kwargs
:dict
, optional- Additional keyword arguments passed to plt.plot() for each subplot. Defaults to black 'o' markers with white edge and linestyle ''.
Returns
axes = list
ofmatplotlib axes objects
- The created subplots in the triangle in row-wise order (left to right, then top to bottom), one for each unique pairing of array columns. All axes have the same limits for both x- and y-axis.
handles = list
ofmatplotlib line objects
- Plot handles corresponding to axes in the same order.
Raises
ValueError
- Breaks if the grid space occupied by a subplot triangle with given corner coordinates would exceed the borders of the full grid.
def plot_spectrogram(signal,
rate,
ax,
spec_kwargs,
quick_render=True,
f_resample=None,
t_resample=None,
**plot_kwargs)-
Expand source code
def plot_spectrogram(signal, rate, ax, spec_kwargs, quick_render=True, f_resample=None, t_resample=None, **plot_kwargs): """ Computes and displays a spectrogram of the signal in the given subplot. Calls spectrogram() for calculation and uses either plt.imshow() or plt.pcolormesh() for plotting. Allows to control the balance between rendering speed and visual quality of the displayed spectrogram. Parameters ---------- signal : 1D array of floats or ints (m,) Signal from which to compute the spectrogram. rate : float or int Sampling rate of the signal in Hz. ax : matplotlib axes object Target subplot in which to plot the spectrogram. spec_kwargs : dict Keyword arguments passed to the spectrogram() wrapper function to specify the computation parameters. Obligated to have some content. quick_render : bool, optional If True, uses plt.imshow() to speed up (re-)rendering at the cost of visual quality. Else, uses plt.pcolormesh() to create prettier plots with a greatly increased computational overhead. The default is True. f_resample : int, optional If specified, reduces the spectrogram's frequency axis load by downsampling with this factor. Must be > 1. The default is None. t_resample : int, optional If specified, reduces the spectrogram's time axis load by downsampling with this factor. Must be > 1. The default is None. **plot_kwargs : dict, optional Additional keyword arguments passed to plt.imshow() or plt.pcolormesh() to modify default settings, particularly imshow()'s 'interpolation' or pcolormesh()'s 'shading', which have a great impact on rendering speed. Default interpolation is 'none', default shading is 'flat'. Returns ------- freqs : 1D array of floats (n,) Frequency axis of the spectrogram in Hz (axis 0 of spectrum). times : 1D array of floats (p,) Time axis of the spectrogram in s (axis 1 of spectrum). spectrum : 2D array of floats (n, p) Spectrogram powers in either unit ** 2 / Hz or dB. """ # Compute spectrogram: f, t, spectrum = spectrogram(signal, rate, **spec_kwargs) # Optional downsampling: if f_resample is not None: # Reduce frequency axis load: f, spectrum = f[::f_resample], spectrum[::f_resample, :] if t_resample is not None: # Reduce time axis load: t, spectrum = t[::t_resample], spectrum[:, ::t_resample] # Plot spectrogram: if quick_render: # With plt.imshow(): plot_settings = { 'interpolation': 'none', 'origin': 'lower', 'aspect': 'auto', 'extent': [t[0], t[-1], f[0], f[-1]], 'rasterized': True } plot_settings.update(plot_kwargs) ax.imshow(spectrum, **plot_settings) else: # With plt.pcolormesh(): plot_settings = { 'shading': 'flat', 'rasterized': True } plot_settings.update(plot_kwargs) if plot_settings['shading'] == 'flat': # Ensure shape compatibility: spectrum = spectrum[:f.size - 1, :t.size - 1] ax.pcolormesh(t, f, spectrum, **plot_settings) return f, t, spectrum
Computes and displays a spectrogram of the signal in the given subplot. Calls spectrogram() for calculation and uses either plt.imshow() or plt.pcolormesh() for plotting. Allows to control the balance between rendering speed and visual quality of the displayed spectrogram.
Parameters
signal
:1D array
offloats
orints (m,)
- Signal from which to compute the spectrogram.
rate
:float
orint
- Sampling rate of the signal in Hz.
ax
:matplotlib axes object
- Target subplot in which to plot the spectrogram.
spec_kwargs
:dict
- Keyword arguments passed to the spectrogram() wrapper function to specify the computation parameters. Obligated to have some content.
quick_render
:bool
, optional- If True, uses plt.imshow() to speed up (re-)rendering at the cost of visual quality. Else, uses plt.pcolormesh() to create prettier plots with a greatly increased computational overhead. The default is True.
f_resample
:int
, optional- If specified, reduces the spectrogram's frequency axis load by downsampling with this factor. Must be > 1. The default is None.
t_resample
:int
, optional- If specified, reduces the spectrogram's time axis load by downsampling with this factor. Must be > 1. The default is None.
**plot_kwargs
:dict
, optional- Additional keyword arguments passed to plt.imshow() or plt.pcolormesh() to modify default settings, particularly imshow()'s 'interpolation' or pcolormesh()'s 'shading', which have a great impact on rendering speed. Default interpolation is 'none', default shading is 'flat'.
Returns
freqs
:1D array
offloats (n,)
- Frequency axis of the spectrogram in Hz (axis 0 of spectrum).
times
:1D array
offloats (p,)
- Time axis of the spectrogram in s (axis 1 of spectrum).
spectrum
:2D array
offloats (n, p)
- Spectrogram powers in either unit ** 2 / Hz or dB.
def time_axis(array,
rate,
axis=0,
start=None,
end=None,
zero_start=True,
pad=None,
pad_start=1,
pad_end=1,
down_rate=None,
maximum=None,
minimum=None)-
Expand source code
def time_axis(array, rate, axis=0, start=None, end=None, zero_start=True, pad=None, pad_start=1, pad_end=1, down_rate=None, maximum=None, minimum=None): """ Creates a custom time axis over an N-dimensional array of data. Initial time axis has given sampling rate and starts at zero. Supports cropping to some time frame, downsampling, and capping of data values. Parameters ---------- array : N-dimensional array of arbitrary type The dataset for which to compute the time axis. The given axis of the array must correspond to time, sampled with rate. rate : float or int Sampling rate of the dataset along the given axis in Hz. axis : int, optional Dimension of array that corresponds to time. The default is 0. start : float or int, optional If specified, crops dataset to start at this time in s. If zero_start is True, recomputes time axis to start at zero again after cropping. The default is None. end : float or int, optional If specified, crops dataset to end at this time in s. If zero_start is True, the last included time point in the time axis changes accordingly. The default is None. zero_start : bool, optional If True, adjusts time axis to start at zero every time it is cropped. Else, cuts returned time axis from the initial time axis to match the specified time frame (for plotting zoom-ins). The default is True. pad : float or int, optional If positive, trims edges of dataset in time by some multiples of this value in s. Adds to any specified start or end. Set pad_start and pad_end to modify the factor of pad at each edge. If zero_start is True, recomputes time axis to start at zero again. Meant to apply fixed temporal buffers or to skip over filter edge effects. The default is 0. pad_start : float or int, optional If specified, trims start of dataset in time by pad * pad_start in s. If zero_start is True, recomputes time axis to start at zero. Ignored if period is zero. The default is None. pad_end : _type_, optional If specified, trims end of dataset in time by pad * pad_end in s. If zero_start is True, the last included time point in the time axis changes accordingly. Ignored if period is zero. The default is None. down_rate : float or int, optional If specified, downsamples cropped or trimmed dataset to this rate in Hz and adjusts time axis accordingly. 1D arrays are downsampled with interpolation if needed. Multi-dimensional arrays are downsampled by simple nth-entry selection with a step size of around rate/down_rate. Meant to reduce data load for plotting, not for analysis. The default is None. minimum : float or int, optional If specified, caps entire array to this minimum value. Applies to all dimensions. The default is None. maximum : float or int, optional If specified, caps entire array to this maximum value. Applies to all dimensions. The default is None. Returns ------- time : 1D array of floats (m,) Customized time axis over the returned array in s. Start and end times depend on the specified keyword arguments. Always starts at zero and encompasses the full given dataset if called with default settings. array : N-dimensional array of arbitrary type Cropped, trimmed, downsampled, and capped dataset of the same shape as the given array. Returns unmodified array if called with default settings. """ # Create initials: array = array.copy() time = np.arange(array.shape[axis]) / rate # Optional trimming or cropping to time frame: if start is not None or end is not None or pad is not None: # Argument fallbacks: if start is None: start = 0 if end is None: end = time[-1] if pad is not None: # Adjust edges for padding: start += pad_start * pad end -= pad_end * pad # Crop to time frame and optionally recompute axis: ind = np.nonzero((time >= start) & (time <= end))[0] array = np.take(array, ind, axis=axis) time = np.arange(array.shape[axis]) / rate if zero_start else time[ind] # Optional downsampling: if down_rate is not None: if array.ndim == 1: # Downsample with interpolation if needed: array = downsampling(array, rate, down_rate) time = np.arange(len(array)) / down_rate if not zero_start: # Adjust again: time += start else: # Simple nth-entry selection: rate_ratio = int(np.round(rate / down_rate)) ind = np.arange(0, array.shape[axis], rate_ratio) array = np.take(array, ind, axis=axis) time = time[ind] # Optional capping of data: if minimum is not None: array[array <= minimum] = minimum if maximum is not None: array[array >= maximum] = maximum return time, array
Creates a custom time axis over an N-dimensional array of data. Initial time axis has given sampling rate and starts at zero. Supports cropping to some time frame, downsampling, and capping of data values.
Parameters
array
:N-dimensional array
ofarbitrary type
- The dataset for which to compute the time axis. The given axis of the array must correspond to time, sampled with rate.
rate
:float
orint
- Sampling rate of the dataset along the given axis in Hz.
axis
:int
, optional- Dimension of array that corresponds to time. The default is 0.
start
:float
orint
, optional- If specified, crops dataset to start at this time in s. If zero_start is True, recomputes time axis to start at zero again after cropping. The default is None.
end
:float
orint
, optional- If specified, crops dataset to end at this time in s. If zero_start is True, the last included time point in the time axis changes accordingly. The default is None.
zero_start
:bool
, optional- If True, adjusts time axis to start at zero every time it is cropped. Else, cuts returned time axis from the initial time axis to match the specified time frame (for plotting zoom-ins). The default is True.
pad
:float
orint
, optional- If positive, trims edges of dataset in time by some multiples of this value in s. Adds to any specified start or end. Set pad_start and pad_end to modify the factor of pad at each edge. If zero_start is True, recomputes time axis to start at zero again. Meant to apply fixed temporal buffers or to skip over filter edge effects. The default is 0.
pad_start
:float
orint
, optional- If specified, trims start of dataset in time by pad * pad_start in s. If zero_start is True, recomputes time axis to start at zero. Ignored if period is zero. The default is None.
pad_end
:_type_
, optional- If specified, trims end of dataset in time by pad * pad_end in s. If zero_start is True, the last included time point in the time axis changes accordingly. Ignored if period is zero. The default is None.
down_rate
:float
orint
, optional- If specified, downsamples cropped or trimmed dataset to this rate in Hz and adjusts time axis accordingly. 1D arrays are downsampled with interpolation if needed. Multi-dimensional arrays are downsampled by simple nth-entry selection with a step size of around rate/down_rate. Meant to reduce data load for plotting, not for analysis. The default is None.
minimum
:float
orint
, optional- If specified, caps entire array to this minimum value. Applies to all dimensions. The default is None.
maximum
:float
orint
, optional- If specified, caps entire array to this maximum value. Applies to all dimensions. The default is None.
Returns
time
:1D array
offloats (m,)
- Customized time axis over the returned array in s. Start and end times depend on the specified keyword arguments. Always starts at zero and encompasses the full given dataset if called with default settings.
array
:N-dimensional array
ofarbitrary type
- Cropped, trimmed, downsampled, and capped dataset of the same shape as the given array. Returns unmodified array if called with default settings.
def text_box(ax, text, xy, width, height, transform=None, ha='center', va='center', **kwargs)
-
Expand source code
def text_box(ax, text, xy, width, height, transform=None, ha='center', va='center', **kwargs): """ Maximizes fontsize of text to fit into a given bounding box. Calculated fontsize depends on the aspect ratio of the bounding box, the aspect ratio and alignment of the text, and the resolution and size of the underlying figure. Text is not updated when resizing the figure. Parameters ---------- ax : matplotlib axes object Target subplot to annotate the text. text : str Text to fit into the specified bounding box under the given alignments. xy : tuple of floats or ints (2,) Text position in the coordinate system specified by transform. width : float or int Rectangle width in the coordinate system specified by transform. height : float or int Rectangle height in the coordinate system specified by transform. transform : matplotlib transform, optional Underlying coordinate system of the bounding box. Determines the interpretation of xy, width, and height. Falls back to data coordinates if unspecified. The default is None. ha : str, optional Horizontal alignment of bounding box and text relative to the given xy. The default is 'center'. va : str, optional Vertical alignment of bounding box and text relative to the given xy. The default is 'center'. **kwargs : dict, optional Additional keyword arguments passed to ax.annotate() for specifying different font properties of the returned text object. Returns ------- t : matplotlib text object Annotated text object with adjusted fontsize to fit the bounding box. """ # Input interpretation: if transform is None: transform = ax.transData fig = ax.get_figure() x, y = xy # Alignment-specific anchor points: x_align1, x_align2 = { 'center': (x - width / 2, x + width / 2), 'left': (x, x + width), 'right': (x - width, x), }[ha] y_align1, y_align2 = { 'center': (y - height / 2, y + height / 2), 'bottom': (y, y + height), 'top': (y - height, y), }[va] # Anchor points in pixel: left_corner = transform.transform((x_align1, y_align1)) right_corner = transform.transform((x_align2, y_align2)) # Bounding rectangle size in pixel: pixel_width = right_corner[0] - left_corner[0] pixel_height = right_corner[1] - left_corner[1] # Adjust fontsize to box height (inch): dpi = fig.dpi rect_height = pixel_height / dpi fs_initial = rect_height * 72 # Plot first draft of the text: t = ax.annotate(text, xy, ha=ha, va=va, xycoords=transform, **kwargs) t.set_fontsize(fs_initial) # Adjust fontsize to box width (inch): bbox = t.get_window_extent(fig.canvas.get_renderer()) fs_adjusted = fs_initial * pixel_width / bbox.width t.set_fontsize(fs_adjusted) return t
Maximizes fontsize of text to fit into a given bounding box. Calculated fontsize depends on the aspect ratio of the bounding box, the aspect ratio and alignment of the text, and the resolution and size of the underlying figure. Text is not updated when resizing the figure.
Parameters
ax
:matplotlib axes object
- Target subplot to annotate the text.
text
:str
- Text to fit into the specified bounding box under the given alignments.
xy
:tuple
offloats
orints (2,)
- Text position in the coordinate system specified by transform.
width
:float
orint
- Rectangle width in the coordinate system specified by transform.
height
:float
orint
- Rectangle height in the coordinate system specified by transform.
transform
:matplotlib transform
, optional- Underlying coordinate system of the bounding box. Determines the interpretation of xy, width, and height. Falls back to data coordinates if unspecified. The default is None.
ha
:str
, optional- Horizontal alignment of bounding box and text relative to the given xy. The default is 'center'.
va
:str
, optional- Vertical alignment of bounding box and text relative to the given xy. The default is 'center'.
**kwargs
:dict
, optional- Additional keyword arguments passed to ax.annotate() for specifying different font properties of the returned text object.
Returns
t
:matplotlib text object
- Annotated text object with adjusted fontsize to fit the bounding box.
def text_graph(text, save_str=None, size=None, ax=None, show=False, close=False, **kwargs)
-
Expand source code
def text_graph(text, save_str=None, size=None, ax=None, show=False, close=False, **kwargs): """ Turns entire subplot into a text box that displays the given text. Fontsize is maximized to fit the available bounding box. Text is always centered in the subplot. Meant for creating scalable text elements that comply with the style of other plot elements, especially for posters. Parameters ---------- text : str Text to be displayed. Can be multiline. Text fontsize is maximized by text_box() to fit a bounding box that covers the entire axes area. save_str : str, optional If specified, saves the underlying figure under the given path. For best results, use a vector format such as .svg). The default is None. size : tuple of floats or ints (2,), optional If specified, creates a new figure with given size in inches and a single subplot. Indirectly controls the aspect ratio of the text box. Must be specified if ax is None. The default is None. ax : matplotlib axes object, optional If specified, the target subplot to turn into a text box. Can be used to set more properties such as the background color of the text box. Must be specified if size is None. The default is None. show : bool, optional If True, displays the figure before returning. Else, returns without showing the figure. The default is False. **kwargs : dict, optional Keyword arguments passed to text_box() and further to ax.annotate() for specifying additional font properties of the displayed text. Raises ------ ValueError Breaks if neither size nor ax is specified to define a target subplot. """ # Input interpretation: if size is not None: fig, ax = plt.subplots(figsize=size) elif ax is not None: fig = ax.get_figure() else: raise ValueError('Either size or ax must be specified.') # Turn drawable area of axes into a single text box: text_box(ax, text, (0.5, 0.5), 1, 1, ax.transAxes, **kwargs) # Hide other axes elements: ax.xaxis.set_visible(False) ax.yaxis.set_visible(False) ax.spines[:].set_visible(False) # Return options: if save_str is not None: fig.savefig(save_str, bbox_inches='tight') if show: plt.show() return None
Turns entire subplot into a text box that displays the given text. Fontsize is maximized to fit the available bounding box. Text is always centered in the subplot. Meant for creating scalable text elements that comply with the style of other plot elements, especially for posters.
Parameters
text
:str
- Text to be displayed. Can be multiline. Text fontsize is maximized by text_box() to fit a bounding box that covers the entire axes area.
save_str
:str
, optional- If specified, saves the underlying figure under the given path. For best results, use a vector format such as .svg). The default is None.
size
:tuple
offloats
orints (2,)
, optional- If specified, creates a new figure with given size in inches and a single subplot. Indirectly controls the aspect ratio of the text box. Must be specified if ax is None. The default is None.
ax
:matplotlib axes object
, optional- If specified, the target subplot to turn into a text box. Can be used to set more properties such as the background color of the text box. Must be specified if size is None. The default is None.
show
:bool
, optional- If True, displays the figure before returning. Else, returns without showing the figure. The default is False.
**kwargs
:dict
, optional- Keyword arguments passed to text_box() and further to ax.annotate() for specifying additional font properties of the displayed text.
Raises
ValueError
- Breaks if neither size nor ax is specified to define a target subplot.
def serial_save(fig, ax_stages, name, x_temp=None, y_temp=None, delimit='_')
-
Expand source code
def serial_save(fig, ax_stages, name, x_temp=None, y_temp=None, delimit='_'): """ Iteratively saves a figure with different axes revealed at each stage. Supports options for synchronized axes so that only one axis bears visible axes labels and tick labels at a given stage, which are cleared before the next stage. Discouraged for use with shared axes. Instead, use sync_axes(hide_labels=False) and empty axes labels before calling this function with either the x_temp or the y_temp keyword argument. Parameters ---------- fig : matplotlib figure object Target figure in the finalized layout before plt.show(). ax_stages : list (m,) of matplotlib axes objects or lists of axes objects Subplots to be revealed at each of the m stages. Saves one file for each element in ax_stages, so that the last one shows the full figure. Multiple subplots can be bundled to reveal them at once. If given an ndarray of axes (Matplotlib standard), converts it to list so that each subplot row in the grid is treated as a single stage. name : str or list/tuple of str (2,) Path template under which all files are saved. Adds a number in [1, m] to indicate the current stage in each filename. If given a single string, sets tag as last filename component before the file extension. If given two string segments, places tag in between. Tags are separated from the rest of the filename by the delimit string. x_temp : str, optional If specified, assumes a synchronized x-axis between certain subplots and reveals or hides x-axis labels and tick labels accordingly at each stage. Upon revealing a new stage, applies the temporary label to the staged subplot. For multiple staged subplots, applies label to the last subplot in line and hides the tick labels of the others. After saving the given stage, clears temporary label and hides tick labels of all staged subplots before revealing the next stage. The default is None. y_temp : str, optional If specified, assumes a synchronized y-axis between certain subplots and reveals or hides y-axis labels and tick labels accordingly at each stage. Upon revealing a new stage, applies the temporary label to the staged subplot. For multiple staged subplots, applies label to the last subplot in line and hides the tick labels of the others. After saving the given stage, clears temporary label and hides tick labels of all staged subplots before revealing the next stage. The default is None. delimit : str, optional Delimiter string to separate the stage tag from the rest of name when creating the path for each saved figure. The default is '_'. """ # Input interpretation: if isinstance(ax_stages, np.ndarray): # Fallback for axes grids: ax_stages = ax_stages.tolist() else: # Assert iterable of iterables: ax_stages = check_list(ax_stages) ax_stages = [check_list(stage) for stage in ax_stages] if isinstance(name, (tuple, list)): # Tag between given segments: pre_str = name[0] + delimit post_str = delimit + name[1] else: # Tag in last place before extension: post_str = '.' + name.split('.')[-1] pre_str = name[:-len(post_str)] + delimit # Initialize by hiding all staged axes: [ax.set_visible(False) for ax in flat_list(ax_stages)] for i, new_axes in enumerate(ax_stages): # Add temporary labels to main axes: if x_temp is not None: new_axes[-1].set_xlabel(x_temp) [ax.set_xticks(ax.get_xticks(), []) for ax in new_axes[:-1]] if y_temp is not None: new_axes[-1].set_ylabel(y_temp) [ax.set_yticks(ax.get_yticks(), []) for ax in new_axes[:-1]] # Reveal current stage and save step: [ax.set_visible(True) for ax in new_axes] fig.savefig(f'{pre_str}{i + 1}{post_str}') # Clear temporary labels: if x_temp is not None and (i < len(ax_stages) - 1): new_axes[-1].set_xlabel('') new_axes[-1].set_xticks(new_axes[-1].get_xticks(), []) if y_temp is not None and (i < len(ax_stages) - 1): new_axes[-1].set_ylabel('') new_axes[-1].set_yticks(new_axes[-1].get_yticks(), []) return None
Iteratively saves a figure with different axes revealed at each stage. Supports options for synchronized axes so that only one axis bears visible axes labels and tick labels at a given stage, which are cleared before the next stage. Discouraged for use with shared axes. Instead, use sync_axes(hide_labels=False) and empty axes labels before calling this function with either the x_temp or the y_temp keyword argument.
Parameters
fig
:matplotlib figure object
- Target figure in the finalized layout before plt.show().
ax_stages
:list (m,)
ofmatplotlib axes objects
orlists
ofaxes objects
- Subplots to be revealed at each of the m stages. Saves one file for each element in ax_stages, so that the last one shows the full figure. Multiple subplots can be bundled to reveal them at once. If given an ndarray of axes (Matplotlib standard), converts it to list so that each subplot row in the grid is treated as a single stage.
name
:str
orlist/tuple
ofstr (2,)
- Path template under which all files are saved. Adds a number in [1, m] to indicate the current stage in each filename. If given a single string, sets tag as last filename component before the file extension. If given two string segments, places tag in between. Tags are separated from the rest of the filename by the delimit string.
x_temp
:str
, optional- If specified, assumes a synchronized x-axis between certain subplots and reveals or hides x-axis labels and tick labels accordingly at each stage. Upon revealing a new stage, applies the temporary label to the staged subplot. For multiple staged subplots, applies label to the last subplot in line and hides the tick labels of the others. After saving the given stage, clears temporary label and hides tick labels of all staged subplots before revealing the next stage. The default is None.
y_temp
:str
, optional- If specified, assumes a synchronized y-axis between certain subplots and reveals or hides y-axis labels and tick labels accordingly at each stage. Upon revealing a new stage, applies the temporary label to the staged subplot. For multiple staged subplots, applies label to the last subplot in line and hides the tick labels of the others. After saving the given stage, clears temporary label and hides tick labels of all staged subplots before revealing the next stage. The default is None.
delimit
:str
, optional- Delimiter string to separate the stage tag from the rest of name when creating the path for each saved figure. The default is '_'.
def pick_legend(legend_artists, plot_artists, radius=5.0)
-
Expand source code
def pick_legend(legend_artists, plot_artists, radius=5.): """ Makes legend artists pickable and maps them to chosen plot artists. Allows to trigger events by clicking on legend artists while the resulting action is applied to the linked plot artists. Parameters ---------- legend_artists : Matplotlib legend object or (list of) legend artists (m,) Artists of the legend entries to make pickable. Accepts a single handle or a list of handles. If given a legend object, extracts all inlcuded legend handles as legend.legend_handles. plot_artists : plot artist or list (m,) (of lists) of plot artists Artists of the plot elements to link to each legend artist. Accepts a single handle (if legend_artists is a single handle) or a list of one or several handles (one for each legend artist). Number and order of provided plot_artists must correspond to legend_artists for correct mapping. radius : float or int, optional Pick radius in points to apply to legend artists that are lines (but not patches). The default is 5.0. Returns ------- linked_handles : dict Mapping of each provided legend artist (keys) to its linked plot artists (values). Plot artists are always lists of handles, even if only one is linked to a legend artist. If an event is triggered by clicking on a specific legend artist, this artist can be used to identify all plot artists that should be affected by the action. """ # Input intepretation: if 'Legend' in str(type(legend_artists)): legend_artists = legend_artists.legend_handles else: # Assert iterables: legend_artists = check_list(legend_artists) plot_artists = check_list(plot_artists) linked_handles = {} for handle_legend, handle_plot in zip(legend_artists, plot_artists): # Make legend artists pickable: handle_legend.set_picker(True) if 'Line2D' in str(type(handle_legend)): handle_legend.set_pickradius(radius) # Map legend artists to one or several wrapped plot artists: linked_handles[handle_legend] = check_list(handle_plot) return linked_handles
Makes legend artists pickable and maps them to chosen plot artists. Allows to trigger events by clicking on legend artists while the resulting action is applied to the linked plot artists.
Parameters
legend_artists
:Matplotlib legend object
or(list of) legend artists (m,)
- Artists of the legend entries to make pickable. Accepts a single handle or a list of handles. If given a legend object, extracts all inlcuded legend handles as legend.legend_handles.
plot_artists
:plot artist
orlist (m,) (of lists)
ofplot artists
- Artists of the plot elements to link to each legend artist. Accepts a single handle (if legend_artists is a single handle) or a list of one or several handles (one for each legend artist). Number and order of provided plot_artists must correspond to legend_artists for correct mapping.
radius
:float
orint
, optional- Pick radius in points to apply to legend artists that are lines (but not patches). The default is 5.0.
Returns
linked_handles
:dict
- Mapping of each provided legend artist (keys) to its linked plot artists (values). Plot artists are always lists of handles, even if only one is linked to a legend artist. If an event is triggered by clicking on a specific legend artist, this artist can be used to identify all plot artists that should be affected by the action.