Source code for tp.plot.heatmap

"""Heatmap plotters.

``add_heatmap`` is a base function, which handles axes limits, colourbar
formatting and extra colourmap options compared to ``matplotlib.pyplot.pcolormesh``.
The other functions plot specific quantites using this function.
"""

#Functions
#---------
#
#    add_heatmap:
#        heatmap.
#    add_pfmap:
#        power factor vs temperature and carrier concentration.
#    add_pfdiff:
#        power factor difference vs temperature and carrier concentration.
#    add_ztmap:
#        ZT vs temperature and carrier concentration.
#    add_ztdiff:
#        ZT difference vs temperature and carrier concentration.
#    add_kappa_target:
#        kappa_l needed to reach a given ZT.
#"""

from copy import copy
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import os
import tp
import warnings
import yaml
from scipy.interpolate import interp2d

warnings.filterwarnings('ignore', module='matplotlib')

try:
    filename = '{}/.config/tprc.yaml'.format(os.path.expanduser("~"))
    with open(filename, 'r') as f:
        conf = yaml.safe_load(f)
except yaml.parser.ParserError:
    warnings.warn('Failed to read ~/.config/tprc.yaml')
    conf = None
except FileNotFoundError:
    conf = None

[docs]def add_heatmap(ax, x, y, c, xinterp=None, yinterp=None, kind='linear', xscale='linear', yscale='linear', cscale='linear', xmin=None, xmax=None, ymin=None, ymax=None, cmin=None, cmax=None, colour='viridis', undercolour=None, overcolour=None, discrete=False, levels=None, contours=None, contourcolours='black', contourkwargs=None, **kwargs): """Adds a heatmap to a set of axes. Formats limits, parses extra colourmap options, makes sure data isn't obscured. Arguments --------- ax : axes axes to plot on. x : array-like x data. y : array-like y data. c : array-like (shape: x, y) colour data. xinterp : int, optional density of interpolation. None turns it off. Default: None. yinterp : int, optional density of interpolation. None turns it off. Default: None. kind : str, optional interpolation kind. Default: linear. xscale : str, optional x scale (linear or log). Default: linear. yscale : str, optional y scale (linear or log). Default: linear cscale : str, optional colour scale (linear or log). Default: linear. xmin : float, optional override x minimum. Default: None. xmax : float, optional override x maximum. Default: None. ymin : float, optional override y minimum. Default: None. ymax : float, optional override y maximum. Default: None. cmin : float, optional override colour scale minimum. Default: None. cmax : float, optional override colour scale maximum. Default: None. colour : colourmap or str or array-like or dict, optional colourmap or colourmap name or highlight colour or highlight, min, max colours in that order, or dictionary with mid and min and/or max keys. Colour format must be hex or rgb (array) or a named colour recognised by matplotlib. Default: Blues. discrete : bool, optional use colour bands rather than a continuously shifting colour sequence. Default: False. levels : int or array-like, optional sets levels for discrete plots. Lists directly specify the contour levels while integers specify the maximum-1 number of "nice" levels to plot. Default: None. undercolour : str or array-like, optional colour for values under cmin. Default: None. overcolour : str or array-like, optional colour for values over cmax. Default: None. contours : int or float or array-like, optional contours to plot. Default: None. contourcolours : string or array-like, optional colours of the contours. If fewer are supplied, they repeat. Default: black. contourkwargs : dict, optional keyword arguments passed to matplotlib.pyplot.contour. Default: None kwargs keyword arguments passed to matplotlib.pyplot.pcolormesh or matplotlib.pyplot.contourf. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: rasterized: True Returns ------- colourbar colourbar. """ # defaults defkwargs = {'rasterized': True} if conf is None or 'heatmap_kwargs' not in conf or \ conf['heatmap_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['heatmap_kwargs'], **kwargs} # data trimming x = np.array(x) y = np.array(y) c = np.array(c) if xmin is None: xmin = np.nanmin(x) if xmax is None: xmax = np.nanmax(x) if ymin is None: ymin = np.nanmin(y) if ymax is None: ymax = np.nanmax(y) xi = np.where((x >= xmin) & (x <= xmax))[0] yi = np.where((y >= ymin) & (y <= ymax))[0] y = y[yi] x = x[xi] try: c = c[np.ix_(xi, yi)] except IndexError: c = c[np.ix_(xi[:-1], yi[:-1])] # colour # Sets colourbar extension. extend = 'neither' if cmin is None: cmin = np.nanmin(c) elif cmin > np.nanmin(c): extend = 'min' if cmax is None: cmax = np.nanmax(c) elif cmax < np.nanmax(c): if extend == 'min': extend = 'both' else: extend = 'max' if cscale == 'linear': cnorm = mpl.colors.Normalize(vmin=cmin, vmax=cmax) elif cscale == 'log': cnorm = mpl.colors.LogNorm(vmin=cmin, vmax=cmax) # Tries to read as a colourmap or colourmap name, or uses a single # #rrggbb colour as the highlight colour for a tp.plot.colour.uniform. try: colours = copy(mpl.cm.get_cmap(colour)) except ValueError: if isinstance(colour, mpl.colors.ListedColormap): colours = colour elif isinstance(colour, str): colours = tp.plot.colour.uniform(colour) elif isinstance(colour, list): colours = tp.plot.colour.uniform(*colour) elif isinstance(colour, dict): colours = tp.plot.colour.uniform(**colour) else: raise Exception('colour must be a colourmap, colourmap ' 'name, single highlight colour or ' 'highlight, min, max colours in that ' 'order, or a dictionary with mid and min ' 'and/or max keys. Colour format must be ' 'hex or rgb (array) or a named colour ' 'recognised by matplotlib.') if undercolour is not None: colours.set_under(undercolour) if overcolour is not None: colours.set_over(overcolour) # data interpolation if xinterp is not None or yinterp is not None: cinterp = interp2d(x, y, np.transpose(c), kind=kind) if xinterp is not None: if xscale == 'linear': x = np.linspace(x[0], x[-1], xinterp) if xscale == 'log': x = np.geomspace(x[0], x[-1], xinterp) if yinterp is not None: if yscale == 'linear': y = np.linspace(y[0], y[-1], yinterp) if yscale == 'log': y = np.geomspace(y[0], y[-1], yinterp) x = np.array(x) y = np.array(y) c = cinterp(x, y) else: c = np.transpose(c) # ensure all data is shown if len(x) == len(c[0]): x = list(x) if xscale == 'linear': x.append(2 * x[-1] - x[-2]) elif xscale =='log': x.append(x[-1] ** 2 / x[-2]) if len(y) == len(c): y = list(y) if yscale == 'linear': y.append(2 * y[-1] - y[-2]) elif yscale =='log': y.append(y[-1] ** 2 / y[-2]) # plotting if discrete: kwargs.pop('rasterized') if levels in [None, (), [None], (None,)]: levels = 10 else: if isinstance(levels, (list, np.ndarray, tuple)) and len(levels) == 1: levels = int(levels[0]) elif isinstance(levels, float): raise TypeError( 'levels must be an int or array-like, not float') heat = ax.contourf(x[:-1], y[:-1], c, cmap=colours, norm=cnorm, levels=levels, **kwargs) else: heat = ax.pcolormesh(x, y, c, cmap=colours, norm=cnorm, **kwargs) fig = ax.get_figure() if 'dos' in fig.__dict__ and fig.__dict__['dos']: # place colourbar outside dos cbar = plt.colorbar(heat, extend=extend) else: cbar = plt.colorbar(heat, ax=ax, extend=extend) # contours if contours not in [None, [None], (), (None,)]: if contourkwargs == None: contourkwargs = {} if not isinstance(contours, (list, np.ndarray)): contours = list(contours) if not isinstance(contourcolours, (list, np.ndarray)): contourcolours = list(contourcolours) if len(contours) > 1: ctnorm = [(ct-np.amin(contours))/ (np.amax(contours)-np.amin(contours)) for ct in contours] else: ctnorm = 0 cmap = None try: cmap = contourcolours contourcolours = mpl.cm.get_cmap(contourcolours)(ctnorm) plt.contour(x[:-1], y[:-1], c, contours, cmap=cmap, **contourkwargs) except ValueError: cmap = None if isinstance(contourcolours, mpl.colors.ListedColormap): cmap = contourcolours contourcolours = contourcolours(ctnorm) plt.contour(x[:-1], y[:-1], c, contours, cmap=cmap, **contourkwargs) elif not isinstance(contourcolours, (list, np.ndarray)): contourcolours = [contourcolours] while len(contourcolours) < len(contours): contourcolours += contourcolours if cmap is None: plt.contour(x[:-1], y[:-1], c, contours, colors=contourcolours, **contourkwargs) for i, c in enumerate(contours): cbar.ax.axhline(c, color=contourcolours[i], **contourkwargs) # axes formatting tp.plot.utilities.set_locators(ax, x=xscale, y=yscale) tp.plot.utilities.set_locators(cbar.ax, y=cscale) ax.set_xlim(x[0], x[-1]) ax.set_ylim(y[0], y[-1]) return cbar
[docs]def add_pfmap(ax, data, direction='avg', xinterp=200, yinterp=200, kind='linear', xmin=None, xmax=None, ymin=None, ymax=None, cmin=None, cmax=None, colour='viridis', discrete=False, levels=None, contours=None, contourcolours='black', contourkwargs=None, **kwargs): """Convenience wrapper for plotting power factor heatmaps. Calculates power factor, plots and formats labels etc. Arguments --------- ax : axes axes to plot on. data : dict dictionary containing temperature and doping, and either power_factor or conductivity and seebeck. direction : str, optional crystal direction, accepts x-z/ a-c or average/ avg. Default: average. xinterp : int, optional density of interpolation. None turns it off. Default: 200. yinterp : int, optional density of interpolation. None turns it off. Default: 200. kind : str, optional interpolation kind. Default: linear. xmin : float, optional override temperature minimum. Default: None. xmax : float, optional override temperature maximum. Default: None. ymin : float, optional override doping minimum. Default: None. ymax : float, optional override doping maximum. Default: None. cmin : float, optional override ZT minimum. Default: None. cmax : float, optional override ZT maximum. Default: None. colour : colourmap or str or array-like, optional colourmap or colourmap name; or key colour or min and max RGB colours to generate a colour map. Colour format must be hex or rgb (array) or a named colour recognised by matplotlib. Default: viridis. discrete : bool, optional use colour bands rather than a continuously shifting colour sequence. Default: False. levels : int or array-like, optional sets levels for discrete plots. Lists directly specify the contour levels while integers specify the maximum-1 number of "nice" levels to plot. Default: None. contours : int or float or array-like, optional PF contours to plot. Default: None. contourcolours : string or array-like, optional colours of the PF contours. If fewer are supplied, they repeat. Default: black. contourkwargs : dict, optional keyword arguments passed to matplotlib.pyplot.contour. Default: None kwargs keyword arguments passed to matplotlib.pyplot.pcolormesh or matplotlib.pyplot.contourf. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: rasterized: True Returns ------- colourbar colourbar. """ # defaults defkwargs = {'rasterized': True} if conf is None or 'pfmap_kwargs' not in conf or \ conf['pfmap_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['pfmap_kwargs'], **kwargs} equants = ['conductivity', 'seebeck'] # data formatting if 'power_factor' in data: data = tp.data.utilities.resolve(data, 'power_factor', direction=direction) else: data = tp.data.utilities.resolve(data, equants, direction=direction) data = tp.calculate.power_factor_fromdict(data, use_tprc=True) # plotting cbar = add_heatmap(ax, data['temperature'], list(np.abs(data['doping'])), data['power_factor'], xinterp=xinterp, yinterp=yinterp, kind=kind, yscale='log', xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, cmin=cmin, cmax=cmax, colour=colour, discrete=discrete, levels=levels, contours=contours, countourcolours=contourcolours, contourkwargs=contourkwargs, **kwargs) # axes formatting labels = tp.settings.labels() ax.set_xlabel(labels['temperature']) ax.set_ylabel(labels['doping']) cbar.set_label(labels['power_factor']) return cbar
[docs]def add_pfdiff(ax, data1, data2, direction='avg', xinterp=200, yinterp=200, kind='linear', xmin=None, xmax=None, ymin=None, ymax=None, cmin=None, cmax=None, colour1='#800080', colour2='#FF8000', midcolour='#FFFFFF', label1=None, label2=None, discrete=False, levels=None, contours=None, contourcolours='black', contourkwargs=None, **kwargs): """Plots a difference of two power factors heatmap. Calculates power factor, plots and formats labels etc. Arguments --------- ax : axes axes to plot on. data(1,2) : dict dictionaries containing temperature and doping, and either power_factor or conductivity and seebeck. The result is data1 - data2. direction : str, optional crystal direction, accepts x-z/ a-c or average/ avg. Default: average. xinterp : int, optional density of interpolation. None turns it off. Default: 200. yinterp : int, optional density of interpolation. None turns it off. Default: 200. kind : str, optional interpolation kind. Default: linear. xmin : float, optional override temperature minimum. Default: None. xmax : float, optional override temperature maximum. Default: None. ymin : float, optional override doping minimum. Default: None. ymax : float, optional override doping maximum. Default: None. cmin : float, optional override ZT minimum. Default: None. cmax : float, optional override ZT maximum. Default: None. colour(1,2) : str, optional colours for data(1,2). Colour format must be hex or rgb (array) or a named colour recognised by matplotlib. Deault: #800080, #FF8000. midcolour : str, optional colour at 0 difference. Default: #FFFFFF. label(1,2) : str, optional labels for data(1,2) to go in a legend. Default: None. discrete : bool, optional use colour bands rather than a continuously shifting colour sequence. Default: False. levels : int or array-like, optional sets levels for discrete plots. Lists directly specify the contour levels while integers specify the maximum-1 number of "nice" levels to plot. Default: None. contours : int or float or array-like, optional PF contours to plot. Default: None. contourcolours : string or array-like, optional colours of the PF contours. If fewer are supplied, they repeat. Default: black. contourkwargs : dict, optional keyword arguments passed to matplotlib.pyplot.contour. Default: None kwargs keyword arguments passed to matplotlib.pyplot.pcolormesh or matplotlib.pyplot.contourf. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: rasterized: True Returns ------- colourbar colourbar. list legend handles. list legend labels. """ # defaults defkwargs = {'rasterized': True} if conf is None or 'pfdiff_kwargs' not in conf or \ conf['pfdiff_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['pfdiff_kwargs'], **kwargs} equants = ['conductivity', 'seebeck'] # data formatting data = [data1, data2] for i in [0, 1]: data[i]['doping'] = np.abs(data[i]['doping']) if 'power_factor' in data[i]: data[i] = tp.data.utilities.resolve(data[i], 'power_factor', direction=direction) else: data[i] = tp.data.utilities.resolve(data[i], equants, direction=direction) data[i] = tp.calculate.power_factor_fromdict(data[i], use_tprc=True) data[0], data[1] = tp.calculate.interpolate(*data, dependent='temperature', keys1='power_factor', keys2='power_factor') data[0], data[1] = tp.calculate.interpolate(*data, dependent='doping', keys1='power_factor', axis1=1, keys2='power_factor', axis2=1) diff = np.subtract(data[0]['power_factor'], data[1]['power_factor']) dmin, dmax = np.nanmin(diff), np.nanmax(diff) mid = dmin / (dmin - dmax) # colours # legend handles and labels h = [mpl.patches.Patch(facecolor=colour1, label=label1), mpl.patches.Patch(facecolor=colour2, label=label2)] l = [label1, label2] # if one is uniformly less than the other, its colour doesn't show if dmin > 0: colour2 = midcolour elif dmax < 0: colour1 = midcolour colour = tp.plot.colour.elbow(cmin=colour2, cmax=colour1, cmid=midcolour, midpoint=mid) # plotting cbar = add_heatmap(ax, data[0]['temperature'], list(data[0]['doping']), diff, xinterp=xinterp, yinterp=yinterp, kind=kind, yscale='log', xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, cmin=cmin, cmax=cmax, colour=colour, discrete=discrete, levels=levels, contours=contours, contourcolours=contourcolours, contourkwargs=contourkwargs, **kwargs) # axes formatting labels = tp.settings.labels() ax.set_xlabel(labels['temperature']) ax.set_ylabel(labels['doping']) cbar.set_label('$\Delta$ '+labels['power_factor']) return cbar, h, l
[docs]def add_ztmap(ax, data, kdata=1., direction='avg', xinterp=200, yinterp=200, kind='linear', xmin=None, xmax=None, ymin=None, ymax=None, cmin=None, cmax=None, colour='viridis', discrete=False, levels=None, contours=None, contourcolours='black', contourkwargs=None, **kwargs): """Convenience wrapper for plotting ZT heatmaps. Calculates ZT, plots and formats labels etc. Arguments --------- ax : axes axes to plot on. data : dict dictionary containing temperature and doping, and either zt or conductivity, seebeck and electronic_thermal_conductivity. kdata : dict or int or float, optional dictionary containing lattice_thermal_conductivity and temperature. Ignored if zt in data. Can specify a constant value instead. Default: 1. direction : str, optional crystal direction, accepts x-z/ a-c or average/ avg. Default: average. xinterp : int, optional density of interpolation. None turns it off. Default: 200. yinterp : int, optional density of interpolation. None turns it off. Default: 200. kind : str, optional interpolation kind. Default: linear. xmin : float, optional override temperature minimum. Default: None. xmax : float, optional override temperature maximum. Default: None. ymin : float, optional override doping minimum. Default: None. ymax : float, optional override doping maximum. Default: None. cmin : float, optional override ZT minimum. Default: None. cmax : float, optional override ZT maximum. Default: None. colour : colourmap or str or array-like, optional colourmap or colourmap name; or key colour or min and max colours to generate a colour map. Colour format must be hex or rgb (array) or a named colour recognised by matplotlib. Default: viridis. discrete : bool, optional use colour bands rather than a continuously shifting colour sequence. Default: False. levels : int or array-like, optional sets levels for discrete plots. Lists directly specify the contour levels while integers specify the maximum-1 number of "nice" levels to plot. Default: None. contours : int or float or array-like, optional ZT contours to plot. Default: None. contourcolours : string or array-like, optional colours of the ZT contours. If fewer are supplied, they repeat. Default: black. contourkwargs : dict, optional keyword arguments passed to matplotlib.pyplot.contour. Default: None kwargs keyword arguments passed to matplotlib.pyplot.pcolormesh or matplotlib.pyplot.contourf. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: rasterized: True Returns ------- colourbar colourbar. """ # defaults defkwargs = {'rasterized': True} if conf is None or 'ztmap_kwargs' not in conf or \ conf['ztmap_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['ztmap_kwargs'], **kwargs} ltc = 'lattice_thermal_conductivity' equants = ['conductivity', 'seebeck', 'electronic_thermal_conductivity'] # data formatting if 'zt' in data: data = tp.data.utilities.resolve(data, 'zt', direction=direction) else: if kdata is None: kdata = 1. if not isinstance(kdata, (int, float)): data, kdata = tp.calculate.interpolate(data, kdata, 'temperature', equants, ltc, kind='cubic') data[ltc] = kdata[ltc] data['meta']['dimensions'][ltc] = kdata['meta']['dimensions'][ltc] data['meta']['units'][ltc] = kdata['meta']['units'][ltc] data['meta']['kappa_source'] = kdata['meta']['kappa_source'] else: data[ltc] = kdata * np.ones(len(data['temperature'])) data['meta']['dimensions'][ltc] = ['temperature'] data['meta']['units'][ltc] = tp.settings.units()[ltc] data['meta']['kappa_source'] = 'Set to {} {}'.format(kdata, data['meta']['units'][ltc]) data = tp.data.utilities.resolve(data, [*equants, ltc], direction=direction) data = tp.calculate.zt_fromdict(data, use_tprc=True) # plotting cbar = add_heatmap(ax, data['temperature'], list(np.abs(data['doping'])), data['zt'], xinterp=xinterp, yinterp=yinterp, kind=kind, yscale='log', xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, cmin=cmin, cmax=cmax, colour=colour, discrete=discrete, levels=levels, contours=contours, contourcolours=contourcolours, contourkwargs=contourkwargs, **kwargs) # axes formatting labels = tp.settings.labels() ax.set_xlabel(labels['temperature']) ax.set_ylabel(labels['doping']) cbar.set_label(labels['zt']) return cbar
[docs]def add_ztdiff(ax, data1, data2, kdata1=1., kdata2=1., direction='avg', xinterp=200, yinterp=200, kind='linear', xmin=None, xmax=None, ymin=None, ymax=None, cmin=None, cmax=None, colour1='#800080', colour2='#FF8000', midcolour='#FFFFFF', label1=None, label2=None, discrete=False, levels=None, contours=None, contourcolours='black', contourkwargs=None, **kwargs): """Plots a difference of two ZTs heatmap. Calculates ZT, plots and formats labels etc. Arguments --------- ax : axes axes to plot on. data(1,2) : dict dictionaries containing temperature and doping, and either zt or conductivity, seebeck and electronic_thermal_conductivity. The result is data1 - data2. kdata(1,2) : dict or int or float, optional dictionaries containing lattice_thermal_conductivity and temperature. Ignored if zt in data. Can specify constant values instead. Default: 1. direction : str, optional crystal direction, accepts x-z/ a-c or average/ avg. Default: average. xinterp : int, optional density of interpolation. None turns it off. Default: 200. yinterp : int, optional density of interpolation. None turns it off. Default: 200. kind : str, optional interpolation kind. Default: linear. xmin : float, optional override temperature minimum. Default: None. xmax : float, optional override temperature maximum. Default: None. ymin : float, optional override doping minimum. Default: None. ymax : float, optional override doping maximum. Default: None. cmin : float, optional override ZT minimum. Default: None. cmax : float, optional override ZT maximum. Default: None. colour(1,2) : str, optional colours for data(1,2). Colour format must be hex or rgb (array) or a named colour recognised by matplotlib. Default: #800080, #FF8000. midcolour : str, optional colour at 0 difference. Default: #FFFFFF. label(1,2) : str, optional labels for data(1,2) to go in a legend. Default: None. discrete : bool, optional use colour bands rather than a continuously shifting colour sequence. Default: False. levels : int or array-like, optional sets levels for discrete plots. Lists directly specify the contour levels while integers specify the maximum-1 number of "nice" levels to plot. Default: None. contours : int or float or array-like, optional ZT contours to plot. Default: None. contourcolours : string or array-like, optional colours of the ZT contours. If fewer are supplied, they repeat. Default: black. contourkwargs : dict, optional keyword arguments passed to matplotlib.pyplot.contour. Default: None kwargs keyword arguments passed to matplotlib.pyplot.pcolormesh or matplotlib.pyplot.contourf. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: rasterized: True Returns ------- colourbar colourbar. list legend handles. list legend labels. """ # defaults defkwargs = {'rasterized': True} if conf is None or 'ztdiff_kwargs' not in conf or \ conf['ztdiff_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['ztdiff_kwargs'], **kwargs} ltc = 'lattice_thermal_conductivity' equants = ['conductivity', 'seebeck', 'electronic_thermal_conductivity'] # data formatting data = [data1, data2] kdata = [kdata1, kdata2] for i in [0, 1]: data[i]['doping'] = np.abs(data[i]['doping']) if 'zt' in data[i]: data[i] = tp.data.utilities.resolve(data[i], 'zt', direction=direction) else: if kdata[i] is None: kdata[i] = 1. if not isinstance(kdata[i], (int, float)): data[i], kdata[i] = tp.calculate.interpolate(data[i], kdata[i], 'temperature', equants, ltc, kind='cubic') data[i][ltc] = kdata[i][ltc] data[i]['meta']['dimensions'][ltc] = kdata[i]['meta']['dimensions'][ltc] data[i]['meta']['units'][ltc] = kdata[i]['meta']['units'][ltc] data[i]['meta']['kappa_source'] = kdata[i]['meta']['kappa_source'] else: data[i][ltc] = kdata[i] * np.ones(len(data[i]['temperature'])) data[i]['meta']['dimensions'][ltc] = ['temperature'] data[i]['meta']['units'][ltc] = tp.settings.units()[ltc] data[i]['meta']['kappa_source'] = 'Set to {} {}'.format(kdata[i], data[i]['meta']['units'][ltc]) data[i] = tp.data.utilities.resolve(data[i], [*equants, ltc], direction=direction) data[i] = tp.calculate.zt_fromdict(data[i], use_tprc=True) data[0], data[1] = tp.calculate.interpolate(*data, dependent='temperature', keys1='zt', keys2='zt') data[0], data[1] = tp.calculate.interpolate(*data, dependent='doping', keys1='zt', axis1=1, keys2='zt', axis2=1) diff = np.subtract(data[0]['zt'], data[1]['zt']) dmin, dmax = np.nanmin(diff), np.nanmax(diff) mid = dmin / (dmin - dmax) # colours # legend handles and labels h = [mpl.patches.Patch(facecolor=colour1, label=label1), mpl.patches.Patch(facecolor=colour2, label=label2)] l = [label1, label2] # if one is uniformly less than the other, its colour doesn't show if dmin > 0: colour2 = midcolour elif dmax < 0: colour1 = midcolour colour = tp.plot.colour.elbow(cmin=colour2, cmax=colour1, cmid=midcolour, midpoint=mid) # plotting cbar = add_heatmap(ax, data[0]['temperature'], list(data[0]['doping']), diff, xinterp=xinterp, yinterp=yinterp, kind=kind, yscale='log', xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, cmin=cmin, cmax=cmax, colour=colour, discrete=discrete, levels=levels, contours=contours, contourcolours=contourcolours, contourkwargs=contourkwargs, **kwargs) # axes formatting labels = tp.settings.labels() ax.set_xlabel(labels['temperature']) ax.set_ylabel(labels['doping']) cbar.set_label('$\Delta$ '+labels['zt']) return cbar, h, l
[docs]def add_kappa_target(ax, data, zt=2, direction='avg', xinterp=200, yinterp=200, kind='linear', xmin=None, xmax=None, ymin=None, ymax=None, cmin=0, cmax=None, colour='viridis', negativecolour='grey', discrete=False, levels=None, contours=None, contourcolours='black', contourkwargs=None, **kwargs): """Plots a heatmap of k_latt required for a target ZT Calculates lattice thermal conductivity, plots and formats labels etc. May be useful to screen materials to calculate kappa_l for. Arguments --------- ax : axes axes to plot on. data : dict dictionary containing temperature and doping, and either zt or conductivity, seebeck and electronic_thermal_conductivity. zt : float, optional target ZT. Default: 2. direction : str, optional crystal direction, accepts x-z/ a-c or average/ avg. Default: average. xinterp : int, optional density of interpolation. None turns it off. Default: 200. yinterp : int, optional density of interpolation. None turns it off. Default: 200. kind : str, optional interpolation kind. Default: linear. xmin : float, optional override temperature minimum. Default: None. xmax : float, optional override temperature maximum. Default: None. ymin : float, optional override doping minimum. Default: None. ymax : float, optional override doping maximum. Default: None. cmin : float, optional override kappa minimum. Default: 0. cmax : float, optional override kappa maximum. Default: None. colour : colourmap or str or array-like, optional colourmap or colourmap name; or key colour or min and max RGB colours to generate a colour map. Colour format must be hex or rgb (array) or a named colour recognised by matplotlib. Default: viridis. negativecolour : str or array-like, optional colour for values under cmin. Default: grey. discrete : bool, optional use colour bands rather than a continuously shifting colour sequence. Default: False. levels : int or array-like, optional sets levels for discrete plots. Lists directly specify the contour levels while integers specify the maximum-1 number of "nice" levels to plot. Default: None. contours : int or float or array-like, optional kappa contours to plot. Default: None. contourcolours : string or array-like, optional colours of the kappa contours. If fewer are supplied, they repeat. Default: black. contourkwargs : dict, optional keyword arguments passed to matplotlib.pyplot.contour. Default: None kwargs keyword arguments passed to matplotlib.pyplot.pcolormesh or matplotlib.pyplot.contourf. Defaults are defined below, which are overridden by those in ``~/.config/tprc.yaml``, both of which are overridden by arguments passed to this function. Defaults: rasterized: True Returns ------- colourbar colourbar. """ # defaults defkwargs = {'rasterized': True} if conf is None or 'kappa_target_kwargs' not in conf or \ conf['kappa_target_kwargs'] is None: kwargs = {**defkwargs, **kwargs} else: kwargs = {**defkwargs, **conf['kappa_target_kwargs'], **kwargs} ltc = 'lattice_thermal_conductivity' equants = ['conductivity', 'seebeck', 'electronic_thermal_conductivity'] # data formatting data['zt'] = zt data = tp.calculate.kl_fromdict(data, use_tprc=True) data = tp.data.utilities.resolve(data, ltc, direction=direction) # plotting cbar = add_heatmap(ax, data['temperature'], list(np.abs(data['doping'])), data[ltc], xinterp=xinterp, yinterp=yinterp, kind=kind, yscale='log', xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, cmin=cmin, cmax=cmax, colour=colour, undercolour=negativecolour, discrete=discrete, levels=levels, contours=contours, contourcolours=contourcolours, contourkwargs=contourkwargs, **kwargs) # axes formatting labels = tp.settings.labels() ax.set_xlabel(labels['temperature']) ax.set_ylabel(labels['doping']) cbar.set_label(labels[ltc]) return cbar