def l2w_required(inputfile, required, data={}, att={}): from acolite.shared import nc_data, nc_datasets, nc_atts datasets = nc_datasets(inputfile) if all([rd in datasets for rd in required]): for rd in required: if rd not in data: data[rd], att[rd] = nc_data(inputfile, rd, attributes=True) #att[rd] = nc_atts(inputfile, rd) return (True) else: return (False)
def planetscope_ac( bundle, output, limit=None, gas_transmittance=True, uoz_default=0.3, uwv_default=1.5, wvlut='201710C', ## use ancillary data for gas transmittances rather than defaults ancillary_data=True, ## do sky glint correction sky_correction=True, sky_correction_option='all', lut_pressure=True, pressure=None, model_selection='min_tau', rdark_list_selection='intercept', luts=['PONDER-LUT-201704-MOD1', 'PONDER-LUT-201704-MOD2'], extra_ac_parameters=True, ignore_sr_image=True, extend_limit=False, keep_l1r_ncdf=False, map_rgb=True, map_rgb_rhos=True, rgb_autorange=False, rgb_percentiles=[10, 90], rgb_range_min=[0.0, 0.0, 0.0], rgb_range_max=[0.15, 0.15, 0.15], nc_compression=True): import os from numpy import nanmax, nanmin, nanpercentile import dateutil from osgeo import gdal, osr from acolite.shared import nc_gatts, nc_datasets, nc_data, rtoa_to_rhos from acolite.output import nc_write, write_rgb from acolite.plotting import plot_dark_spectrum from acolite import planetscope, ac import acolite as aco import matplotlib as mpl data_type = None sub = None sr_image_file = None if bundle[-3:] == '.nc': try: import dateutil.parser metadata = nc_gatts(bundle) ## fix some metadata not supported in NetCDF metadata['TIME'] = dateutil.parser.parse(metadata["isotime"]) for mk in metadata: if ('BAND' in mk): metadata[mk] = metadata[mk].split(',') data_type = "NetCDF" except: data_type = None zipped = False if data_type == None: data_type = 'PlanetScope' if bundle[-4:] == '.zip': zipped = True import zipfile, shutil bundle_orig = '{}'.format(bundle) bundle, ext = os.path.splitext(bundle_orig) zip_ref = zipfile.ZipFile(bundle_orig, 'r') zip_ref.extractall(bundle) zip_ref.close() files = planetscope.bundle_test(bundle) metafile = None image_file = None if 'metadata' in files: metafile = files['metadata']['path'] if 'analytic' in files: image_file = files['analytic']['path'] if 'sr' in files: sr_image_file = files['sr']['path'] if metafile is not None: metadata = planetscope.parse_metadata(metafile) metadata['image_file'] = image_file else: bn, ex = os.path.splitext(os.path.basename(image_file)) sp = bn.split('_') fdate = sp[0] ftime = sp[1] sat = sp[3] time = dateutil.parser.parse(fdate + ftime) ## SuperDove! if sat[0] == '2': print('Processing SuperDove file!') metadata = {} metadata['lut_sensor'] = 'PlanetScope_SuperDove' metadata['platform'] = "PlanetScope" metadata['platform_id'] = sat #metadata['orbit'] = "DESCENDING" metadata['SATELLITE_ID'] = sat[0:2] metadata['SATELLITE_SENSOR'] = "PlanetScope_{}".format(sat) metadata['LUT_SENSOR'] = "PlanetScope_SuperDove" metadata['SENSOR'] = "PlanetScope" metadata['SATELLITE_PREFIX'] = "ps" metadata['ViewingIncidence'] = 0 metadata['ViewingAzimuth'] = 0. metadata['ViewZenith'] = 0. metadata['isotime'] = time.isoformat() metadata['THV'] = 0. metadata['PHIV'] = 0. metadata['DOY'] = time.strftime('%j') metadata['SE_DISTANCE'] = aco.shared.distance_se( metadata['DOY']) metadata['isodate'] = time.isoformat() metadata['image_file'] = image_file metadata['limit'] = limit metadata['TIME'] = time sd_bands = { 'Coastal-Blue': '444', 'Blue': '492', 'Green_i': '533', 'Green_ii': '566', 'Yellow': '612', 'Red': '666', 'Red-edge': '707', 'NIR': '866' } metadata['BANDS_ALL'] = [k for k in sd_bands.keys()] for ib, band in enumerate(sd_bands): metadata['{}-wave'.format(band)] = float( sd_bands[band]) / 1000. metadata['{}-wave_name'.format(band)] = sd_bands[band] metadata['{}-band_idx'.format(band)] = ib + 1 metadata['{}-f0'.format(band)] = 0 metadata['{}-to_radiance'.format(band)] = 0.01 # metadata['{}-to_reflectance'.format(band)] = 0.0001 metadata['{}-to_reflectance'.format(band)] = 1e-4 ds = gdal.Open(metadata['image_file']) gt = ds.GetGeoTransform() metadata['dims'] = (ds.RasterXSize, ds.RasterYSize) metadata['resolution'] = (gt[1], gt[5]) ds = None p, (xrange, yrange) = aco.planetscope.geo.get_projection(metadata) clon, clat = p((xrange[1] + xrange[0]) / 2, (yrange[1] + yrange[0]) / 2, inverse=True) sun = aco.shared.sunposition(metadata['isotime'], clon, clat) metadata['THS'] = sun['zenith'] metadata['PHIS'] = sun['azimuth'] metadata['AZI'] = 0 # metadata['PHIS'] - metadata['PHIV'] if limit is not None: ret = planetscope.geo.get_sub(metadata, limit) if type(ret) == int: print('Error computing subset.') return (1) sub, p, (xrange, yrange, grid_region) = ret sensor = metadata['LUT_SENSOR'] print(metadata) if sensor == 'PlanetScope_0d': print('Sensor {} not yet implemented'.format(sensor)) return () if ('lat' not in locals()) or ('lat' not in locals()): #print('Computing lat lon') if (data_type == "NetCDF") & ('limit' in metadata) & (limit is None): datasets = nc_datasets(bundle) print(datasets) if ('lon' in datasets) & ('lat' in datasets): lon = nc_data(bundle, 'lon') lat = nc_data(bundle, 'lat') else: lon, lat = planetscope.get_ll(metadata, limit=metadata['limit'], extend_limit=True) else: lon, lat = planetscope.get_ll(metadata, limit=limit, extend_limit=extend_limit) ## get NCEP & TOAST ancillary data if ancillary_data: ## use image/region mid-point pc_lon = lon[int(lon.shape[0] / 2), int(lon.shape[1] / 2)] pc_lat = lat[int(lat.shape[0] / 2), int(lat.shape[1] / 2)] pc_date = metadata['TIME'].strftime('%Y-%m-%d') pc_time = metadata['TIME'].hour + metadata[ 'TIME'].minute / 60. + metadata['TIME'].second / 3600. pc_anc = ac.ancillary.ancillary_get(pc_date, pc_lon, pc_lat, ftime=pc_time, kind='nearest') ## get pressure from ancillary data if not determined by user or by DEM if (pressure == None) & (lut_pressure): if 'press' not in pc_anc: print('No ancillary pressure found: using default.') pressure = None else: pressure = pc_anc['press']['interp'] if pressure is None: pressure = 1013.25 ## get gas transmittances if gas_transmittance: uoz = uoz_default uwv = uwv_default ## use ancillary data if provided if ancillary_data: if 'ozone' in pc_anc: uoz = pc_anc['ozone']['interp'] else: print( 'No ancillary ozone found: using default {}.'.format(uoz)) if 'p_water' in pc_anc: uwv = pc_anc['p_water']['interp'] / 10. else: print( 'No ancillary ozone found: using default {}.'.format(uwv)) ## compute transmittances tt_oz = ac.o3_transmittance(sensor, metadata, uoz=uoz) tt_wv = ac.wvlut_interp(min(79.999, metadata['THS']), metadata['THV'], uwv=uwv, sensor=sensor, config=wvlut) tt_gas = {btag: tt_oz[btag] * tt_wv[btag] for btag in tt_oz.keys()} ## Sky reflectance correction if sky_correction: rsky = ac.toa_rsky(metadata, pressure=pressure) if not os.path.exists(output): os.makedirs(output) if data_type == "NetCDF": obase = metadata['obase'] nc_l1r_new = False nc_file_l1r = '{}'.format(bundle) else: ## add PS satellite id if metadata['SENSOR'] == 'PlanetScope': obase = '{}_{}_{}'.format( metadata['SENSOR'], metadata['TIME'].strftime('%Y_%m_%d_%H_%M_%S'), 'PS{}'.format(metadata['SATELLITE_SENSOR'].split('_')[1])) else: obase = '{}_{}_{}'.format( metadata['SENSOR'], metadata['TIME'].strftime('%Y_%m_%d_%H_%M_%S'), 'RE{}'.format(metadata['SATELLITE_SENSOR'].split('-')[1])) nc_l1r_new = True nc_file_l1r = '{}/{}_L1R.nc'.format(output, obase) nc_file_l2r = '{}/{}_L2R.nc'.format(output, obase) bands = metadata['BANDS_ALL'] if extend_limit: offset = grid_region['off'] global_dims = (grid_region['dims'][1], grid_region['dims'][0]) else: offset = None global_dims = None ## read RTOA and get rdark rdark = {} rhod = {} for bi, band in enumerate(bands): ds_att = planetscope.get_band_att(metadata, band) parname_t = 'rhot_{}'.format(ds_att['wave_name']) parname_s = 'rhos_{}'.format(ds_att['wave_name']) print(parname_t) if data_type == "NetCDF": band_data = nc_data(bundle, parname_t) else: band_data = planetscope.get_rtoa(image_file, bi + 1, band, metadata, sub=sub) ## write to L1R NetCDF nc_write(nc_file_l1r, parname_t, band_data, dataset_attributes=ds_att, new=nc_l1r_new, attributes=metadata, global_dims=global_dims, offset=offset, nc_compression=nc_compression) nc_l1r_new = False ## apply gas correction if gas_transmittance: band_data /= tt_gas[band] ds_att['tt_gas'] = tt_gas[band] ## apply sky correction if sky_correction: if sky_correction_option == 'all': band_data -= rsky[band] ds_att['rsky'] = rsky[band] ## get rdark rdark[band] = nanpercentile(band_data, (0.1)) rhod[band] = { 'rhod': rdark[band], 'wave': ds_att['wave'] * 1000., 'tt_gas': tt_gas[band], 'raa': metadata['AZI'], 'vza': metadata['THV'], 'sza': metadata['THS'] } band_data = None print(rhod) ## select model lutd = aco.aerlut.import_luts(base_luts=luts) res = aco.ac.select_model2(rhod, sensor, pressure=pressure, lutd=lutd, rhod_tgas_cutoff=0.90, rhod_model_selection='min_tau') attributes = metadata ## a/c parameters if extra_ac_parameters: pars = res['lut_meta']['par'] else: pars = ['romix', 'dtott', 'utott', 'astot', 'rorayl'] ## get sensor RSR rsr_file = '{}/RSR/{}.txt'.format(aco.config['pp_data_dir'], sensor) rsr, rsr_bands = aco.shared.rsr_read(file=rsr_file) raa = metadata['AZI'] vza = metadata['THV'] sza = metadata['THS'] waves_mu = res['lut_meta']['wave'] band_pars = {b: {} for b in rhod} for ip, par in enumerate(pars): ip = [ i for i, value in enumerate(res['lut_meta']['par']) if value == par ] if len(ip) == 1: ip = ip[0] else: continue ret = res['rgi']((pressure, ip, waves_mu, raa, vza, sza, res['taua'])) for b in rhod: band_pars[b][par] = aco.shared.rsr_convolute( ret, waves_mu, rsr[b]['response'], rsr[b]['wave']) for b in res['rhod_sel']: attributes['{}-rdark'.format(b)] = res['rhod_sel'][b] for b in band_pars: attributes['{}-rpath'.format(b)] = band_pars[b]['romix'] for b in band_pars: for p in band_pars[b]: attributes['{}-{}'.format(b, p)] = band_pars[b][p] sel_model_lut_meta = res['lut_meta'] dark_idx = str(bands[res['sel_idx']]) tau550 = res['taua'] sel_rmsd = res['rmsd'] if 'aermod' in sel_model_lut_meta.keys(): sel_mod_num = sel_model_lut_meta['aermod'] if type(sel_mod_num) is list: sel_mod_num = sel_mod_num[0] sel_model_lut_meta['aermod'] = str(sel_mod_num) if sel_model_lut_meta['aermod'] == "1": model_char = 'C' if sel_model_lut_meta['aermod'] == "2": model_char = 'M' if sel_model_lut_meta['aermod'] == "3": model_char = 'U' else: model_char = '4C' model_char = '4C: {}/{}/{}/{}'.format(sel_model_lut_meta['mod1'], sel_model_lut_meta['mod2'], sel_model_lut_meta['mod3'], sel_model_lut_meta['mod4']) pixel_idx = -1 attributes['dsf_pixel_idx'] = pixel_idx attributes['dsf_percentile'] = 0.1 attributes['dsf_model_selection'] = model_selection attributes['ac_model'] = sel_model_lut_meta['base'] #[0] attributes['ac_model_char'] = model_char if type(dark_idx) == str: attributes['ac_band'] = dark_idx else: attributes['ac_band'] = ','.join(dark_idx) attributes['ac_aot550'] = tau550 attributes['ac_rmsd'] = sel_rmsd print('model:{} band:{} aot={:.3f}'.format(attributes['ac_model_char'], attributes['ac_band'], attributes['ac_aot550'])) ## plot dark spectrum ds_plot = '{}/{}_{}.{}'.format(output, obase, 'dark_spectrum', 'png') band_names = bands data_type = 'NetCDF' waves = [metadata['{}-{}'.format(b, 'wave_name')] for b in bands] dsf_spectrum_option = 'fixed' ratm_s = {b: band_pars[b]['romix'] for b in band_pars} rorayl_s = {b: band_pars[b]['rorayl'] for b in band_pars} plot_dark_spectrum(metadata, ds_plot, waves, ratm_s, rorayl_s, rdark, dark_idx, tau550, sel_model_lut_meta, xlim=(430, 900)) ## compute RHOS nc_l2r_new = True for bi, band in enumerate(bands): ds_att = planetscope.get_band_att(metadata, band) parname_t = 'rhot_{}'.format(ds_att['wave_name']) parname_s = 'rhos_{}'.format(ds_att['wave_name']) ## read from L1R NetCDF band_data = nc_data(nc_file_l1r, parname_t) nc_write(nc_file_l2r, 'lon', lon, new=nc_l2r_new, attributes=attributes, nc_compression=nc_compression) nc_l2r_new = False nc_write(nc_file_l2r, 'lat', lat, new=nc_l2r_new, attributes=attributes, nc_compression=nc_compression) nc_l2r_new = False ## write rhot nc_write(nc_file_l2r, parname_t, band_data, dataset_attributes=ds_att, new=nc_l2r_new, attributes=attributes, nc_compression=nc_compression) nc_l2r_new = False ## apply gas correction if gas_transmittance: band_data /= tt_gas[band] ds_att['tt_gas'] = tt_gas[band] ## apply sky correction if sky_correction: if sky_correction_option == 'all': band_data -= rsky[band] ds_att['rsky'] = rsky[band] for k in band_pars[band]: ds_att[k] = band_pars[band][k] ## compute rhos band_data = rtoa_to_rhos(band_data, ds_att['romix'], ds_att['utott'], ds_att['dtott'], ds_att['astot'], tt_gas=1.) nc_write(nc_file_l2r, parname_s, band_data, dataset_attributes=ds_att, new=nc_l2r_new, attributes=attributes, nc_compression=nc_compression) nc_l2r_new = False ## make RGB if metadata['LUT_SENSOR'] == "PlanetScope_SuperDove": wave_red = metadata['Red-wave_name'] wave_green = metadata['Green_ii-wave_name'] wave_blue = metadata['Blue-wave_name'] else: wave_red = metadata['Red-wave_name'] wave_green = metadata['Green-wave_name'] wave_blue = metadata['Blue-wave_name'] ## map rgb images ## keep image 3d matrix for further plotting (if needed) rgb_image = None if map_rgb: for par in ['rhot', 'rhos']: rgb_dir = '{}'.format(output) if not os.path.exists(rgb_dir): os.makedirs(rgb_dir) if (par == 'rhos') & (map_rgb_rhos == False): continue ## read data from NCDF file data_r = nc_data(nc_file_l2r, '{}_{}'.format(par, wave_red)) data_g = nc_data(nc_file_l2r, '{}_{}'.format(par, wave_green)) data_b = nc_data(nc_file_l2r, '{}_{}'.format(par, wave_blue)) rgb_file = '{}/{}_{}.{}'.format(rgb_dir, obase, 'RGB_{}'.format(par.upper()), 'png') rgb_image = write_rgb(rgb_file, data_r, data_g, data_b, rgb_autorange=rgb_autorange, rgb_percentiles=rgb_percentiles, rgb_range_min=rgb_range_min, rgb_range_max=rgb_range_max, return_image=True) rgb_image = None data_r = None data_g = None data_b = None ## get PlanetScope surface reflectance if (sr_image_file is not None) & (not ignore_sr_image): nc_file_sr = '{}/{}_SR.nc'.format(output, obase) nc_sr_new = True attributes['auto_grouping'] = 'rhot:rhorc:rhos:rhow:sr' for bi, band in enumerate(bands): ds_att = planetscope.get_band_att(metadata, band) parname_sr = 'sr_{}'.format(ds_att['wave_name']) parname_s = 'rhos_{}'.format(ds_att['wave_name']) band_data = planetscope.get_rsur(sr_image_file, bi + 1, sub=sub) nc_write(nc_file_sr, parname_sr, band_data, dataset_attributes=ds_att, new=nc_sr_new, attributes=metadata, global_dims=global_dims, offset=offset, nc_compression=nc_compression) nc_sr_new = False ## find out overlap with L1 product to save in the same file if True: data_rhos = nc_data(nc_file_l2r, parname_s) nc_write(nc_file_sr, parname_s, data_rhos, dataset_attributes=ds_att, new=nc_sr_new, attributes=metadata, nc_compression=nc_compression) nc_sr_new = False if False: ## read data from NCDF file data_r = nc_data(nc_file_l2r, '{}_{}'.format('rhos', wave_red)) ## remove the extracted bundle if zipped: shutil.rmtree(bundle) bundle = '{}'.format(bundle_orig) if (not keep_l1r_ncdf) & (not data_type == "NetCDF"): shutil.rmtree(nc_file_l1r) lutd = None mpl.pyplot.close('all') return (nc_file_l2r)
def acolite_map( inputfile=None, output=None, parameters=None, dpi=300, ext='png', mapped=True, max_dim=1000, limit=None, auto_range=False, range_percentiles=(5, 95), dataset_rescale=False, map_title=True, map_colorbar=False, map_colorbar_orientation='vertical', #'horizontal', rgb_rhot=False, rgb_rhos=False, red_wl=660, green_wl=560, blue_wl=480, rgb_min=[0.0] * 3, rgb_max=[0.15] * 3, rgb_pan_sharpen=False, map_parameters_pan=True, map_fillcolor='White', map_scalepos='LR', map_scalebar=True, map_scalecolor='Black', map_scalecolor_rgb='White', map_scalelen=None, map_projection='tmerc', map_colorbar_edge=True, map_points=None, return_image=False, map_raster=False): import os, copy import datetime, time, dateutil.parser from acolite.shared import datascl, nc_data, nc_datasets, nc_gatts, qmap, closest_idx from acolite.acolite import pscale import acolite as ac from numpy import nanpercentile, log10, isnan, dstack from scipy.ndimage import zoom import matplotlib import matplotlib.pyplot as plt if not os.path.exists(inputfile): print('File {} not found.'.format(inputfile)) return (False) ## run through maps maps = { 'rhot': rgb_rhot, 'rhos': rgb_rhos, 'parameters': parameters != None } if all([maps[m] == False for m in maps]): return () ## get parameter scaling psc = pscale() ## read netcdf info l2w_datasets = nc_datasets(inputfile) print(l2w_datasets) gatts = nc_gatts(inputfile) if 'MISSION_INDEX' in gatts: sat, sen = gatts['MISSION'], gatts['MISSION_INDEX'] stime = dateutil.parser.parse(gatts['IMAGING_DATE'] + ' ' + gatts['IMAGING_TIME']) obase = '{}_{}_{}'.format(sat, sen, stime.strftime('%Y_%m_%d_%H_%M_%S')) else: sp = gatts['sensor'].split( '_') if 'sensor' in gatts else gatts['SATELLITE_SENSOR'].split('_') sat, sen = sp[0], sp[1] stime = dateutil.parser.parse(gatts['isodate'] if 'isodate' in gatts else gatts['ISODATE']) obase = gatts['output_name'] if 'output_name' in gatts else gatts[ 'obase'] ## find pan sharpening dataset if rgb_pan_sharpen: if sat not in ['L7', 'L8']: rgb_pan_sharpen = False tmp = os.path.splitext(inputfile) l1_pan_ncdf = '{}L1R_pan{}'.format(tmp[0][0:-3], tmp[1]) if os.path.exists(l1_pan_ncdf): pan_data = nc_data(l1_pan_ncdf, 'rhot_pan') else: print('L1 pan NetCDF file not found') rgb_pan_sharpen = False if output is not None: odir = output else: odir = gatts['output_dir'] if not os.path.exists(odir): os.makedirs(odir) scf = 1. rescale = 1.0 #if dataset_rescale or mapped: lon = nc_data(inputfile, 'lon') if mapped: lat = nc_data(inputfile, 'lat') if rgb_pan_sharpen: lon_pan = zoom(lon, zoom=2, order=1) lat_pan = zoom(lat, zoom=2, order=1) ## set up mapping info if True: from numpy import linspace, tile, ceil, isnan, nan mask_val = -9999.9999 from scipy.ndimage.interpolation import map_coordinates ## rescale to save memory dims = lon.shape dsc = (dims[0] / max_dim, dims[1] / max_dim) scf /= max(dsc) if rgb_pan_sharpen: scf = 1.0 if (scf < 1.) and dataset_rescale: sc_dims = (int(ceil(dims[0] * scf)), int(ceil(dims[1] * scf))) xdim = linspace(0, dims[1], sc_dims[1]).reshape(1, sc_dims[1]) ydim = linspace(0, dims[0], sc_dims[0]).reshape(sc_dims[0], 1) xdim = tile(xdim, (sc_dims[0], 1)) ydim = tile(ydim, (1, sc_dims[1])) resc = [ydim, xdim] xdim, ydim = None, None lon = map_coordinates(lon, resc, mode='nearest') lat = map_coordinates(lat, resc, mode='nearest') else: rescale = scf ## run through parameters for mi in maps: if not maps[mi]: continue if mi == 'parameters': if rgb_pan_sharpen: if map_parameters_pan & mapped: lon = lon_pan * 1.0 lon_pan = None lat = lat_pan * 1.0 lat_pan = None pan_data, lon_pan, lat_pan = None, None, None print('Mapping {}'.format(mi)) if type(parameters) is not list: parameters = [parameters] for pid, par in enumerate(parameters): par = par.strip() pard = None ## check if this parameter exists if par not in l2w_datasets: print('Parameter {} not in file {}.'.format( par, inputfile)) continue print('Mapping {}'.format(par)) ## read data data = nc_data(inputfile, par) if (rgb_pan_sharpen) & (map_parameters_pan): data = zoom(data, zoom=2, order=1) ## rescale data if (scf != 1.0) and dataset_rescale: data[isnan(data)] = mask_val data = map_coordinates(data, resc, cval=mask_val) data[data <= int(mask_val)] = nan data[data <= 0] = nan data_range = nanpercentile(data, range_percentiles) ## get parameter mapping configuration if par in psc: pard = copy.deepcopy(psc[par]) else: tmp = par.split('_') par_generic = '_'.join((tmp[0:-1] + ['*'])) if par_generic in psc: pard = copy.deepcopy(psc[par_generic]) try: ## add wavelength to generic name wave = int(tmp[len(tmp) - 1]) pard['name'] = '{} ({} nm)'.format( pard['name'], wave) except: pass else: pard = { 'color table': 'default', 'min': data_range[0], 'max': data_range[1], 'log': False, 'name': par, 'unit': '', 'parameter': par } if pard['color table'] == 'default': pard['color table'] = 'viridis' ctfile = "{}/{}/{}.txt".format(ac.config['pp_data_dir'], 'Shared/ColourTables', pard['color table']) if os.path.exists(ctfile): from matplotlib.colors import ListedColormap from numpy import loadtxt pard['color table'] = ListedColormap( loadtxt(ctfile) / 255.) if 'title' not in pard: pard['title'] = '{} [{}]'.format(pard['name'], pard['unit']) if auto_range: pard['min'] = data_range[0] pard['max'] = data_range[1] if isnan(pard['min']): pard['min'] = data_range[0] if isnan(pard['max']): pard['max'] = data_range[1] ## outputfile outputfile = '{}/{}_{}.png'.format(odir, obase, par) if map_title: title = '{} {}/{} {}'.format( pard['name'], sat, sen, stime.strftime('%Y-%m-%d (%H:%M UTC)')) else: title = None ## use qmap option if mapped: range = (pard['min'], pard['max']) if 'limit' in gatts: limit = gatts['limit'] if ('xx' not in locals()): xx, yy, m = qmap(data, lon, lat, outputfile=outputfile, title=title, rescale=rescale, colorbar=map_colorbar_orientation, colorbar_edge=map_colorbar_edge, cmap=pard['color table'], label=pard['title'], range=range, log=pard['log'], map_fillcolor=map_fillcolor, limit=limit, dpi=dpi, points=map_points, projection=map_projection, scalebar=map_scalebar, scalepos=map_scalepos, scalecolor=map_scalecolor, scalelen=map_scalelen) else: xx, yy, m = qmap(data, lon, lat, outputfile=outputfile, title=title, rescale=rescale, colorbar=map_colorbar_orientation, colorbar_edge=map_colorbar_edge, cmap=pard['color table'], label=pard['title'], range=range, log=pard['log'], map_fillcolor=map_fillcolor, limit=limit, dpi=dpi, points=map_points, projection=map_projection, scalebar=map_scalebar, scalepos=map_scalepos, scalecolor=map_scalecolor, scalelen=map_scalelen, xx=xx, yy=yy, m=m) else: import matplotlib.cm as cm from matplotlib.colors import ListedColormap cmap = cm.get_cmap(pard['color table']) cmap.set_bad(map_fillcolor) cmap.set_under(map_fillcolor) if not map_raster: ## set up plot fig = plt.figure() canvas = matplotlib.backends.backend_agg.FigureCanvasAgg( fig) ax = fig.add_subplot(111) print(pard['min'], pard['max']) if pard['log']: from matplotlib.colors import LogNorm cax = ax.imshow(data, vmin=pard['min'], vmax=pard['max'], cmap=cmap, norm=LogNorm(vmin=pard['min'], vmax=pard['max'])) else: cax = ax.imshow(data, vmin=pard['min'], vmax=pard['max'], cmap=cmap) if map_colorbar: if map_colorbar_orientation == 'vertical': cbar = fig.colorbar(cax, orientation='vertical') cbar.ax.set_ylabel(pard['title']) else: cbar = fig.colorbar(cax, orientation='horizontal') cbar.ax.set_xlabel(pard['title']) if map_title: ax.set_title(title) ax.axis('off') canvas.print_figure(outputfile, dpi=dpi, bbox_inches='tight') plt.close() else: from PIL import Image ## rescale for mapping if pard['log']: from numpy import log10 datasc = datascl(log10(data), dmin=log10(pard['min']), dmax=log10(pard['max'])) else: datasc = datascl(data, dmin=pard['min'], dmax=pard['max']) d = cmap(datasc) for wi in (0, 1, 2): ## convert back to 8 bit channels (not ideal) d_ = datascl(d[:, :, wi], dmin=0, dmax=1) if wi == 0: im = d_ else: im = dstack((im, d_)) img = Image.fromarray(im) ## output image img.save(outputfile) print('Wrote {}'.format(outputfile)) else: print('Mapping RGB {}'.format(mi)) ## RGBs waves = [ float(ds.split('_')[1]) for ds in l2w_datasets if ds[0:4] == mi ] if len(waves) == 0: print('No appropriate datasets found for RGB {} in {}'.format( mi, inputfile)) continue ## read datasets for wi, wl in enumerate([red_wl, green_wl, blue_wl]): idx, wave = closest_idx(waves, wl) cpar = '{}_{}'.format(mi, int(wave)) ## read data data = nc_data(inputfile, cpar) if rgb_pan_sharpen: data = zoom(data, zoom=2, order=1) if wi == 0: vis_i = data * 1.0 else: vis_i += data if wi == 2: vis_i /= 3 pan_i = vis_i / pan_data vis_i = None ## rescale data if (scf != 1.0) and dataset_rescale: data[isnan(data)] = mask_val data = map_coordinates(data, resc, cval=mask_val) data[data <= int(mask_val)] = nan data[data <= 0] = nan ## stack image if wi == 0: image = data else: image = dstack((image, data)) ## rescale data between 0 and 1 for wi in (2, 1, 0): if rgb_pan_sharpen: image[:, :, wi] /= pan_i image[:, :, wi] = datascl( image[:, :, wi], dmin=rgb_min[wi], dmax=rgb_max[wi]) / 255. par = r'$\rho_{}$'.format(mi[3]) + ' RGB' if map_title: title = '{} {}/{} {}'.format( par, sat, sen, stime.strftime('%Y-%m-%d (%H:%M UTC)')) else: title = None ## outputfile if rgb_pan_sharpen: outputfile = '{}/{}_rgb_{}_pan.png'.format(odir, obase, mi) else: outputfile = '{}/{}_rgb_{}.png'.format(odir, obase, mi) # use qmap option if mapped: if 'limit' in gatts: limit = gatts['limit'] if rgb_pan_sharpen: ret = qmap(image, lon_pan, lat_pan, outputfile=outputfile, title=title, rescale=rescale, colorbar=map_colorbar_orientation, colorbar_edge=map_colorbar_edge, limit=limit, dpi=dpi, points=map_points, projection=map_projection, scalebar=map_scalebar, scalepos=map_scalepos, scalecolor=map_scalecolor_rgb, scalelen=map_scalelen) ret = None else: if ('xx' not in locals()): xx, yy, m = qmap(image, lon, lat, outputfile=outputfile, title=title, rescale=rescale, colorbar=map_colorbar_orientation, colorbar_edge=map_colorbar_edge, limit=limit, dpi=dpi, points=map_points, projection=map_projection, scalebar=map_scalebar, scalepos=map_scalepos, scalecolor=map_scalecolor_rgb, scalelen=map_scalelen) else: xx, yy, m = qmap(image, lon, lat, outputfile=outputfile, title=title, rescale=rescale, colorbar=map_colorbar_orientation, colorbar_edge=map_colorbar_edge, limit=limit, dpi=dpi, points=map_points, projection=map_projection, scalebar=map_scalebar, scalepos=map_scalepos, scalecolor=map_scalecolor_rgb, scalelen=map_scalelen, xx=xx, yy=yy, m=m) else: if not map_raster: ## set up plot fig = plt.figure() canvas = matplotlib.backends.backend_agg.FigureCanvasAgg( fig) ax = fig.add_subplot(111) ax.imshow(image) image = None if map_title: ax.set_title(title) ax.axis('off') canvas.print_figure(outputfile, dpi=dpi, bbox_inches='tight') plt.close() else: from PIL import Image for wi in (0, 1, 2): # convert again to 8 bit channels (not ideal) data = datascl(image[:, :, wi], dmin=0, dmax=1) if wi == 0: im = data else: im = dstack((im, data)) img = Image.fromarray(im) img.save(outputfile) print('Wrote {}'.format(outputfile))