Source code for tofu.data._plot

# coding utf-8

# Built-in
import itertools as itt
import warnings

# Common
import numpy as np
import scipy.integrate as scpinteg
import matplotlib.pyplot as plt
from matplotlib import gridspec
import matplotlib as mpl
from mpl_toolkits.axes_grid1 import make_axes_locatable

# tofu
try:
    from tofu.version import __version__
    import tofu.utils as utils
    import tofu.data._def as _def
except Exception:
    from tofu.version import __version__
    from .. import utils as utils
    from . import _def as _def



__all__ = ['Data_plot', 'Data_plot_combine',
           'Data_plot_spectrogram']
#__author_email__ = 'didier.vezinet@cea.fr'
__github = 'https://github.com/ToFuProject/tofu/issues'
_wintit = 'tofu-%s        report issues / requests at %s'%(__version__, __github)
_nchMax, _ntMax, _nfMax, _nlbdMax = 4, 3, 3, 3
_fontsize = 8
_labelpad = 0
_lls = ['-','--','-.',':']
_lct = [plt.cm.tab20.colors[ii] for ii in [0,2,4,1,3,5]]
_lcch = [plt.cm.tab20.colors[ii] for ii in [6,8,10,7,9,11]]
_lclbd = [plt.cm.tab20.colors[ii] for ii in [12,16,18,13,17,19]]
_lcm = _lclbd
_cbck = (0.8,0.8,0.8)
_dmarker = {'ax':'o', 'x':'x'}


[docs]def Data_plot(lData, key=None, bck=True, indref=0, cmap=None, ms=4, vmin=None, vmax=None, vmin_map=None, vmax_map=None, cmap_map=None, normt_map=False, ntMax=None, nchMax=None, nlbdMax=None, inct=[1,10], incX=[1,5], inclbd=[1,10], lls=None, lct=None, lcch=None, lclbd=None, cbck=None, fmt_t='06.3f', fmt_X='01.0f', fmt_l='07.3f', invert=True, Lplot='In', dmarker=None, sharey=True, sharelamb=True, fs=None, dmargin=None, wintit=None, tit=None, fontsize=None, labelpad=None, draw=True, connect=True): # ------------------ # Preliminary checks if not isinstance(lData,list): lData = [lData] c0 = [dd._is2D() == lData[0]._is2D() for dd in lData[1:]] if not all(c0): msg = "All Data objects must be either 1D or 2D, not mixed !\n" msg += " (check on self._is2D())" raise Exception(msg) c0 = [dd._isSpectral() for dd in lData] if any(c0) and not all(c0): msg = "All Data should be either spectral or non-spectral !\n" msg += " (check self._isSpectral())" raise Exception(msg) nD = 2 if lData[0]._is2D() else 1 c0 = nD > 1 and len(lData) > 2 if c0: msg = "Compare not implemented for more than 2 CamLOS2D yet!" raise Exception(msg) c0 = [dd.ddata['indtX'] is None for dd in lData] if not all(c0): msg = "Cases with indtX != None not properly handled yet !" raise Exception(msg) # ------------------ # Input formatting if fontsize is None: fontsize = _fontsize if ntMax is None: ntMax = _ntMax if nD == 2: ntMax = min(ntMax,2) if nchMax is None: nchMax = _nchMax if cmap_map is None: cmap_map = plt.cm.gray_r if cmap is None: cmap = plt.cm.gray_r if wintit is None: wintit = _wintit if labelpad is None: labelpad = _labelpad if lct is None: lct = _lct if lcch is None: lcch = _lcch if lclbd is None: lclbd = _lclbd if lls is None: lls = _lls if cbck is None: cbck = _cbck if dmarker is None: dmarker = _dmarker if lData[0]._isSpectral(): nchMax = min(2,nchMax) assert isinstance(cmap, mpl.colors.Colormap) or cmap == 'touch' if cmap == 'touch': msg = "Option cmap='touch' will be available in future releases :-)" raise Exception(msg) # ------------------ # Plot if lData[0]._isSpectral(): if nD == 2: if len(lData) > 2: msg = "Cannot compare more than 2 DataCam2DSpectral instances !" raise Exception(msg) if len(lData) == 2: ntMax = 1 kh = _DataCam12D_plot_spectral(lData, key=key, nchMax=nchMax, ntMax=ntMax, nlbdMax=nlbdMax, indref=indref, bck=bck, lls=lls, lct=lct, lcch=lcch, lclbd=lclbd, cbck=cbck, fs=fs, dmargin=dmargin, wintit=wintit, tit=tit, Lplot=Lplot, ms=ms, inct=inct, incX=incX, inclbd=inclbd, cmap=cmap, vmin=vmin, vmax=vmax, vmin_map=vmin_map, vmax_map=vmax_map, cmap_map=cmap_map, normt_map=normt_map, fmt_t=fmt_t, fmt_X=fmt_X, fmt_l=fmt_l, dmarker=dmarker, fontsize=fontsize, labelpad=labelpad, invert=invert, draw=draw, connect=connect, nD=nD, sharey=sharey, sharelamb=sharelamb) else: kh = _DataCam12D_plot(lData, nD=nD, key=key, indref=indref, nchMax=nchMax, ntMax=ntMax, inct=inct, incX=incX, bck=bck, lls=lls, lct=lct, lcch=lcch, cbck=cbck, cmap=cmap, ms=ms, vmin=vmin, vmax=vmax, cmap_map=cmap_map, vmin_map=vmin_map, vmax_map=vmax_map, normt_map=normt_map, fmt_t=fmt_t, fmt_X=fmt_X, labelpad=labelpad, Lplot=Lplot, invert=invert, dmarker=dmarker, fs=fs, dmargin=dmargin, wintit=wintit, tit=tit, fontsize=fontsize, draw=draw, connect=connect) return kh
[docs]def Data_plot_combine(lData, key=None, bck=True, indref=0, cmap=None, ms=4, vmin=None, vmax=None, vmin_map=None, vmax_map=None, cmap_map=None, normt_map=False, ntMax=None, nchMax=None, nlbdMax=3, inct=[1,10], incX=[1,5], inclbd=[1,10], lls=None, lct=None, lcch=None, lclbd=None, cbck=None, fmt_t='06.3f', fmt_X='01.0f', sharex=False, invert=True, Lplot='In', dmarker=None, fs=None, dmargin=None, wintit=None, tit=None, fontsize=None, labelpad=None, draw=True, connect=True): # ------------------ # Preliminary checks if not isinstance(lData,list): lData = [lData] c0 = [dd._isSpectral() for dd in lData] if any(c0): msg = "Only provide non-spectral Data !\n" msg += " (check self._isSpectral()" raise Exception(msg) c0 = [dd.ddata['indtX'] is None for dd in lData] if not all(c0): msg = "Cases with indtX != None not properly handled yet !" raise Exception(msg) lis2D = [dd._is2D() for dd in lData] # ------------------ # Input formatting if fontsize is None: fontsize = _fontsize if ntMax is None: ntMax = _ntMax if any(lis2D): ntMax = 1 if nchMax is None: nchMax = _nchMax if cmap_map is None: cmap_map = plt.cm.gray_r if cmap is None: cmap = plt.cm.gray_r if wintit is None: wintit = _wintit if labelpad is None: labelpad = _labelpad if lct is None: lct = _lct if lcch is None: lcch = _lcch if lclbd is None: lctlbd = _lclbd if lls is None: lls = _lls if cbck is None: cbck = _cbck if dmarker is None: dmarker = _dmarker assert isinstance(cmap, mpl.colors.Colormap) or cmap == 'touch' if cmap == 'touch': msg = "Option cmap='touch' will be available in future releases :-)" raise Exception(msg) # ------------------ # Plot kh = _DataCam12D_plot_combine(lData, lis2D=lis2D, key=key, indref=indref, nchMax=nchMax, ntMax=ntMax, inct=inct, incX=incX, bck=bck, lls=lls, lct=lct, lcch=lcch, cbck=cbck, cmap=cmap, ms=ms, vmin=vmin, vmax=vmax, cmap_map=cmap_map, vmin_map=vmin_map, vmax_map=vmax_map, normt_map=normt_map, fmt_t=fmt_t, fmt_X=fmt_X, labelpad=labelpad, Lplot=Lplot, invert=invert, dmarker=dmarker, fs=fs, dmargin=dmargin, wintit=wintit, tit=tit, fontsize=fontsize, draw=draw, connect=connect, sharex=sharex) return kh
####################################################################### ####################################################################### ####################################################################### # Plot data ####################################################################### ####################################################################### def _init_DataCam12D(fs=None, dmargin=None, fontsize=8, wintit=_wintit, nchMax=4, ntMax=4, nD=1, nDat=1): # Figure axCol = "w" fs = utils.get_figuresize(fs, fsdef=_def.fs1D) if dmargin is None: dmargin = _def.dmargin1D fig = plt.figure(facecolor=axCol,figsize=fs) if wintit != False: fig.canvas.set_window_title(wintit) # Axes gs1 = gridspec.GridSpec(6, 5, **dmargin) Laxt = [fig.add_subplot(gs1[:3,:2], fc='w')] Laxt.append(fig.add_subplot(gs1[3:,:2],fc='w', sharex=Laxt[0])) if nD == 1: Laxp = [fig.add_subplot(gs1[:,2:-1], fc='w', sharey=Laxt[1])] else: if nDat == 1 and ntMax == 1: Laxp = [fig.add_subplot(gs1[:,2:4], fc='w')] elif nDat == 1 and ntMax == 2: Laxp = [fig.add_subplot(gs1[:,2], fc='w')] Laxp.append(fig.add_subplot(gs1[:,3], fc='w', sharex=Laxp[0], sharey=Laxp[0])) elif nDat == 2 and ntMax == 1: Laxp = [fig.add_subplot(gs1[:3,2:4], fc='w')] Laxp.append(fig.add_subplot(gs1[3:,2:4], fc='w', sharex=Laxp[0], sharey=Laxp[0])) else: Laxp = [fig.add_subplot(gs1[:3,2], fc='w')] Laxp += [fig.add_subplot(gs1[:3,3], fc='w', sharex=Laxp[0], sharey=Laxp[0]), fig.add_subplot(gs1[3:,2], fc='w', sharex=Laxp[0], sharey=Laxp[0]), fig.add_subplot(gs1[3:,3], fc='w', sharex=Laxp[0], sharey=Laxp[0])] # Do not specify datalim due to both axis shared (depends on # matplotlib version) Laxp[0].set_aspect('equal') axH = fig.add_subplot(gs1[0:2,4], fc='w') axC = fig.add_subplot(gs1[2:,4], fc='w') axC.set_aspect('equal', adjustable='datalim') axH.set_aspect('equal', adjustable='datalim') # Text Ytxt = Laxt[1].get_position().bounds[1]+Laxt[1].get_position().bounds[3] DY = Laxt[0].get_position().bounds[1] - Ytxt Xtxt = Laxt[1].get_position().bounds[0] DX = Laxt[1].get_position().bounds[2] axtxtch = fig.add_axes([Xtxt+0.1*(DX-Xtxt), Ytxt, DX, DY], fc='None') Ytxt = Laxp[0].get_position().bounds[1] + Laxp[0].get_position().bounds[3] Xtxt = Laxp[0].get_position().bounds[0] DX = Laxp[0].get_position().bounds[2] axtxtt = fig.add_axes([Xtxt+0.2*(DX-Xtxt), Ytxt, DX, DY], fc='None') xtxt, Ytxt, dx, DY = 0.01, 0.98, 0.15, 0.02 axtxtg = fig.add_axes([xtxt, Ytxt, dx, DY], fc='None') # dax dax = {'t':Laxt, 'X':Laxp, 'cross':[axC], 'hor':[axH], 'txtg':[axtxtg], 'txtx':[axtxtch], 'txtt':[axtxtt]} # Format all axes for kk in dax.keys(): for ii in range(0,len(dax[kk])): dax[kk][ii].tick_params(labelsize=fontsize) if 'txt' in kk: dax[kk][ii].patch.set_alpha(0.) for ss in ['left','right','bottom','top']: dax[kk][ii].spines[ss].set_visible(False) dax[kk][ii].set_xticks([]), dax[kk][ii].set_yticks([]) dax[kk][ii].set_xlim(0,1), dax[kk][ii].set_ylim(0,1) return dax def _DataCam12D_plot(lData, key=None, nchMax=_nchMax, ntMax=_ntMax, indref=0, bck=True, lls=_lls, lct=_lct, lcch=_lcch, cbck=_cbck, fs=None, dmargin=None, wintit=_wintit, tit=None, Lplot='In', inct=[1,10], incX=[1,5], ms=4, cmap=None, vmin=None, vmax=None, vmin_map=None, vmax_map=None, cmap_map=None, normt_map=False, fmt_t='06.3f', fmt_X='01.0f', dmarker=_dmarker, fontsize=_fontsize, labelpad=_labelpad, invert=True, draw=True, connect=True, nD=1): ######### # Prepare ######### fldict = dict(fontsize=fontsize, labelpad=labelpad) # Use tuple unpacking to make sure indref is 0 if not indref==0: lData[0], lData[indref] = lData[indref], lData[0] nDat = len(lData) c0 = [all([dd.dlabels[kk] == lData[0].dlabels[kk] for dd in lData[1:]]) for kk in ['t','X','data']] if not all(c0): msg = "All Data objects do not have the same:\n" msg += " dlabels['t'], dlabels['X'] and dlabels['data'] !" warnings.warn(msg) # --------- # Get time lt = [dd.t for dd in lData] nt = lData[0].nt if nt == 1: Dt = [lt[0][0]-0.001, lt[0][0]+0.001] else: Dt = np.array([[np.nanmin(t), np.nanmax(t)] for t in lt]) Dt = [np.min(Dt[:,0]), np.max(Dt[:,1])] tlab = r"{0} ({1})".format(lData[0].dlabels['t']['name'], lData[0].dlabels['t']['units']) ttype = 'x' lidt = [id(t) for t in lt] # --------- # Check nch and X c0 = [dd.nch == lData[0].nch for dd in lData[1:]] if not all(c0): msg = ("All Data objects must have the same nb. of channels\n" + "\t- self.nch: {}\n".format([dd.nch for dd in lData]) + "\n => use self.set_indch()") raise Exception(msg) nch = lData[0].nch #X, nch, nnch, indtX = lData[0]['X'], lData[0]['nch'], lData[0]['nnch'], lData[0]['indtX'] if nD == 1: if nch == 1: X = lData[0].X DX = [X[0,0]-0.1*X[0,0], X[0,0]+0.1*X[0,0]] else: DX = np.array([[np.nanmin(dd.X), np.nanmax(dd.X)] for dd in lData]) DX = [np.min(DX[:,0]), np.max(DX[:,1])] Xlab = r"{0} ({1})".format(lData[0].dlabels['X']['name'], lData[0].dlabels['X']['units']) lXtype = ['x' if lData[ii].ddata['nnch'] == 1 else 'x1' for ii in range(0,nDat)] lXother = [None if lData[ii].ddata['nnch'] == 1 else lidt[ii] for ii in range(0,nDat)] lindtX = [(None if lData[ii].ddata['nnch'] == 1 else lData[ii].ddata['indtX']) for ii in range(0,nDat)] else: c0 = [dd.ddata['nnch'] > 1 for dd in lData] if any(c0): msg = "DataCam2D cannot have nnch > 1 !" raise Exception(msg) c0 = [dd.ddata['indtX'] is None for dd in lData] if not all(c0): msg = "All DataCam2D objects must have indtX is None !" raise Exception(msg) c0 = [dd.get_X12plot('imshow') for dd in lData] c0 = [all([np.allclose(cc[ii],c0[0][ii]) for ii in range(0,4)]) for cc in c0[1:]] if not all(c0): msg = "All DataCam2D must have the same (x1,x2,indr,extent) !\n" msg += " Check x1, x2, indr, extent = self.get_X12plot('imshow')" raise Exception(msg) x1, x2, indr, extent = lData[0].get_X12plot('imshow') if bck: indbck = np.r_[indr[0,0], indr[0,-1], indr[-1,0], indr[-1,-1]] nan2 = np.full((2,1),np.nan) idx12 = id((x1,x2)) n12 = [x1.size, x2.size] # Other lXtype = ['x']*nDat lXother = [None]*nDat lindtX = [None]*nDat lX = [dd.X for dd in lData] lidX = [id(X) for X in lX] # dchans if key is None: dchans = np.arange(0,nch) else: dchans = lData[0].dchans(key) idchans = id(dchans) # --------- # Check data ldata = [dd.data for dd in lData] indany = [np.any(~np.isnan(dat)) for dat in ldata] if any(indany): if vmin is None: vmin = np.min([np.nanmin(dat) for ii, dat in enumerate(ldata) if indany[ii]]) if vmax is None: vmax = np.max([np.nanmax(dat) for ii, dat in enumerate(ldata) if indany[ii]]) else: vmin, vmax = 0, 1 Dlim = [min(0., vmin), max(0., vmax)] Dd = [Dlim[0]-0.05*np.diff(Dlim), Dlim[1]+0.05*np.diff(Dlim)] Dlab = r"{0} ({1})".format(lData[0].dlabels['data']['name'], lData[0].dlabels['data']['units']) liddata = [id(dat) for dat in ldata] if nD == 2: norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax) nan2_data = np.full((x2.size,x1.size),np.nan) if cmap == 'touch': lcols = [dd['lCam'][0]._get_touchcols( vmin=vmin, vmax=vmax, cdef=cbck, ind=None)[0] for dd in lData] # To be finished if vmin_map is None: vmin_map = vmin if vmax_map is None: vmax_map = vmax # --------- # Extra lkex = sorted(set(itt.chain.from_iterable([list(lData[ii].dextra.keys()) for ii in range(0,nDat) if lData[ii].dextra is not None]))) dEq_corres = dict.fromkeys(['ax','sep','x']) for k0 in dEq_corres.keys(): lkEq_temp = list(set([kk for kk in lkex if k0 == kk.split('.')[-1].lower()])) assert len(lkEq_temp) <= 1 if len(lkEq_temp) == 1: dEq_corres[k0] = lkEq_temp[0] if k0 in dmarker.keys(): dmarker[lkEq_temp[0]] = str(dmarker[k0]) del dmarker[k0] lkEq = sorted([vv for vv in dEq_corres.values() if vv is not None]) kSep = dEq_corres['sep'] lkEqmap = lkEq + ['map'] dlextra = dict([(k,[None for ii in range(0,nDat)]) for k in lkEqmap]) dteq = dict([(ii,{}) for ii in range(0,nDat)]) for ii in range(0,nDat): if lData[ii].dextra not in [None, False]: for k in set(lkEqmap).intersection(lData[ii].dextra.keys()): idteq = id(lData[ii].dextra[k]['t']) if idteq not in dteq[ii].keys(): # test if any existing t matches values lidalready = [[k1 for k1,v1 in v0.items() if (v1.size == lData[ii].dextra[k]['t'].size and np.allclose(v1, lData[ii].dextra[k]['t']))] for v0 in dteq.values()] lidalready = list(set(itt.chain.from_iterable(lidalready))) assert len(lidalready) in [0,1] if len(lidalready) == 1: idteq = lidalready[0] dteq[ii][idteq] = lData[ii].dextra[k]['t'] idteq = list(dteq[ii].keys())[0] dlextra[k][ii] = dict([(kk,v) for kk,v in lData[ii].dextra[k].items() if not kk == 't']) dlextra[k][ii]['id'] = id(dlextra[k][ii]['data2D']) dlextra[k][ii]['idt'] = idteq if (k in [dEq_corres['x'],dEq_corres['ax']] and 'marker' not in dlextra[k][ii].keys()): dlextra[k][ii]['marker'] = dmarker[k] if len(dteq[ii].keys()) > 1: msg = "Several distinct time bases in self.dextra for:\n" msg += " - lData[%s]: %s:\n"%(ii,lData[ii].Id.SaveName) msg += " - " + "\n - ".join(lkEqmap) warnings.warn(msg) ######### # Plot ######### # Format axes dax = _init_DataCam12D(fs=fs, dmargin=dmargin, wintit=wintit, nchMax=nchMax, ntMax=ntMax, nD=nD, nDat=nDat) fig = dax['t'][0].figure if tit is None: tit = [] if lData[0].Id.Exp not in [None, False]: tit.append(lData[0].Id.Exp) if lData[0].Id.Diag not in [None, False]: tit.append(lData[0].Id.Diag) if lData[0].Id.shot not in [None, False]: tit.append(r"{0:05.0f}".format(lData[0].Id.shot)) tit = ' - '.join(tit) if tit != False: fig.suptitle(tit) # ----------------- # Plot conf and bck c0 = (lData[0]._dgeom['config'] is not None and lData[0]._dgeom['config'] is not False) c1 = (c0 and lData[0]._dgeom['lCam'] is not None and lData[0]._dgeom['lCam'] is not False) if c0: out = lData[0]._dgeom['config'].plot(lax=[dax['cross'][0], dax['hor'][0]], element='P', tit=False, wintit=False, dLeg=None, draw=False) dax['cross'][0], dax['hor'][0] = out if c1 and 'LOS' in lData[0]._dgeom['lCam'][0].Id.Cls: lCross, lHor, llab = [], [], [] for cc in lData[0]._dgeom['lCam']: lCross += cc._get_plotL(Lplot=Lplot, proj='cross', return_pts=True, multi=True) lHor += cc._get_plotL(Lplot=Lplot, proj='hor', return_pts=True, multi=True) if bck and nD == 2: crossbck = [lCross[indbck[0]],nan2,lCross[indbck[1]],nan2, lCross[indbck[2]],nan2,lCross[indbck[3]]] crossbck = np.concatenate(crossbck,axis=1) horbck = [lHor[indbck[0]],nan2,lHor[indbck[1]],nan2, lHor[indbck[2]],nan2,lHor[indbck[3]]] horbck = np.concatenate(horbck,axis=1) dax['cross'][0].plot(crossbck[0,:], crossbck[1,:], c=cbck, ls='-', lw=1.) dax['hor'][0].plot(horbck[0,:], horbck[1,:], c=cbck, ls='-', lw=1.) elif bck: out = cc.plot(lax=[dax['cross'][0], dax['hor'][0]], element='L', Lplot=Lplot, dL={'c':(0.4,0.4,0.4,0.4),'lw':0.5}, wintit=False, tit=False, dLeg=None, draw=False) dax['cross'][0], dax['hor'][0] = out lHor = np.stack(lHor) idlCross = id(lCross) idlHor = id(lHor) elif c1: lCross, lHor = None, None else: lCross, lHor = None, None else: lCross, lHor = None, None # Background (optional) if bck: if nD == 1: if lData[0].ddata['nnch'] == 1: env = [np.nanmin(ldata[0],axis=0), np.nanmax(ldata[0],axis=0)] dax['X'][0].fill_between(lX[0].ravel(), env[0], env[1], facecolor=cbck) tbck = np.tile(np.r_[lt[0], np.nan], nch) dbck = np.vstack((ldata[0], np.full((1,nch),np.nan))).T.ravel() dax['t'][1].plot(tbck, dbck, lw=1., ls='-', c=cbck) else: dax['t'][1].fill_between(lt[0], np.nanmin(ldata[0],axis=1), np.nanmax(ldata[0],axis=1), facecolor=cbck) # Static extra (time traces) for ii in range(0,nDat): if lData[ii].dextra not in [None, False]: lk = [k for k in lData[ii].dextra.keys() if k not in lkEqmap] for kk in lk: dd = lData[ii].dextra[kk] if 't' in dd.keys(): try: co = dd['c'] if 'c' in dd.keys() else 'k' lab = dd['label'] + ' (%s)'%dd['units'] if ii==0 else None dax['t'][0].plot(dd['t'], dd['data'], ls=lls[ii], lw=1., c=co, label=lab) except Exception: pass dax['t'][0].legend(bbox_to_anchor=(0.,1.01,1.,0.1), loc=3, ncol=4, mode='expand', borderaxespad=0., prop={'size':fontsize}) # --------------- # Lims and labels dax['t'][0].set_xlim(Dt) dax['t'][1].set_ylim(Dd) dax['t'][1].set_xlabel(tlab, **fldict) dax['t'][1].set_ylabel(Dlab, **fldict) if nD == 1: dax['X'][0].set_xlim(DX) dax['X'][0].set_xlabel(Xlab, **fldict) else: dax['X'][0].set_xlim(extent[:2]) dax['X'][0].set_ylim(extent[2:]) if invert: dax['X'][0].invert_xaxis() dax['X'][0].invert_yaxis() ################## # Interactivity dict dgroup = {'time': {'nMax':ntMax, 'key':'f1', 'defid':lidt[0], 'defax':dax['t'][1]}, 'channel': {'nMax':nchMax, 'key':'f2', 'defid':lidX[0], 'defax':dax['X'][0]}} # Group info (make dynamic in later versions ?) msg = ' '.join(['%s: %s'%(v['key'],k) for k, v in dgroup.items()]) l0 = dax['txtg'][0].text(0., 0., msg, color='k', fontweight='bold', fontsize=6., ha='left', va='center') # dref dref = {} for ii in range(0,nDat): dref[lidt[ii]] = {'group':'time', 'val':lt[ii], 'inc':inct} dref[lidX[ii]] = {'group':'channel', 'val':lX[ii], 'inc':incX, 'otherid':lXother[ii], 'indother':lindtX[ii]} if nD == 2: dref[lidX[ii]]['2d'] = (x1,x2) for ii in range(0,nDat): if len(list(dteq[ii])) > 0: idteq, teq = list(dteq[ii].items())[0] break else: idteq, teq = lidt[0], lt[0] dref[idteq] = {'group':'time', 'val':teq, 'inc':inct} # ddata ddat = dict([(liddata[ii], {'val':ldata[ii], 'refids':[lidt[ii],lidX[ii]]}) for ii in range(0,nDat)]) ddat[idchans] = {'val':dchans, 'refids':[lidX[0]]} if lCross not in [None, False]: ddat[idlCross] = {'val':lCross, 'refids':[lidX[0]]} ddat[idlHor] = {'val':lHor, 'refids':[lidX[0]]} if nD == 2: ddat[idx12] = {'val':(x1,x2), 'refids':[lidX[0]]} if dlextra['map'][0] not in [None, False]: ddat[dlextra['map'][0]['id']] = {'val':dlextra['map'][0]['data2D'], 'refids':[dlextra['map'][0]['idt']]} for ii in range(0,nDat): for k in set(lkEq).intersection(dlextra.keys()): if dlextra[k][ii] not in [None, False]: ddat[dlextra[k][ii]['id']] = {'val':dlextra[k][ii]['data2D'], 'refids':[dlextra[k][ii]['idt']]} # dax lax_fix = [dax['cross'][0], dax['hor'][0], dax['txtg'][0], dax['txtt'][0], dax['txtx'][0]] dax2 = {dax['t'][1]: {'ref':dict([(idt,'x') for idt in lidt]), 'graph':{lidt[0]:'x'}}, dax['t'][0]: {'ref':{}, 'graph':{}}} for ii in range(0,nDat): ll = list(dteq[ii].keys()) if len(ll) == 0: ll = [lidt[0]] else: dax2[dax['t'][0]]['ref'][ll[0]] = 'x' if ii == 0: dax2[dax['t'][0]]['graph'][ll[0]] = 'x' if nD == 1: dax2.update({dax['X'][0]: {'ref':dict([(idX,'x') for idX in lidX]), 'graph':{lidX[0]:'x'}}}) else: for ii in range(0,nDat): for jj in range(0,ntMax): dax2[dax['X'][ii*ntMax+jj]] = {'ref':{lidX[ii]:'2d'},'invert':invert} dobj = {} ################## # Populating dobj # ------------- # One-shot and one-time 2D map if dlextra['map'][0] not in [None, False]: map_ = dlextra['map'][0]['data2D'] if normt_map: map_ = map_ / np.nanmax(map_,axis=0)[np.newaxis,:,:] vmin_map = np.nanmin(map_) if vmin_map is None else vmin_map vmax_map = np.nanmax(map_) if vmax_map is None else vmax_map norm_map = mpl.colors.Normalize(vmin=vmin_map, vmax=vmax_map) nan2_map = np.full(map_.shape[1:],np.nan) im = dax['cross'][0].imshow(nan2_map, aspect='equal', extent= dlextra['map'][0]['extent'], interpolation='nearest', origin='lower', zorder=0, norm=norm_map, cmap=cmap_map) dobj[im] = {'dupdate':{'data':{'id':dlextra['map'][0]['id'], 'lrid':[dlextra['map'][0]['idt']]}}, 'drefid':{dlextra['map'][0]['idt']:0}} # ------------- # One-shot channels for jj in range(0,nchMax): # Channel text l0 = dax['txtx'][0].text((0.5+jj)/nchMax, 0., r'', color='k', fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':idchans, 'lrid':[lidX[0]], 'bstr':'{0:%s}'%fmt_X}}, 'drefid':{lidX[0]:jj}} # los if c1: l, = dax['cross'][0].plot([np.nan,np.nan], [np.nan,np.nan], c=lcch[jj], ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':idlCross, 'lrid':[lidX[0]]}}, 'drefid':{lidX[0]:jj}} l, = dax['hor'][0].plot([np.nan,np.nan], [np.nan,np.nan], c=lcch[jj], ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':idlHor, 'lrid':[lidX[0]]}}, 'drefid':{lidX[0]:jj}} # ------------- # One-shot time for jj in range(0,ntMax): # Time txt l0 = dax['txtt'][0].text((0.5+jj)/ntMax, 0., r'', color=lct[jj], fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':lidt[0], 'lrid':[lidt[0]], 'bstr':'{0:%s} s'%fmt_t}}, 'drefid':{lidt[0]:jj}} # ------------- # Data-specific for ii in range(0,nDat): # Time for jj in range(0,ntMax): # Time vlines for ll in range(0,len(dax['t'])): l0 = dax['t'][ll].axvline(np.nan, c=lct[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidt[ii], 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} # Time data profiles if nD == 1: l0, = dax['X'][0].plot(lX[ii][0,:], np.full((nch,),np.nan), c=lct[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':liddata[ii], 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} if lXother[ii] not in [None, False]: dobj[l0]['dupdate']['xdata'] = {'id':lidX[ii], 'lrid':[lXother[ii]]} else: im = dax['X'][ii*ntMax+jj].imshow( nan2_data, extent=extent, aspect='equal', interpolation='nearest', origin='lower', zorder=-1, norm=norm, cmap=cmap) dobj[im] = {'dupdate':{'data-reshape':{'id':liddata[ii], 'n12':n12, 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} # Time equilibrium and map if lData[ii].dextra not in [None, False]: for kk in set(lkEq).intersection(lData[ii].dextra.keys()): id_ = dlextra[kk][ii]['id'] idt = dlextra[kk][ii]['idt'] if kk == kSep: l0, = dax['cross'][0].plot([np.nan],[np.nan], c=lct[jj], ls=lls[ii], lw=1.) else: marker = dlextra[kk][ii].get('marker', 'o') l0, = dax['cross'][0].plot([np.nan],[np.nan], mec=lct[jj], mfc='None', ls=lls[ii], ms=ms, marker=marker) dobj[l0] = {'dupdate':{'data':{'id':id_, 'lrid':[idt]}}, 'drefid':{idt:jj}} # Channel for jj in range(0,nchMax): # Channel time trace l0, = dax['t'][1].plot(lt[ii], np.full((lt[ii].size,),np.nan), c=lcch[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':liddata[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} # Channel vlines or pixels if nD == 1: if lXother[ii] is None: l0 = dax['X'][0].axvline(np.nan, c=lcch[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidX[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} else: for ll in range(0,ntMax): l0 = dax['X'][0].axvline(np.nan, c=lcch[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidX[ii], 'lrid':[lidt[ii],lidX[ii]]}}, 'drefid':{lidX[ii]:jj, lidt[ii]:ll}} else: for ll in range(0,ntMax): l0, = dax['X'][ii*ntMax+ll].plot([np.nan],[np.nan], mec=lcch[jj], ls='None', marker='s', mew=2., ms=ms, mfc='None', zorder=10) # Here we put lidX[0] because all have the same (and it # avoids overdefining ddat[idx12] dobj[l0] = {'dupdate':{'data':{'id':idx12, 'lrid':[lidX[0]]}}, 'drefid':{lidX[0]:jj}} ################## # Instanciate KeyHandler can = fig.canvas can.draw() kh = utils.KeyHandler_mpl(can=can, dgroup=dgroup, dref=dref, ddata=ddat, dobj=dobj, dax=dax2, lax_fix=lax_fix, groupinit='time', follow=True) if connect: kh.disconnect_old() kh.connect() if draw: can.draw() return kh ####################################################################### ####################################################################### ####################################################################### # Plot data spectral ####################################################################### ####################################################################### def _init_DataCam12D_spectral(fs=None, dmargin=None, sharey=True, sharelamb=True, fontsize=8, wintit=_wintit, nchMax=4, nch=1, nD=1, ntMax=1, nDat=1): # Figure axCol = "w" fs = utils.get_figuresize(fs, fsdef=_def.fs1D) if dmargin is None: dmargin = dict(left=0.05, bottom=0.06, right=0.99, top=0.92, wspace=0.4, hspace=2.) fig = plt.figure(facecolor=axCol,figsize=fs) if wintit != False: fig.canvas.set_window_title(wintit) # ------------- # Axes grid # ------- gs1 = gridspec.GridSpec(12, 5, **dmargin) # time if nch == 1 or nchMax == 1: axH = fig.add_subplot(gs1[:4,4], fc='w') axC = fig.add_subplot(gs1[4:,4], fc='w') laxt = [fig.add_subplot(gs1[:4,:2], fc='w')] laxt.append(fig.add_subplot(gs1[4:8,:2],fc='w', sharex=laxt[0])) laxt.append(fig.add_subplot(gs1[8:,:2],fc='w', sharex=laxt[0])) else: axH = fig.add_subplot(gs1[:3,4], fc='w') axC = fig.add_subplot(gs1[3:,4], fc='w') laxt = [fig.add_subplot(gs1[:3,:2], fc='w')] laxt.append(fig.add_subplot(gs1[3:6,:2],fc='w', sharex=laxt[0])) shy = laxt[1] if sharey else None laxt.append(fig.add_subplot(gs1[6:9,:2],fc='w', sharex=laxt[0], sharey=shy)) laxt.append(fig.add_subplot(gs1[9:,:2],fc='w', sharex=laxt[0])) # lambda and profiles if nch == 1: laxp = None laxl = [fig.add_subplot(gs1[4:,2:-1], fc='w', sharey=laxt[1])] elif nchMax == 1: laxl = [fig.add_subplot(gs1[4:8,2:-1], fc='w', sharey=laxt[1])] shy = laxt[-1] if nD == 1 else None laxp = [fig.add_subplot(gs1[8:,2:-1], fc='w', sharey=shy)] else: laxl = [fig.add_subplot(gs1[3:6,2:-1], fc='w', sharey=laxt[1])] if nchMax == 2: shl = laxl[0] if sharelamb else None laxl += [fig.add_subplot(gs1[6:9,2:-1], fc='w', sharex=shl, sharey=laxt[2])] shy = laxt[3] if nD == 1 else None if nD == 2 and (ntMax == 2 or nDat == 2): laxp = [fig.add_subplot(gs1[9:,2], fc='w', sharey=shy)] laxp += [fig.add_subplot(gs1[9:,3], fc='w', sharex=laxp[0], sharey=laxp[0])] else: laxp = [fig.add_subplot(gs1[9:,2:-1], fc='w', sharey=shy)] if laxp not in [None, False] and nD == 2: laxp[0].set_aspect('equal', adjustable='datalim') from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable ax_divider = make_axes_locatable(laxp[0]) laxcb = [ax_divider.append_axes("right", size="5%", pad="5%")] else: laxcb = None axC.set_aspect('equal', adjustable='datalim') axH.set_aspect('equal', adjustable='datalim') # ------------- # txt axes # ------- DX0 = laxt[0].get_position().bounds[2] DY0 = 0.75*(laxt[0].get_position().bounds[1] - np.sum(laxt[1].get_position().bounds[1::2])) DX1 = 0.5*(laxl[0].get_position().bounds[0] - np.sum(laxt[1].get_position().bounds[0::2])) DY1 = laxl[0].get_position().bounds[3] # text ch if nch > 1: X = np.sum(laxl[0].get_position().bounds[0::2]) Y = laxl[0].get_position().bounds[1] laxtxtch = [fig.add_axes([X, Y, DX1, DY1], fc='None')] if nchMax == 2: Y = np.sum(laxl[1].get_position().bounds[1]) laxtxtch += [fig.add_axes([X, Y, DX1, DY1], fc='None')] else: laxtxtch = None # text t X = laxl[0].get_position().bounds[0] Y = np.sum(laxl[0].get_position().bounds[1::2]) laxtxtt = [fig.add_axes([X, Y, DX0, DY0], fc='None')] if nchMax == 2: Y = np.sum(laxl[1].get_position().bounds[1::2]) laxtxtt += [fig.add_axes([X, Y, DX0, DY0], fc='None')] if nch > 1: Y = np.sum(laxp[0].get_position().bounds[1::2]) laxtxtt += [fig.add_axes([X, Y, DX0, DY0], fc='None')] # text lambda X = laxt[1].get_position().bounds[0] Y = np.sum(laxt[1].get_position().bounds[1::2]) laxtxtl = [fig.add_axes([X, Y, DX0, DY0], fc='None')] if nchMax == 2: Y = np.sum(laxt[2].get_position().bounds[1::2]) laxtxtl += [fig.add_axes([X, Y, DX0, DY0], fc='None')] Y = np.sum(laxt[-1].get_position().bounds[1::2]) laxtxtl += [fig.add_axes([X, Y, DX0, DY0], fc='None')] # text group X, DX, Y = 0., 0.15, 1.-DY0 axtxtg = fig.add_axes([X, Y, DX, DY0], fc='None') # ------------- # format output # ------- # dax dax = {'t':laxt, 'X':laxp, 'lamb':laxl, 'cross':[axC], 'hor':[axH], 'txtg':[axtxtg], 'txtx':laxtxtch, 'txtl':laxtxtl, 'txtt':laxtxtt} # Format all axes for kk in dax.keys(): if dax[kk] not in [None, False]: for ii in range(0,len(dax[kk])): dax[kk][ii].tick_params(labelsize=fontsize) if 'txt' in kk: dax[kk][ii].patch.set_alpha(0.) for ss in ['left','right','bottom','top']: dax[kk][ii].spines[ss].set_visible(False) dax[kk][ii].set_xticks([]), dax[kk][ii].set_yticks([]) dax[kk][ii].set_xlim(0,1), dax[kk][ii].set_ylim(0,1) return dax def _DataCam12D_plot_spectral(lData, key=None, nchMax=_nchMax, ntMax=_ntMax, nlbdMax=_nlbdMax, indref=0, bck=True, lls=_lls, lct=_lct, lcch=_lcch, lclbd=_lclbd, cbck=_cbck, fs=None, dmargin=None, wintit=_wintit, tit=None, Lplot='In', inct=[1,10], incX=[1,5], inclbd=[1,10], ms=4, cmap=None, vmin=None, vmax=None, vmin_map=None, vmax_map=None, cmap_map=None, normt_map=False, fmt_t='06.3f', fmt_X='01.0f', fmt_l='07.3f', dmarker=_dmarker, fontsize=_fontsize, labelpad=_labelpad, invert=True, draw=True, connect=True, nD=1, sharey=True, sharelamb=True): ######### # Prepare ######### fldict = dict(fontsize=fontsize, labelpad=labelpad) # Use tuple unpacking to make sure indref is 0 if not indref==0: lData[0], lData[indref] = lData[indref], lData[0] nDat = len(lData) c0 = [all([dd.dlabels[kk] == lData[0].dlabels[kk] for dd in lData[1:]]) for kk in ['t','X','data','lamb']] if not all(c0): msg = "All Data objects must have the same:\n" msg += " dlabels[k], for k in ['t','X','lambda','data'] !" raise Exception(msg) # --------- # Get time lt = [dd.t for dd in lData] nt = lData[0].nt if nt == 1: Dt = [lt[0] - 0.001, lt[0] + 0.001] else: Dt = np.array([[np.nanmin(t), np.nanmax(t)] for t in lt]) Dt = [np.min(Dt[:,0]), np.max(Dt[:,1])] tlab = r"{0} ({1})".format(lData[0].dlabels['t']['name'], lData[0].dlabels['t']['units']) ttype = 'x' lidt = [id(t) for t in lt] # --------- # Check nch and X c0 = [dd.nch == lData[0].nch for dd in lData[1:]] if not all(c0): msg = "All Data objects must have the same number of channels (self.nch)" msg += "\nYou can set the indices of the channels with self.set_indch()" raise Exception(msg) nch = lData[0].nch #X, nch, nnch, indtX = lData[0]['X'], lData[0]['nch'], lData[0]['nnch'], lData[0]['indtX'] if nD == 1: if nch == 1: X = lData[0].X DX = [X[0,0]-0.1*X[0,0], X[0,0]+0.1*X[0,0]] else: DX = np.array([[np.nanmin(dd.X), np.nanmax(dd.X)] for dd in lData]) DX = [np.min(DX[:,0]), np.max(DX[:,1])] Xlab = r"{0} ({1})".format(lData[0].dlabels['X']['name'], lData[0].dlabels['X']['units']) lXtype = ['x' if lData[ii].ddata['nnch'] == 1 else 'x1' for ii in range(0,nDat)] lXother = [None if lData[ii].ddata['nnch'] == 1 else lidt[ii] for ii in range(0,nDat)] lindtX = [(None if lData[ii].ddata['nnch'] == 1 else lData[ii].ddata['indtX']) for ii in range(0,nDat)] else: c0 = [dd.ddata['nnch'] > 1 for dd in lData] if any(c0): msg = "DataCam2D cannot have nnch > 1 !" raise Exception(msg) c0 = [dd.ddata['indtX'] is None for dd in lData] if not all(c0): msg = "All DataCam2D objects must have indtX is None !" raise Exception(msg) c0 = [dd.get_X12plot('imshow') for dd in lData] c0 = [all([np.allclose(cc[ii],c0[0][ii]) for ii in range(0,4)]) for cc in c0[1:]] if not all(c0): msg = "All DataCam2D must have the same (x1,x2,indr,extent) !\n" msg += " Check x1, x2, indr, extent = self.get_X12plot('imshow')" raise Exception(msg) x1, x2, indr, extent = lData[0].get_X12plot('imshow') if bck: indbck = np.r_[indr[0,0], indr[0,-1], indr[-1,0], indr[-1,-1]] nan2 = np.full((2,1),np.nan) idx12 = id((x1,x2)) n12 = [x1.size, x2.size] # Other lXtype = ['x']*nDat lXother = [None]*nDat lindtX = [None]*nDat lX = [dd.X for dd in lData] lidX = [id(X) for X in lX] # dchans if key is None: dchans = np.arange(0,nch) else: dchans = lData[0].dchans(key) idchans = id(dchans) # --------- # Check nlamb and lambda c0 = [dd.nlamb == lData[0].nlamb for dd in lData[1:]] if not all(c0): msg = "All Data objects must have the same number of wavelengths" msg += "\nYou can set the indices of lambda with self.set_indlamb()" raise Exception(msg) nlamb = lData[0].nlamb Dlamb = np.array([[np.nanmin(dd.lamb), np.nanmax(dd.lamb)] for dd in lData]) Dlamb = [np.min(Dlamb[:,0]), np.max(Dlamb[:,1])] lamblab = r"{0} ({1})".format(lData[0].dlabels['lamb']['name'], lData[0].dlabels['lamb']['units']) llambtype = ['x' if lData[ii].ddata['nnlamb'] == 1 else 'x1' for ii in range(0,nDat)] llambother = [None if lData[ii].ddata['nnlamb'] == 1 else lidX[ii] for ii in range(0,nDat)] lindXlamb = [(None if lData[ii].ddata['nnlamb'] == 1 else lData[ii].ddata['indXlamb']) for ii in range(0,nDat)] llamb = [dd.lamb for dd in lData] lidlamb = [id(lamb) for lamb in llamb] # --------- # Check data ldata = [dd.data for dd in lData] vmin = np.min([np.nanmin(dat) for dat in ldata]) vmax = np.max([np.nanmax(dat) for dat in ldata]) Dlim = [min(0.,vmin), max(0.,vmax)] Dd = [Dlim[0]-0.05*np.diff(Dlim), Dlim[1]+0.05*np.diff(Dlim)] Dlab = r"{0} ({1})".format(lData[0].dlabels['data']['name'], lData[0].dlabels['data']['units']) liddata = [id(dat) for dat in ldata] if nD == 2: if vmin is None: vmin = np.min([np.nanmin(dd) for dd in ldata]) if vmax is None: vmax = np.max([np.nanmax(dd) for dd in ldata]) norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax) nan2_data = np.full((x2.size,x1.size),np.nan) if cmap == 'touch': lcols = [dd['lCam'][0]._get_touchcols(vmin=vmin, vmax=vmax, cdef=cbck, ind=None)[0] for dd in lData] # To be finished # -------------- # data sum ldataint = [scpinteg.trapz(ldata[ii], x=llamb[ii].ravel(), axis=2) if llambother[ii] is None else np.vstack([scpinteg.trapz(ldata[ii][:,jj,:], x=llamb[ii][jj,:],axis=1) for jj in range(0,nch)]).T for ii in range(0,nDat)] liddataint = [id(dd) for dd in ldataint] Dintlab = (r"%s"%lData[0].dlabels['data']['name'], r"%s"%lData[0].dlabels['data']['units']) Dintlab = r"$\int_{\lambda}$%s ($\int_{\lambda}$%s)"%Dintlab # --------- # Extra lkex = sorted(set(itt.chain.from_iterable([list(lData[ii].dextra.keys()) for ii in range(0,nDat) if lData[ii].dextra is not None]))) dEq_corres = dict.fromkeys(['ax','sep','x']) for k0 in dEq_corres.keys(): lkEq_temp = list(set([kk for kk in lkex if k0 == kk.split('.')[-1].lower()])) assert len(lkEq_temp) <= 1 if len(lkEq_temp) == 1: dEq_corres[k0] = lkEq_temp[0] if k0 in dmarker.keys(): dmarker[lkEq_temp[0]] = str(dmarker[k0]) del dmarker[k0] lkEq = sorted([vv for vv in dEq_corres.values() if vv is not None]) kSep = dEq_corres['sep'] lkEqmap = lkEq + ['map'] dlextra = dict([(k,[None for ii in range(0,nDat)]) for k in lkEqmap]) dteq = dict([(ii,{}) for ii in range(0,nDat)]) for ii in range(0,nDat): if lData[ii].dextra not in [None, False]: for k in set(lkEqmap).intersection(lData[ii].dextra.keys()): idteq = id(lData[ii].dextra[k]['t']) if idteq not in dteq[ii].keys(): # test if any existing t matches values lidalready = [[k1 for k1,v1 in v0.items() if (v1.size == lData[ii].dextra[k]['t'].size and np.allclose(v1, lData[ii].dextra[k]['t']))] for v0 in dteq.values()] lidalready = list(set(itt.chain.from_iterable(lidalready))) assert len(lidalready) in [0,1] if len(lidalready) == 1: idteq = lidalready[0] dteq[ii][idteq] = lData[ii].dextra[k]['t'] idteq = list(dteq[ii].keys())[0] dlextra[k][ii] = dict([(kk,v) for kk,v in lData[ii].dextra[k].items() if not kk == 't']) dlextra[k][ii]['id'] = id(dlextra[k][ii]['data2D']) dlextra[k][ii]['idt'] = idteq if (k in [dEq_corres['ax'],dEq_corres['x']] and 'marker' not in dlextra[k][ii].keys()): dlextra[k][ii]['marker'] = dmarker[k] if len(dteq[ii].keys()) > 1: msg = "Several distinct time bases in self.dextra for:\n" msg += " - lData[%s]: %s:\n"%(ii,lData[ii].Id.SaveName) msg += " - " + "\n - ".join(lkEqmap) warnings.warn(msg) ######### # Plot ######### # Format axes dax = _init_DataCam12D_spectral(fs=fs, dmargin=dmargin, sharey=sharey, sharelamb=sharelamb, fontsize=fontsize, wintit=wintit, nchMax=nchMax, nch=nch, nD=nD, ntMax=ntMax, nDat=nDat) fig = dax['t'][0].figure if tit is None: tit = [] if lData[0].Id.Exp not in [None, False]: tit.append(lData[0].Id.Exp) if lData[0].Id.Diag not in [None, False]: tit.append(lData[0].Id.Diag) if lData[0].Id.shot not in [None, False]: tit.append(r"{0:05.0f}".format(lData[0].Id.shot)) tit = ' - '.join(tit) if tit != False: fig.suptitle(tit) # ----------------- # Plot conf and bck c0 = (lData[0]._dgeom['config'] is not None and lData[0]._dgeom['config'] is not False) c1 = (c0 and lData[0]._dgeom['lCam'] is not None and lData[0]._dgeom['lCam'] is not False) if c0: out = lData[0]._dgeom['config'].plot(lax=[dax['cross'][0], dax['hor'][0]], element='P', dLeg=None, tit=False, draw=False) dax['cross'][0], dax['hor'][0] = out if c1 and 'LOS' in lData[0]._dgeom['lCam'][0].Id.Cls: lCross, lHor, llab = [], [], [] for cc in lData[0]._dgeom['lCam']: lCross += cc._get_plotL(Lplot=Lplot, proj='cross', return_pts=True, multi=True) lHor += cc._get_plotL(Lplot=Lplot, proj='hor', return_pts=True, multi=True) if bck and nD == 2: crossbck = [lCross[indbck[0]],nan2,lCross[indbck[1]],nan2, lCross[indbck[2]],nan2,lCross[indbck[3]]] crossbck = np.concatenate(crossbck,axis=1) horbck = [lHor[indbck[0]],nan2,lHor[indbck[1]],nan2, lHor[indbck[2]],nan2,lHor[indbck[3]]] horbck = np.concatenate(horbck,axis=1) dax['cross'][0].plot(crossbck[0,:], crossbck[1,:], c=cbck, ls='-', lw=1.) dax['hor'][0].plot(horbck[0,:], horbck[1,:], c=cbck, ls='-', lw=1.) elif bck: out = cc.plot(lax=[dax['cross'][0], dax['hor'][0]], element='L', Lplot=Lplot, dL={'c':(0.4,0.4,0.4,0.4),'lw':0.5}, dLeg=None, tit=False, draw=False) dax['cross'][0], dax['hor'][0] = out lHor = np.stack(lHor) idlCross = id(lCross) idlHor = id(lHor) elif c1: lCross, lHor = None, None else: lCross, lHor = None, None else: lCross, lHor = None, None # Background (optional) if bck: if nD == 1: if lData[0].ddata['nnch'] == 1 and dax['X'] not in [None, False]: env = [np.nanmin(ldataint[0],axis=0), np.nanmax(ldataint[0],axis=0)] dax['X'][0].fill_between(lX[0].ravel(), env[0], env[1], facecolor=cbck) tbck = np.tile(np.r_[lt[0], np.nan], nch) dbck = np.vstack((ldataint[0], np.full((1,nch),np.nan))).T.ravel() dax['t'][-1].plot(tbck, dbck, lw=1., ls='-', c=cbck) else: dax['t'][-1].fill_between(lt[0], np.nanmin(ldataint[0],axis=1), np.nanmax(ldataint[0],axis=1), facecolor=cbck) # Static extra (time traces) for ii in range(0,nDat): if lData[ii].dextra not in [None, False]: lk = [k for k in lData[ii].dextra.keys() if k not in lkEqmap] for kk in lk: dd = lData[ii].dextra[kk] if 't' in dd.keys(): co = dd['c'] if 'c' in dd.keys() else 'k' lab = dd['label'] + ' (%s)'%dd['units'] if ii==0 else None dax['t'][0].plot(dd['t'], dd['data'], ls=lls[ii], lw=1., c=co, label=lab) dax['t'][0].legend(bbox_to_anchor=(0.,1.01,1.,0.1), loc=3, ncol=4, mode='expand', borderaxespad=0., prop={'size':fontsize}) # --------------- # Lims and labels dax['t'][0].set_xlim(Dt) dax['t'][1].set_ylim(Dd) dax['t'][1].set_ylabel(Dlab, **fldict) dax['t'][-1].set_ylabel(Dintlab, **fldict) dax['t'][-1].set_xlabel(tlab, **fldict) dax['lamb'][0].set_xlim(Dlamb) dax['lamb'][-1].set_xlabel(lamblab, **fldict) if nchMax == 2: dax['t'][2].set_ylabel(Dlab, **fldict) if not sharey: dax['t'][2].set_ylim(Dd) if nD == 1: dax['X'][0].set_xlim(DX) dax['X'][0].set_xlabel(Xlab, **fldict) else: dax['X'][0].set_xlim(extent[:2]) dax['X'][0].set_ylim(extent[2:]) if invert: dax['X'][0].invert_xaxis() dax['X'][0].invert_yaxis() ################## # Interactivity dict dgroup = {'time': {'nMax':ntMax, 'key':'f1', 'defid':lidt[0], 'defax':dax['t'][1]}} if dax['X'] not in [None, False]: dgroup['channel'] = {'nMax':nchMax, 'key':'f2', 'defid':lidX[0], 'defax':dax['X'][0]} dgroup['lambda'] = {'nMax':nlbdMax, 'key':'f%s'%str(len(dgroup.keys())+1), 'defid':lidlamb[0], 'defax':dax['lamb'][0]} # Group info (make dynamic in later versions ?) msg = ' '.join(['%s: %s'%(v['key'],k) for k, v in dgroup.items()]) l0 = dax['txtg'][0].text(0.05, 0.9, msg, color='k', fontweight='bold', fontsize=6., ha='left', va='top') # dref dref = {} for ii in range(0,nDat): dref[lidt[ii]] = {'group':'time', 'val':lt[ii], 'inc':inct} dref[lidX[ii]] = {'group':'channel', 'val':lX[ii], 'inc':incX, 'otherid':lXother[ii], 'indother':lindtX[ii]} dref[lidlamb[ii]] = {'group':'lambda', 'val':llamb[ii], 'inc':inclbd, 'otherid':llambother[ii], 'indother':lindXlamb[ii]} if nD == 2: dref[lidX[ii]]['2d'] = (x1,x2) for ii in range(0,nDat): if len(list(dteq[ii])) > 0: idteq, teq = list(dteq[ii].items())[0] break else: idteq, teq = lidt[0], lt[0] dref[idteq] = {'group':'time', 'val':teq, 'inc':inct} # ddata ddat = dict([(liddata[ii], {'val':ldata[ii], 'refids':[lidt[ii],lidX[ii],lidlamb[ii]]}) for ii in range(0,nDat)]) ddat.update(dict([(liddataint[ii], {'val':ldataint[ii], 'refids':[lidt[ii],lidX[ii]]}) for ii in range(0,nDat)])) ddat[idchans] = {'val':dchans, 'refids':[lidX[0]]} if lCross not in [None, False]: ddat[idlCross] = {'val':lCross, 'refids':[lidX[0]]} ddat[idlHor] = {'val':lHor, 'refids':[lidX[0]]} if nD == 2: ddat[idx12] = {'val':(x1,x2), 'refids':[lidX[0]]} if dlextra['map'][0] not in [None, False]: ddat[dlextra['map'][0]['id']] = {'val':dlextra['map'][0]['data2D'], 'refids':[dlextra['map'][0]['idt']]} for ii in range(0,nDat): for k in set(lkEq).intersection(dlextra.keys()): if dlextra[k][ii] not in [None, False]: ddat[dlextra[k][ii]['id']] = {'val':dlextra[k][ii]['data2D'], 'refids':[dlextra[k][ii]['idt']]} # dax lax_fix = (dax['cross'] + dax['hor'] + dax['txtg'] + dax['txtt'] + dax['txtx'] + dax['txtl']) dax2 = {dax['t'][0]: {'ref':{}, 'graph':{}}} dax2.update(dict([(dax['t'][ii], {'ref':dict([(idt,'x') for idt in lidt]), 'graph':{lidt[0]:'x'}}) for ii in range(1,len(dax['t']))])) for ii in range(0,nDat): ll = list(dteq[ii].keys()) if len(ll) == 0: ll = [lidt[0]] else: dax2[dax['t'][0]]['ref'][ll[0]] = 'x' if ii == 0: dax2[dax['t'][0]]['graph'][ll[0]] = 'x' dax2.update(dict([(dax['lamb'][ii], {'ref':dict([(idl,'x') for idl in lidlamb]), 'graph':{lidlamb[0]:'x'}}) for ii in range(0,len(dax['lamb']))])) if nD == 1 and dax['X'] not in [None, False]: dax2.update({dax['X'][0]: {'ref':dict([(idX,'x') for idX in lidX]), 'graph':{lidX[0]:'x'}}}) elif nD == 2: for ii in range(0,nDat): for jj in range(0,ntMax): dax2[dax['X'][ii*ntMax+jj]] = {'ref':{lidX[ii]:'2d'},'invert':invert} dobj = {} ################## # Populating dobj # ------------- # One-shot and one-time 2D map if dlextra['map'][0] not in [None, False]: map_ = dlextra['map'][0]['data2D'] if normt_map: map_ = map_ / np.nanmax(map_,axis=0)[np.newaxis,:,:] vmin_map = np.nanmin(map_) if vmin_map is None else vmin_map vmax_map = np.nanmax(map_) if vmax_map is None else vmax_map norm_map = mpl.colors.Normalize(vmin=vmin_map, vmax=vmax_map) nan2_map = np.full(map_.shape[1:],np.nan) im = dax['cross'][0].imshow(nan2_map, aspect='equal', extent= dlextra['map'][0]['extent'], interpolation='nearest', origin='lower', zorder=0, norm=norm_map, cmap=cmap_map) dobj[im] = {'dupdate':{'data':{'id':dlextra['map'][0]['id'], 'lrid':[dlextra['map'][0]['idt']]}}, 'drefid':{dlextra['map'][0]['idt']:0}} # ------------- # One-shot channels for jj in range(0,nchMax): # Channel text l0 = dax['txtx'][jj].text(0.05, 0.5, r'', rotation=90, color=lcch[jj], fontweight='bold', fontsize=6., ha='left', va='center') dobj[l0] = {'dupdate':{'txt':{'id':idchans, 'lrid':[lidX[0]], 'bstr':'channel {0:%s}'%fmt_X}}, 'drefid':{lidX[0]:jj}} # los if c1: l, = dax['cross'][0].plot([np.nan,np.nan], [np.nan,np.nan], c=lcch[jj], ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':idlCross, 'lrid':[lidX[0]]}}, 'drefid':{lidX[0]:jj}} l, = dax['hor'][0].plot([np.nan,np.nan], [np.nan,np.nan], c=lcch[jj], ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':idlHor, 'lrid':[lidX[0]]}}, 'drefid':{lidX[0]:jj}} # ------------- # One-shot time for jj in range(0,ntMax): # Time txt for ll in range(0,len(dax['txtt'])): l0 = dax['txtt'][ll].text((0.5+jj)/ntMax, 0., r'', color=lct[jj], fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':lidt[0], 'lrid':[lidt[0]], 'bstr':'{0:%s} s'%fmt_t}}, 'drefid':{lidt[0]:jj}} # ------------- # One-shot lambda for jj in range(0,nlbdMax): # lambda txt for ll in range(0,nchMax): for ii in range(0,nDat): l0 = dax['txtl'][ll].text((0.5+jj)/nlbdMax, 0., r'', color=lclbd[jj], fontweight='bold', fontsize=6., ha='center', va='bottom') if llambother[ii] is None: dobj[l0] = {'dupdate':{'txt':{'id':lidlamb[0], 'lrid':[lidlamb[0]], 'bstr':'{0:%s}'%fmt_l}}, 'drefid':{lidlamb[0]:jj}} else: dobj[l0] = {'dupdate':{'txt':{'id':lidlamb[0], 'lrid':[llambother[ii], lidlamb[0]], 'bstr':'{0:%s}'%fmt_l}}, 'drefid':{llambother[ii]:ll, lidlamb[0]:jj}} # ------------- # Data-specific nanch = np.full((nch,),np.nan) for ii in range(0,nDat): nant = np.full((lt[ii].size,),np.nan) nanlamb = np.full((nlamb,), np.nan) # Time for jj in range(0,ntMax): # Time vlines for ll in range(0,len(dax['t'])): l0 = dax['t'][ll].axvline(np.nan, c=lct[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidt[ii], 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} # Time data profiles if nch > 1 if nch > 1: if nD == 1: l0, = dax['X'][0].plot(lX[ii][0,:], nanch, c=lct[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':liddataint[ii], 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} if lXother[ii] not in [None, False]: dobj[l0]['dupdate']['xdata'] = {'id':lidX[ii], 'lrid':[lXother[ii]]} else: im = dax['X'][ii+jj].imshow(nan2_data, extent=extent, aspect='equal', interpolation='nearest', origin='lower', zorder=-1, norm=norm, cmap=cmap) dobj[im] = {'dupdate':{'data-reshape':{'id':liddataint[ii], 'n12':n12, 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} # Time equilibrium and map if lData[ii].dextra not in [None, False]: for kk in set(lkEq).intersection(lData[ii].dextra.keys()): id_ = dlextra[kk][ii]['id'] idt = dlextra[kk][ii]['idt'] if kk == kSep: l0, = dax['cross'][0].plot([np.nan],[np.nan], c=lct[jj], ls=lls[ii], lw=1.) else: marker = dlextra[kk][ii].get('marker', 'o') l0, = dax['cross'][0].plot([np.nan],[np.nan], mec=lct[jj], mfc='None', ls=lls[ii], ms=ms, marker=marker) dobj[l0] = {'dupdate':{'data':{'id':id_, 'lrid':[idt]}}, 'drefid':{idt:jj}} # Channel for jj in range(0,nchMax): # Channel time trace l0, = dax['t'][-1].plot(lt[ii], nant, c=lcch[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':liddataint[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} # Channel vlines or pixels if nD == 1: if lXother[ii] is None: l0 = dax['X'][0].axvline(np.nan, c=lcch[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidX[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} else: for ll in range(0,ntMax): l0 = dax['X'][0].axvline(np.nan, c=lcch[jj], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidX[ii], 'lrid':[lidt[ii],lidX[ii]]}}, 'drefid':{lidX[ii]:jj, lidt[ii]:ll}} else: for ll in range(0,ntMax): l0, = dax['X'][ii*ntMax+ll].plot([np.nan],[np.nan], mec=lcch[jj], ls='None', marker='s', mew=2., ms=ms, mfc='None', zorder=10) # Here we put lidX[0] because all have the same (and it # avoids overdefining ddat[idx12] dobj[l0] = {'dupdate':{'data':{'id':idx12, 'lrid':[lidX[0]]}}, 'drefid':{lidX[0]:jj}} # ------- # lambda # lambda time trace for ll in range(0,nlbdMax): l0, = dax['t'][1+jj].plot(lt[ii], nant, c=lclbd[ll], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':liddata[ii], 'lrid':[lidX[ii],lidlamb[ii]]}}, 'drefid':{lidX[ii]:jj, lidlamb[ii]:ll}} # lambda profile for ll in range(0,ntMax): l0, = dax['lamb'][jj].plot(llamb[ii][0,:], nanlamb, c=lct[ll], ls=lls[ii], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':liddata[ii], 'lrid':[lidt[ii],lidX[ii]]}}, 'drefid':{lidt[ii]:ll, lidX[ii]:jj}} # lambda vlines for ll in range(0,nlbdMax): l0 = dax['lamb'][jj].axvline(np.nan, c=lclbd[ll], ls=lls[ii], lw=1.) if llambother[ii] is None: dobj[l0] = {'dupdate':{'xdata':{'id':lidlamb[ii], 'lrid':[lidlamb[ii]]}}, 'drefid':{lidlamb[ii]:ll}} else: dobj[l0] = {'dupdate':{'xdata':{'id':lidlamb[ii], 'lrid':[lidX[ii],lidlamb[ii]]}}, 'drefid':{lidX[ii]:jj, lidlamb[ii]:ll}} ################## # Instanciate KeyHandler can = fig.canvas can.draw() kh = utils.KeyHandler_mpl(can=can, dgroup=dgroup, dref=dref, ddata=ddat, dobj=dobj, dax=dax2, lax_fix=lax_fix, groupinit='time', follow=True) if connect: kh.disconnect_old() kh.connect() if draw: can.draw() return kh ####################################################################### ####################################################################### ####################################################################### # Plot combine ####################################################################### ####################################################################### def _init_DataCam12D_combine(fs=None, dmargin=None, fontsize=8, wintit=_wintit, fldict=None, nchMax=4, ntMax=1, nDat=1, lis2D=None, sharex=False): assert nDat<=5, "Cannot display more than 5 Data objects !" assert nDat == len(lis2D) axCol = "w" fs = utils.get_figuresize(fs, fsdef=_def.fs2D) if dmargin is None: dmargin = _def.dmargin_combine fig = plt.figure(facecolor=axCol,figsize=fs) if wintit != False: fig.canvas.set_window_title(wintit) # Axes gs1 = gridspec.GridSpec(nDat+1, 5, **dmargin) laxp, laxc, laxC, laxtxtch = [], [], [], [] Laxt = [fig.add_subplot(gs1[0,:2], fc='w')] axH = fig.add_subplot(gs1[0,4], fc='w') axH.set_aspect('equal', adjustable='datalim') axH.set_xlabel(r'X ($m$)', **fldict) axH.set_ylabel(r'Y ($m$)', **fldict) for ii in range(1,nDat+1): Laxt.append(fig.add_subplot(gs1[ii,:2],fc='w', sharex=Laxt[0])) if lis2D[ii-1]: axp = fig.add_subplot(gs1[ii,2:-1],fc='w') axp.set_aspect('equal', adjustable='datalim') cb = make_axes_locatable(axp) cb = cb.append_axes('right', size='10%', pad=0.1) cb.yaxis.tick_right() cb.set_xticks([]) cb.set_xticklabels([]) else: if sharex and ii>1: axp = fig.add_subplot(gs1[ii,2:-1],fc='w', sharex=laxp[-1], sharey=Laxt[-1]) else: axp = fig.add_subplot(gs1[ii,2:-1],fc='w', sharey=Laxt[-1]) cb = None laxp.append(axp) laxc.append(cb) axC = fig.add_subplot(gs1[ii,4], fc='w') axC.set_aspect('equal', adjustable='datalim') axC.set_ylabel(r'Z ($m$)', **fldict) laxC.append(axC) # Text boxes Ytxt = Laxt[-1].get_position().bounds[1]+Laxt[-1].get_position().bounds[3] if ii==1: DY = Laxt[-2].get_position().bounds[1] - Ytxt Xtxt = Laxt[-1].get_position().bounds[0] DX = Laxt[-1].get_position().bounds[2] laxtxtch.append( fig.add_axes([Xtxt+0.1*(DX-Xtxt), Ytxt, DX, DY], fc='None') ) laxC[-1].set_xlabel(r'R ($m$)', **fldict) Ytxt = laxp[0].get_position().bounds[1] + laxp[0].get_position().bounds[3] Xtxt = laxp[0].get_position().bounds[0] DX = laxp[0].get_position().bounds[2] axtxtt = fig.add_axes([Xtxt+0.2*(DX-Xtxt), Ytxt, DX, DY], fc='None') xtxt, Ytxt, dx, DY = 0.01, 0.98, 0.15, 0.02 axtxtg = fig.add_axes([xtxt, Ytxt, dx, DY], fc='None') # dax dax = {'t':Laxt, 'X':laxp, 'cross':laxC, 'hor':[axH], 'txtg':[axtxtg], 'txtx':laxtxtch, 'txtt':[axtxtt]} # Format all axes for kk in dax.keys(): for ii in range(0,len(dax[kk])): if dax[kk][ii] not in [None, False]: dax[kk][ii].tick_params(labelsize=fontsize) if 'txt' in kk: dax[kk][ii].patch.set_alpha(0.) for ss in ['left','right','bottom','top']: dax[kk][ii].spines[ss].set_visible(False) dax[kk][ii].set_xticks([]), dax[kk][ii].set_yticks([]) dax[kk][ii].set_xlim(0,1), dax[kk][ii].set_ylim(0,1) return dax def _DataCam12D_plot_combine(lData, key=None, nchMax=_nchMax, ntMax=_ntMax, indref=0, bck=True, lls=_lls, lct=_lct, lcch=_lcch, cbck=_cbck, fs=None, dmargin=None, wintit=_wintit, tit=None, Lplot='In', inct=[1,10], incX=[1,5], ms=4, cmap=None, vmin=None, vmax=None, vmin_map=None, vmax_map=None, cmap_map=None, normt_map=False, sharex=False, fmt_t='06.3f', fmt_X='01.0f', dmarker=_dmarker, fontsize=_fontsize, labelpad=_labelpad, invert=True, draw=True, connect=True, lis2D=None): ######### # Prepare ######### fldict = dict(fontsize=fontsize, labelpad=labelpad) # Use tuple unpacking to make sure indref is 0 if not indref==0: lData[0], lData[indref] = lData[indref], lData[0] nDat = len(lData) # --------- # Get time lt = [dd.t for dd in lData] lnt = [dd.nt for dd in lData] Dt = np.array([[np.nanmin(t), np.nanmax(t)] for t in lt]) Dt = [np.min(Dt[:,0]), np.max(Dt[:,1])] tlab = r"{0} ({1})".format(lData[0].dlabels['t']['name'], lData[0].dlabels['t']['units']) ttype = 'x' lidt = [id(t) for t in lt] # --------- # Check nch and X lnch = [dd.nch for dd in lData] lX = [dd.X for dd in lData] lidX = [id(X) for X in lX] lDX = [None if X is None else np.r_[np.nanmin(X), np.nanmax(X)] for X in lX] lXlab = [None if lis2D[ii] else r'%s (%s)'%(lData[ii].dlabels['X']['name'], lData[ii].dlabels['X']['units']) for ii in range(0,nDat)] lnnX = [lData[ii].ddata['nnch'] > 1 and lis2D[ii] for ii in range(0,nDat)] if any(lnnX): msg = "No DataCam2D can have nnX > 1!" raise Exception(msg) lXtype = ['x' if lData[ii].ddata['nnch'] == 1 else 'x1' for ii in range(0,nDat)] lXother = [None if lData[ii].ddata['nnch'] == 1 else lidt[ii] for ii in range(0,nDat)] lindtX = [(None if lData[ii].ddata['nnch'] == 1 else lData[ii].ddata['indtX']) for ii in range(0,nDat)] lx1, lx2, lindr, lextent = zip(*[lData[ii].get_X12plot('imshow') if lis2D[ii] else (None, None, None, None) for ii in range(0,nDat)]) lidx12 = [id((x1, x2)) if x1 is not None else None for x1, x2 in zip(lx1, lx2)] ln12 = [(x1.size, x2.size) if x1 is not None else None for x1, x2 in zip(lx1, lx2)] # dchans if key is None: ldchans = [np.arange(0,dd.nch) for dd in lData] else: ldchans = [dd.dchans(key) for dd in lData] lidchans = [id(dchans) for dchans in ldchans] # --------- # Check data ldata = [dd.data for dd in lData] lvmin = [np.nanmin(dat) for dat in ldata] lvmax = [np.nanmax(dat) for dat in ldata] lDd = [None if lis2D[ii] else (lvmin[ii]-0.05*(lvmax[ii]-lvmin[ii]), lvmax[ii]+0.05*(lvmax[ii]-lvmin[ii])) for ii in range(0,nDat)] lDlab = [r"%s (%s)"%(dd.dlabels['data']['name'], dd.dlabels['data']['units']) for dd in lData] liddata = [id(dat) for dat in ldata] lnorm = [mpl.colors.Normalize(vmin=lvmin[ii], vmax=lvmax[ii]) if lis2D[ii] else None for ii in range(0,nDat)] lnan2_data = [np.full(ln12[ii],np.nan) if lis2D[ii] else None for ii in range(0,nDat)] # --------- # Extra lkex = sorted(set(itt.chain.from_iterable([list(lData[ii].dextra.keys()) for ii in range(0,nDat) if lData[ii].dextra is not None]))) dEq_corres = dict.fromkeys(['ax','sep','x']) for k0 in dEq_corres.keys(): lkEq_temp = list(set([kk for kk in lkex if k0 == kk.split('.')[-1].lower()])) assert len(lkEq_temp) <= 1 if len(lkEq_temp) == 1: dEq_corres[k0] = lkEq_temp[0] if k0 in dmarker.keys(): dmarker[lkEq_temp[0]] = str(dmarker[k0]) del dmarker[k0] lkEq = sorted([vv for vv in dEq_corres.values() if vv not in [None, False]]) kSep = dEq_corres['sep'] lkEqmap = lkEq + ['map'] dlextra = dict([(k,[None for ii in range(0,nDat)]) for k in lkEqmap]) dteq = dict([(ii,{}) for ii in range(0,nDat)]) for ii in range(0,nDat): if lData[ii].dextra not in [None, False]: for k in set(lkEqmap).intersection(lData[ii].dextra.keys()): idteq = id(lData[ii].dextra[k]['t']) if idteq not in dteq[ii].keys(): # test if any existing t matches values lidalready = [[k1 for k1,v1 in v0.items() if (v1.size == lData[ii].dextra[k]['t'].size and np.allclose(v1, lData[ii].dextra[k]['t']))] for v0 in dteq.values()] lidalready = list(set(itt.chain.from_iterable(lidalready))) assert len(lidalready) in [0,1] if len(lidalready) == 1: idteq = lidalready[0] dteq[ii][idteq] = lData[ii].dextra[k]['t'] idteq = list(dteq[ii].keys())[0] dlextra[k][ii] = dict([(kk,v) for kk,v in lData[ii].dextra[k].items() if not kk == 't']) dlextra[k][ii]['id'] = id(dlextra[k][ii]['data2D']) dlextra[k][ii]['idt'] = idteq if (k in [dEq_corres['ax'], dEq_corres['x']] and 'marker' not in dlextra[k][ii].keys()): dlextra[k][ii]['marker'] = dmarker[k] if len(dteq[ii].keys()) > 1: msg = "Several distinct time bases in self.dextra for:\n" msg += " - lData[%s]: %s:\n"%(ii,lData[ii].Id.SaveName) msg += " - " + "\n - ".join(lkEqmap) warnings.warn(msg) ######### # Plot ######### # Format axes dax = _init_DataCam12D_combine(fs=fs, dmargin=dmargin, wintit=wintit, nchMax=nchMax, ntMax=ntMax, nDat=nDat, lis2D=lis2D, fldict=fldict, sharex=sharex) fig = dax['t'][0].figure if tit is None: tit = [str(getattr(lData[0].Id, aa)) for aa in ['Exp', 'Diag', 'shot'] if getattr(lData[0].Id, aa) not in [None, False]] tit = ' - '.join(tit) if tit != False: fig.suptitle(tit) # ----------------- # Plot ref dextra and ref conf H # conf c0 = (lData[0]._dgeom['config'] is not None and lData[0]._dgeom['config'] is not False) if c0: dax['hor'][0] = lData[0]._dgeom['config'].plot(lax=dax['hor'][0], proj='hor', element='P', tit=False, dLeg=None, draw=False) # dextra if lData[0].dextra not in [None, False]: lk = [k for k in lData[0].dextra.keys() if k not in lkEqmap] for kk in lk: dd = lData[0].dextra[kk] if 't' in dd.keys(): co = dd['c'] if 'c' in dd.keys() else 'k' lab = dd['label'] + ' (%s)'%dd['units'] if ii==0 else None dax['t'][0].plot(dd['t'], dd['data'], ls=lls[0], lw=1., c=co, label=lab) dax['t'][0].legend(bbox_to_anchor=(0.,1.01,1.,0.1), loc=3, ncol=4, mode='expand', borderaxespad=0., prop={'size':fontsize}) # ----------------- # Plot cross config, los and bck for each Data llCross = [None for ii in range(0,nDat)] llHor = [None for ii in range(0,nDat)] lidCross = [None for ii in range(0,nDat)] lidHor = [None for ii in range(0,nDat)] nan2 = np.full((2,1),np.nan) for ii in range(0,nDat): # cross config c0 = (lData[0]._dgeom['config'] is not None and lData[0]._dgeom['config'] is not False) if c0: dax['cross'][ii] = lData[ii].config.plot(lax=dax['cross'][ii], element='P', dLeg=None, proj='cross', tit=False, draw=False) # los c1 = (lData[ii]._dgeom['lCam'] is not None and lData[ii]._dgeom['lCam'] is not False) c2 = c1 and lData[ii]._isLOS if c2: llCross[ii] = [None for jj in range(0,len(lData[ii]._dgeom['lCam']))] llHor[ii] = [None for jj in range(0,len(lData[ii]._dgeom['lCam']))] for jj in range(0,len(lData[ii]._dgeom['lCam'])): cc = lData[ii]._dgeom['lCam'][jj] llCross[ii][jj] = cc._get_plotL(Lplot=Lplot, proj='cross', return_pts=True, multi=True) llHor[ii][jj] = cc._get_plotL(Lplot=Lplot, proj='hor', return_pts=True, multi=True) if c2 and lis2D[ii] and bck: indbck = np.r_[lindr[ii][0,0], lindr[ii][0,-1], lindr[ii][-1,0], lindr[ii][-1,-1]] for jj in range(0,len(lData[ii]._dgeom['lCam'])): crossbck = [llCross[ii][jj][indbck[0]],nan2,llCross[ii][jj][indbck[1]],nan2, llCross[ii][jj][indbck[2]],nan2,llCross[ii][jj][indbck[3]]] crossbck = np.concatenate(crossbck,axis=1) dax['cross'][ii].plot(crossbck[0,:], crossbck[1,:], c=cbck, ls='-', lw=1.) elif c2 and not lis2D[ii]: for jj in range(0,len(lData[ii]._dgeom['lCam'])): dax['cross'][ii] = cc.plot(lax=dax['cross'][ii], proj='cross', element='L', Lplot=Lplot, dL={'c':(0.4,0.4,0.4,0.4),'lw':0.5}, dLeg=None, draw=False) if c2: llCross[ii] = list( itt.chain( *llCross[ii] ) ) llHor[ii] = list( itt.chain( *llHor[ii] )) lidCross[ii] = id(llCross[ii]) lidHor[ii] = id(llHor[ii]) # bck signal if lis2D[ii] and bck: dax['t'][ii+1].fill_between(lt[ii], np.nanmin(ldata[ii],axis=1), np.nanmax(ldata[ii],axis=1), facecolor=cbck) elif bck and not lis2D[ii]: if lData[ii].ddata['nnch'] == 1: env = [np.nanmin(ldata[ii],axis=0), np.nanmax(ldata[ii],axis=0)] dax['X'][ii].fill_between(lX[ii].ravel(), env[0], env[1], facecolor=cbck) tbck = np.tile(np.r_[lt[ii], np.nan], lnch[ii]) dbck = np.vstack((ldata[ii], np.full((1,lnch[ii]),np.nan))).T.ravel() dax['t'][ii+1].plot(tbck, dbck, lw=1., ls='-', c=cbck) # --------------- # Lims and labels dax['t'][0].set_xlim(Dt) for ii in range(0,nDat): dax['t'][ii+1].set_ylim(lDd[ii]) dax['t'][ii+1].set_ylabel(lDlab[ii], **fldict) if lis2D[ii]: dax['X'][ii].set_xlim(lextent[ii][:2]) dax['X'][ii].set_ylim(lextent[ii][2:]) if invert: dax['X'][ii].invert_xaxis() dax['X'][ii].invert_yaxis() else: if not sharex: dax['X'][ii].set_xlim(lDX[ii]) dax['X'][ii].set_xlabel(lXlab[ii], **fldict) if sharex: dax['X'][0].set_xlim(np.nanmin(np.array(lDX)[:,0]), np.nanmax(np.array(lDX)[:,1])) ################## # Interactivity dict dgroup = {'time': {'nMax':ntMax, 'key':'f1', 'defid':lidt[0], 'defax':dax['t'][1]}} lgroup = ['channel-%s'%int(ii+1) for ii in range(0,nDat)] for ii in range(0,nDat): key = 'f{0:01.0f}'.format(ii+2) dgroup[lgroup[ii]] = {'nMax':nchMax, 'key':key, 'defid':lidX[ii], 'defax':dax['X'][ii]} # Group info (make dynamic in later versions ?) msg = ' '.join(['%s: %s'%(group,dgroup[group]['key']) for group in ['time']+lgroup]) l0 = dax['txtg'][0].text(0., 0., msg, color='k', fontweight='bold', fontsize=6., ha='left', va='center') # dref dref = {} for ii in range(0,nDat): dref[lidt[ii]] = {'group':'time', 'val':lt[ii], 'inc':inct} dref[lidX[ii]] = {'group':lgroup[ii], 'val':lX[ii], 'inc':incX, 'otherid':lXother[ii], 'indother':lindtX[ii]} if lis2D[ii]: dref[lidX[ii]]['2d'] = (lx1[ii],lx2[ii]) for ii in range(0,nDat): if len(list(dteq[ii])) > 0: idteq, teq = list(dteq[ii].items())[0] break else: idteq, teq = lidt[0], lt[0] dref[idteq] = {'group':'time', 'val':teq, 'inc':inct} # ddata ddat = {} for ii in range(0,nDat): ddat[liddata[ii]] = {'val':ldata[ii], 'refids':[lidt[ii],lidX[ii]]} ddat[lidchans[ii]] = {'val':ldchans[ii], 'refids':[lidX[ii]]} if llCross[ii] not in [None, False]: ddat[lidCross[ii]] = {'val':llCross[ii], 'refids':[lidX[ii]]} ddat[lidHor[ii]] = {'val':llHor[ii], 'refids':[lidX[ii]]} if lis2D[ii]: ddat[lidx12[ii]] = {'val':(lx1[ii],lx2[ii]), 'refids':[lidX[ii]]} if dlextra['map'][ii] not in [None, False]: ddat[dlextra['map'][ii]['id']] = {'val':dlextra['map'][ii]['data2D'], 'refids':[dlextra['map'][ii]['idt']]} for k in set(lkEq).intersection(dlextra.keys()): if dlextra[k][ii] not in [None, False]: ddat[dlextra[k][ii]['id']] = {'val':dlextra[k][ii]['data2D'], 'refids':[dlextra[k][ii]['idt']]} for kk in ddat.keys(): # DB if len(ddat[kk]['val']) == 1: import ipdb ipdb.set_trace() # dax lax_fix = dax['cross'] + dax['txtg'] + dax['hor'] + dax['txtt'] + dax['txtx'] dax2 = {dax['t'][0]: {'ref':{idteq:'x'}}} for ii in range(0,nDat): dax2[dax['t'][ii+1]] = {'ref':{lidt[ii]:'x'}} if lis2D[ii]: dax2[dax['X'][ii]] = {'ref':{lidX[ii]:'2d'},'invert':invert} else: dax2[dax['X'][ii]] = {'ref':{lidX[ii]:'x'}} dobj = {} ################## # Populating dobj # ------------- # One-shot and one-time 2D map for ii in range(0,nDat): if dlextra['map'][ii] not in [None, False]: map_ = dlextra['map'][ii]['data2D'] if normt_map: map_ = map_ / np.nanmax(map_,axis=0)[np.newaxis,:,:] vmin_map = np.nanmin(map_) if vmin_map is None else vmin_map vmax_map = np.nanmax(map_) if vmax_map is None else vmax_map norm_map = mpl.colors.Normalize(vmin=vmin_map, vmax=vmax_map) nan2_map = np.full(map_.shape[1:],np.nan) im = dax['cross'][ii].imshow(nan2_map, aspect='equal', extent=dlextra['map'][ii]['extent'], interpolation='nearest', origin='lower', zorder=0, norm=norm_map, cmap=cmap_map) dobj[im] = {'dupdate':{'data':{'id':dlextra['map'][ii]['id'], 'lrid':[dlextra['map'][ii]['idt']]}}, 'drefid':{dlextra['map'][ii]['idt']:0}} # ------------- # One-shot channels for ii in range(0,nDat): for jj in range(0,nchMax): # Channel text l0 = dax['txtx'][ii].text((0.5+jj)/nchMax, 0., r'', color='k', fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':lidchans[ii], 'lrid':[lidX[ii]], 'bstr':'{0:%s}'%fmt_X}}, 'drefid':{lidX[ii]:jj}} # los if lData[ii]._isLOS: l, = dax['cross'][ii].plot([np.nan,np.nan], [np.nan,np.nan], c=lcch[jj], ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':lidCross[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} l, = dax['hor'][0].plot([np.nan,np.nan], [np.nan,np.nan], c=lcch[jj], ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':lidHor[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} # ------------- # One-shot time # Time vlines on first axes for jj in range(0,ntMax): l0 = dax['t'][0].axvline(np.nan, c=lct[jj], ls=lls[0], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':idteq, 'lrid':[idteq]}}, 'drefid':{idteq:jj}} # time txt for jj in range(0,ntMax): # Time txt l0 = dax['txtt'][0].text((0.5+jj)/ntMax, 0., r'', color=lct[jj], fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':lidt[0], 'lrid':[lidt[0]], 'bstr':'{0:%s} s'%fmt_t}}, 'drefid':{lidt[0]:jj}} # ------------- # Data-specific for ii in range(0,nDat): # Time for jj in range(0,ntMax): # Time vlines l0 = dax['t'][ii+1].axvline(np.nan, c=lct[jj], ls=lls[0], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidt[ii], 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} # Time data profiles if lis2D[ii]: im = dax['X'][ii].imshow(lnan2_data[ii], extent=lextent[ii], aspect='equal', interpolation='nearest', origin='lower', zorder=-1, norm=lnorm[ii], cmap=cmap) dobj[im] = {'dupdate':{'data-reshape':{'id':liddata[ii], 'n12':ln12[ii], 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} else: l0, = dax['X'][ii].plot(lX[ii][0,:], np.full((lnch[ii],),np.nan), c=lct[jj], ls=lls[0], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':liddata[ii], 'lrid':[lidt[ii]]}}, 'drefid':{lidt[ii]:jj}} if lXother[ii] not in [None, False]: dobj[l0]['dupdate']['xdata'] = {'id':lidX[ii], 'lrid':[lXother[ii]]} # Time equilibrium and map if lData[ii].dextra not in [None, False]: for kk in set(lkEq).intersection(lData[ii].dextra.keys()): id_ = dlextra[kk][ii]['id'] idt = dlextra[kk][ii]['idt'] if kk == kSep: l0, = dax['cross'][ii].plot([np.nan],[np.nan], c=lct[jj], ls=lls[0], lw=1.) else: marker = dlextra[kk][ii].get('marker', 'o') l0, = dax['cross'][ii].plot([np.nan],[np.nan], mec=lct[jj], mfc='None', ls=lls[0], ms=ms, marker=marker) dobj[l0] = {'dupdate':{'data':{'id':id_, 'lrid':[idt]}}, 'drefid':{idt:jj}} # Channel for jj in range(0,nchMax): # Channel time trace l0, = dax['t'][ii+1].plot(lt[ii], np.full((lnt[ii],),np.nan), c=lcch[jj], ls=lls[0], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':liddata[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} # Channel vlines or pixels if lis2D[ii]: l0, = dax['X'][ii].plot([np.nan],[np.nan], mec=lcch[jj], ls='None', marker='s', mew=2., ms=ms, mfc='None', zorder=10) # Here we put lidX[0] because all have the same (and it # avoids overdefining ddat[idx12] dobj[l0] = {'dupdate':{'data':{'id':lidx12[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} else: if lXother[ii] is None: l0 = dax['X'][ii].axvline(np.nan, c=lcch[jj], ls=lls[0], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidX[ii], 'lrid':[lidX[ii]]}}, 'drefid':{lidX[ii]:jj}} else: for ll in range(0,ntMax): l0 = dax['X'][ii].axvline(np.nan, c=lcch[jj], ls=lls[ll], lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':lidX[ii], 'lrid':[lidt[ii],lidX[ii]]}}, 'drefid':{lidX[ii]:jj, lidt[ii]:ll}} ################## # Instanciate KeyHandler can = fig.canvas can.draw() kh = utils.KeyHandler_mpl(can=can, dgroup=dgroup, dref=dref, ddata=ddat, dobj=dobj, dax=dax2, lax_fix=lax_fix, groupinit='time', follow=True) if connect: kh.disconnect_old() kh.connect() if draw: can.draw() return kh ####################################################################### ####################################################################### ####################################################################### # Plot spectrogram ####################################################################### #######################################################################
[docs]def Data_plot_spectrogram(Data, tf, f, lpsd, lang, fmax=None, key=None, bck=True, indref=0, cmap_f=None, cmap_img=None, ms=4, vmin=None, vmax=None, normt=False, ntMax=None, nfMax=3, lls=_lls, lct=_lct, lcch=_lcch, plotmethod='imshow', invert=False, fs=None, dmargin=None, wintit=_wintit, tit=None, fontsize=None, draw=True, connect=True): if wintit is None: wintit = _wintit if fontsize is None: fontsize = _fontsize ntMax = _ntMax if ntMax is None else ntMax nfMax = _nfMax if nfMax is None else nfMax nD = 1 if Data._is2D(): nD = 2 ntMax = 1 nfMax = 1 kh = _Data1D_plot_spectrogram(Data, tf, f, lpsd, lang, fmax=fmax, key=key, nD=nD, ntMax=ntMax, nfMax=nfMax, bck=bck, llsf=lls, lct=lct, cmap_f=cmap_f, cmap_img=cmap_img, normt=normt, invert=invert, vmin=vmin, vmax=vmax, ms=ms, fs=fs, dmargin=dmargin, wintit=wintit, tit=tit, fontsize=fontsize, draw=draw, connect=connect) return kh
def _init_Data1D_spectrogram(fs=None, dmargin=None, nD=1, fontsize=8, wintit=_wintit): axCol = "w" fs = utils.get_figuresize(fs) if dmargin is None: dmargin = _def.dmargin1D fig = plt.figure(facecolor=axCol,figsize=fs) if wintit != False: fig.canvas.set_window_title(wintit) gs1 = gridspec.GridSpec(6, 5, **dmargin) laxt = [fig.add_subplot(gs1[:2,:2], fc='w')] laxt += [fig.add_subplot(gs1[2:4,:2], fc='w', sharex=laxt[0])] laxt += [fig.add_subplot(gs1[4:,:2], fc='w', sharex=laxt[0],sharey=laxt[1])] if nD == 1: laxp = [fig.add_subplot(gs1[:2,2:4], fc='w', sharey=laxt[0])] laxp += [fig.add_subplot(gs1[2:4,2:4], fc='w', sharex=laxp[0]), fig.add_subplot(gs1[4:,2:4], fc='w', sharex=laxp[0])] else: from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable laxp = [fig.add_subplot(gs1[:2,2:4], fc='w')] laxp += [fig.add_subplot(gs1[2:4,2:4], fc='w', sharex=laxp[0], sharey=laxp[0]), fig.add_subplot(gs1[4:,2:4], fc='w', sharex=laxp[0], sharey=laxp[0])] laxcb = [None for ii in [0,1,2]] for ii in range(0,len(laxp)): ax_divider = make_axes_locatable(laxp[ii]) laxcb[ii] = ax_divider.append_axes("right", size="5%", pad="5%") axH = fig.add_subplot(gs1[0:2,4], fc='w') axC = fig.add_subplot(gs1[2:,4], fc='w') axC.set_aspect('equal', adjustable='datalim') axH.set_aspect('equal', adjustable='datalim') # text group xtxt, Ytxt, dx, DY = 0.01, 0.98, 0.15, 0.02 axtxtg = fig.add_axes([xtxt, Ytxt, dx, DY], fc='None') # text x Ytxt = laxt[0].get_position().bounds[1]+laxt[0].get_position().bounds[3] DY = (laxt[0].get_position().bounds[1] - (laxt[1].get_position().bounds[1]+laxt[1].get_position().bounds[3])) Xtxt = laxt[0].get_position().bounds[0] DX = laxt[0].get_position().bounds[2] xtxt = Xtxt + 0.15*(DX-Xtxt) dx = DX - 0.15*(DX-Xtxt) axtxtx = fig.add_axes([xtxt, Ytxt, dx, DY], fc='None') # text t and f Ytxt = laxp[0].get_position().bounds[1]+laxp[0].get_position().bounds[3] Xtxt = laxp[0].get_position().bounds[0] DX = laxp[0].get_position().bounds[2] xtxt = Xtxt + 0.15*(DX-Xtxt) dx = DX - 0.15*(DX-Xtxt) axtxtt = fig.add_axes([xtxt, Ytxt, dx, DY], fc='None') Ytxt = laxp[1].get_position().bounds[1]+laxp[1].get_position().bounds[3] axtxtf = fig.add_axes([xtxt, Ytxt, dx, DY], fc='None') # formatting text for ax in [axtxtg, axtxtx, axtxtt, axtxtf]: ax.patch.set_alpha(0.) for ss in ['left','right','bottom','top']: ax.spines[ss].set_visible(False) ax.set_xticks([]), ax.set_yticks([]) ax.set_xlim(0,1), ax.set_ylim(0,1) # Return ax dict dax = {'t':laxt, 'X':laxp, 'cross':[axC], 'hor':[axH], 'txtg':[axtxtg], 'txtx':[axtxtx], 'txtt':[axtxtt], 'txtf':[axtxtf]} # Add colorbars if 2D if nD == 2: dax['colorbar'] = laxcb # Format all axes for kk in dax.keys(): for ii in range(0,len(dax[kk])): dax[kk][ii].tick_params(labelsize=fontsize) # For faster plotting : if kk not in ['cross','hor']: dax[kk][ii].autoscale(False) dax[kk][ii].use_sticky_edges = False return dax def _Data1D_plot_spectrogram(Data, tf, f, lpsd, lang, fmax=None, key=None, nD=1, ntMax=_ntMax, nfMax=_nfMax, bck=True, llsf=_lls, lct=_lct, inct=[1,10], incX=[1,5], incf=[1,10], fmt_t='06.3f', fmt_X='01.0f', fmt_f='05.2f', cmap_f=None, cmap_img=None, normt=False, ms=4, invert=True, vmin=None, vmax=None, cbck=_cbck, Lplot='In', fs=None, dmargin=None, wintit=_wintit, tit=None, fontsize=_fontsize, labelpad=_labelpad, draw=True, connect=True): assert Data.Id.Cls in ['DataCam1D','DataCam2D'] assert nD in [1,2] if cmap_f is None: cmap_f = plt.cm.gray_r if cmap_img is None: cmap_img = plt.cm.viridis ######### # Prepare ######### # Start extracting data fldict = dict(fontsize=fontsize, labelpad=labelpad) Dt, Dch = [np.inf,-np.inf], [np.inf,-np.inf] # Force update for safety ddata = Data.ddata # t t, nt = ddata['t'], ddata['nt'] if nt == 1: Dt = [t[0]-0.001,t[0]+0.001] else: Dt = [np.nanmin(t), np.nanmax(t)] tlab = r"{0} ({1})".format(Data.dlabels['t']['name'], Data.dlabels['t']['units']) ttype = 'x' idt = id(t) # X X, nch, nnch, indtX = ddata['X'], ddata['nch'], ddata['nnch'], ddata['indtX'] if nD == 1: if nch == 1: DX = [X[0,0]-0.1*X[0,0], X[0,0]+0.1*X[0,0]] else: DX = [np.nanmin(X), np.nanmax(X)] Xlab = r"{0} ({1})".format(Data.dlabels['X']['name'], Data.dlabels['X']['units']) else: assert nnch == 1 assert indtX is None x1, x2, indr, extent = Data.get_X12plot('imshow') if bck: indbck = np.r_[indr[0,0], indr[0,-1], indr[-1,0], indr[-1,-1]] nan2 = np.full((2,1),np.nan) idx12 = id((x1,x2)) n12 = [x1.size, x2.size] if nnch == 1: Xtype = 'x' Xother = None elif indtX is None: Xtype = 'x1' Xother = idt idX = id(X) # dchans if key is None: dchans = np.arange(0,nch) else: dchans = Data.dchans(key) idchans = id(dchans) # data data = Data.data vmin = np.nanmin(data) vmax = np.nanmax(data) Dlim = [min(0.,vmin), max(0.,vmax)] Dd = [Dlim[0]-0.05*np.diff(Dlim), Dlim[1]+0.05*np.diff(Dlim)] Dlab = r"{0} ({1})".format(Data.dlabels['data']['name'], Data.dlabels['data']['units']) iddata = id(data) # tf Dtf = [np.nanmin(tf), np.nanmax(tf)] dtf = 0.5*(tf[1]-tf[0]) idtf = id(tf) # f Df = [np.nanmin(f), np.nanmax(f)] flab = r'f ($Hz$)' psdlab = r'$\|F\|^2$ (a.u.)' anglab = r'$ang(F)$ ($rad$)' ftype = 'y' idf = id(f) df = 0.5*(f[1]-f[0]) extentf = (Dtf[0]-dtf,Dtf[1]+dtf, Df[0]-df, Df[1]+df) # lpsd and lang lpsd = np.swapaxes(np.stack(lpsd,axis=0),1,2) maxx = np.nanmax(np.nanmax(lpsd,axis=1,keepdims=True),axis=2).ravel() lpsd_norm = lpsd / maxx[:,None,None] if normt: maxx = np.nanmax(lpsd_norm,axis=2,keepdims=True) lpsd_norm = lpsd_norm / maxx lang = np.swapaxes(np.stack(lang,axis=0),1,2) Dpsd = [np.nanmin(lpsd), np.nanmax(lpsd)] Dpsd_norm = [np.nanmin(lpsd_norm), np.nanmax(lpsd_norm)] angmax = np.pi idlpsd = id(lpsd) idlpsd_norm = id(lpsd_norm) idlang = id(lang) ############ # Format axes dax = _init_Data1D_spectrogram(fs=fs, dmargin=dmargin, wintit=wintit, nD=nD) fig = dax['t'][0].figure if tit is None: tit = [] if Data.Id.Exp not in [None, False]: tit.append(Data.Id.Exp) if Data.Id.Diag not in [None, False]: tit.append(Data.Id.Diag) if Data.Id.shot not in [None, False]: tit.append(r"{0:05.0f}".format(Data.Id.shot)) tit = ' - '.join(tit) if tit != False: fig.suptitle(tit) # Plot vessel c0 = (Data._dgeom['config'] is not None and Data._dgeom['config'] is not False) c1 = (c0 and Data._dgeom['lCam'] is not None and Data._dgeom['lCam'] is not False) if c0: out = Data._dgeom['config'].plot(lax=[dax['cross'][0], dax['hor'][0]], element='P', dLeg=None, draw=False) dax['cross'][0], dax['hor'][0] = out if c1 and 'LOS' in Data._dgeom['lCam'][0].Id.Cls: lCross, lHor, llab = [], [], [] for cc in Data._dgeom['lCam']: lCross += cc._get_plotL(Lplot=Lplot, proj='cross', return_pts=True, multi=True) lHor += cc._get_plotL(Lplot=Lplot, proj='hor', return_pts=True, multi=True) if bck and cc._is2D(): crossbck = [lCross[indbck[0]],nan2,lCross[indbck[1]],nan2, lCross[indbck[2]],nan2,lCross[indbck[3]]] crossbck = np.concatenate(crossbck,axis=1) horbck = [lHor[indbck[0]],nan2,lHor[indbck[1]],nan2, lHor[indbck[2]],nan2,lHor[indbck[3]]] horbck = np.concatenate(horbck,axis=1) dax['cross'][0].plot(crossbck[0,:], crossbck[1,:], c=cbck, ls='-', lw=1.) dax['hor'][0].plot(horbck[0,:], horbck[1,:], c=cbck, ls='-', lw=1.) elif bck: out = cc.plot(lax=[dax['cross'][0], dax['hor'][0]], element='L', Lplot=Lplot, dL={'c':(0.4,0.4,0.4,0.4),'lw':0.5}, dLeg=None, draw=False) dax['cross'][0], dax['hor'][0] = out lHor = np.stack(lHor) idlCross = id(lCross) idlHor = id(lHor) elif c1: lCross, lHor = None, None else: lCross, lHor = None, None else: lCross, lHor = None, None if bck: if nD == 1: if nnch == 1: env = [np.nanmin(data,axis=0), np.nanmax(data,axis=0)] dax['X'][0].fill_between(X.ravel(), env[0], env[1], facecolor=cbck) tbck = np.tile(np.r_[t, np.nan], nch) dbck = np.vstack((data, np.full((1,nch),np.nan))).T.ravel() dax['t'][0].plot(tbck, dbck, lw=1., ls='-', c=cbck) else: dax['t'][0].fill_between(t, np.nanmin(data,axis=1), np.nanmax(data,axis=1), facecolor=cbck) # Colorbars if 2D if nD == 2: norm_data = mpl.colors.Normalize(vmin=vmin, vmax=vmax) cb = mpl.colorbar.ColorbarBase(dax['colorbar'][0], cmap=cmap_img, orientation='vertical', norm=norm_data) dax['colorbar'][0].set_ylabel(Dlab, **fldict) norm_psd0 = mpl.colors.Normalize(vmin=Dpsd[0], vmax=Dpsd[1]) cb = mpl.colorbar.ColorbarBase(dax['colorbar'][1], cmap=cmap_img, orientation='vertical', norm=norm_psd0) dax['colorbar'][1].set_ylabel(psdlab, **fldict) norm_ang = mpl.colors.Normalize(vmin=-angmax, vmax=angmax) cb = mpl.colorbar.ColorbarBase(dax['colorbar'][2], cmap=plt.cm.seismic, orientation='vertical', norm=norm_ang, ticks=[-angmax, 0, angmax]) dax['colorbar'][2].set_ylabel(anglab, **fldict) norm_psd1 = mpl.colors.Normalize(vmin=Dpsd_norm[0], vmax=Dpsd_norm[1]) # --------------- # Lims and labels fmax = extentf[3] if fmax is None else fmax dax['t'][0].set_xlim(Dt) dax['t'][0].set_ylim(Dd) dax['t'][1].set_ylim(extentf[2], fmax) dax['t'][-1].set_xlabel(tlab, **fldict) dax['t'][0].set_ylabel(Dlab, **fldict) dax['t'][1].set_ylabel(flab, **fldict) dax['t'][2].set_ylabel(flab, **fldict) if nD == 1: dax['X'][0].set_xlim(DX) dax['X'][0].set_ylim(Dd) dax['X'][1].set_ylim(Dpsd) dax['X'][2].set_ylim([-np.pi,np.pi]) dax['X'][-1].set_xlabel(Xlab, **fldict) dax['X'][0].set_ylabel(Dlab, **fldict) dax['X'][1].set_ylabel(psdlab, **fldict) dax['X'][2].set_ylabel(anglab, **fldict) else: dax['X'][0].set_xlim(extent[:2]) dax['X'][0].set_ylim(extent[2:]) # invert if invert and nD == 2: for ii in range(0,3): dax['X'][ii].invert_xaxis() dax['X'][ii].invert_yaxis() ################## # Interactivity dict dgroup = {'time': {'nMax':ntMax, 'key':'f1', 'defid':idtf, 'defax':dax['t'][0]}, 'channel': {'nMax':1, 'key':'f2', 'defid':idX, 'defax':dax['X'][0]}, 'frequency': {'nMax':nfMax, 'key':'f3', 'defid':idf, 'defax':dax['t'][1]}} # Group info (make dynamic in later versions ?) msg = ' '.join(['%s: %s'%(v['key'],k) for k, v in dgroup.items()]) l0 = dax['txtg'][0].text(0., 0., msg, color='k', fontweight='bold', fontsize=6., ha='left', va='center') dref = {idt: {'group':'time', 'val':t, 'inc':inct}, idtf: {'group':'time', 'val':tf, 'inc':inct}, idX: {'group':'channel', 'val':X, 'inc':incX, 'otherid':Xother, 'indother':indtX}, idf: {'group':'frequency', 'val':f, 'inc':incf}} if nD == 2: dref[idX]['2d'] = (x1,x2) ddat = {iddata: {'val':data, 'refids':[idt,idX]}, idlpsd: {'val':lpsd, 'refids':[idX,idf,idtf]}, idlpsd_norm: {'val':lpsd_norm, 'refids':[idX,idf,idtf]}, idlang: {'val':lang, 'refids':[idX,idf,idtf]}, idchans:{'val':dchans, 'refids':[idX]}} if lCross not in [None, False]: ddat[idlCross] = {'val':lCross, 'refids':[idX]} ddat[idlHor] = {'val':lHor, 'refids':[idX]} if nD == 2: ddat[idx12] = {'val':(x1,x2), 'refids':[idX]} lax_fix = [dax['cross'][0], dax['hor'][0], dax['txtg'][0], dax['txtt'][0], dax['txtx'][0], dax['txtf'][0]] dax2 = {dax['t'][0]: {'ref':{idt:'x'}}, dax['t'][1]: {'ref':{idtf:'x', idf:'y'}, 'defrefid':idf}, dax['t'][2]: {'ref':{idtf:'x', idf:'y'}, 'defrefid':idf}} if nD == 1: dax2.update({dax['X'][0]: {'ref':{idX:'x'}}, dax['X'][1]: {'ref':{idX:'x'}}, dax['X'][2]: {'ref':{idX:'x'}}}) else: dax2.update({dax['X'][0]: {'ref':{idX:'2d'}, 'invert':invert}, dax['X'][1]: {'ref':{idX:'2d'}, 'invert':invert}, dax['X'][2]: {'ref':{idX:'2d'}, 'invert':invert}}) dobj = {} ################## # Populating dobj ################## # Channel for jj in range(0,1): # Channel text l0 = dax['txtx'][0].text(0.5, 0., r'', color='k', fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':idchans, 'lrid':[idX], 'bstr':'{0:%s}'%fmt_X}}, 'drefid':{idX:jj}} # Channel time trace l0, = dax['t'][0].plot(t, np.full((nt,),np.nan), c='k', ls='-', lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':iddata, 'lrid':[idX]}}, 'drefid':{idX:jj}} # Channel vlines or pixels if nD == 1: if Xother is None: for ll in range(0,len(dax['X'])): l0 = dax['X'][ll].axvline(np.nan, c='k', ls='-', lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':idX, 'lrid':[idX]}}, 'drefid':{idX:jj}} else: for ll in range(0,len(dax['X'])): for ii in range(0,ntMax): l0 = dax['X'][ll].axvline(np.nan, c='k', ls='-', lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':idX, 'lrid':[idt,idX]}}, 'drefid':{idX:jj, idt:ii}} # psd imshow l0 = dax['t'][1].imshow(np.full(lpsd.shape[1:],np.nan), cmap=cmap_f, origin='lower', aspect='auto', extent=extentf, norm=norm_psd1, interpolation='nearest') dobj[l0] = {'dupdate':{'data':{'id':idlpsd_norm, 'lrid':[idX]}}, 'drefid':{idX:jj}} # ang imshow l0 = dax['t'][2].imshow(np.full(lang.shape[1:],np.nan), cmap=plt.cm.seismic, origin='lower', aspect='auto', extent=extentf, vmin=-np.pi, vmax=np.pi, interpolation='nearest') dobj[l0] = {'dupdate':{'data':{'id':idlang, 'lrid':[idX]}}, 'drefid':{idX:jj}} # los if c1: l, = dax['cross'][0].plot([np.nan,np.nan], [np.nan,np.nan], c='k', ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':idlCross, 'lrid':[idX]}}, 'drefid':{idX:jj}} l, = dax['hor'][0].plot([np.nan,np.nan], [np.nan,np.nan], c='k', ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':idlHor, 'lrid':[idX]}}, 'drefid':{idX:jj}} # Time for jj in range(0,ntMax): # Time txt l0 = dax['txtt'][0].text((0.5+jj)/ntMax, 0., r'', color=lct[jj], fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':idt, 'lrid':[idt], 'bstr':'{0:%s} s'%fmt_t}}, 'drefid':{idt:jj}} # Time vlines for ll in range(0,len(dax['t'])): l0 = dax['t'][ll].axvline(np.nan, c=lct[jj], ls='-', lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':idt, 'lrid':[idt]}}, 'drefid':{idt:jj}} # Time data profiles if nD == 1: l0, = dax['X'][0].plot(X[0,:], np.full((nch,),np.nan), c=lct[jj], ls='-', lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':iddata, 'lrid':[idt]}}, 'drefid':{idt:jj}} if Xother not in [None, False]: dobj[l0]['dupdate']['xdata'] = {'id':idX, 'lrid':[Xother]} # lpsd and ang profiles for ii in range(0,nfMax): l0, = dax['X'][1].plot(X[0,:], np.full((nch,),np.nan), c=lct[jj], ls=llsf[ii], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':idlpsd, 'lrid':[idtf,idf]}}, 'drefid':{idtf:jj, idf:ii}} l1, = dax['X'][2].plot(X[0,:], np.full((nch,),np.nan), c=lct[jj], ls=llsf[ii], lw=1.) dobj[l1] = {'dupdate':{'ydata':{'id':idlang, 'lrid':[idtf,idf]}}, 'drefid':{idtf:jj, idf:ii}} if Xother not in [None, False]: dobj[l0]['dupdate']['xdata'] = {'id':idX, 'lrid':[Xother]} dobj[l0]['drefid'][Xother] = jj dobj[l1]['dupdate']['xdata'] = {'id':idX, 'lrid':[Xother]} dobj[l1]['drefid'][Xother] = jj else: nan2 = np.full((x2.size,x1.size),np.nan) im = dax['X'][0].imshow(nan2, extent=extent, aspect='equal', interpolation='nearest', origin='lower', zorder=-1, norm=norm_data, cmap=cmap_img) dobj[im] = {'dupdate':{'data-reshape':{'id':iddata, 'n12':n12, 'lrid':[idt]}}, 'drefid':{idt:jj}} im = dax['X'][1].imshow(nan2, extent=extent, aspect='equal', interpolation='nearest', origin='lower', zorder=-1, norm=norm_psd0, cmap=cmap_img) dobj[im] = {'dupdate':{'data-reshape':{'id':idlpsd, 'n12':n12, 'lrid':[idtf,idf]}}, 'drefid':{idtf:jj, idf:0}} im = dax['X'][2].imshow(nan2, extent=extent, aspect='equal', interpolation='nearest', origin='lower', zorder=-1, norm=norm_ang, cmap=plt.cm.seismic) dobj[im] = {'dupdate':{'data-reshape':{'id':idlang, 'n12':n12, 'lrid':[idtf,idf]}}, 'drefid':{idtf:jj, idf:0}} # pixel on top of imshows if nD == 2: jj = 0 for ll in range(0,len(dax['X'])): l0, = dax['X'][ll].plot([np.nan],[np.nan], mec='k', ls='None', marker='s', mew=2., ms=ms, mfc='None', zorder=10) dobj[l0] = {'dupdate':{'data':{'id':idx12, 'lrid':[idX]}}, 'drefid':{idX:jj}} # Frequency for jj in range(0,nfMax): # Frequency text l0 = dax['txtf'][0].text((0.5+jj)/ntMax, 0., r'', color='k', fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':idf, 'lrid':[idf], 'bstr':'{0:%s} Hz'%fmt_t}}, 'drefid':{idf:jj}} # Frequency hlines x 2 l0 = dax['t'][1].axhline(np.nan, c='k', ls=llsf[jj], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':idf, 'lrid':[idf]}}, 'drefid':{idf:jj}} l0 = dax['t'][2].axhline(np.nan, c='k', ls=llsf[jj], lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':idf, 'lrid':[idf]}}, 'drefid':{idf:jj}} # Instanciate KeyHandler can = fig.canvas can.draw() kh = utils.KeyHandler_mpl(can=can, dgroup=dgroup, dref=dref, ddata=ddat, dobj=dobj, dax=dax2, lax_fix=lax_fix, groupinit='time', follow=True) if connect: kh.disconnect_old() kh.connect() if draw: can.draw() return kh ####################################################################### ####################################################################### ####################################################################### # Plot svd ####################################################################### ####################################################################### def Data_plot_svd(Data, chronos, s, topos, modes=None, key=None, bck=True, Lplot='In', cmap=None, vmin=None, vmax=None, cmap_topos=None, vmin_topos=None, vmax_topos=None, ntMax=None, nchMax=None, ms=4, inct=[1,10], incX=[1,5], incm=[1,5], lls=None, lct=None, lcch=None, lcm=None, cbck=None, invert=True, fmt_t='06.3f', fmt_X='01.0f', fmt_m='03.0f', fs=None, dmargin=None, labelpad=None, wintit=None, tit=None, fontsize=None, draw=True, connect=True): assert issubclass(Data.__class__, utils.ToFuObject) assert Data._isSpectral() is False nD = 2 if Data._is2D() else 1 # ------------------ # Input formatting if fontsize is None: fontsize = _fontsize if ntMax is None: ntMax = _ntMax if Data._is2D(): ntMax = 1 if nchMax is None: nchMax = _nchMax if cmap is None: cmap = plt.cm.gray_r if cmap_topos is None: cmap = plt.cm.seismic if wintit is None: wintit = _wintit if labelpad is None: labelpad = _labelpad if lct is None: lct = _lct if lcch is None: lcch = _lcch if lcm is None: lcm = _lcm if lls is None: lls = _lls if cbck is None: cbck = _cbck if modes is None: modes = np.arange(0,6) # ------------------ # Plotting kh = _Data_plot_svd(Data, chronos, s, topos, modes=modes, key=key, bck=bck, Lplot=Lplot, cmap=cmap, vmin=vmin, vmax=vmax, cmap_topos=cmap_topos, vmin_topos=vmin_topos, vmax_topos=vmax_topos, nD=nD, ntMax=ntMax, nchMax=nchMax, ms=ms, inct=inct, incX=incX, incm=incm, lls=lls, lct=lct, lcch=lcch, lcm=lcm, cbck=cbck, invert=invert, fmt_t=fmt_t, fmt_X=fmt_X, fmt_m=fmt_m, fs=fs, dmargin=dmargin, labelpad=labelpad, wintit=wintit, tit=tit, fontsize=fontsize, draw=draw, connect=connect) return kh def _init_Data_svd(fs=None, dmargin=None, nD=1, fontsize=8, wintit=_wintit): # Prepare axCol = "w" fs = utils.get_figuresize(fs) if dmargin is None: dmargin = _def.dmargin1D fig = plt.figure(facecolor=axCol,figsize=fs) if wintit != False: fig.canvas.set_window_title(wintit) # Axes array gs1 = gridspec.GridSpec(4, 5, **dmargin) laxt = [fig.add_subplot(gs1[0,:2], fc='w')] laxt += [fig.add_subplot(gs1[1,:2], fc='w', sharex=laxt[0])] for ii in range(2,4): laxt += [fig.add_subplot(gs1[ii,:2], fc='w', sharex=laxt[0],sharey=laxt[1])] if nD == 1: laxp = [fig.add_subplot(gs1[0,2:4], fc='w', sharey=laxt[0])] laxp += [fig.add_subplot(gs1[1,2:4], fc='w', sharex=laxp[0])] for ii in range(2,4): laxp += [fig.add_subplot(gs1[ii,2:4], fc='w', sharex=laxp[0], sharey=laxp[1])] else: from mpl_toolkits.axes_grid1.axes_divider import make_axes_locatable laxp = [fig.add_subplot(gs1[0,2:4], fc='w')] for ii in range(0,6): laxp += [fig.add_subplot(gs1[1+ii//2, 2+ii%2], fc='w', sharex=laxp[0], sharey=laxp[0])] ax_divider = make_axes_locatable(laxp[0]) laxcb = [ax_divider.append_axes("right", size="5%", pad="15%")] laxcb += [ax_divider.append_axes("right", size="5%", pad="30%")] axm = fig.add_subplot(gs1[0,4], fc='w', yscale='log') axH = fig.add_subplot(gs1[1,4], fc='w') axC = fig.add_subplot(gs1[2:,4], fc='w') axC.set_aspect('equal', adjustable='datalim') axH.set_aspect('equal', adjustable='datalim') # text x Ytxt = np.sum(laxt[0].get_position().bounds[1::2]) DY = (laxt[0].get_position().bounds[1] - np.sum(laxt[1].get_position().bounds[1::2]))/2. Xtxt = laxt[0].get_position().bounds[0] DX = laxt[0].get_position().bounds[2] axtxtx = fig.add_axes([Xtxt, Ytxt, DX, DY], fc='None') # text t Ytxt = np.sum(laxp[0].get_position().bounds[1::2]) Xtxt = laxp[0].get_position().bounds[0] axtxtt = fig.add_axes([Xtxt, Ytxt, DX, DY], fc='None') # text group xtxt, dx, Ytxt = 0., 0.15, 1.-DY axtxtg = fig.add_axes([xtxt, Ytxt, dx, DY], fc='None') # texts modes laxtxtm = [None for ii in range(0,6)] for ii in range(0,6): Xtxt = laxp[0].get_position().bounds[0] + (ii%2)*DX/2. indax = ii//(3-nD) + 1 Ytxt = np.sum(laxp[indax].get_position().bounds[1::2]) ax = fig.add_axes([Xtxt, Ytxt, DX/2., DY], fc='None') laxtxtm[ii] = ax # Return ax dict dax = {'t':laxt, 'X':laxp, 'm':[axm], 'cross':[axC], 'hor':[axH], 'txtg':[axtxtg], 'txtx':[axtxtx], 'txtt':[axtxtt], 'txtm':laxtxtm} # Add colorbars if 2D if nD == 2: dax['colorbar'] = laxcb # Format all axes for kk in dax.keys(): for ii in range(0,len(dax[kk])): dax[kk][ii].tick_params(labelsize=fontsize) # For faster plotting : if kk not in ['cross','hor']: dax[kk][ii].autoscale(False) dax[kk][ii].use_sticky_edges = False if 'txt' in kk: for ii in range(0,len(dax[kk])): dax[kk][ii].patch.set_alpha(0.) for ss in ['left','right','bottom','top']: dax[kk][ii].spines[ss].set_visible(False) dax[kk][ii].set_xticks([]), dax[kk][ii].set_yticks([]) dax[kk][ii].set_xlim(0,1), dax[kk][ii].set_ylim(0,1) return dax def _Data_plot_svd(Data, chronos, s, topos, modes=None, key=None, bck=True, Lplot='In', cmap=None, vmin=None, vmax=None, cmap_topos=None, vmin_topos=None, vmax_topos=None, ntMax=None, nchMax=None, ms=4, inct=[1,10], incX=[1,5], incm=[1,5], lls=_lls, lct=_lct, lcch=_lcch, lcm=_lcm, cbck=_cbck, invert=False, fmt_t='06.3f', fmt_X='01.0f', fmt_m='03.0f', fs=None, dmargin=None, labelpad=None, wintit=_wintit, tit=None, fontsize=None, draw=True, connect=True, nD=1): assert Data.Id.Cls in ['DataCam1D','DataCam2D'] assert nD in [1,2] if cmap is None: cmap = plt.cm.gray_r if cmap_topos is None: cmap_topos = plt.cm.seismic nmMax = 6 invert = True ######### # Prepare ######### # Start extracting data fldict = dict(fontsize=fontsize, labelpad=labelpad) Dt, Dch = [np.inf,-np.inf], [np.inf,-np.inf] # Force update for safety ddata = Data.ddata # t t, nt = ddata['t'], ddata['nt'] if nt == 1: Dt = [t[0]-0.001,t[0]+0.001] else: Dt = [np.nanmin(t), np.nanmax(t)] tlab = r"{0} ({1})".format(Data.dlabels['t']['name'], Data.dlabels['t']['units']) ttype = 'x' idt = id(t) #------ # X X, nch, nnch, indtX = ddata['X'], ddata['nch'], ddata['nnch'], ddata['indtX'] # svd will only be displayed vs channel (no varying X, for the topos) if nnch > 1: X = np.arange(0,nch)[None,:] nnch = 1 if nD == 1: if nch == 1: DX = [X[0,0]-0.1*X[0,0], X[0,0]+0.1*X[0,0]] else: DX = [np.nanmin(X), np.nanmax(X)] Xlab = r"{0} ({1})".format(Data.dlabels['X']['name'], Data.dlabels['X']['units']) else: assert nnch == 1 assert indtX is None x1, x2, indr, extent = Data.get_X12plot('imshow') if bck: indbck = np.r_[indr[0,0], indr[0,-1], indr[-1,0], indr[-1,-1]] nan2 = np.full((2,1),np.nan) idx12 = id((x1,x2)) n12 = [x1.size, x2.size] Xtype = 'x' Xother = None idX = id(X) # dchans if key is None: dchans = np.arange(0,nch) else: dchans = Data.dchans(key) idchans = id(dchans) # data data = Data.data vmin = np.nanmin(data) vmax = np.nanmax(data) Dlim = [min(0.,vmin), max(0.,vmax)] Dd = [Dlim[0]-0.05*np.diff(Dlim), Dlim[1]+0.05*np.diff(Dlim)] Dlab = r"{0} ({1})".format(Data.dlabels['data']['name'], Data.dlabels['data']['units']) iddata = id(data) # singular values Ds = (np.min(s),np.max(s)) Ds = (Ds[0], Ds[1]+0.05*np.diff(Ds)) indmodes = np.arange(0,s.size) Dm = (-1, np.max(modes)+1) idm = id(indmodes) # chronos vabs_chronos = np.nanmax(np.abs(chronos[:,modes])) Dchronos = (-vabs_chronos, vabs_chronos) idchronos = id(chronos) # topos vabs_topos = np.nanmax(np.abs(topos[modes,:])) Dtopos = (-vabs_topos, vabs_topos) if vmin_topos is None: vmin_topos = -vabs_topos if vmax_topos is None: vmax_topos = vabs_topos idtopos = id(topos) ############ # Format axes ############ dax = _init_Data_svd(fs=fs, dmargin=dmargin, wintit=wintit, nD=nD) fig = dax['t'][0].figure if tit is None: tit = [] if Data.Id.Exp not in [None, False]: tit.append(Data.Id.Exp) if Data.Id.Diag not in [None, False]: tit.append(Data.Id.Diag) if Data.Id.shot not in [None, False]: tit.append(r"{0:05.0f}".format(Data.Id.shot)) tit = ' - '.join(tit) if tit != False: fig.suptitle(tit) ############ # Plot static ############ # Config and LOS c0 = (Data._dgeom['config'] is not None and Data._dgeom['config'] is not False) c1 = (c0 and Data._dgeom['lCam'] is not None and Data._dgeom['lCam'] is not False) if c0: out = Data._dgeom['config'].plot(lax=[dax['cross'][0], dax['hor'][0]], element='P', dLeg=None, draw=False) dax['cross'][0], dax['hor'][0] = out if c1 and 'LOS' in Data._dgeom['lCam'][0].Id.Cls: lCross, lHor, llab = [], [], [] for cc in Data._dgeom['lCam']: lCross += cc._get_plotL(Lplot=Lplot, proj='cross', return_pts=True, multi=True) lHor += cc._get_plotL(Lplot=Lplot, proj='hor', return_pts=True, multi=True) if bck and cc._is2D(): crossbck = [lCross[indbck[0]],nan2,lCross[indbck[1]],nan2, lCross[indbck[2]],nan2,lCross[indbck[3]]] crossbck = np.concatenate(crossbck,axis=1) horbck = [lHor[indbck[0]],nan2,lHor[indbck[1]],nan2, lHor[indbck[2]],nan2,lHor[indbck[3]]] horbck = np.concatenate(horbck,axis=1) dax['cross'][0].plot(crossbck[0,:], crossbck[1,:], c=cbck, ls='-', lw=1.) dax['hor'][0].plot(horbck[0,:], horbck[1,:], c=cbck, ls='-', lw=1.) elif bck: out = cc.plot(lax=[dax['cross'][0], dax['hor'][0]], element='L', Lplot=Lplot, dL={'c':(0.4,0.4,0.4,0.4),'lw':0.5}, dLeg=None, draw=False) dax['cross'][0], dax['hor'][0] = out lHor = np.stack(lHor) idlCross = id(lCross) idlHor = id(lHor) elif c1: lCross, lHor = None, None else: lCross, lHor = None, None else: lCross, lHor = None, None # Background if bck: if nD == 1: if nnch == 1: env = [np.nanmin(data,axis=0), np.nanmax(data,axis=0)] dax['X'][0].fill_between(X.ravel(), env[0], env[1], facecolor=cbck) tbck = np.tile(np.r_[t, np.nan], nch) dbck = np.vstack((data, np.full((1,nch),np.nan))).T.ravel() dax['t'][0].plot(tbck, dbck, lw=1., ls='-', c=cbck) else: dax['t'][0].fill_between(t, np.nanmin(data,axis=1), np.nanmax(data,axis=1), facecolor=cbck) # Colorbars if 2D if nD == 2: # Data norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax) cb = mpl.colorbar.ColorbarBase(dax['colorbar'][0], cmap=cmap, orientation='vertical', norm=norm) dax['colorbar'][0].set_ylabel(Dlab, **fldict) # topos norm_topos = mpl.colors.Normalize(vmin=vmin_topos, vmax=vmax_topos) cb = mpl.colorbar.ColorbarBase(dax['colorbar'][1], cmap=cmap_topos, orientation='vertical', norm=norm_topos) dax['colorbar'][1].set_ylabel(r'topos (a.u.)', **fldict) # modes dax['m'][0].plot(s, ls='-', marker='.', c='k', lw=1.) # Zero for chronos and topos for ii in range(1,len(dax['t'])): dax['t'][ii].axhline(0., c='k', ls='--', lw=1.) if nD == 1: for ii in range(1,len(dax['t'])): dax['X'][ii].axhline(0., c='k', ls='--', lw=1.) # --------------- # Lims and labels dax['t'][0].set_xlim(Dt) dax['t'][0].set_ylim(Dd) dax['t'][1].set_ylim(Dchronos) for ii in range(0,len(dax['t'])): dax['t'][ii].set_ylabel(Dlab, **fldict) dax['t'][-1].set_xlabel(tlab, **fldict) dax['m'][0].set_xlabel(r'mode index') dax['m'][0].set_ylabel(r'sing. value') dax['m'][0].set_xlim(Dm) dax['m'][0].set_ylim(Ds) if nD == 1: dax['X'][0].set_xlim(DX) dax['X'][-1].set_xlabel(Xlab, **fldict) dax['X'][1].set_ylim(Dtopos) else: dax['X'][0].set_xlim(extent[:2]) dax['X'][0].set_ylim(extent[2:]) # invert if invert and nD == 2: # shared axis => inverting the reference is enough dax['X'][0].invert_xaxis() dax['X'][0].invert_yaxis() ################## # Interactivity dict ################## # dgroup dgroup = {'time': {'nMax':ntMax, 'key':'f1', 'defid':idt, 'defax':dax['t'][0]}, 'channel': {'nMax':nchMax, 'key':'f2', 'defid':idX, 'defax':dax['X'][0]}, 'mode': {'nMax':nmMax, 'key':'f3', 'defid':idm, 'defax':dax['m'][0]}} msg = ' '.join(['%s: %s'%(v['key'],k) for k, v in dgroup.items()]) l0 = dax['txtg'][0].text(0.05, 0.4, msg, color='k', fontweight='bold', fontsize=6., ha='left', va='center') # dref dref = {idt: {'group':'time', 'val':t, 'inc':inct}, idX: {'group':'channel', 'val':X, 'inc':incX, 'otherid':Xother, 'indother':indtX}, idm: {'group':'mode', 'val':indmodes, 'inc':incm}} if nD == 2: dref[idX]['2d'] = (x1,x2) # ddata ddat = {iddata: {'val':data, 'refids':[idt,idX]}, idchans:{'val':dchans, 'refids':[idX]}, idchronos: {'val':chronos.T, 'refids':[idm]}, idtopos: {'val':topos, 'refids':[idm]}} if lCross not in [None, False]: ddat[idlCross] = {'val':lCross, 'refids':[idX]} ddat[idlHor] = {'val':lHor, 'refids':[idX]} if nD == 2: ddat[idx12] = {'val':(x1,x2), 'refids':[idX]} # dax lax_fix = (dax['cross'] + dax['hor'] + dax['txtg'] + dax['txtt'] + dax['txtx'] + dax['txtm']) dax2 = dict([(ax, {'ref':{idt:'x'}}) for ax in dax['t']]) if nD == 1: dax2.update(dict([(ax, {'ref':{idX:'x'}}) for ax in dax['X']])) else: dax2.update(dict([(ax, {'ref':{idX:'2d'}, 'invert':invert}) for ax in dax['X']])) dax2[dax['m'][0]] = {'ref':{idm:'x'}} # dobj dobj = {} ################## # Populating dobj ################## nant = np.full((nt,),np.nan) nanch = np.full((nch,),np.nan) # Channel for jj in range(0,nchMax): # Channel text l0 = dax['txtx'][0].text((0.5+jj)/nchMax, 0., r'', color=lcch[jj], fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':idchans, 'lrid':[idX], 'bstr':'{0:%s}'%fmt_X}}, 'drefid':{idX:jj}} # Channel time trace l0, = dax['t'][0].plot(t, nant, c=lcch[jj], ls='-', lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':iddata, 'lrid':[idX]}}, 'drefid':{idX:jj}} # Channel vlines or pixels if nD == 1: if Xother is None: for ll in range(0,len(dax['X'])): l0 = dax['X'][ll].axvline(np.nan, c=lcch[jj], ls='-', lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':idX, 'lrid':[idX]}}, 'drefid':{idX:jj}} else: for ll in range(0,len(dax['X'])): for ii in range(0,ntMax): l0 = dax['X'][ll].axvline(np.nan, c=lcch[jj], ls='-', lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':idX, 'lrid':[idt,idX]}}, 'drefid':{idX:jj, idt:ii}} # los if c1: l, = dax['cross'][0].plot([np.nan,np.nan], [np.nan,np.nan], c=lcch[jj], ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':idlCross, 'lrid':[idX]}}, 'drefid':{idX:jj}} l, = dax['hor'][0].plot([np.nan,np.nan], [np.nan,np.nan], c='k', ls='-', lw=2.) dobj[l] = {'dupdate':{'data':{'id':idlHor, 'lrid':[idX]}}, 'drefid':{idX:jj}} # Time if nD == 2: nan2 = np.full((x2.size,x1.size),np.nan) for jj in range(0,ntMax): # Time txt l0 = dax['txtt'][0].text((0.5+jj)/ntMax, 0., r'', color=lct[jj], fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':idt, 'lrid':[idt], 'bstr':'{0:%s} s'%fmt_t}}, 'drefid':{idt:jj}} # Time vlines for ll in range(0,len(dax['t'])): l0 = dax['t'][ll].axvline(np.nan, c=lct[jj], ls='-', lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':idt, 'lrid':[idt]}}, 'drefid':{idt:jj}} # Time data profiles if nD == 1: l0, = dax['X'][0].plot(X[0,:], nanch, c=lct[jj], ls='-', lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':iddata, 'lrid':[idt]}}, 'drefid':{idt:jj}} if Xother not in [None, False]: dobj[l0]['dupdate']['xdata'] = {'id':idX, 'lrid':[Xother]} else: im = dax['X'][0].imshow(nan2, extent=extent, aspect='equal', interpolation='nearest', origin='lower', zorder=-1, norm=norm, cmap=cmap) dobj[im] = {'dupdate':{'data-reshape':{'id':iddata, 'n12':n12, 'lrid':[idt]}}, 'drefid':{idt:jj}} # modes for jj in range(0,nmMax): # mode txt l0 = dax['txtm'][jj].text(0.5, 0., r'', color=lcm[jj%2], fontweight='bold', fontsize=6., ha='center', va='bottom') dobj[l0] = {'dupdate':{'txt':{'id':idm, 'lrid':[idm], 'bstr':'mode {0:%s}'%fmt_m}}, 'drefid':{idm:jj}} # mode vlines l0 = dax['m'][0].axvline(np.nan, c=lcm[jj%2], ls='-', lw=1.) dobj[l0] = {'dupdate':{'xdata':{'id':idm, 'lrid':[idm]}}, 'drefid':{idm:jj}} # Chronos l0, = dax['t'][jj//2+1].plot(t, nant, c=lcm[jj%2], ls='-', lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':idchronos, 'lrid':[idm]}}, 'drefid':{idm:jj}} # Topos if nD == 1: l0, = dax['X'][jj//2+1].plot(X[0,:], nanch, c=lcm[jj%2], ls='-', lw=1.) dobj[l0] = {'dupdate':{'ydata':{'id':idtopos, 'lrid':[idm]}}, 'drefid':{idm:jj}} if Xother not in [None, False]: dobj[l0]['dupdate']['xdata'] = {'id':idX, 'lrid':[Xother]} else: im = dax['X'][jj+1].imshow(nan2, extent=extent, aspect='equal', interpolation='nearest', origin='lower', zorder=-1, norm=norm_topos, cmap=cmap_topos) dobj[im] = {'dupdate':{'data-reshape':{'id':idtopos, 'n12':n12, 'lrid':[idm]}}, 'drefid':{idm:jj}} # pixel on top of imshows if nD == 2: for jj in range(0,nchMax): for ll in range(0,len(dax['X'])): l0, = dax['X'][ll].plot([np.nan],[np.nan], mec=lcch[jj], ls='None', marker='s', mew=2., ms=ms, mfc='None', zorder=10) dobj[l0] = {'dupdate':{'data':{'id':idx12, 'lrid':[idX]}}, 'drefid':{idX:jj}} # Instanciate KeyHandler can = fig.canvas can.draw() kh = utils.KeyHandler_mpl(can=can, dgroup=dgroup, dref=dref, ddata=ddat, dobj=dobj, dax=dax2, lax_fix=lax_fix, groupinit='time', follow=True) if connect: kh.disconnect_old() kh.connect() if draw: can.draw() return kh