MLD_obs = netCDF4.Dataset(cmdLineArgs.obsdata).variables['MLD'][:] x_obs = netCDF4.Dataset(cmdLineArgs.obsdata).variables['LONGITUDE'][:] y_obs = netCDF4.Dataset(cmdLineArgs.obsdata).variables['LATITUDE'][:] ciMin = m6plot.linCI(0,95,5) ciMax = m6plot.linCI(0,680,20) # Plot of shallowest model MLD (summer) m6plot.xyplot( MLD.min(axis=0), x, y, area=area, suptitle=rootGroup.title+' '+cmdLineArgs.label, title='Annual-minimum MLD$_{0.03}$ [m]', clim=ciMin, extend='max', colormap='dunneRainbow', save=cmdLineArgs.outdir+'/MLD_003_minimum.png') # 2-panel plot of shallowest model MLD + obs (summer) m6plot.setFigureSize(aspect=[3,3], verticalresolution=976, npanels=0) ax1 = plt.subplot(2,1,1) m6plot.xyplot( numpy.roll(MLD_obs.min(axis=0),300,axis=-1), x_obs-300, y_obs, suptitle=rootGroup.title+' '+cmdLineArgs.label, title='Hosoda et al., 2010, annual-minimum MLD$_{0.03}$ [m]', clim=ciMin, extend='max', colormap='dunneRainbow', axis=ax1) ax2 = plt.subplot(2,1,2) m6plot.xyplot( MLD.min(axis=0), x, y, area=area, suptitle=rootGroup.title+' '+cmdLineArgs.label, title='Annual-minimum MLD$_{0.03}$ [m]', clim=ciMin, extend='max', colormap='dunneRainbow', axis=ax2, save=cmdLineArgs.outdir+'/MLD_003_minimum.2_panel.png') # Plot of deepest model MLD (winter) m6plot.xyplot( MLD.max(axis=0), x, y, area=area, suptitle=rootGroup.title+' '+cmdLineArgs.label, title='Annual-maximum MLD$_{0.03}$ [m]',
def main(cmdLineArgs, stream=False): rootGroup = netCDF4.MFDataset(cmdLineArgs.infile) if 'MLD_003' not in rootGroup.variables: raise Exception('Could not find "MLD_003" in file "%s"' % (cmdLineArgs.infile)) if not os.path.exists(cmdLineArgs.gridspec): raise ValueError( 'Specified gridspec directory/tar file does not exist.') if os.path.isdir(cmdLineArgs.gridspec): x = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['x'][::2, ::2] y = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['y'][::2, ::2] msk = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_mask.nc').variables['mask'][:] area = msk * netCDF4.Dataset( cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['area'][:, :].reshape( [msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) elif os.path.isfile(cmdLineArgs.gridspec): x = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'x')[::2, ::2] y = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'y')[::2, ::2] msk = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_mask.nc', 'mask')[:] area = msk * m6toolbox.readNCFromTar( cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'area')[:, :].reshape( [msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) else: raise ValueError( 'Unable to extract grid information from gridspec directory/tar file.' ) variable = rootGroup.variables['MLD_003'] shape = variable.shape MLD = variable[:].reshape(shape[0] / 12, 12, shape[1], shape[2]).mean(axis=0) if not hasattr(cmdLineArgs, 'obsdata') or cmdLineArgs.obsdata == '': cmdLineArgs.obsdata = '/archive/gold/datasets/obs/Hosada2010_MLD_climatology.v20140515.nc' MLD_obs = netCDF4.Dataset(cmdLineArgs.obsdata).variables['MLD'][:] x_obs = netCDF4.Dataset(cmdLineArgs.obsdata).variables['LONGITUDE'][:] y_obs = netCDF4.Dataset(cmdLineArgs.obsdata).variables['LATITUDE'][:] ciMin = m6plot.linCI(0, 95, 5) ciMax = m6plot.linCI(0, 680, 20) imgbufs = [] # Plot of shallowest model MLD (summer) m6plot.xyplot(MLD.min(axis=0), x, y, area=area, suptitle=rootGroup.title + ' ' + cmdLineArgs.label, title='Annual-minimum MLD$_{0.03}$ [m]', clim=ciMin, extend='max', colormap='dunneRainbow', save=cmdLineArgs.outdir + '/MLD_003_minimum.png') # 2-panel plot of shallowest model MLD + obs (summer) if stream is True: img = io.BytesIO() else: img = cmdLineArgs.outdir + '/MLD_003_minimum.2_panel.png' m6plot.setFigureSize(aspect=[3, 3], verticalresolution=976, npanels=0) ax1 = plt.subplot(2, 1, 1) m6plot.xyplot(numpy.roll(MLD_obs.min(axis=0), 300, axis=-1), x_obs - 300, y_obs, suptitle=rootGroup.title + ' ' + cmdLineArgs.label, title='Hosoda et al., 2010, annual-minimum MLD$_{0.03}$ [m]', clim=ciMin, extend='max', colormap='dunneRainbow', axis=ax1) ax2 = plt.subplot(2, 1, 2) m6plot.xyplot(MLD.min(axis=0), x, y, area=area, suptitle=rootGroup.title + ' ' + cmdLineArgs.label, title='Annual-minimum MLD$_{0.03}$ [m]', clim=ciMin, extend='max', colormap='dunneRainbow', axis=ax2, save=img) if stream is True: imgbufs.append(img) # Plot of deepest model MLD (winter) m6plot.xyplot(MLD.max(axis=0), x, y, area=area, suptitle=rootGroup.title + ' ' + cmdLineArgs.label, title='Annual-maximum MLD$_{0.03}$ [m]', clim=ciMax, extend='max', colormap='dunneRainbow', save=cmdLineArgs.outdir + '/MLD_003_maximum.png') # 2-panel plot of deepest model MLD + obs (winter) if stream is True: img = io.BytesIO() else: img = cmdLineArgs.outdir + '/MLD_003_maximum.2_panel.png' m6plot.setFigureSize(aspect=[3, 3], verticalresolution=976, npanels=0) ax1 = plt.subplot(2, 1, 1) m6plot.xyplot(numpy.roll(MLD_obs.max(axis=0), 300, axis=-1), x_obs - 300, y_obs, suptitle=rootGroup.title + ' ' + cmdLineArgs.label, title='Hosoda et al., 2010, annual-maximum MLD$_{0.03}$ [m]', clim=ciMax, extend='max', colormap='dunneRainbow', axis=ax1) ax2 = plt.subplot(2, 1, 2) m6plot.xyplot(MLD.max(axis=0), x, y, area=area, suptitle=rootGroup.title + ' ' + cmdLineArgs.label, title='Annual-maximum MLD$_{0.03}$ [m]', clim=ciMax, extend='max', colormap='dunneRainbow', axis=ax2, save=img) if stream is True: imgbufs.append(img) if stream is True: return imgbufs
def main(cmdLineArgs, stream=None): if not os.path.exists(cmdLineArgs.gridspec): raise ValueError( 'Specified gridspec directory/tar file does not exist.') if os.path.isdir(cmdLineArgs.gridspec): x = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['x'][::2, ::2] xcenter = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['x'][1::2, 1::2] y = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['y'][::2, ::2] ycenter = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['y'][1::2, 1::2] msk = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_mask.nc').variables['mask'][:] area = msk * netCDF4.Dataset( cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['area'][:, :].reshape( [msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) depth = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_topog.nc').variables['depth'][:] try: basin_code = netCDF4.Dataset( cmdLineArgs.gridspec + '/basin_codes.nc').variables['basin'][:] except: basin_code = m6toolbox.genBasinMasks(xcenter, ycenter, depth) elif os.path.isfile(cmdLineArgs.gridspec): x = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'x')[::2, ::2] xcenter = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'x')[1::2, 1::2] y = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'y')[::2, ::2] ycenter = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'y')[1::2, 1::2] msk = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_mask.nc', 'mask')[:] area = msk * m6toolbox.readNCFromTar( cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'area')[:, :].reshape( [msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) depth = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_topog.nc', 'depth')[:] try: basin_code = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'basin_codes.nc', 'basin')[:] except: basin_code = m6toolbox.genBasinMasks(xcenter, ycenter, depth) else: raise ValueError( 'Unable to extract grid information from gridspec directory/tar file.' ) if stream != None: if len(stream) != 2: raise ValueError( 'If specifying output streams, exactly two streams are needed for this analysis' ) rootGroup = netCDF4.MFDataset(cmdLineArgs.annual_file) if 'vh' in rootGroup.variables: varName = 'vh' conversion_factor = 1.e-9 elif 'vmo' in rootGroup.variables: varName = 'vmo' conversion_factor = 1.e-9 else: raise Exception('Could not find "vh" or "vmo" in file "%s"' % (cmdLineArgs.annual_file)) if len(rootGroup.variables[varName].shape) == 4: VHmod = rootGroup.variables[varName][:].mean(axis=0) else: VHmod = rootGroup.variables[varName][:] try: VHmod = VHmod.filled(0.) except: pass if 'e' in rootGroup.variables: Zmod = rootGroup.variables['e'][0] elif 'zw' in rootGroup.variables: zw = rootGroup.variables['zw'][:] Zmod = numpy.zeros((zw.shape[0], depth.shape[0], depth.shape[1])) for k in range(zw.shape[0]): Zmod[k] = -numpy.minimum(depth, abs(zw[k])) else: raise Exception( 'Neither a model-space output file or a z-space diagnostic file?') def MOCpsi(vh, vmsk=None): """Sums 'vh' zonally and cumulatively in the vertical to yield an overturning stream function, psi(y,z).""" shape = list(vh.shape) shape[-3] += 1 psi = numpy.zeros(shape[:-1]) if len(shape) == 3: for k in range(shape[-3] - 1, 0, -1): if vmsk is None: psi[k - 1, :] = psi[k, :] - vh[k - 1].sum(axis=-1) else: psi[k - 1, :] = psi[k, :] - (vmsk * vh[k - 1]).sum(axis=-1) else: for n in range(shape[0]): for k in range(shape[-3] - 1, 0, -1): if vmsk is None: psi[n, k - 1, :] = psi[n, k, :] - vh[n, k - 1].sum(axis=-1) else: psi[n, k - 1, :] = psi[n, k, :] - (vmsk * vh[n, k - 1]).sum(axis=-1) return psi def plotPsi(y, z, psi, ci, title): cmap = plt.get_cmap('dunnePM') plt.contourf(y, z, psi, levels=ci, cmap=cmap, extend='both') cbar = plt.colorbar() plt.contour(y, z, psi, levels=ci, colors='k', hold='on') plt.gca().set_yscale('splitscale', zval=[0, -2000, -6500]) plt.title(title) cbar.set_label('[Sv]') plt.ylabel('Elevation [m]') def findExtrema(y, z, psi, min_lat=-90., max_lat=90., min_depth=0., mult=1.): psiMax = mult * numpy.amax( mult * numpy.ma.array(psi)[(y >= min_lat) & (y <= max_lat) & (z < -min_depth)]) idx = numpy.argmin(numpy.abs(psi - psiMax)) (j, i) = numpy.unravel_index(idx, psi.shape) plt.plot(y[j, i], z[j, i], 'kx', hold=True) plt.text(y[j, i], z[j, i], '%.1f' % (psi[j, i])) m6plot.setFigureSize(npanels=1) cmap = plt.get_cmap('dunnePM') if cmdLineArgs.suptitle != '': suptitle = cmdLineArgs.suptitle + ' ' + cmdLineArgs.label else: suptitle = rootGroup.title + ' ' + cmdLineArgs.label # Global MOC z = Zmod.min(axis=-1) psiPlot = MOCpsi(VHmod) * conversion_factor yy = y[1:, :].max(axis=-1) + 0 * z ci = m6plot.pmCI(0., 40., 5.) plotPsi(yy, z, psiPlot, ci, 'Global MOC [Sv]') plt.xlabel(r'Latitude [$\degree$N]') plt.suptitle(suptitle) findExtrema(yy, z, psiPlot, max_lat=-30.) findExtrema(yy, z, psiPlot, min_lat=25.) findExtrema(yy, z, psiPlot, min_depth=2000., mult=-1.) if stream != None: plt.savefig(stream[0]) else: plt.savefig(cmdLineArgs.outdir + '/MOC_global.png') # Atlantic MOC plt.clf() m = 0 * basin_code m[(basin_code == 2) | (basin_code == 4) | (basin_code == 6) | (basin_code == 7) | (basin_code == 8)] = 1 ci = m6plot.pmCI(0., 22., 2.) z = (m * Zmod).min(axis=-1) psiPlot = MOCpsi(VHmod, vmsk=m * numpy.roll(m, -1, axis=-2)) * conversion_factor yy = y[1:, :].max(axis=-1) + 0 * z plotPsi(yy, z, psiPlot, ci, 'Atlantic MOC [Sv]') plt.xlabel(r'Latitude [$\degree$N]') plt.suptitle(suptitle) findExtrema(yy, z, psiPlot, min_lat=26.5, max_lat=27.) # RAPID findExtrema(yy, z, psiPlot, max_lat=-33.) findExtrema(yy, z, psiPlot) findExtrema(yy, z, psiPlot, min_lat=5.) if stream != None: plt.savefig(stream[1]) else: plt.savefig(cmdLineArgs.outdir + '/MOC_Atlantic.png')
def main(cmdLineArgs,stream=None): if not os.path.exists(cmdLineArgs.gridspec): raise ValueError('Specified gridspec directory/tar file does not exist.') if os.path.isdir(cmdLineArgs.gridspec): x = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['x'][::2,::2] xcenter = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['x'][1::2,1::2] y = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['y'][::2,::2] ycenter = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['y'][1::2,1::2] msk = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_mask.nc').variables['mask'][:] area = msk*netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['area'][:,:].reshape([msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) depth = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_topog.nc').variables['depth'][:] try: basin_code = netCDF4.Dataset(cmdLineArgs.gridspec+'/basin_codes.nc').variables['basin'][:] except: basin_code = m6toolbox.genBasinMasks(xcenter, ycenter, depth) elif os.path.isfile(cmdLineArgs.gridspec): x = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','x')[::2,::2] xcenter = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','x')[1::2,1::2] y = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','y')[::2,::2] ycenter = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','y')[1::2,1::2] msk = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_mask.nc','mask')[:] area = msk*m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','area')[:,:].reshape([msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) depth = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_topog.nc','depth')[:] try: basin_code = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'basin_codes.nc','basin')[:] except: basin_code = m6toolbox.genBasinMasks(xcenter, ycenter, depth) else: raise ValueError('Unable to extract grid information from gridspec directory/tar file.') if stream != None: if len(stream) != 2: raise ValueError('If specifying output streams, exactly two streams are needed for this analysis') rootGroup = netCDF4.MFDataset( cmdLineArgs.annual_file ) if 'vh' in rootGroup.variables: varName = 'vh'; conversion_factor = 1.e-9 elif 'vmo' in rootGroup.variables: varName = 'vmo'; conversion_factor = 1.e-9 else: raise Exception('Could not find "vh" or "vmo" in file "%s"'%(cmdLineArgs.annual_file)) if len(rootGroup.variables[varName].shape)==4: VHmod = rootGroup.variables[varName][:].mean(axis=0) else: VHmod = rootGroup.variables[varName][:] try: VHmod = VHmod.filled(0.) except: pass if 'e' in rootGroup.variables: Zmod = rootGroup.variables['e'][0] elif 'zw' in rootGroup.variables: zw = rootGroup.variables['zw'][:] Zmod = numpy.zeros((zw.shape[0], depth.shape[0], depth.shape[1] )) for k in range(zw.shape[0]): Zmod[k] = -numpy.minimum( depth, abs(zw[k]) ) else: raise Exception('Neither a model-space output file or a z-space diagnostic file?') def MOCpsi(vh, vmsk=None): """Sums 'vh' zonally and cumulatively in the vertical to yield an overturning stream function, psi(y,z).""" shape = list(vh.shape); shape[-3] += 1 psi = numpy.zeros(shape[:-1]) if len(shape)==3: for k in range(shape[-3]-1,0,-1): if vmsk is None: psi[k-1,:] = psi[k,:] - vh[k-1].sum(axis=-1) else: psi[k-1,:] = psi[k,:] - (vmsk*vh[k-1]).sum(axis=-1) else: for n in range(shape[0]): for k in range(shape[-3]-1,0,-1): if vmsk is None: psi[n,k-1,:] = psi[n,k,:] - vh[n,k-1].sum(axis=-1) else: psi[n,k-1,:] = psi[n,k,:] - (vmsk*vh[n,k-1]).sum(axis=-1) return psi def plotPsi(y, z, psi, ci, title): cmap = plt.get_cmap('dunnePM') plt.contourf(y, z, psi, levels=ci, cmap=cmap, extend='both') cbar = plt.colorbar() plt.contour(y, z, psi, levels=ci, colors='k', hold='on') plt.gca().set_yscale('splitscale',zval=[0,-2000,-6500]) plt.title(title) cbar.set_label('[Sv]'); plt.ylabel('Elevation [m]') def findExtrema(y, z, psi, min_lat=-90., max_lat=90., min_depth=0., mult=1.): psiMax = mult*numpy.amax( mult * numpy.ma.array(psi)[(y>=min_lat) & (y<=max_lat) & (z<-min_depth)] ) idx = numpy.argmin(numpy.abs(psi-psiMax)) (j,i) = numpy.unravel_index(idx, psi.shape) plt.plot(y[j,i],z[j,i],'kx',hold=True) plt.text(y[j,i],z[j,i],'%.1f'%(psi[j,i])) m6plot.setFigureSize(npanels=1) cmap = plt.get_cmap('dunnePM') if cmdLineArgs.suptitle != '': suptitle = cmdLineArgs.suptitle + ' ' + cmdLineArgs.label else: suptitle = rootGroup.title + ' ' + cmdLineArgs.label # Global MOC z = Zmod.min(axis=-1); psiPlot = MOCpsi(VHmod)*conversion_factor yy = y[1:,:].max(axis=-1)+0*z ci=m6plot.pmCI(0.,40.,5.) plotPsi(yy, z, psiPlot, ci, 'Global MOC [Sv]') plt.xlabel(r'Latitude [$\degree$N]') plt.suptitle(suptitle) findExtrema(yy, z, psiPlot, max_lat=-30.) findExtrema(yy, z, psiPlot, min_lat=25.) findExtrema(yy, z, psiPlot, min_depth=2000., mult=-1.) if stream != None: plt.savefig(stream[0]) else: plt.savefig(cmdLineArgs.outdir+'/MOC_global.png') # Atlantic MOC plt.clf() m = 0*basin_code; m[(basin_code==2) | (basin_code==4) | (basin_code==6) | (basin_code==7) | (basin_code==8)]=1 ci=m6plot.pmCI(0.,22.,2.) z = (m*Zmod).min(axis=-1); psiPlot = MOCpsi(VHmod, vmsk=m*numpy.roll(m,-1,axis=-2))*conversion_factor yy = y[1:,:].max(axis=-1)+0*z plotPsi(yy, z, psiPlot, ci, 'Atlantic MOC [Sv]') plt.xlabel(r'Latitude [$\degree$N]') plt.suptitle(suptitle) findExtrema(yy, z, psiPlot, min_lat=26.5, max_lat=27.) # RAPID findExtrema(yy, z, psiPlot, max_lat=-33.) findExtrema(yy, z, psiPlot) findExtrema(yy, z, psiPlot, min_lat=5.) if stream != None: plt.savefig(stream[1]) else: plt.savefig(cmdLineArgs.outdir+'/MOC_Atlantic.png')
def main(cmdLineArgs, stream=False): if not os.path.exists(cmdLineArgs.gridspec): raise ValueError( 'Specified gridspec directory/tar file does not exist.') if os.path.isdir(cmdLineArgs.gridspec): x = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['x'][::2, ::2] xcenter = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['x'][1::2, 1::2] y = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['y'][::2, ::2] ycenter = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['y'][1::2, 1::2] msk = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_mask.nc').variables['mask'][:] area = msk * netCDF4.Dataset( cmdLineArgs.gridspec + '/ocean_hgrid.nc').variables['area'][:, :].reshape( [msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) depth = netCDF4.Dataset(cmdLineArgs.gridspec + '/ocean_topog.nc').variables['depth'][:] try: basin_code = netCDF4.Dataset( cmdLineArgs.gridspec + '/basin_codes.nc').variables['basin'][:] except: basin_code = m6toolbox.genBasinMasks(xcenter, ycenter, depth) elif os.path.isfile(cmdLineArgs.gridspec): x = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'x')[::2, ::2] xcenter = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'x')[1::2, 1::2] y = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'y')[::2, ::2] ycenter = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'y')[1::2, 1::2] msk = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_mask.nc', 'mask')[:] area = msk * m6toolbox.readNCFromTar( cmdLineArgs.gridspec, 'ocean_hgrid.nc', 'area')[:, :].reshape( [msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) depth = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'ocean_topog.nc', 'depth')[:] try: basin_code = m6toolbox.readNCFromTar(cmdLineArgs.gridspec, 'basin_codes.nc', 'basin')[:] except: basin_code = m6toolbox.genBasinMasks(xcenter, ycenter, depth) else: raise ValueError( 'Unable to extract grid information from gridspec directory/tar file.' ) rootGroup = netCDF4.MFDataset(cmdLineArgs.infile) if 'T_ady_2d' in rootGroup.variables: varName = 'T_ady_2d' advective = rootGroup.variables[varName] advective.data = advective[:].filled(0.) else: raise Exception('Could not find "T_ady_2d" in file "%s"' % (cmdLineArgs.infile)) if 'T_diffy_2d' in rootGroup.variables: varName = 'T_diffy_2d' diffusive = rootGroup.variables[varName][:].filled(0.) else: diffusive = None warnings.warn( 'Diffusive temperature term not found. This will result in an underestimation of the heat transport.' ) def heatTrans(advective, diffusive=None, vmask=None): """Converts vertically integrated temperature advection into heat transport""" if diffusive != None: HT = advective[:] + diffusive[:] else: HT = advective[:] if len(HT.shape) == 3: HT = HT.mean(axis=0) if advective.units == "Celsius meter3 second-1": rho0 = 1.035e3 Cp = 3989. HT = HT * (rho0 * Cp) HT = HT * 1.e-15 # convert to PW elif advective.units == "W m-2": HT = HT * 1.e-15 else: print('Unknown units') if vmask != None: HT = HT * vmask HT = HT.sum(axis=-1) HT = HT.squeeze() # sum in x-direction return HT def plotHeatTrans(y, HT, title, xlim=(-80, 90)): plt.plot(y, y * 0., 'k', linewidth=0.5) plt.plot(y, HT, 'r', linewidth=1.5, label='Model') plt.xlim(xlim) plt.ylim(-2.5, 3.0) plt.title(title) plt.grid(True) def annotatePlot(label): fig = plt.gcf() #fig.text(0.1,0.85,label) fig.text(0.535, 0.12, label) def annotateObs(): fig = plt.gcf() fig.text( 0.1, 0.85, r"Trenberth, K. E. and J. M. Caron, 2001: Estimates of Meridional Atmosphere and Ocean Heat Transports. J.Climate, 14, 3433-3443.", fontsize=8) fig.text( 0.1, 0.825, r"Ganachaud, A. and C. Wunsch, 2000: Improved estimates of global ocean circulation, heat transport and mixing from hydrographic data.", fontsize=8) fig.text(0.13, 0.8, r"Nature, 408, 453-457", fontsize=8) m6plot.setFigureSize(npanels=1) # Load Observations fObs = netCDF4.Dataset( '/archive/John.Krasting/obs/TC2001/Trenberth_and_Caron_Heat_Transport.nc' ) #Trenberth and Caron yobs = fObs.variables['ylat'][:] NCEP = {} NCEP['Global'] = fObs.variables['OTn'] NCEP['Atlantic'] = fObs.variables['ATLn'][:] NCEP['IndoPac'] = fObs.variables['INDPACn'][:] ECMWF = {} ECMWF['Global'] = fObs.variables['OTe'][:] ECMWF['Atlantic'] = fObs.variables['ATLe'][:] ECMWF['IndoPac'] = fObs.variables['INDPACe'][:] #G and W Global = {} Global['lat'] = numpy.array([-30., -19., 24., 47.]) Global['trans'] = numpy.array([-0.6, -0.8, 1.8, 0.6]) Global['err'] = numpy.array([0.3, 0.6, 0.3, 0.1]) Atlantic = {} Atlantic['lat'] = numpy.array( [-45., -30., -19., -11., -4.5, 7.5, 24., 47.]) Atlantic['trans'] = numpy.array( [0.66, 0.35, 0.77, 0.9, 1., 1.26, 1.27, 0.6]) Atlantic['err'] = numpy.array( [0.12, 0.15, 0.2, 0.4, 0.55, 0.31, 0.15, 0.09]) IndoPac = {} IndoPac['lat'] = numpy.array([-30., -18., 24., 47.]) IndoPac['trans'] = numpy.array([-0.9, -1.6, 0.52, 0.]) IndoPac['err'] = numpy.array([ 0.3, 0.6, 0.2, 0.05, ]) GandW = {} GandW['Global'] = Global GandW['Atlantic'] = Atlantic GandW['IndoPac'] = IndoPac def plotGandW(lat, trans, err): low = trans - err high = trans + err for n in range(0, len(low)): if n == 0: plt.plot([lat[n], lat[n]], [low[n], high[n]], 'c', linewidth=2.0, label='G&W') else: plt.plot([lat[n], lat[n]], [low[n], high[n]], 'c', linewidth=2.0) plt.scatter(lat, trans, marker='s', facecolor='cyan') if cmdLineArgs.suptitle != '': suptitle = cmdLineArgs.suptitle + ' ' + cmdLineArgs.label else: suptitle = rootGroup.title + ' ' + cmdLineArgs.label imgbufs = [] # Global Heat Transport HTplot = heatTrans(advective, diffusive) yy = y[1:, :].max(axis=-1) plotHeatTrans(yy, HTplot, title='Global Y-Direction Heat Transport [PW]') plt.plot(yobs, NCEP['Global'], 'k--', linewidth=0.5, label='NCEP') plt.plot(yobs, ECMWF['Global'], 'k.', linewidth=0.5, label='ECMWF') plotGandW(GandW['Global']['lat'], GandW['Global']['trans'], GandW['Global']['err']) plt.xlabel(r'Latitude [$\degree$N]') plt.suptitle(suptitle) plt.legend(loc=0, fontsize=10) annotateObs() if diffusive is None: annotatePlot('Warning: Diffusive component of transport is missing.') if stream is True: objOut = io.BytesIO() else: objOut = cmdLineArgs.outdir + '/HeatTransport_global.png' plt.savefig(objOut) if stream is True: imgbufs.append(objOut) # Atlantic Heat Transport plt.clf() m = 0 * basin_code m[(basin_code == 2) | (basin_code == 4) | (basin_code == 6) | (basin_code == 7) | (basin_code == 8)] = 1 HTplot = heatTrans(advective, diffusive, vmask=m * numpy.roll(m, -1, axis=-2)) yy = y[1:, :].max(axis=-1) HTplot[yy < -34] = numpy.nan plotHeatTrans(yy, HTplot, title='Atlantic Y-Direction Heat Transport [PW]') plt.plot(yobs, NCEP['Atlantic'], 'k--', linewidth=0.5, label='NCEP') plt.plot(yobs, ECMWF['Atlantic'], 'k.', linewidth=0.5, label='ECMWF') plotGandW(GandW['Atlantic']['lat'], GandW['Atlantic']['trans'], GandW['Atlantic']['err']) plt.xlabel(r'Latitude [$\degree$N]') plt.suptitle(suptitle) plt.legend(loc=0, fontsize=10) annotateObs() if diffusive is None: annotatePlot('Warning: Diffusive component of transport is missing.') if stream is True: objOut = io.BytesIO() else: objOut = cmdLineArgs.outdir + '/HeatTransport_Atlantic.png' plt.savefig(objOut) if stream is True: imgbufs.append(objOut) # Indo-Pacific Heat Transport plt.clf() m = 0 * basin_code m[(basin_code == 3) | (basin_code == 5)] = 1 HTplot = heatTrans(advective, diffusive, vmask=m * numpy.roll(m, -1, axis=-2)) yy = y[1:, :].max(axis=-1) HTplot[yy < -34] = numpy.nan plotHeatTrans(yy, HTplot, title='Indo-Pacific Y-Direction Heat Transport [PW]') plt.plot(yobs, NCEP['IndoPac'], 'k--', linewidth=0.5, label='NCEP') plt.plot(yobs, ECMWF['IndoPac'], 'k.', linewidth=0.5, label='ECMWF') plotGandW(GandW['IndoPac']['lat'], GandW['IndoPac']['trans'], GandW['IndoPac']['err']) plt.xlabel(r'Latitude [$\degree$N]') annotateObs() if diffusive is None: annotatePlot('Warning: Diffusive component of transport is missing.') plt.suptitle(suptitle) plt.legend(loc=0, fontsize=10) if stream is True: objOut = io.BytesIO() else: objOut = cmdLineArgs.outdir + '/HeatTransport_IndoPac.png' plt.savefig(objOut) if stream is True: imgbufs.append(objOut) if stream is True: return imgbufs
ciMax = m6plot.linCI(0, 680, 20) # Plot of shallowest model MLD (summer) m6plot.xyplot(MLD.min(axis=0), x, y, area=area, suptitle=rootGroup.title + ' ' + cmdLineArgs.label, title='Annual-minimum MLD$_{0.03}$ [m]', clim=ciMin, extend='max', colormap='dunneRainbow', save=cmdLineArgs.outdir + '/MLD_003_minimum.png') # 2-panel plot of shallowest model MLD + obs (summer) m6plot.setFigureSize(aspect=[3, 3], verticalresolution=976, npanels=0) ax1 = plt.subplot(2, 1, 1) m6plot.xyplot(numpy.roll(MLD_obs.min(axis=0), 300, axis=-1), x_obs - 300, y_obs, suptitle=rootGroup.title + ' ' + cmdLineArgs.label, title='Hosoda et al., 2010, annual-minimum MLD$_{0.03}$ [m]', clim=ciMin, extend='max', colormap='dunneRainbow', axis=ax1) ax2 = plt.subplot(2, 1, 2) m6plot.xyplot(MLD.min(axis=0), x, y, area=area,
suptitle=rootGroup.title+' '+cmdLineArgs.label, title=r'''170$\degree$W $\theta$ bias (w.r.t. WOA'05) [$\degree$C]''', clim=ci, colormap='dunnePM', centerlabels=True, extend='both') cs1 = plt.contour( y[j0:j1,i][:] + 0*z, z, tObsPlot, levels=numpy.arange(0.,45,2.), colors='k' ); plt.clabel(cs1,fmt='%.0f') cs2 = plt.contour( y[j0:j1,i][:] + 0*z, z, tPlot, levels=numpy.arange(0.,45,2.), colors='g' ); plt.clabel(cs2,fmt='%.0f') plt.ylim(-1200,0) plt.savefig(cmdLineArgs.outdir+'/T_170W_bias_WOA05.png') m6plot.yzcompare( tPlot, tObsPlot , y[j0:j1,i], zi, splitscale=[0., -1000., -6500.], suptitle=rootGroup.title+' '+cmdLineArgs.label, title1=r'170$\degree$W $\theta$ [$\degree$C]', title2=r'''WOA'05 $\theta$ [$\degree$C]''', clim=m6plot.linCI(-2,29,.5), colormap='dunneRainbow', extend='max', dlim=ci, dcolormap='dunnePM', dextend='both', centerdlabels=True, save=cmdLineArgs.outdir+'/T_170W_bias_WOA05.3_panel.png') m6plot.setFigureSize(); axis=plt.gca() uPlot = rootGroup.variables['uo'][0,:,j0:j1,i] plt.contourf( y[j0:j1,i][:] + 0*z, z, uPlot, levels=m6plot.linCI(-0.5,1.3,0.1), cmap='spectral', extend='both') plt.colorbar(extend='both') cs1 = plt.contour( y[j0:j1,i][:] + 0*z, z, uPlot, levels=m6plot.linCI(-0.5,1.3,0.1), colors='k'); plt.clabel(cs1,cs1.levels[::2],fmt='%.1f',inline_spacing=1) plt.ylim(-600,0); plt.suptitle(rootGroup.title+' '+cmdLineArgs.label);plt.title(r'170$\degree$W u [m/s]') plt.xlabel(r'Latitude [$\degree$N]'); plt.ylabel('Elevation [m]') plt.savefig(cmdLineArgs.outdir+'/U_170W_bias_WOA05.png') # 140W, 20S-20N j0 = numpy.abs( y[:,0] + 20. ).argmin() j1 = numpy.abs( y[:,0] - 20. ).argmin() i = numpy.abs( numpy.mod( x[j0,:] + 140. + 360., 360. ) ).argmin() tPlot = rootGroup.variables[varName][0,:,j0:j1,i] tObsPlot = obsRootGroup.variables[OTvar][0,:,j0:j1,i] zi = Zobs[:,j0:j1,i]; z = 0.5 * ( zi[:-1] + zi[1:] )
plt.contourf(y, z, psi, levels=ci, cmap=cmap, extend='both') cbar = plt.colorbar() plt.contour(y, z, psi, levels=ci, colors='k', hold='on') plt.gca().set_yscale('splitscale',zval=[0,-2000,-6500]) plt.title(title) cbar.set_label('[Sv]'); plt.ylabel('Elevation [m]') #plt.xlabel(r'Latitude [$\degree$N]') def findExtrema(y, z, psi, min_lat=-90., max_lat=90., min_depth=0., mult=1.): psiMax = mult*numpy.amax( mult * numpy.ma.array(psi)[(y>=min_lat) & (y<=max_lat) & (z<-min_depth)] ) idx = numpy.argmin(numpy.abs(psi-psiMax)) (j,i) = numpy.unravel_index(idx, psi.shape) plt.plot(y[j,i],z[j,i],'kx',hold=True) plt.text(y[j,i],z[j,i],'%.1f'%(psi[j,i])) m6plot.setFigureSize(npanels=3) if len(cmdLineArgs.label1): title1 = cmdLineArgs.label1 else: title1 = rootGroup.title if len(cmdLineArgs.label2): title2 = cmdLineArgs.label2 else: title2 = rootGroupRef.title # Global MOC z = Zmod.min(axis=-1) yy = y[1:,:].max(axis=-1)+0*z psiPlotM = MOCpsi(VHmod)/1e6 psiPlotR = MOCpsi(VHref)/1e6 ci=m6plot.pmCI(0.,40.,5.) di=m6plot.pmCI(0.,5.,0.5) plt.subplot(311) plotPsi(yy, z, psiPlotM, ci, title1) findExtrema(yy, z, psiPlotM, max_lat=-30.)
def main(cmdLineArgs,stream=None): if not os.path.exists(cmdLineArgs.gridspec): raise ValueError('Specified gridspec directory/tar file does not exist.') if os.path.isdir(cmdLineArgs.gridspec): x = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['x'][::2,::2] xcenter = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['x'][1::2,1::2] y = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['y'][::2,::2] ycenter = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['y'][1::2,1::2] msk = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_mask.nc').variables['mask'][:] area = msk*netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_hgrid.nc').variables['area'][:,:].reshape([msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) depth = netCDF4.Dataset(cmdLineArgs.gridspec+'/ocean_topog.nc').variables['depth'][:] try: basin_code = netCDF4.Dataset(cmdLineArgs.gridspec+'/basin_codes.nc').variables['basin'][:] except: basin_code = m6toolbox.genBasinMasks(xcenter, ycenter, depth) elif os.path.isfile(cmdLineArgs.gridspec): x = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','x')[::2,::2] xcenter = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','x')[1::2,1::2] y = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','y')[::2,::2] ycenter = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','y')[1::2,1::2] msk = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_mask.nc','mask')[:] area = msk*m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_hgrid.nc','area')[:,:].reshape([msk.shape[0], 2, msk.shape[1], 2]).sum(axis=-3).sum(axis=-1) depth = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'ocean_topog.nc','depth')[:] try: basin_code = m6toolbox.readNCFromTar(cmdLineArgs.gridspec,'basin_codes.nc','basin')[:] except: basin_code = m6toolbox.genBasinMasks(xcenter, ycenter, depth) else: raise ValueError('Unable to extract grid information from gridspec directory/tar file.') if stream != None: if len(stream) != 3: raise ValueError('If specifying output streams, exactly three streams are needed for this analysis') rootGroup = netCDF4.MFDataset( cmdLineArgs.annual_file ) if 'T_ady_2d' in rootGroup.variables: varName = 'T_ady_2d' if len(rootGroup.variables[varName].shape)==3: advective = rootGroup.variables[varName][:].mean(axis=0).filled(0.) else: advective = rootGroup.variables[varName][:].filled(0.) else: raise Exception('Could not find "T_ady_2d" in file "%s"'%(cmdLineArgs.annual_file)) if 'T_diffy_2d' in rootGroup.variables: varName = 'T_diffy_2d' if len(rootGroup.variables[varName].shape)==3: diffusive = rootGroup.variables[varName][:].mean(axis=0).filled(0.) else: diffusive = rootGroup.variables[varName][:].filled(0.) else: diffusive = None warnings.warn('Diffusive temperature term not found. This will result in an underestimation of the heat transport.') def heatTrans(advective, diffusive=None, vmask=None): """Converts vertically integrated temperature advection into heat transport""" rho0 = 1.035e3; Cp = 3989. if diffusive != None: HT = advective + diffusive else: HT = advective HT = HT * (rho0 * Cp); HT = HT * 1.e-15 # convert to PW if vmask != None: HT = HT*vmask HT = HT.sum(axis=-1); HT = HT.squeeze() # sum in x-direction return HT def plotHeatTrans(y, HT, title, xlim=(-80,90)): plt.plot(y, y*0., 'k', linewidth=0.5) plt.plot(y, HT, 'r', linewidth=1.5,label='Model') plt.xlim(xlim); plt.ylim(-2.5,3.0) plt.title(title) plt.grid(True) def annotatePlot(label): fig = plt.gcf() #fig.text(0.1,0.85,label) fig.text(0.535,0.12,label) def annotateObs(): fig = plt.gcf() fig.text(0.1,0.85,r"Trenberth, K. E. and J. M. Caron, 2001: Estimates of Meridional Atmosphere and Ocean Heat Transports. J.Climate, 14, 3433-3443.", fontsize=8) fig.text(0.1,0.825,r"Ganachaud, A. and C. Wunsch, 2000: Improved estimates of global ocean circulation, heat transport and mixing from hydrographic data.", fontsize=8) fig.text(0.13,0.8,r"Nature, 408, 453-457", fontsize=8) m6plot.setFigureSize(npanels=1) # Load Observations fObs = netCDF4.Dataset('/archive/John.Krasting/obs/TC2001/Trenberth_and_Caron_Heat_Transport.nc') #Trenberth and Caron yobs = fObs.variables['ylat'][:] NCEP = {}; NCEP['Global'] = fObs.variables['OTn'] NCEP['Atlantic'] = fObs.variables['ATLn'][:]; NCEP['IndoPac'] = fObs.variables['INDPACn'][:] ECMWF = {}; ECMWF['Global'] = fObs.variables['OTe'][:] ECMWF['Atlantic'] = fObs.variables['ATLe'][:]; ECMWF['IndoPac'] = fObs.variables['INDPACe'][:] #G and W Global = {} Global['lat'] = numpy.array([-30., -19., 24., 47.]) Global['trans'] = numpy.array([-0.6, -0.8, 1.8, 0.6]) Global['err'] = numpy.array([0.3, 0.6, 0.3, 0.1]) Atlantic = {} Atlantic['lat'] = numpy.array([-45., -30., -19., -11., -4.5, 7.5, 24., 47.]) Atlantic['trans'] = numpy.array([0.66, 0.35, 0.77, 0.9, 1., 1.26, 1.27, 0.6]) Atlantic['err'] = numpy.array([0.12, 0.15, 0.2, 0.4, 0.55, 0.31, 0.15, 0.09]) IndoPac = {} IndoPac['lat'] = numpy.array([-30., -18., 24., 47.]) IndoPac['trans'] = numpy.array([-0.9, -1.6, 0.52, 0.]) IndoPac['err'] = numpy.array([0.3, 0.6, 0.2, 0.05,]) GandW = {} GandW['Global'] = Global GandW['Atlantic'] = Atlantic GandW['IndoPac'] = IndoPac def plotGandW(lat,trans,err): low = trans - err high = trans + err for n in range(0,len(low)): if n == 0: plt.plot([lat[n],lat[n]], [low[n],high[n]], 'c', linewidth=2.0, label='G&W') else: plt.plot([lat[n],lat[n]], [low[n],high[n]], 'c', linewidth=2.0) plt.scatter(lat,trans,marker='s',facecolor='cyan') if cmdLineArgs.suptitle != '': suptitle = cmdLineArgs.suptitle + ' ' + cmdLineArgs.label else: suptitle = rootGroup.title + ' ' + cmdLineArgs.label # Global Heat Transport HTplot = heatTrans(advective,diffusive) yy = y[1:,:].max(axis=-1) plotHeatTrans(yy,HTplot,title='Global Y-Direction Heat Transport [PW]') plt.plot(yobs,NCEP['Global'],'k--',linewidth=0.5,label='NCEP') plt.plot(yobs,ECMWF['Global'],'k.',linewidth=0.5,label='ECMWF') plotGandW(GandW['Global']['lat'],GandW['Global']['trans'],GandW['Global']['err']) plt.xlabel(r'Latitude [$\degree$N]') plt.suptitle(suptitle) plt.legend(loc=0,fontsize=10) annotateObs() if diffusive is None: annotatePlot('Warning: Diffusive component of transport is missing.') if stream != None: plt.savefig(stream[0]) else: plt.savefig(cmdLineArgs.outdir+'/HeatTransport_global.png') # Atlantic Heat Transport plt.clf() m = 0*basin_code; m[(basin_code==2) | (basin_code==4) | (basin_code==6) | (basin_code==7) | (basin_code==8)] = 1 HTplot = heatTrans(advective, diffusive, vmask=m*numpy.roll(m,-1,axis=-2)) yy = y[1:,:].max(axis=-1) HTplot[yy<-34] = numpy.nan plotHeatTrans(yy,HTplot,title='Atlantic Y-Direction Heat Transport [PW]') plt.plot(yobs,NCEP['Atlantic'],'k--',linewidth=0.5,label='NCEP') plt.plot(yobs,ECMWF['Atlantic'],'k.',linewidth=0.5,label='ECMWF') plotGandW(GandW['Atlantic']['lat'],GandW['Atlantic']['trans'],GandW['Atlantic']['err']) plt.xlabel(r'Latitude [$\degree$N]') plt.suptitle(suptitle) plt.legend(loc=0,fontsize=10) annotateObs() if diffusive is None: annotatePlot('Warning: Diffusive component of transport is missing.') if stream != None: plt.savefig(stream[1]) else: plt.savefig(cmdLineArgs.outdir+'/HeatTransport_Atlantic.png') # Indo-Pacific Heat Transport plt.clf() m = 0*basin_code; m[(basin_code==3) | (basin_code==5)] = 1 HTplot = heatTrans(advective, diffusive, vmask=m*numpy.roll(m,-1,axis=-2)) yy = y[1:,:].max(axis=-1) HTplot[yy<-34] = numpy.nan plotHeatTrans(yy,HTplot,title='Indo-Pacific Y-Direction Heat Transport [PW]') plt.plot(yobs,NCEP['IndoPac'],'k--',linewidth=0.5,label='NCEP') plt.plot(yobs,ECMWF['IndoPac'],'k.',linewidth=0.5,label='ECMWF') plotGandW(GandW['IndoPac']['lat'],GandW['IndoPac']['trans'],GandW['IndoPac']['err']) plt.xlabel(r'Latitude [$\degree$N]') annotateObs() if diffusive is None: annotatePlot('Warning: Diffusive component of transport is missing.') plt.suptitle(suptitle) plt.legend(loc=0,fontsize=10) if stream != None: plt.savefig(stream[2]) else: plt.savefig(cmdLineArgs.outdir+'/HeatTransport_IndoPac.png')