Source code for autoarray.plot.wrap.wrap_base

import matplotlib
import pickle

from autoconf import conf
from autoarray.structures.arrays.uniform_2d import Array2D

from typing import Union, List, Optional, Tuple


def set_backend():

    backend = conf.get_matplotlib_backend()

    if backend not in "default":
        matplotlib.use(backend)

    try:
        hpc_mode = conf.instance["general"]["hpc"]["hpc_mode"]
    except KeyError:
        hpc_mode = False

    if hpc_mode:
        matplotlib.use("Agg")


import matplotlib.pyplot as plt
import matplotlib.colors as colors
import matplotlib.cm as cm
from matplotlib.ticker import FormatStrFormatter

import numpy as np
from os import path
import os


from autoarray.structures.abstract_structure import Structure
from autoarray import exc


[docs]class Units:
[docs] def __init__( self, use_scaled: Optional[bool] = None, conversion_factor: Optional[float] = None, in_kpc: Optional[bool] = None, ): """ This object controls the units of a plotted figure, and performs multiple tasks when making the plot: 1: Species the units of the plot (e.g. meters, kilometers) and contains a conversion factor which converts the plotted data from its current units (e.g. meters) to the units plotted (e.g. kilometeters). Pixel units can be used if `use_scaled=False`. 2: Uses the conversion above to manually override the yticks and xticks of the figure, so it appears in the converted units. 3: Sets the ylabel and xlabel to include a string containing the units. Parameters ---------- use_scaled If True, plot the 2D data with y and x ticks corresponding to its scaled coordinates (its `pixel_scales` attribute is used as the `conversion_factor`). If `False` plot them in pixel units. conversion_factor If plotting the labels in scaled units, this factor multiplies the values that are used for the labels. This allows for additional unit conversions of the figure labels. in_kpc If True, the scaled units are converted to kilo-parsecs via the input Comsology of the plot (this is only relevant for the projects PyAutoGalaxy / PyAutoLens). """ self.use_scaled = use_scaled self.conversion_factor = conversion_factor self.in_kpc = in_kpc if use_scaled is not None: self.use_scaled = use_scaled else: try: self.use_scaled = conf.instance["visualize"]["general"]["units"][ "use_scaled" ] except: self.use_scaled = True try: self.in_kpc = ( in_kpc if in_kpc is not None else conf.instance["visualize"]["general"]["units"]["in_kpc"] ) except: self.in_kpc = None
class AbstractMatWrap: def __init__(self, **kwargs): """ An abstract base class for wrapping matplotlib plotting methods. Classes are used to wrap matplotlib so that the data structures in the `autoarray.structures` package can be plotted in standardized withs. This exploits how these structures have specific formats, units, properties etc. This allows us to make a simple API for plotting structures, for example to plot an `Array2D` structure: import autoarray as aa import autoarray.plot as aplt arr = aa.Array2D.manual_native(array=[[1.0, 1.0], [2.0, 2.0]], pixel_scales=2.0) aplt.Array2D(array=arr) The wrapped Mat objects make it simple to customize how matplotlib visualizes this data structure, for example we can customize the figure size and colormap using the `Figure` and `Cmap` objects. figure = aplt.Figure(figsize=(7,7), aspect="square") cmap = aplt.Cmap(cmap="jet", vmin=1.0, vmax=2.0) plotter = aplt.MatPlot2D(figure=figure, cmap=cmap) aplt.Array2D(array=arr, plotter=plotter) The `Plotter` object is detailed in the `autoarray.plot.plotter` package. The matplotlib wrapper objects in ths module also use configuration files to choose their default settings. For example, in `autoarray.config.visualize.mat_base.Figure.ini` you will note the section: [figure] figsize=(7, 7) [subplot] figsize=auto This specifies that when a data structure (like the `Array2D` above) is plotted, the figsize will always be (7,7) when a single figure is plotted and it will be chosen automatically if a subplot is plotted. This allows one to customize the matplotlib settings of every plot in a project. """ self.is_for_subplot = False self.kwargs = kwargs @property def config_dict(self): if not self.is_for_subplot: config_dict = conf.instance["visualize"][self.config_folder][ self.__class__.__name__ ]["figure"]._dict else: config_dict = conf.instance["visualize"][self.config_folder][ self.__class__.__name__ ]["subplot"]._dict if "c" in config_dict: config_dict["c"] = remove_spaces_and_commas_from(colors=config_dict["c"]) config_dict = {**config_dict, **self.kwargs} if "c" in config_dict: if config_dict["c"] is None: config_dict.pop("c") return config_dict @property def config_folder(self): return "mat_wrap"
[docs]class Figure(AbstractMatWrap): """ Sets up the Matplotlib figure before plotting (this is used when plotting individual figures and subplots). This object wraps the following Matplotlib methods: - plt.figure: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.figure.html - plt.close: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.close.html It also controls the aspect ratio of the figure plotted. """ @property def config_dict(self): """ Creates a config dict of valid inputs of the method `plt.figure` from the object's config_dict. """ config_dict = super().config_dict if config_dict["figsize"] == "auto": config_dict["figsize"] = None elif isinstance(config_dict["figsize"], str): config_dict["figsize"] = tuple( map(int, config_dict["figsize"][1:-1].split(",")) ) return config_dict def aspect_for_subplot_from(self, extent): ratio = float((extent[1] - extent[0]) / (extent[3] - extent[2])) if self.config_dict["aspect"] in "square": return ratio elif self.config_dict["aspect"] in "auto": return 1.0 / ratio elif self.config_dict["aspect"] in "equal": return 1.0 def aspect_from(self, shape_native: Union[Tuple[int, int]]) -> Union[float, str]: """ Returns the aspect ratio of the figure from the 2D shape of a data structure. This is used to ensure that rectangular arrays are plotted as square figures on sub-plots. Parameters ---------- shape_native The two dimensional shape of an `Array2D` that is to be plotted. """ if isinstance(self.config_dict["aspect"], str): if self.config_dict["aspect"] in "square": return float(shape_native[1]) / float(shape_native[0]) return self.config_dict["aspect"] def open(self): """ Wraps the Matplotlib method 'plt.figure' for opening a figure. """ if not plt.fignum_exists(num=1): config_dict = self.config_dict config_dict.pop("aspect") plt.figure(**config_dict) def close(self): """ Wraps the Matplotlib method 'plt.close' for closing a figure. """ if plt.fignum_exists(num=1): plt.close()
[docs]class Axis(AbstractMatWrap):
[docs] def __init__(self, symmetric_source_centre: bool = False, **kwargs): """ Customizes the axis of the plotted figure. This object wraps the following Matplotlib method: - plt.axis: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.axis.html Parameters ---------- symmetric_source_centre If `True`, the axis is symmetric around the centre of the plotted structure's coordinates. """ super().__init__(**kwargs) self.symmetric_around_centre = symmetric_source_centre
def set(self, extent: List[float] = None, grid=None): """ Set the axis limits of the figure the grid is plotted on. Parameters ---------- extent The extent of the figure which set the axis-limits on the figure the grid is plotted, following the format [xmin, xmax, ymin, ymax]. """ config_dict = self.config_dict extent_dict = config_dict.get("extent") if extent_dict is not None: config_dict.pop("extent") if self.symmetric_around_centre: ymin = np.min(grid[:, 0]) ymax = np.max(grid[:, 0]) xmin = np.min(grid[:, 1]) xmax = np.max(grid[:, 1]) x = np.max([np.abs(xmin), np.abs(xmax)]) y = np.max([np.abs(ymin), np.abs(ymax)]) extent_symmetric = [-x, x, -y, y] plt.axis(extent_symmetric, **config_dict) else: if extent_dict is not None: plt.axis(extent_dict, **config_dict) else: plt.axis(extent, **config_dict)
[docs]class Cmap(AbstractMatWrap): """ Customizes the Matplotlib colormap and its normalization. This object wraps the following Matplotlib methods: - colors.Linear: https://matplotlib.org/3.3.2/tutorials/colors/colormaps.html - colors.LogNorm: https://matplotlib.org/3.3.2/tutorials/colors/colormapnorms.html - colors.SymLogNorm: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.colors.SymLogNorm.html The cmap that is created is passed into various Matplotlib methods, most notably imshow: - https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.imshow.html """ def vmin_from(self, array: np.ndarray): if self.config_dict["vmin"] is None: return np.min(array) else: return self.config_dict["vmin"] def vmax_from(self, array: np.ndarray): if self.config_dict["vmax"] is None: return np.max(array) else: return self.config_dict["vmax"] def norm_from(self, array: np.ndarray) -> object: """ Returns the `Normalization` object which scales of the colormap. If vmin / vmax are not manually input by the user, the minimum / maximum values of the data being plotted are used. Parameters ---------- array The array of data which is to be plotted. """ vmin = self.vmin_from(array=array) vmax = self.vmax_from(array=array) if isinstance(self.config_dict["norm"], colors.Normalize): return self.config_dict["norm"] if self.config_dict["norm"] in "linear": return colors.Normalize(vmin=vmin, vmax=vmax) elif self.config_dict["norm"] in "log": if vmin == 0.0: vmin = 1.0e-4 return colors.LogNorm(vmin=vmin, vmax=vmax) elif self.config_dict["norm"] in "symmetric_log": return colors.SymLogNorm( vmin=vmin, vmax=vmax, linthresh=self.config_dict["linthresh"], linscale=self.config_dict["linscale"], ) elif self.config_dict["norm"] in "diverge": return colors.TwoSlopeNorm(vmin=vmin, vcenter=0, vmax=vmax) else: raise exc.PlottingException( "The normalization (norm) supplied to the plotter is not a valid string must be " "{linear, log, symmetric_log}" ) @property def cmap(self): if self.config_dict["cmap"] == "default": directory = path.dirname(path.realpath(__file__)) with open(path.join(directory, f"cmap.pkl"), "rb") as f: return pickle.load(f) return self.config_dict["cmap"]
[docs]class Colorbar(AbstractMatWrap):
[docs] def __init__( self, manual_tick_labels: Optional[List[float]] = None, manual_tick_values: Optional[List[float]] = None, **kwargs, ): """ Customizes the colorbar of the plotted figure. This object wraps the following Matplotlib method: - plt.colorbar: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.colorbar.html The colorbar object `cb` that is created is also customized using the following methods: - cb.set_yticklabels: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.axes.Axes.set_yticklabels.html Parameters ---------- manual_tick_labels Manually override the colorbar tick labels to an input list of float. manual_tick_values If the colorbar tick labels are manually specified the locations on the colorbar they appear running 0 -> 1. """ super().__init__(**kwargs) self.manual_tick_labels = manual_tick_labels self.manual_tick_values = manual_tick_values
def set(self): """ Set the figure's colorbar, optionally overriding the tick labels and values with manual inputs. """ if self.manual_tick_values is None and self.manual_tick_labels is None: cb = plt.colorbar(**self.config_dict) elif ( self.manual_tick_values is not None and self.manual_tick_labels is not None ): cb = plt.colorbar(ticks=self.manual_tick_values, **self.config_dict) cb.ax.set_yticklabels(labels=self.manual_tick_labels) else: raise exc.PlottingException( "Only 1 entry of tick_values or tick_labels was input. You must either supply" "both the values and labels, or neither." ) return cb def set_with_color_values(self, cmap: str, color_values: np.ndarray): """ Set the figure's colorbar using an array of already known color values. This method is used for producing the color bar on a Voronoi mesh plot, which is unable to use the in-built Matplotlib colorbar method. Parameters ---------- cmap The colormap used to map normalized data values to RGBA colors (see https://matplotlib.org/3.3.2/api/cm_api.html). color_values The values of the pixels on the Voronoi mesh which are used to create the colorbar. """ cax = cm.ScalarMappable(cmap=cmap) cax.set_array(color_values) if self.manual_tick_values is None and self.manual_tick_labels is None: cb = plt.colorbar(mappable=cax, **self.config_dict) elif ( self.manual_tick_values is not None and self.manual_tick_labels is not None ): cb = plt.colorbar( mappable=cax, ticks=self.manual_tick_values, **self.config_dict ) cb.ax.set_yticklabels(self.manual_tick_labels) return cb
[docs]class ColorbarTickParams(AbstractMatWrap): """ Customizes the ticks of the colorbar of the plotted figure. This object wraps the following Matplotlib colorbar method: - cb.set_yticklabels: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.axes.Axes.set_yticklabels.html """ def set(self, cb): cb.ax.tick_params(**self.config_dict)
[docs]class TickParams(AbstractMatWrap): """ The settings used to customize a figure's y and x ticks parameters. This object wraps the following Matplotlib methods: - plt.tick_params: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.tick_params.html """ def set(self): """Set the tick_params of the figure using the method `plt.tick_params`.""" plt.tick_params(**self.config_dict)
class AbstractTicks(AbstractMatWrap): def __init__( self, manual_values: Optional[List[float]] = None, manual_units: Optional[str] = None, **kwargs, ): """ The settings used to customize a figure's y and x ticks using the `YTicks` and `XTicks` objects. This object wraps the following Matplotlib methods: - plt.yticks: https://matplotlib.org/3.3.1/api/_as_gen/matplotlib.pyplot.yticks.html - plt.xticks: https://matplotlib.org/3.3.1/api/_as_gen/matplotlib.pyplot.xticks.html Parameters ---------- manual_values Manually override the tick labels to display the labels as the input list of floats. """ super().__init__(**kwargs) self.manual_values = manual_values self.manual_units = manual_units def tick_values_from(self, min_value: float, max_value: float) -> np.ndarray: """ Calculate the ticks used for the yticks or xticks from input values of the minimum and maximum coordinate values of the y and x axis. Parameters ---------- min_value the minimum value of the ticks that figure is plotted using. max_value the maximum value of the ticks that figure is plotted using. """ if self.manual_values is not None: return self.manual_values return np.linspace(min_value, max_value, 5) def tick_values_in_units_from( self, array: Array2D, min_value: float, max_value: float, units: Units, axis: int, ) -> Optional[np.ndarray]: """ Calculate the labels used for the yticks or xticks from input values of the minimum and maximum coordinate values of the y and x axis. The values are converted to the `Units` of the figure, via its conversion factor or using data properties. Parameters ---------- array The array of data that is to be plotted, whose 2D shape is used to determine the tick values in units of pixels if this is the units specified by `units`. min_value the minimum value of the ticks that figure is plotted using. max_value the maximum value of the ticks that figure is plotted using. units The units the tick values are plotted using. axis Whether to use the y or x axis to estimate the tick labels. """ if self.manual_values is not None: return np.asarray(self.manual_values) elif not units.use_scaled: try: return np.linspace(0, array.shape_native[axis], 5).astype("int") except IndexError: return np.linspace(0, array.shape_native[0], 5).astype("int") except AttributeError: try: return np.linspace(0, np.asarray(array).shape[axis], 5).astype( "int" ) except IndexError: return np.linspace(0, np.asarray(array).shape[0], 5).astype("int") elif (units.use_scaled and units.conversion_factor is None) or not units.in_kpc: return np.round(np.linspace(min_value, max_value, 5), 2) elif units.use_scaled and units.conversion_factor is not None: return np.round( np.linspace( min_value * units.conversion_factor, max_value * units.conversion_factor, 5, ), 2, ) else: raise exc.PlottingException( "The tick labels cannot be computed using the input options." )
[docs]class YTicks(AbstractTicks): def set( self, array: Optional[Array2D], min_value: float, max_value: float, units: Units ): """ Set the y ticks of a figure using the shape of an input `Array2D` object and input units. Parameters ---------- array The 2D array of data which is plotted. min_value the minimum value of the yticks that figure is plotted using. max_value the maximum value of the yticks that figure is plotted using. units The units of the figure. """ ticks = self.tick_values_from(min_value=min_value, max_value=max_value) labels = self.tick_values_in_units_from( array=array, min_value=min_value, max_value=max_value, units=units, axis=0 ) plt.yticks(ticks=ticks, labels=labels, **self.config_dict) if self.manual_units is not None: plt.gca().yaxis.set_major_formatter( FormatStrFormatter(f"{self.manual_units}") ) if not units.use_scaled: plt.gca().invert_yaxis()
[docs]class XTicks(AbstractTicks): def set( self, array: Optional[Array2D], min_value: float, max_value: float, units: Units, use_integers=False, ): """ Set the x ticks of a figure using the shape of an input `Array2D` object and input units. Parameters ---------- array The 2D array of data which is plotted. min_value the minimum value of the xticks that figure is plotted using. max_value the maximum value of the xticks that figure is plotted using. units The units of the figure. """ if use_integers: ticks = np.arange(int(max_value - min_value)) labels = ticks else: ticks = self.tick_values_from(min_value=min_value, max_value=max_value) labels = self.tick_values_in_units_from( array=array, min_value=min_value, max_value=max_value, units=units, axis=1, ) plt.xticks(ticks=ticks, labels=labels, **self.config_dict) if self.manual_units is not None: plt.gca().xaxis.set_major_formatter( FormatStrFormatter(f"{self.manual_units}") )
[docs]class Title(AbstractMatWrap):
[docs] def __init__(self, **kwargs): """ The settings used to customize the figure's title. This object wraps the following Matplotlib methods: - plt.title: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.title.html The title will automatically be set if not specified, using the name of the function used to plot the data. """ super().__init__(**kwargs) self.manual_label = self.kwargs.get("label")
def set(self, auto_title=None): config_dict = self.config_dict label = auto_title if self.manual_label is None else self.manual_label if "label" in config_dict: config_dict.pop("label") plt.title(label=label, **config_dict)
class Text(AbstractMatWrap): """ The settings used to customize text on the figure. This object wraps the following Matplotlib methods: - plt.text: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.text.html """ def set(self): if "x" not in self.kwargs and "y" not in self.kwargs and "s" not in self.kwargs: return plt.text(**self.config_dict) class AbstractLabel(AbstractMatWrap): def __init__(self, **kwargs): """ The settings used to customize the figure's title and y and x labels. This object wraps the following Matplotlib methods: - plt.ylabel: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.ylabel.html - plt.xlabel: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.xlabel.html The y and x labels will automatically be set if not specified, using the input units. Parameters ---------- units The units the data is plotted using. manual_label A manual label which overrides the default computed via the units if input. """ super().__init__(**kwargs) self.manual_label = self.kwargs.get("label") def label_from(self, units: Units) -> Optional[str]: """ Returns the label of an object, by determining it from the figure units if the label is not manually specified. Parameters ---------- units The units of the data structure that is plotted which informs the appropriate label text. """ if units is None: return None if units.in_kpc is not None and units.use_scaled: if units.in_kpc: return "kpc" else: return "arcsec" if units.use_scaled: return "scaled" return "pixels"
[docs]class YLabel(AbstractLabel): def set( self, units: Units, include_brackets: bool = True, auto_label: Optional[str] = None, ): """ Set the y labels of the figure, including the fontsize. The y labels are always the distance scales, thus the labels are either arc-seconds or kpc and depending on the unit_label the figure is plotted in. Parameters ---------- units The units of the image that is plotted which informs the appropriate y label text. include_brackets Whether to include brackets around the y label text of the units. """ config_dict = self.config_dict if "label" in self.config_dict: config_dict.pop("label") if self.manual_label is not None: plt.ylabel(ylabel=self.manual_label, **config_dict) elif auto_label is not None: plt.ylabel(ylabel=auto_label, **config_dict) else: if include_brackets: plt.ylabel(ylabel=f"y ({self.label_from(units=units)})", **config_dict) else: plt.ylabel(ylabel=self.label_from(units=units), **config_dict)
[docs]class XLabel(AbstractLabel): def set( self, units: Units, include_brackets: bool = True, auto_label: Optional[str] = None, ): """ Set the x labels of the figure, including the fontsize. The x labels are always the distance scales, thus the labels are either arc-seconds or kpc and depending on the unit_label the figure is plotted in. Parameters ---------- units The units of the image that is plotted which informs the appropriate x label text. include_brackets Whether to include brackets around the x label text of the units. """ config_dict = self.config_dict if "label" in self.config_dict: config_dict.pop("label") if self.manual_label is not None: plt.xlabel(xlabel=self.manual_label, **config_dict) elif auto_label is not None: plt.xlabel(xlabel=auto_label, **config_dict) else: if include_brackets: plt.xlabel(xlabel=f"x ({self.label_from(units=units)})", **config_dict) else: plt.xlabel(xlabel=self.label_from(units=units), **config_dict)
[docs]class Legend(AbstractMatWrap): """ The settings used to include and customize a legend on a figure. This object wraps the following Matplotlib methods: - plt.legend: https://matplotlib.org/3.3.2/api/_as_gen/matplotlib.pyplot.legend.html """
[docs] def __init__(self, include=True, **kwargs): super().__init__(**kwargs) self.include = include
def set(self): if self.include: config_dict = self.config_dict config_dict.pop("include") if "include" in config_dict else None config_dict.pop("include_2d") if "include_2d" in config_dict else None plt.legend(**config_dict)
[docs]class Output:
[docs] def __init__( self, path: Optional[str] = None, filename: Optional[str] = None, prefix: Optional[str] = None, suffix: Optional[str] = None, format: Union[str, List[str]] = None, format_folder: bool = False, bypass: bool = False, ): """ Sets how the figure or subplot is output, either by displaying it on the screen or writing it to hard-disk. This object wraps the following Matplotlib methods: - plt.show: https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.show.html - plt.savefig: https://matplotlib.org/3.1.1/api/_as_gen/matplotlib.pyplot.savefig.html The default behaviour is the display the figure on the computer screen, as opposed to outputting to hard-disk as a file. Parameters ---------- path If the figure is output to hard-disk the path of the folder it is saved to. filename If the figure is output to hard-disk the filename used to save it. prefix A prefix appended before the file name, e.g. ("prefix_filename"). prefix A prefix appended after the file name, e.g. ("filenam_suffix"). format The format of the output, 'show' displays on the computer screen, 'png' outputs to .png, 'fits' outputs to `.fits` format. format_folder If `True`, all images are output in a folder giving the format name, for example `path/to/output/png/filename.png`. This can make managing large image catalogues easier. bypass Whether to bypass the `plt.show` or `plt.savefig` methods, used when plotting a subplot. """ self.path = path if path is not None and path: os.makedirs(path, exist_ok=True) self.filename = filename self.prefix = prefix self.suffix = suffix self._format = format self.format_folder = format_folder self.bypass = bypass
@property def format(self) -> str: if self._format is None: return "show" return self._format @property def format_list(self): if not isinstance(self.format, list): return [self.format] return self.format def output_path_from(self, format): if format in "show": return None if self.format_folder: output_path = path.join(self.path, format) else: output_path = self.path os.makedirs(output_path, exist_ok=True) return output_path def filename_from(self, auto_filename): filename = auto_filename if self.filename is None else self.filename if self.prefix is not None: filename = f"{self.prefix}{filename}" if self.suffix is not None: filename = f"{filename}{self.suffix}" return filename def to_figure( self, structure: Optional[Structure], auto_filename: Optional[str] = None ): """ Output the figure, by either displaying it on the user's screen or to the hard-disk as a .png or .fits file. Parameters ---------- structure The 2D array of image to be output, required for outputting the image as a fits file. auto_filename If the filename is not manually specified this name is used instead, which is defined in the parent plotter. """ filename = self.filename_from(auto_filename=auto_filename) for format in self.format_list: output_path = self.output_path_from(format=format) if not self.bypass: if format == "show": plt.show() elif format == "png": plt.savefig(path.join(output_path, f"{filename}.png")) elif format == "pdf": plt.savefig(path.join(output_path, f"{filename}.pdf")) elif format == "fits": if structure is not None: structure.output_to_fits( file_path=path.join(output_path, f"{filename}.fits"), overwrite=True, ) def subplot_to_figure(self, auto_filename: Optional[str] = None): """ Output a subplot figure, either as an image on the screen or to the hard-disk as a png or fits file. Parameters ---------- auto_filename If the filename is not manually specified this name is used instead, which is defined in the parent plotter. """ filename = self.filename_from(auto_filename=auto_filename) for format in self.format_list: output_path = self.output_path_from(format=format) if format == "show": plt.show() elif format == "png": plt.savefig(path.join(output_path, f"{filename}.png")) elif format == "pdf": plt.savefig(path.join(output_path, f"{filename}.pdf"))
def remove_spaces_and_commas_from(colors): colors = [color.strip(",") for color in colors] colors = [color.strip(" ") for color in colors] colors = list(filter(None, colors)) if len(colors) == 1: return colors[0] return colors