Source code for pyH2A.Utilities.output_utilities

import math
from pathlib import PurePath
from pathlib import Path
import matplotlib.pyplot as plt
import matplotlib.ticker as mticker
import matplotlib.image as mpimg
from matplotlib.offsetbox import OffsetImage, AnnotationBbox
import numpy as np
from pyH2A.Utilities.input_modification import file_import

[docs]def make_bold(string): '''Convert provided string to a string which is formatted to be bold. "%" signs cannot be rendered bold with this approach and are hence returned normal''' if isinstance(string, str): string = string.split(' ') elif isinstance(string, float): string = [str(string)] output = '' for word in string: if '%' in word: output += r'$\bf{' + word[:-1] + '}$' + word[-1] + ' ' else: output += r'$\bf{' + word + '}$' + ' ' return output
[docs]def set_font(font_family, font, font_size): '''Set font for plot. Parameters ---------- font_family : str Font family, either 'serif' or 'sans-serif'. font : str Name of font. font_size : float Font size. ''' from matplotlib import rcParams rcParams['font.family'] = font_family rcParams['font.sans-serif'] = [font] rcParams['font.size'] = font_size
[docs]class Figure_Lean: '''Wrapper class for figures. Parameters ---------- name : str Name of figure, used for saving. directory : str Path to directory where figure is to be saved. provided_figure_and_axis : tuple or None, optional Tuple of matplotlib.fig and matplotlib.ax objects. If ``None`` new `fig` and `ax` objects are generated. show : bool, optional If True, figure is shown. save : bool, optional If True, figure is saved. pdf : bool, optional If True, figure is saved as a PDF file. If False, it is saved as a PNG file. dpi : int, optional Dots per inch resolution of figure. transparent : bool, optional Flag to control if background of figure is transparent or not. nrows : int, optional Number of rows for subplots. ncols : int, optional Number of columns for suplots. fig_width : float, optional Width of figure in inches. fig_height : float, optional Height of figure in inches. left : float, optional Left edge of plot in axis fraction coordinates. right : float, optional Right edge of plot in axis fraction coordinates. top : float, optional Top edge of plot in axis fraction coordinates. bottom : float, optional Bottom edge of plot in axis fraction coordinates. wspace : float, optional Vertical white space between subplots. hspace : float, optional Horizontal white space between subplots. font_family : str, optional Font family, either 'serif' or 'sans-serif'. font : str, optional Name of font. font_size : float, optional Font size. sharex : bool, optional Flag to control if x axis is shared between subplots. input_file_name : str, optional Name of input file. append_file_name ; bool, optional Flag to control if `input_file_name` is appended to file name of figure. Notes ----- Provided figure is shown and/or saved in provided directory with given name by running `Figure_Lean.execute()`. ''' def __init__(self, name, directory, provided_figure_and_axis = None, show = False, save = False, pdf = True, dpi = 300, transparent = False, nrows = 1, ncols = 1, fig_width = 6.4, fig_height = 4.8, left = 0.125, right = 0.9, top = 0.88, bottom = 0.11, wspace = 0.2, hspace = 0.2, font_family = 'sans-serif', font = 'Arial', font_size = 12, sharex = False, input_file_name = None, append_file_name = True): set_font(font_family, font, font_size) if provided_figure_and_axis is None: fig, ax = plt.subplots(nrows = nrows, ncols = ncols, figsize = (fig_width, fig_height), sharex = sharex) else: fig, ax = provided_figure_and_axis fig.subplots_adjust(left = left, right = right, top = top, bottom = bottom, wspace = wspace, hspace = hspace) self.fig = fig self.ax = ax self.directory = directory self.show = show self.save = save self.pdf = pdf self.dpi = dpi self.transparent = transparent if append_file_name and input_file_name is not None: self.name = f'{name}_{input_file_name}' else: self.name = name
[docs] def execute(self): '''Running `self.execute()` executes desired `show` and `save` options. ''' if self.show: plt.show() else: plt.close() if self.save: self.save_figure(self.pdf, self.dpi, self.transparent)
[docs] def save_figure(self, pdf, dpi, transparent): '''Saving figure in target dictionary with specified parameters. ''' if pdf is True: suffix = '.pdf' else: suffix = '.png' path_to_file = PurePath(self.directory, self.name + suffix) self.fig.savefig(path_to_file, transparent = transparent, dpi = dpi) plt.close()
[docs]def millify(n, dollar_sign = True): '''Converts n to a string with shorthand notation for thousand-steps''' millnames = ['','K','M','B','T'] n = float(n) millidx = max(0,min(len(millnames)-1, int(math.floor(0 if n == 0 else math.log10(abs(n))/3)))) if dollar_sign: return '${:.2f}{}'.format(n / 10**(3 * millidx), millnames[millidx]) else: return '{:.2f}{}'.format(n / 10**(3 * millidx), millnames[millidx])
[docs]class MathTextSciFormatter(mticker.Formatter): '''Formatter for scientific notation in MathText. Methods ------- __call__: Call method. fix_minus: Fixing minus. format_data: Format data method. format_data_short: Format data shortened method. format_ticks: Format ticks methods. ''' def __init__(self, fmt="%1.1e"): self.fmt = fmt def __call__(self, x, pos=None): s = self.fmt % x decimal_point = '.' positive_sign = '+' tup = s.split('e') significand = tup[0].rstrip(decimal_point) sign = tup[1][0].replace(positive_sign, '') exponent = tup[1][1:].lstrip('0') if exponent: exponent = '10^{%s%s}' % (sign, exponent) if significand and exponent: s = r'%s{\times}%s' % (significand, exponent) else: s = r'%s%s' % (significand, exponent) return "${}$".format(s)
[docs]def format_scientific(value): '''Converts value to string with scientfic (10**x) notation''' formatter = MathTextSciFormatter() return formatter(value)
[docs]def dynamic_value_formatting(value, cutoff = 6): '''Dynamic formatiing of value to string. Parameters ---------- cutoff : int, optional Cutoff value for string length. Below cutoff value a string is shown without special formatting. Notes ----- If value is an int (or a float that can be represented as an int) and its length as a string is less than the `cutoff value`, it will be printed as such. If its length as a string is more than the cutoff value, it will be either printed using the `millify` function (if the value is larger than 1), or using the `format_scientific` function (if the value is smaller than 1). ''' if isinstance(value, int) or isinstance(value, np.int64): pass elif isinstance(value, float): if value.is_integer(): value = int(value) else: raise ValueError('{0} is non-numeric. type = {1}'.format(value, type(value))) if len(str(value)) < cutoff: return str(value) else: if value > 1: return millify(value, dollar_sign = False) else: return format_scientific(value)
[docs]def bottom_offset(self, bboxes, bboxes2): '''Bottom offset for cost contribution plot labels. ''' pad = plt.rcParams["xtick.major.size"] + plt.rcParams["xtick.major.pad"] bottom = self.axes.bbox.ymin self.offsetText.set(va="top", ha="left") oy = bottom - pad * self.figure.dpi / 72.0 self.offsetText.set_position((1.02, oy))
[docs]def insert_image(path, x, y, zoom, ax): '''Insert image into plot. Parameters ---------- path : str Path to image to be inserted. x : float x axis coordinate of image in axis fraction coordinates. y : float y axis coordinate of image in axis fraction coordinates. ax : matplotlib.ax matplotlib.ax object into which image is inserted. ''' img = mpimg.imread(file_import(path)) imagebox = OffsetImage(img, zoom = zoom) ab = AnnotationBbox(imagebox, (x, y), frameon = False, xycoords = ax.transAxes) ax.add_artist(ab)