Source code for comet.pyhed.plot.plot_bib

"""
Part of comet/pyhed/plot
"""
# COMET - COupled Magnetic resonance Electrical resistivity Tomography
# Copyright (C) 2019  Nico Skibbe

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.

import pygimli as pg
# from comet.pyhed.misc import vec
from comet.pyhed.misc import plt_ioff
from comet.pyhed import log
import inspect
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as mpatches
from pathlib import Path


[docs]def cmap_phase(): from matplotlib import colors white = '#ffffff' black = '#444444' red = '#ff0000' blue = '#0000ff' # anglemap = colors.ListedColormap( # [black, blue, white, red, black], N=721) anglemap = colors.LinearSegmentedColormap.from_list( 'anglemap', [black, blue, white, red, black], N=721) return anglemap
[docs]def quantile(data, perc=0.99, add_rel=0.1, add_abs=0.0): """ Returns the the data point that lies over a given percentage (50 %) of a data set and returns value (+ 10%). Parameters ---------- data: Dataset for which the value is to be searched. perc: float [ 0.5 ] Percentage [0...1] defining he search for a parameter. Searches for the value in the dataset that lies above *perc* of the other data. add_rel: float [ 0.1 ] Relative value added to the result of the search. add_abs: float [ 0.0 ] Absolute value added to the result of the search. For very small values in data, add_rel should be replaced by add_abs (and an appropriate value) or set 0. For add_rel = 0.0 and add_abs = 0.0, the returned value will always be part of the given dataset. Hint for colorbars: usually a median(data, perc=...) with perc = 0.95 for small data sets and perc = 0.99 for large data sets will result in nice colorbar settings as it effectively removes spikes. """ quant = np.quantile(data, perc) quant = quant * (1.0 + add_rel) + add_abs return quant
[docs]def amp(field): """ Amplitude of a complex field. Internally used. """ log.warning('Deprication Warning. Function "amp" should not be used ' 'anymore. I have to remove this.') XX = field[0].real**2 + field[0].imag**2 YY = field[1].real**2 + field[1].imag**2 ZZ = field[2].real**2 + field[2].imag**2 return np.sqrt(XX + YY + ZZ)
[docs]def printv(string, *args): """ print function for maintenance and debugging """ callerframerecord = inspect.stack()[1] # print(callerframerecord) frame = callerframerecord[0] # frame/namespace des callers caller_globals = frame.f_globals # globals des Callers debugging_value = caller_globals['debugging']['debugging'] # print('printv: %s' % (debugging_value)) if debugging_value is True: # print(inspect.stack()[:][1]) # if inspect.stack()[0][1] != inspect.stack()[1][1]: # origin = '\.: ' # else: origin = callerframerecord[1].split('\\')[-1] + ': ' info = inspect.getframeinfo(frame) # mit info.lineno bekommt man die zeilennummer, # in der die funktion ausgeführt wird if not args: print(origin + str(info.lineno) + ' ', string) else: if type(args[0]) != np.float64: try: print(origin + str(info.lineno), string + '\t', args[0].shape) except AttributeError: print(origin + str(info.lineno), string + '\t', str(args[0]) + '\t', str(type(args[0]))) else: print(origin + str(info.lineno), string + '\t', str(args[0]) + '\tnp.float') else: return
[docs]def returnFigureAndAx(ax, *args, **kwargs): """ Returns figure and ax of given ax or creates subplots. Not used inside pyhed. """ if ax is None: return plt.subplots(*args, **kwargs) else: return ax.figure, ax
[docs]def pickleFig(savename, fig): import pickle with open(savename, 'wb') as fileout: pickle.dump(fig, fileout)
[docs]def loadPickledFig(savename): import pickle with open(savename, 'rb') as filein: fig = pickle.load(filein) return fig
[docs]def setAxSize(ax, size): for item in ([ax.title, ax.xaxis.label, ax.yaxis.label] + ax.get_xticklabels() + ax.get_yticklabels()): item.set_fontsize(size)
[docs]def addPatch(ax, cbar_ax=None, offset_left=28.5, offset_top=1, distance=1, color='lightgray', lw=0, z_order=0): from pylab import Rectangle axis = ax.axis() if cbar_ax is not None: x1, y1, width, height = cbar_ax.bbox.bounds # offset_left = width # Rectangle input: # (x, y), width, height, **kwargs rec = Rectangle((axis[0] - offset_left, axis[2] + distance), (axis[1] - axis[0]) + offset_left + distance + 0.5, (axis[3] - axis[2]) - 2 * distance - offset_top, fill=True, color=color, lw=lw) rec = ax.add_patch(rec) rec.set_zorder(z_order) rec.set_clip_on(False) return rec
[docs]def showLoop(pos, phi, ds, referenzpunkte=None, ax=None, color=None, **kwargs): """ Plots a loop as set of dipoles on a given axis. Used by *show* method of loop class. """ if ax is None: fig, ax = plt.subplots(1, 1) for i in range(len(phi)): if color is not None: ax.scatter(pos[i][0], pos[i][1], color=color) else: ax.scatter(pos[i][0], pos[i][1]) ax.arrow(pos[i][0], pos[i][1], np.cos(phi[i]) * ds[i]/2.5, np.sin(phi[i]) * ds[i]/2.5, head_width=ds[i]/25., head_length=ds[i]/25., fc='k', ec='k') if referenzpunkte is not None: ax.scatter(referenzpunkte[i][0], referenzpunkte[i][1], color='red') bbox = np.max(np.abs(pos))*0.1 xlim = kwargs.pop('xlim', None) if xlim is None: minx = np.min(pos[:, 0]) - bbox maxx = np.max(pos[:, 0]) + bbox if np.isclose(minx, maxx): minx -= 1 maxx += 1 xlim = [minx, maxx] ax.set_xlim(xlim) ylim = kwargs.pop('ylim', None) if ylim is None: miny = np.min(pos[:, 1]) - bbox maxy = np.max(pos[:, 1]) + bbox if np.isclose(miny, maxy): miny -= 1 maxy += 1 ylim = [miny, maxy] ax.set_ylim(ylim) ax.grid(True) ax.set_aspect('equal') # plt.show() pg.checkAndFixLocaleDecimal_point() return ax
[docs]def showLoopLayout(*loops, ax=None, **kwargs): """ Shows multiple loops at once on a given axis. """ fig, ax = returnFigureAndAx(ax, 1, 1) if isinstance(loops[0], (list, tuple)): loops = loops[0] color = iter(plt.cm.rainbow(np.linspace(0, 1, len(loops)))) num_loops = len(loops) label = kwargs.pop('label', 'loop {}') if isinstance(label, str): if '{}' not in label: label_master = label + ' {}' else: label_master = label + '' label = [] for i in range(num_loops): label.append(label_master.format(i)) elif isinstance(label, (tuple, list, np.ndarray)): if len(label) != num_loops: raise Exception( 'Error in showLoopLayout: either give one label per loop or a' ' single string containing {} or not (it will be appended' + ' otherwise). Got {} for {} loops.'.format(label, num_loops)) min_x = [] max_x = [] min_y = [] max_y = [] patches = [] for idx, loop in enumerate(loops): c = next(color) ax = loop.show(ax=ax, color=c, **kwargs) cur_x_lim = ax.get_xlim() cur_y_lim = ax.get_ylim() min_x.append(cur_x_lim[0]) max_x.append(cur_x_lim[1]) min_y.append(cur_y_lim[0]) max_y.append(cur_y_lim[1]) patches.append( mpatches.Patch(color=c, label=label[idx])) ax.set_xlim(np.min(min_x), np.max(max_x)) ax.set_ylim(np.min(min_y), np.max(max_y)) plt.legend(handles=patches, bbox_to_anchor=(0., 1.02, 1., .102), loc=3, ncol=int(len(loops)/2), mode="expand", borderaxespad=0.) return ax
[docs]def drawMeshLines(ax, mesh, color='white', linewidth=0.5, marker=None, **kwargs): """ Draw all mesh boundaries in given ax. """ if marker is not None: marker = np.atleast_1d(marker) for bound in mesh.boundaries(): if marker is None or bound.marker() in marker: a = np.row_stack([bound.nodes()[0].pos().array(), bound.nodes()[1].pos().array()]) ax.plot(a[:, 0], a[:, 1], color=color, linewidth=linewidth, **kwargs)
[docs]def getCMapAndLim(toplot, phase=False, misfit=False, perc=0.99, minimum=False, lut=None): """ Chooses colorbar limits and appropriate colobar based on input. lut: If lut is not None it must be an integer giving the number of entries desired in the lookup table, and name must be a standard mpl colormap name. """ toplot = np.array(toplot) if phase: cmap = cmap_phase() clim = [-np.pi, np.pi] elif misfit: cmap = plt.get_cmap('bwr', lut=lut) clim = [-4, 4] else: absmax = np.quantile(toplot, perc) absmin = np.quantile(-toplot, perc) bothabs = np.max([np.abs(absmax), np.abs(absmin)]) if np.any(toplot < 0): cmap = plt.get_cmap('bwr', lut=lut) absmin = -bothabs absmax = bothabs else: cmap = plt.get_cmap('bwr', lut=lut) if not minimum: absmin = 0 clim = [absmin, absmax] log.debug('getCMapAndLim(): min/max data: {}/{}, clim: {}/{}' .format(np.min(toplot), np.max(toplot), *clim)) return cmap, clim
[docs]def drawFid(ax, fid, clim=None, clab=None, draw='data', to_plot='real', cmap=None, cbar=True, gated=True, title=None): """Plot any data (or response, error, misfit) cube nicely. if response is True: response vector from fid taken and used for plotting misfit. """ if to_plot.lower() not in ('abs', 'real', 'imag', 'phase', 'rot'): raise Exception('to_plot is limited to "real", "imag", "abs" or "rot" ' '"phase" got {}'.format(to_plot)) to_plot = to_plot.lower() allowed = ('data', 'response', 'misfit', 'error') if draw.lower() not in allowed: raise Exception('draw is limited to {}, ' ' got {}'.format(allowed, draw)) draw = draw.lower() if gated: data = fid.getComplexData() error = fid.error_gated timevec = fid.gates else: data = fid.data_raw error = fid.error_raw timevec = fid.times if data is None: raise Exception(f'No data to plot in fid: {fid!r}, gated={gated}') if draw in ('response', 'misfit'): response = fid.response if response is None: raise Exception('No response vector found in fid.') gated = True if to_plot in ['real', 'rot']: func = np.real elif to_plot == 'imag': func = np.imag elif to_plot == 'abs': func = np.abs elif to_plot == 'phase': func = np.angle if draw == 'misfit': if np.iscomplexobj(error): error = func(error) if to_plot != 'rot': toplot = (func(data) - func(response)) / error else: toplot = (func(data) - np.abs(response)) / error # MMP: not good for rotated Amplitudes # fixed: to_plot == 'rot' elif draw == 'data': if to_plot == 'phase': toplot = func(data) else: toplot = func(data) * 1e9 # V -> nV elif draw == 'error': if to_plot == 'phase': toplot = func(error) else: toplot = func(error) * 1e9 # V -> nV elif draw == 'response': if to_plot == 'phase': toplot = func(response) else: toplot = func(response) * 1e9 # V -> nV if cmap is None or clim is None: cmap_auto, clim_auto = getCMapAndLim( toplot, phase=to_plot == 'phase', misfit=draw == 'misfit') if cmap is None: cmap = cmap_auto if clim is None: clim = clim_auto if cmap == 'bwr': # middle = white = 0 cmax = np.max(np.abs(clim)) clim = [-cmax, cmax] xt = np.linspace(0, len(timevec) - 1, 6) xtl = [] for ixt in xt: xtl.append('{:d}'.format(int(np.round(timevec[int(ixt)] * 1000.)))) # qt = range(0, len(fid.pulses), 5) # including last value qt = np.linspace(0, len(fid.pulses) - 1, 5, dtype=int) qtl = [str(qi) for qi in np.round(fid.pulses[qt] * 10.) / 10.] # plot mat = toplot.reshape((len(fid.pulses), len(timevec))) im = ax.imshow(mat, interpolation='nearest', aspect='auto', cmap=cmap) im.set_clim(clim) ax.set_xticks(xt) ax.set_xticklabels(xtl) ax.set_yticks(qt) ax.set_yticklabels(qtl) ax.set_xlabel('time (ms)') ax.set_ylabel('pulse moment (As)') if title is not None: ax.set_title(title) if cbar: cb = plt.colorbar(im, ax=ax, orientation='horizontal') if clab is not None: cb.ax.set_title(clab) return im, cb # if draw == 'misfit': # figh, axh = plt.subplots() # axh.hist(toplot.flatten(), bins=33, density=True) # axh.set_xlim((-5, 5)) # figh.savefig('histogram.pdf', bbox_inches='tight') # plt.close(figh) return im
[docs]def showEtraData(survey, to_plot='real', draw='data', savename='auto', rdir='.', praefix='', size=12, patch=True, clim=None, perc=0.995, cmap='auto', pdf=True, png=False): """ Plot function to create and save data and misfit plots of etra data. Parameters ---------- datas: array_like Array containing the measured data in nV. Expect one dimensional array of concatenated datas. First dimension defines the different recievers. If array is real, expect first half to contain the real component and second half to contain the imaginary data. gates: array_like Midpoints of the used time gates for plotting in s. pulses: array_like Used pulse moments for plotting in As. errors: array_like [ None ] Assumed errors of the datas for plotting of misfit. Same shape as data. draw: string [ 'data' ] This function can plot 'data', 'response' or 'misfit'. The last two only if fid are eqipped with proper response vector. See setResponse() of Survey class or setResponse() of Fid class for information about setting response vectors. to_plot: string [ 'real' ] Decides weather real or imaginary part of the data is plotted. Alternatively 'abs' can be used to plot absolute values. savename: string [ 'auto' ] If on auto, the savename is generated out of the other given parameters. If other than 'auto', the given savename is used to save the resulting figures. If on 'auto', see *rdir* and *praefix* for additional information. rdir: string ['.'] If *savename*=='auto', rdir defines the directory the results are saved in. This is ignored if savename is not 'auto'. praefix: string [ '' ] If *savename*=='auto', praefix can be used to distinguish different data sets in the same *rdir*. This is ignored if savename is not 'auto'. size: integer [ 17 ] Fontsize for the exported figure ticks and labels. patch: boolean [ True ] As the coincident measurement and the other seven get different colorbars (see *clim*), a grey patch is optionally used as background for the first data plot. This switch can be used to omit this patch. clim: list or list of lists [ None ] The colorbar limits of the plots can be fixed. Except a list of min and maximum value for misfit and two of those lists for the data plot, whereas the first min and max is used fot the coincident measurement, and the second for the other seven measurements. perc: float [ 0.999 ] Percentage to autodefine the colorbar values. The defaults sets the maximum value to the value that is greater than 99.9 % of the data. """ if isinstance(rdir, str): rdir = Path(rdir) to_plot = to_plot.lower() if to_plot not in ('abs', 'real', 'imag', 'phase'): raise Exception('to_plot is limited to "real", "imag", or "abs", ' '"phase" got {}'.format(to_plot)) draw = draw.lower() if draw not in ('data', 'response', 'misfit'): raise Exception('draw is limited to "data", "response", or "misfit", ' ' got {}'.format(draw)) if draw.lower() == 'misfit' or to_plot.lower() == 'phase': patch = False log.info(f'plot etra {draw}, {to_plot}') with plt_ioff(): fig, ax_all = plt.subplots(2, 4, figsize=(16, 9)) fig.subplots_adjust( left=0.12, bottom=None, right=None, top=None, wspace=0.1, hspace=0.125) # limits first (coincident measurement) if to_plot == 'real': func = np.real elif to_plot == 'imag': func = np.imag elif to_plot == 'abs': func = np.abs elif to_plot == 'phase': func = np.angle # determine style and limits for colorbars if draw == 'data': hlp1 = np.ones(0, dtype=complex) for dat in survey.data: hlp1 = np.append(hlp1, dat.flatten()) hlp1 = func(hlp1 * 1e9) hlp2 = np.ones(0, dtype=complex) for dat in survey.data[1:]: hlp2 = np.append(hlp2, dat.flatten()) hlp2 = func(hlp2 * 1e9) elif draw == 'response': hlp1 = np.ones(0, dtype=complex) for dat in survey.response: hlp1 = np.append(hlp1, dat.flatten()) hlp1 = func(hlp1 * 1e9) hlp2 = np.ones(0, dtype=complex) for dat in survey.response[1:]: hlp2 = np.append(hlp2, dat.flatten()) hlp2 = func(hlp2 * 1e9) elif draw == 'misfit': hlp1 = None hlp2 = None # misfit has fixed colorbar and range, no data needed for eval if to_plot == 'phase': unit = ' (rad)' elif draw == 'misfit': unit = '' else: unit = ' (nV)' cbar_label = f'{draw}, {to_plot}{unit}' cmap_auto, clim1 = getCMapAndLim(hlp1, misfit=draw == 'misfit', phase=to_plot == 'phase', perc=perc) cmap_auto, clim2 = getCMapAndLim(hlp2, misfit=draw == 'misfit', phase=to_plot == 'phase', perc=perc) if cmap == 'auto': cmap = cmap_auto onecbar = False if clim is not None: # force colorbar manually -> one colorbar to rule them all if isinstance(clim[0], (list, tuple, np.ndarray)): clim1 = clim[0] clim2 = clim[1] onecbar = False else: clim1 = clim clim2 = clim onecbar = True patch = False bb0 = ax_all[0, 0].figbox.bounds bb1 = ax_all[1, 0].figbox.bounds if draw == 'misfit' or to_plot == 'phase' or onecbar: cba0 = fig.add_axes([0.05, bb1[1], 0.02, bb0[1] - bb1[1] + bb1[3]]) cba1 = None else: cba0 = fig.add_axes([0.05, bb0[1], 0.02, bb0[3]]) cba1 = fig.add_axes([0.05, bb1[1], 0.02, bb0[3]]) for i, ax in enumerate(ax_all.flatten()): im = drawFid(ax, survey.fids[i], draw=draw, cmap=cmap, clim=clim1 if i == 0 else clim2, to_plot=to_plot, cbar=False) if i == 0: ax.set_title('Tx/Rx (coincident)') im0 = im else: ax.set_title('Rx {}'.format(i)) if draw in ('data', 'response') and i == 1: im1 = im if i not in (0, 4): ax.set_ylabel('') ax.set_yticks([]) if i < 4: ax.set_xlabel('') ax.set_xticks([]) setAxSize(ax, size) cb0 = plt.colorbar(im0, cax=cba0, orientation='vertical') cb0.set_label(cbar_label, rotation=90, size=size) cba0.yaxis.set_ticks_position('left') cba0.yaxis.set_label_position('left') cba0.tick_params(labelsize=size) if cba1 is not None: cb1 = plt.colorbar(im1, cax=cba1, orientation='vertical') cb1.set_label(cbar_label, rotation=90, size=size) cba1.yaxis.set_ticks_position('left') cba1.yaxis.set_label_position('left') cba1.tick_params(labelsize=size) if patch: addPatch(ax_all[0, 0], cbar_ax=cba0) if savename == 'auto': name = rdir.joinpath(f'{praefix}{draw}_{to_plot}') else: name = Path(savename) if png: log.info('saving png: {}'.format(name.as_posix())) fig.savefig( name.with_suffix('.png').as_posix(), bbox_inches='tight', facecolor='none', edgecolor='none') if pdf: log.info('saving pdf: {}'.format(name.with_suffix('.pdf') .as_posix())) fig.savefig( name.with_suffix('.pdf').as_posix(), bbox_inches='tight', facecolor='none', edgecolor='none') plt.close(fig)
[docs]def drawCWeight(ax, mesh, cweight, lmin=0, lmax=0.8, cmin=0.2, cmax=1, min_plot=0.02, color='black', cell_indices=None): """ Draws the given cweights defined for given mesh on given ax. Parameters ---------- ax: plt.ax Ax to plot constraint weights in. mesh: pg.Mesh Mesh object where the constraints are defined in. cweight: np.ndarray Constraint values to be plotted. lmin: float [ 0 ] Minimum linewidth for maximum cweight defined via **cmax**. Note that by default high constraint values are plotted with thinner lines. lmin: float [ 0.8 ] Maximum linewidth for minimum cweight defined via **cmin**. cmin: float [ 0 ] Minimum constraint weight to plot. All values smaller than cmin are plotted with the same linewidth as cmin. cmax: float [ 1 ] Maximum constraint weight to plot. All values greater than cmax are plotted with the same linewidth as cmax. min_plot: float [ 0.02 ] Minimum linewidth to plot to avoid large pdfs. color: string [ 'black' ] Color of lines. cell_indices [ None ] f(cweight) -> linewidth: (cmin, cmax) -> (lmax, lmin) if cmin < cweight < cmax Returns: -------- None """ from matplotlib.collections import LineCollection mesh.createNeighbourInfos() lines = [] linewidths = [] bi = 0 if cell_indices is None: # case 1/2: no node indices means we try plotting in implicit order of # boundaries in mesh boundary_ids = np.arange(len(cweight)) bi = 0 for bound in mesh.boundaries(): if bound.rightCell() is not None: pos0 = np.array(bound.node(0).pos())[:2].tolist() pos1 = np.array(bound.node(1).pos())[:2].tolist() linew = (1 - (cweight[bi] - cmin) / (cmax - cmin)) *\ (lmax - lmin) + lmin linew = np.max([np.min([linew, lmax]), lmin]) if linew >= min_plot: lines.append([pos0, pos1]) linewidths.append(linew) bi += 1 else: # case 2/2: node indices are given, which means we plot each entry of # cweight between the nodes with the ids given in node_indices. assert len(cweight) == len(cell_indices[0]) assert len(cweight) == len(cell_indices[1]) cells = mesh.cells() boundary_ids = [] for ci in range(len(cweight)): cell0 = cells[cell_indices[0][ci]] cell1 = cells[cell_indices[1][ci]] try: boundary_ids.append( np.intersect1d([cell0.boundary(0).id(), cell0.boundary(1).id(), cell0.boundary(2).id()], [cell1.boundary(0).id(), cell1.boundary(1).id(), cell1.boundary(2).id()] )[0]) except IndexError as ie: log.error([[cell0.boundary(0).id(), cell0.boundary(1).id(), cell0.boundary(2).id()], [cell1.boundary(0).id(), cell1.boundary(1).id(), cell1.boundary(2).id()]]) raise ie boundaries = mesh.boundaries() for ci, bi in enumerate(boundary_ids): bound = boundaries[bi] if bound.rightCell() is not None: pos0 = np.array(bound.node(0).pos())[:2].tolist() pos1 = np.array(bound.node(1).pos())[:2].tolist() linew = (1 - (cweight[ci] - cmin) / (cmax - cmin)) *\ (lmax - lmin) + lmin linew = np.max([np.min([linew, lmax]), lmin]) if linew >= min_plot: lines.append([pos0, pos1]) linewidths.append(linew) ax.add_collection( LineCollection(lines, linewidths=linewidths, color=color))
[docs]def markCbar(cbar, pos, text=None, color='white', linewidth=0.5, size=None, text_y_pos=1.35, cbar_horizontal=True, **kwargs): """ Marks a given colorbar of a plot at a specific position and optionally displaysa describing text. Useful to remind on a synthetic background or focus the view on a specific range. Parameters ---------- cbar : matplotlib colorbar Colorbar to mark. pos : float Marker position in values of the colorbar (data values). text : string, optional Text to display. The default is None. color : string, optional Color used for the marker. The string is redirected to matplotlib. The default is 'white'. linewidth : float, optional Thickness of the marker line. The default is 0.5. size : integer, optional Size of the Text. If None the size of the ticklabel of the cbar axis is used. If no label is found the size is set to 9. The default is None. text_y_pos : flat, optional Vertical Offset for the displayed text. (or horizontal offset for vertical colorbars, see next argument). The default is 1.35. cbar_horizontal : boolean, optional Flag for a horizontal colorbar. The default is True. **kwargs : dictionary Redirected to the text function. Filled with default values for 'horizontalalignment' ('center') and 'verticalalignment' ('center'). Returns ------- None. """ # get labelsize from cbar if size is None: if cbar_horizontal: cl = cbar.ax.xaxis.get_ticklabels() else: cl = cbar.ax.yaxis.get_ticklabels() if len(cl) > 0: size = cl[0].get_size() else: size = 9 # default size, no label found # transform data -> [0, 1] inv = cbar.ax.transData # transform [0, 1] -> cbar trans axes (plot object) trans = cbar.ax.transAxes.inverted() kwargs.setdefault('horizontalalignment', 'center') kwargs.setdefault('verticalalignment', 'center') clim = cbar.mappable.get_clim() # horizontal line cbar.ax.plot([pos, pos], [clim[0], clim[1]], '-', color=color, linewidth=linewidth) if text is not None: if cbar_horizontal: x_trans = trans.transform(inv.transform((pos, pos)))[0] y_trans = text_y_pos else: y_trans = trans.transform(inv.transform((pos, pos)))[0] x_trans = text_y_pos cbar.ax.text(x_trans, y_trans, text, transform=cbar.ax.transAxes, size=size, **kwargs)
[docs]def setOuterLabelOnly(ax, xlabel='X (m)', ylabel='Z (m)'): """ Removes all ticks from the given axes and labels exept the outer left and lower axes which are labeled using the the given labels. This is a convenience function for multi ax plots, where the subplots have the same outer dimension. """ if len(ax.shape) != 2: log.waring( 'setOuterLabelOnly: Warning expected 2D ax object. ' 'Add dimension, however this function does not know if given ' 'object was a column or row. Fix this by giving a 2D Axes.') ax = np.atleast_2d(ax) for xi in range(ax.shape[0]): for yi in range(ax.shape[1]): if yi == 0: ax[xi, yi].set_ylabel(ylabel) else: ax[xi, yi].yaxis.set_ticks([]) ax[xi, yi].set_ylabel('') if xi == ax.shape[0] - 1: ax[xi, yi].set_xlabel(xlabel) else: ax[xi, yi].xaxis.set_ticks([]) ax[xi, yi].set_xlabel('')
# The End