def savefig(fname, loc=1, decorate=True, **kwargs): import io import os import sys from PIL import Image import matplotlib.pyplot as plt try: from pydecorate import DecoratorAGG pydecorate = True except ImportError: pydecorate = False plt.savefig(fname, **kwargs) if pydecorate and decorate: img = Image.open(fname) dc = DecoratorAGG(img) if loc == 1: dc.align_bottom() elif loc == 2: dc.align_bottom() dc.align_right() elif loc == 3: dc.align_right() # sys.argv[0])[-5] + 'data/MONET_logo.png' # print(os.path.basename(__file__)) logo = os.path.abspath(__file__)[:-17] + 'data/MONET-logo.png' # print(logo) dc.add_logo(logo) if fname.split('.')[-1] == 'png': img.save(fname, "PNG") elif fname.split('.')[-1] == 'jpg': img.save(fname, "JPEG")
def show_image(data, dataname, save_png, colors="rainbow", min_data=None, max_data=None, title=None, add_colorscale=True): if min_data is None: min_data=data.min() if max_data is None: max_data=data.max() img = trollimage(data, mode="L", fill_value=[0,0,0]) colormap = get_colormap(colors, min_data, max_data) img.colorize(colormap) if title is not None: title_color=(255,255,255) from PIL import ImageFont from PIL import ImageDraw PIL_image=img.pil_image() draw = ImageDraw.Draw(PIL_image) fontsize=18 font = ImageFont.truetype("/usr/openv/java/jre/lib/fonts/LucidaTypewriterBold.ttf", fontsize) draw.text( (10, 10), title, title_color, font=font) if add_colorscale: dc = DecoratorAGG(PIL_image) colormap_r = colormap.reverse() dc.align_right() dc.write_vertically() dc.add_scale(colormap_r, extend=True, tick_marks=5, minor_tick_marks=1, line_opacity=100) #, tick_marks=tick_marks, minor_tick_marks=minor_tick_marks, unit=units show_or_save_image(PIL_image, save_png, dataname)
def savefig(fname, loc=1, decorate=True, **kwargs): """save figure and add the MONET logo . Parameters ---------- fname : str output file name. loc : int the location for the monet logo. decorate : bool Description of parameter `decorate`. **kwargs : dict kwargs for the matplotlib.pyplot.savefig function. Returns ------- type Description of returned object. """ import io import os import sys from PIL import Image import matplotlib.pyplot as plt try: from pydecorate import DecoratorAGG pydecorate = True except ImportError: pydecorate = False plt.savefig(fname, **kwargs) if pydecorate and decorate: img = Image.open(fname) dc = DecoratorAGG(img) if loc == 1: dc.align_bottom() elif loc == 2: dc.align_bottom() dc.align_right() elif loc == 3: dc.align_right() # sys.argv[0])[-5] + 'data/MONET_logo.png' # print(os.path.basename(__file__)) logo = os.path.abspath(__file__)[:-17] + 'data/MONET-logo.png' # print(logo) dc.add_logo(logo) if fname.split('.')[-1] == 'png': img.save(fname, "PNG") elif fname.split('.')[-1] == 'jpg': img.save(fname, "JPEG")
add_colorscale = 0 add_title = 1 verbose = 1 layer = ' 2nd layer' ticks = 20 tick_marks = 20 # default minor_tick_marks = 10 # default title_color = 'white' units = global_data[prop_str].info["units"] #global_data[prop_str].units if add_logos: if verbose: print('... add logos') dc.align_right() if add_colorscale: dc.write_vertically() #dc.add_logo("../logos/meteoSwiss3.jpg",height=60.0) #dc.add_logo("../logos/pytroll3.jpg",height=60.0) #dc.add_logo("/data/OWARNA/hau/pytroll/logos/meteoSwiss.png",height=40.0) dc.add_logo("../logos/meteoSwiss.png", height=40.0) #font_scale = aggdraw.Font("black","/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif-Bold.ttf",size=16) fontsize = 18 font = ImageFont.truetype( "/usr/openv/java/jre/lib/fonts/LucidaTypewriterBold.ttf", fontsize) if add_colorscale: print('... add colorscale ranging from min_data (', min_data, ') to max_data (', max_data, ')')
def main(): parser = get_parser() args = parser.parse_args() levels = [logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG] logging.basicConfig(level=levels[min(3, args.verbosity)]) if args.output_filename is None: args.output_filename = [x[:-3] + "png" for x in args.input_tiff] else: assert len(args.output_filename) == len( args.input_tiff ), "Output filenames must be equal to number of input tiffs" if not (args.add_borders or args.add_coastlines or args.add_grid or args.add_rivers or args.add_colorbar): LOG.error( "Please specify one of the '--add-X' options to modify the image") return -1 # we may be dealing with large images that look like decompression bombs # let's turn off the check for the image size in PIL/Pillow Image.MAX_IMAGE_PIXELS = None for input_tiff, output_filename in zip(args.input_tiff, args.output_filename): LOG.info("Creating {} from {}".format(output_filename, input_tiff)) gtiff = gdal.Open(input_tiff) proj4_str = osr.SpatialReference(gtiff.GetProjection()).ExportToProj4() ul_x, res_x, _, ul_y, _, res_y = gtiff.GetGeoTransform() half_pixel_x = res_x / 2. half_pixel_y = res_y / 2. area_extent = ( ul_x - half_pixel_x, # lower-left X ul_y + res_y * gtiff.RasterYSize - half_pixel_y, # lower-left Y ul_x + res_x * gtiff.RasterXSize + half_pixel_x, # upper-right X ul_y + half_pixel_y, # upper-right Y ) img = Image.open(input_tiff).convert('RGBA' if gtiff.RasterCount in ( 2, 4) else 'RGB') area_def = (proj4_str, area_extent) cw = ContourWriterAGG(args.shapes_dir) if args.add_coastlines: outline = args.coastlines_outline[0] if len( args.coastlines_outline) == 1 else tuple( int(x) for x in args.coastlines_outline) if args.coastlines_fill: fill = args.coastlines_fill[0] if len( args.coastlines_fill) == 1 else tuple( int(x) for x in args.coastlines_fill) else: fill = None cw.add_coastlines(img, area_def, resolution=args.coastlines_resolution, level=args.coastlines_level, width=args.coastlines_width, outline=outline, fill=fill) if args.add_rivers: outline = args.rivers_outline[0] if len( args.rivers_outline) == 1 else tuple( int(x) for x in args.rivers_outline) cw.add_rivers(img, area_def, resolution=args.rivers_resolution, level=args.rivers_level, width=args.rivers_width, outline=outline) if args.add_borders: outline = args.borders_outline[0] if len( args.borders_outline) == 1 else tuple( int(x) for x in args.borders_outline) cw.add_borders(img, area_def, resolution=args.borders_resolution, level=args.borders_level, outline=outline, width=args.borders_width) if args.add_grid: outline = args.grid_outline[0] if len( args.grid_outline) == 1 else tuple( int(x) for x in args.grid_outline) minor_outline = args.grid_minor_outline[0] if len( args.grid_minor_outline) == 1 else tuple( int(x) for x in args.grid_minor_outline) fill = args.grid_fill[0] if len(args.grid_fill) == 1 else tuple( int(x) for x in args.grid_fill) font_path = find_font(args.grid_font, args.grid_text_size) font = Font(outline, font_path, size=args.grid_text_size) cw.add_grid(img, area_def, args.grid_D, args.grid_d, font, fill=fill, outline=outline, minor_outline=minor_outline, write_text=args.grid_text, width=args.grid_width, lon_placement=args.grid_lon_placement, lat_placement=args.grid_lat_placement) if args.add_colorbar: from pydecorate import DecoratorAGG font_color = args.colorbar_text_color font_color = font_color[0] if len(font_color) == 1 else tuple( int(x) for x in font_color) font_path = find_font(args.colorbar_font, args.colorbar_text_size) # this actually needs an aggdraw font font = Font(font_color, font_path, size=args.colorbar_text_size) band_count = gtiff.RasterCount if band_count not in [1, 2]: raise ValueError("Can't add colorbar to RGB/RGBA image") # figure out what colormap we are dealing with band = gtiff.GetRasterBand(1) cmap = get_colormap(band, band_count) # figure out our limits vmin = args.colorbar_min vmax = args.colorbar_max metadata = gtiff.GetMetadata_Dict() vmin = vmin or metadata.get('min_in') vmax = vmax or metadata.get('max_in') if isinstance(vmin, str): vmin = float(vmin) if isinstance(vmax, str): vmax = float(vmax) if vmin is None or vmax is None: data = gtiff.GetRasterBand(1).ReadAsArray() vmin = vmin or np.iinfo(data.dtype).min vmax = vmax or np.iinfo(data.dtype).max cmap.set_range(vmin, vmax) dc = DecoratorAGG(img) if args.colorbar_align == 'top': dc.align_top() elif args.colorbar_align == 'bottom': dc.align_bottom() elif args.colorbar_align == 'left': dc.align_left() elif args.colorbar_align == 'right': dc.align_right() if args.colorbar_vertical: dc.write_vertically() else: dc.write_horizontally() if args.colorbar_width is None or args.colorbar_height is None: LOG.warning("'--colorbar-width' or '--colorbar-height' were " "not specified. Forcing '--colorbar-extend'.") args.colorbar_extend = True kwargs = {} if args.colorbar_width: kwargs['width'] = args.colorbar_width if args.colorbar_height: kwargs['height'] = args.colorbar_height dc.add_scale(cmap, extend=args.colorbar_extend, font=font, line=font_color, tick_marks=args.colorbar_tick_marks, title=args.colorbar_title, unit=args.colorbar_units, **kwargs) img.save(output_filename)
def plot_msg_minus_cosmo(in_msg): # do statistics for the last full hour (minutes=0, seconds=0) in_msg.datetime = datetime(in_msg.datetime.year, in_msg.datetime.month, in_msg.datetime.day, in_msg.datetime.hour, 0, 0) area_loaded = choose_area_loaded_msg(in_msg.sat, in_msg.sat_nr, in_msg.datetime) # define contour write for coasts, borders, rivers cw = ContourWriterAGG(in_msg.mapDir) # check if input data is complete if in_msg.verbose: print("*** check input data for ", in_msg.sat_str()) RGBs = check_input(in_msg, in_msg.sat_str(layout="%(sat)s") + in_msg.sat_nr_str(), in_msg.datetime) # in_msg.sat_nr might be changed to backup satellite if in_msg.verbose: print('*** Create plots for ') print(' Satellite/Sensor: ' + in_msg.sat_str()) print(' Satellite number: ' + in_msg.sat_nr_str() + ' // ' + str(in_msg.sat_nr)) print(' Satellite instrument: ' + in_msg.instrument) print(' Date/Time: ' + str(in_msg.datetime)) print(' RGBs: ', in_msg.RGBs) print(' Area: ', in_msg.areas) print(' reader level: ', in_msg.reader_level) # define satellite data object #global_data = GeostationaryFactory.create_scene(in_msg.sat, in_msg.sat_nr_str(), "seviri", in_msg.datetime) global_data = GeostationaryFactory.create_scene(in_msg.sat_str(), in_msg.sat_nr_str(), in_msg.instrument, in_msg.datetime) # global_data = GeostationaryFactory.create_scene("msg-ot", "", "Overshooting_Tops", in_msg.datetime) if len(RGBs) == 0 and len(in_msg.postprocessing_areas) == 0: return RGBs if in_msg.verbose: print( "*** load satellite channels for " + in_msg.sat_str() + in_msg.sat_nr_str() + " ", global_data.fullname) # initialize processed RGBs RGBs_done = [] # ------------------------------------------------------------------- # load reflectivities, brightness temperatures, NWC-SAF products ... # ------------------------------------------------------------------- area_loaded = load_products(global_data, RGBs, in_msg, area_loaded) cosmo_input_file = "input_cosmo_cronjob.py" print("... read COSMO input file: ", cosmo_input_file) in_cosmo = parse_commandline_and_read_inputfile( input_file=cosmo_input_file) # add composite in_msg.scpOutput = True in_msg.resize_montage = 70 in_msg.postprocessing_montage = [[ "MSG_IR-108cpc", "COSMO_SYNMSG-BT-CL-IR10.8", "MSG_IR-108-COSMO-minus-MSGpc" ]] in_msg.scpProducts = [[ "MSG_IR-108cpc", "COSMO_SYNMSG-BT-CL-IR10.8", "MSG_IR-108-COSMO-minus-MSGpc" ]] #in_msg.scpProducts = ["all"] # define satellite data object cosmo_data = GeostationaryFactory.create_scene(in_cosmo.sat_str(), in_cosmo.sat_nr_str(), in_cosmo.instrument, in_cosmo.datetime) area_loaded_cosmo = load_products(cosmo_data, ['SYNMSG_BT_CL_IR10.8'], in_cosmo, area_loaded) # preprojecting the data to another area # -------------------------------------- if len(RGBs) > 0: for area in in_msg.areas: print("") obj_area = get_area_def(area) if area != 'ccs4': print("*** WARNING, diff MSG-COSMO only implemented for ccs4") continue # reproject data to new area print(area_loaded) if obj_area == area_loaded: if in_msg.verbose: print("*** Use data for the area loaded: ", area) #obj_area = area_loaded data = global_data resolution = 'l' else: if in_msg.verbose: print("*** Reproject data to area: ", area, "(org projection: ", area_loaded.name, ")") obj_area = get_area_def(area) # PROJECT data to new area data = global_data.project(area, precompute=True) resolution = 'i' if in_msg.parallax_correction: loaded_products = [chn.name for chn in data.loaded_channels()] if 'CTH' not in loaded_products: print("*** Error in plot_msg (" + inspect.getfile(inspect.currentframe()) + ")") print( " Cloud Top Height is needed for parallax correction " ) print( " either load CTH or specify the estimation of the CTH in the input file (load 10.8 in this case)" ) quit() if in_msg.verbose: print( " perform parallax correction for loaded channels: ", loaded_products) data = data.parallax_corr(fill=in_msg.parallax_gapfilling, estimate_cth=in_msg.estimate_cth, replace=True) # save reprojected data if area in in_msg.save_reprojected_data: save_reprojected_data(data, area, in_msg) # apply a mask to the data (switched off at the moment) if False: mask_data(data, area) # save average values if in_msg.save_statistics: mean_array = zeros(len(RGBs)) #statisticFile = '/data/COALITION2/database/meteosat/ccs4/'+yearS+'/'+monthS+'/'+dayS+'/MSG_'+area+'_'+yearS[2:]+monthS+dayS+'.txt' statisticFile = './' + yearS + '-' + monthS + '-' + dayS + '/MSG_' + area + '_' + yearS[ 2:] + monthS + dayS + '.txt' if in_msg.verbose: print("*** write statistics (average values) to " + statisticFile) f1 = open(statisticFile, 'a') # mode append i_rgb = 0 for rgb in RGBs: if rgb in products.MSG_color: mean_array[i_rgb] = data[rgb.replace("c", "")].data.mean() i_rgb = i_rgb + 1 # create string to write str2write = dateS + ' ' + hourS + ' : ' + minS + ' UTC ' for mm in mean_array: str2write = str2write + ' ' + "%7.2f" % mm str2write = str2write + "\n" f1.write(str2write) f1.close() # creating plots/images if in_msg.make_plots: # choose map resolution in_msg.resolution = choose_map_resolution( area, in_msg.mapResolution) # define area proj4_string = obj_area.proj4_string # e.g. proj4_string = '+proj=geos +lon_0=0.0 +a=6378169.00 +b=6356583.80 +h=35785831.0' area_extent = obj_area.area_extent # e.g. area_extent = (-5570248.4773392612, -5567248.074173444, 5567248.074173444, 5570248.4773392612) area_tuple = (proj4_string, area_extent) RGBs = ['IR_108-COSMO-minus-MSG'] print(data['IR_108'].data.shape) print(cosmo_data['SYNMSG_BT_CL_IR10.8'].data.shape) diff_MSG_COSMO = cosmo_data['SYNMSG_BT_CL_IR10.8'].data - data[ 'IR_108'].data HRV_enhance_str = '' # add IR difference as "channel object" to satellite regional "data" object data.channels.append( Channel(name=RGBs[0], wavelength_range=[0., 0., 0.], resolution=data['IR_108'].resolution, data=diff_MSG_COSMO)) for rgb in RGBs: if not check_loaded_channels(rgb, data): continue PIL_image = create_PIL_image(rgb, data, in_msg, obj_area=obj_area) # !!! in_msg.colorbar[rgb] is initialized inside (give attention to rgbs) !!! add_borders_and_rivers(PIL_image, cw, area_tuple, add_borders=in_msg.add_borders, border_color=in_msg.border_color, add_rivers=in_msg.add_rivers, river_color=in_msg.river_color, resolution=in_msg.resolution, verbose=in_msg.verbose) # indicate mask if in_msg.indicate_mask: PIL_image = indicate_mask(rgb, PIL_image, data, in_msg.verbose) #if area.find("EuropeCanary") != -1 or area.find("ccs4") != -1: dc = DecoratorAGG(PIL_image) # add title to image if in_msg.add_title: add_title(PIL_image, in_msg.title, HRV_enhance_str + rgb, in_msg.sat_str(), data.sat_nr(), in_msg.datetime, area, dc, in_msg.font_file, in_msg.verbose, title_color=in_msg.title_color, title_y_line_nr=in_msg.title_y_line_nr ) # !!! needs change # add MeteoSwiss and Pytroll logo if in_msg.add_logos: if in_msg.verbose: print('... add logos') dc.align_right() if in_msg.add_colorscale: dc.write_vertically() if PIL_image.mode != 'L': height = 60 # height=60.0 normal resolution dc.add_logo(in_msg.logos_dir + "/pytroll3.jpg", height=height) # height=60.0 dc.add_logo(in_msg.logos_dir + "/meteoSwiss3.jpg", height=height) dc.add_logo( in_msg.logos_dir + "/EUMETSAT_logo2_tiny_white_square.png", height=height) # height=60.0 # add colorscale if in_msg.add_colorscale and in_msg.colormap[rgb] != None: if rgb in products.MSG_color: unit = data[rgb.replace("c", "")].info['units'] #elif rgb in products.MSG or rgb in products.NWCSAF or rgb in products.HSAF: # unit = data[rgb].info['units'] else: unit = None loaded_channels = [ chn.name for chn in data.loaded_channels() ] if rgb in loaded_channels: if hasattr(data[rgb], 'info'): print(" hasattr(data[rgb], 'info')", list(data[rgb].info.keys())) if 'units' in list(data[rgb].info.keys()): print( "'units' in data[rgb].info.keys()") unit = data[rgb].info['units'] print("... units = ", unit) add_colorscale(dc, rgb, in_msg, unit=unit) if in_msg.parallax_correction: parallax_correction_str = 'pc' else: parallax_correction_str = '' rgb += parallax_correction_str # create output filename outputDir = format_name( in_msg.outputDir, data.time_slot, area=area, rgb=rgb, sat=data.satname, sat_nr=data.sat_nr()) # !!! needs change outputFile = outputDir + "/" + format_name( in_msg.outputFile, data.time_slot, area=area, rgb=rgb, sat=data.satname, sat_nr=data.sat_nr()) # !!! needs change # check if output directory exists, if not create it path = dirname(outputFile) if not exists(path): if in_msg.verbose: print('... create output directory: ' + path) makedirs(path) # save file if exists(outputFile) and not in_msg.overwrite: if stat(outputFile).st_size > 0: print('... outputFile ' + outputFile + ' already exists (keep old file)') else: print( '*** Warning, outputFile' + outputFile + ' already exists, but is empty (overwrite file)' ) PIL_image.save(outputFile, optimize=True ) # optimize -> minimize file size chmod( outputFile, 0o777 ) ## FOR PYTHON3: 0o664 # give access read/write access to group members else: if in_msg.verbose: print('... save final file: ' + outputFile) PIL_image.save( outputFile, optimize=True) # optimize -> minimize file size chmod( outputFile, 0o777 ) ## FOR PYTHON3: 0o664 # give access read/write access to group members if in_msg.compress_to_8bit: if in_msg.verbose: print('... compress to 8 bit image: display ' + outputFile.replace(".png", "-fs8.png") + ' &') subprocess.call( "/usr/bin/pngquant -force 256 " + outputFile + " 2>&1 &", shell=True) # 256 == "number of colors" #if in_msg.verbose: # print " add coastlines to "+outputFile ## alternative: reopen image and modify it (takes longer due to additional reading and saving) #cw.add_rivers_to_file(img, area_tuple, level=5, outline='blue', width=0.5, outline_opacity=127) #cw.add_coastlines_to_file(outputFile, obj_area, resolution=resolution, level=4) #cw.add_borders_to_file(outputFile, obj_area, outline=outline, resolution=resolution) # secure copy file to another place if in_msg.scpOutput: if (rgb in in_msg.scpProducts) or ('all' in [ x.lower() for x in in_msg.scpProducts if type(x) == str ]): scpOutputDir = format_name(in_msg.scpOutputDir, data.time_slot, area=area, rgb=rgb, sat=data.satname, sat_nr=data.sat_nr()) if in_msg.compress_to_8bit: if in_msg.verbose: print("... secure copy " + outputFile.replace( ".png", "-fs8.png") + " to " + scpOutputDir) subprocess.call( "scp " + in_msg.scpID + " " + outputFile.replace(".png", "-fs8.png") + " " + scpOutputDir + " 2>&1 &", shell=True) else: if in_msg.verbose: print("... secure copy " + outputFile + " to " + scpOutputDir) subprocess.call("scp " + in_msg.scpID + " " + outputFile + " " + scpOutputDir + " 2>&1 &", shell=True) if in_msg.scpOutput and in_msg.scpID2 != None and in_msg.scpOutputDir2 != None: if (rgb in in_msg.scpProducts2) or ('all' in [ x.lower() for x in in_msg.scpProducts2 if type(x) == str ]): scpOutputDir2 = format_name(in_msg.scpOutputDir2, data.time_slot, area=area, rgb=rgb, sat=data.satname, sat_nr=data.sat_nr()) if in_msg.compress_to_8bit: if in_msg.verbose: print("... secure copy " + outputFile.replace( ".png", "-fs8.png") + " to " + scpOutputDir2) subprocess.call( "scp " + in_msg.scpID2 + " " + outputFile.replace(".png", "-fs8.png") + " " + scpOutputDir2 + " 2>&1 &", shell=True) else: if in_msg.verbose: print("... secure copy " + outputFile + " to " + scpOutputDir2) subprocess.call("scp " + in_msg.scpID2 + " " + outputFile + " " + scpOutputDir2 + " 2>&1 &", shell=True) if 'ninjotif' in in_msg.outputFormats: ninjotif_file = format_name(outputDir + '/' + in_msg.ninjotifFilename, data.time_slot, sat_nr=data.sat_nr(), RSS=in_msg.RSS, area=area, rgb=rgb) from plot_coalition2 import pilimage2geoimage GEO_image = pilimage2geoimage(PIL_image, obj_area, data.time_slot) GEO_image.save(ninjotif_file, fformat='mpop.imageo.formats.ninjotiff', ninjo_product_name=rgb, chan_id=products.ninjo_chan_id[ rgb.replace("_", "-") + "_" + area], nbits=8) chmod(ninjotif_file, 0o777) print(("... save ninjotif image: display ", ninjotif_file, " &")) if rgb not in RGBs_done: RGBs_done.append(rgb) ## start postprocessing for area in in_msg.postprocessing_areas: postprocessing(in_msg, global_data.time_slot, int(data.sat_nr()), area) if in_msg.verbose: print(" ") return RGBs_done
def scatter_rad_rcz(in_msg): # get date of the last SEVIRI observation if in_msg.datetime is None: in_msg.get_last_SEVIRI_date() yearS = str(in_msg.datetime.year) #yearS = yearS[2:] monthS = "%02d" % in_msg.datetime.month dayS = "%02d" % in_msg.datetime.day hourS = "%02d" % in_msg.datetime.hour minS = "%02d" % in_msg.datetime.minute dateS = yearS + '-' + monthS + '-' + dayS timeS = hourS + '-' + minS if in_msg.sat_nr is None: in_msg.sat_nr = choose_msg(in_msg.datetime, in_msg.RSS) # check if PyResample is loaded try: # Work around for on demand import of pyresample. pyresample depends # on scipy.spatial which memory leaks on multiple imports IS_PYRESAMPLE_LOADED = False from pyresample import geometry from mpop.projector import get_area_def IS_PYRESAMPLE_LOADED = True except ImportError: LOGGER.warning( "pyresample missing. Can only work in satellite projection") if in_msg.datetime.year > 2012: if in_msg.sat_nr == 8: area_loaded = get_area_def("EuropeCanary35") elif in_msg.sat_nr == 9: # rapid scan service satellite area_loaded = get_area_def("EuropeCanary95") elif in_msg.sat_nr == 10: # default satellite area_loaded = get_area_def( "met09globeFull" ) # full disk service, like EUMETSATs NWC-SAF products elif in_msg.sat_nr == 0: # fake satellite for reprojected ccs4 data in netCDF area_loaded = get_area_def("ccs4") # #area_loaded = get_area_def("EuropeCanary") #area_loaded = get_area_def("alps") # new projection of SAM else: print("*** Error, unknown satellite number ", in_msg.sat_nr) area_loaded = get_area_def("hsaf") # else: if in_msg.sat_nr == 8: area_loaded = get_area_def("EuropeCanary95") elif in_msg.sat_nr == 9: # default satellite area_loaded = get_area_def("EuropeCanary") # define contour write for coasts, borders, rivers cw = ContourWriterAGG(in_msg.mapDir) if type(in_msg.sat_nr) is int: sat_nr_str = str(in_msg.sat_nr).zfill(2) elif type(in_msg.sat_nr) is str: sat_nr_str = in_msg.sat_nr else: print("*** Waring, unknown type of sat_nr", type(in_msg.sat_nr)) sat_nr_str = in_msg.sat_nr if in_msg.verbose: print('*** Create plots for ') print(' Satellite/Sensor: ' + in_msg.sat + ' ' + sat_nr_str) print(' Date/Time: ' + dateS + ' ' + hourS + ':' + minS + 'UTC') print(' RGBs: ', in_msg.RGBs) print(' Area: ', in_msg.areas) # check if input data is complete if in_msg.verbose: print("*** check input data") RGBs = check_input(in_msg, in_msg.sat + sat_nr_str, in_msg.datetime) if len(RGBs) != len(in_msg.RGBs): print("*** Warning, input not complete.") print("*** Warning, process only: ", RGBs) # define time and data object global_data = GeostationaryFactory.create_scene(in_msg.sat, sat_nr_str, "seviri", in_msg.datetime) # print "type(global_data) ", type(global_data) # <class 'mpop.scene.SatelliteInstrumentScene'> # print "dir(global_data)", dir(global_data) [..., '__init__', ... 'area', 'area_def', 'area_id', 'channel_list', 'channels', # 'channels_to_load', 'check_channels', 'fullname', 'get_area', 'image', 'info', 'instrument_name', 'lat', 'load', 'loaded_channels', # 'lon', 'number', 'orbit', 'project', 'remove_attribute', 'satname', 'save', 'set_area', 'time_slot', 'unload', 'variant'] global_data_radar = GeostationaryFactory.create_scene( "swissradar", "", "radar", in_msg.datetime) global_data_radar.load(['precip']) if len(RGBs) == 0: return RGBs if in_msg.verbose: print( "*** load satellite channels for " + in_msg.sat + sat_nr_str + " ", global_data.fullname) # initialize processed RGBs RGBs_done = [] # load all channels / information for rgb in RGBs: if in_msg.verbose: print(" load prerequisites for: ", rgb) if rgb in products.MSG or rgb in products.MSG_color: for channel in products.MSG: if rgb.find( channel ) != -1: # if a channel name (IR_108) is in the rgb name (IR_108c) if in_msg.verbose: print(" load prerequisites by name: ", channel) if in_msg.reader_level is None: global_data.load( [channel], area_extent=area_loaded.area_extent ) # try all reader levels load the corresponding data else: global_data.load([channel], area_extent=area_loaded.area_extent, reader_level=in_msg.reader_level ) # load the corresponding data if rgb in products.RGBs_buildin or rgb in products.RGBs_user: obj_image = get_image(global_data, rgb) # find corresponding RGB image object if in_msg.verbose: print(" load prerequisites by function: ", obj_image.prerequisites) global_data.load( obj_image.prerequisites, area_extent=area_loaded.area_extent) # load prerequisites if rgb in products.CMa or rgb in products.CT or rgb in products.CTTH or rgb in products.SPhR: if rgb in products.CMa: pge = "CloudMask" elif rgb in products.CT: pge = "CloudType" elif rgb in products.CTTH: pge = "CTTH" elif rgb in products.SPhR: pge = "SPhR" else: print("*** Error in scatter_rad_rcz (" + inspect.getfile(inspect.currentframe()) + ")") print(" unknown NWC-SAF PGE ", rgb) quit() if in_msg.verbose: print(" load NWC-SAF product: " + pge) global_data.load( [pge], calibrate=in_msg.nwcsaf_calibrate, reader_level="seviri-level3" ) # False, area_extent=area_loaded.area_extent (difficulties to find correct h5 input file) #print global_data.loaded_channels() #loaded_channels = [chn.name for chn in global_data.loaded_channels()] #if pge not in loaded_channels: # return [] if area_loaded != global_data[pge].area: print("*** Warning: NWC-SAF input file on a differnt grid (" + global_data[pge].area.name + ") than suggested input area (" + area_loaded.name + ")") print(" use " + global_data[pge].area.name + " as standard grid") area_loaded = global_data[pge].area convert_NWCSAF_to_radiance_format(global_data, area_loaded, rgb, IS_PYRESAMPLE_LOADED) if rgb in products.HSAF: if in_msg.verbose: print(" load hsaf product by name: ", rgb) global_data.load( [rgb] ) # , area_extent=area_loaded.area_extent load the corresponding data if in_msg.HRV_enhancement: # load also the HRV channel (there is a check inside in the load function, if the channel is already loaded) if in_msg.verbose: print( " load additionally the HRV channel for HR enhancement") global_data.load(["HRV"], area_extent=area_loaded.area_extent) # loaded_channels = [chn.name for chn in global_data.loaded_channels()] # print loaded_channels # check if all prerequisites are loaded #rgb_complete = [] #for rgb in RGBs: # all_loaded = True # if rgb in products.RGBs_buildin or rgb in products.RGB_user: # obj_image = get_image(global_data, rgb) # for pre in obj_image.prerequisites: # if pre not in loaded_channels: # all_loaded = False # elif rgb in products.MSG_color: # if rgb.replace("c","") not in loaded_channels: # all_loaded = False # else: # if rgb not in loaded_channels: # all_loaded = False # if all_loaded: # rgb_complete.append(rgb) #print "rgb_complete", rgb_complete # preprojecting the data to another area # -------------------------------------- for area in in_msg.areas: print("") obj_area = get_area_def(area) if obj_area == area_loaded: if in_msg.verbose: print("*** Use data for the area loaded: ", area) #obj_area = area_loaded data = global_data resolution = 'l' else: if in_msg.verbose: print("*** Reproject data to area: ", area, "(org projection: ", area_loaded.name, ")") obj_area = get_area_def(area) # PROJECT data to new area data = global_data.project(area) resolution = 'i' if in_msg.mapResolution is None: if area.find("EuropeCanary") != -1: resolution = 'l' if area.find("ccs4") != -1: resolution = 'i' if area.find("ticino") != -1: resolution = 'h' else: resolution = in_msg.mapResolution # define area proj4_string = obj_area.proj4_string # e.g. proj4_string = '+proj=geos +lon_0=0.0 +a=6378169.00 +b=6356583.80 +h=35785831.0' area_extent = obj_area.area_extent # e.g. area_extent = (-5570248.4773392612, -5567248.074173444, 5567248.074173444, 5570248.4773392612) area_tuple = (proj4_string, area_extent) # save reprojected data if area in in_msg.save_reprojected_data: # and area != area_loaded _sat_nr = int(data.number) - 7 if int(data.number) - 7 > 0 else 0 nc_dir = ( global_data.time_slot.strftime(in_msg.reprojected_data_dir) % { "area": area, "msg": "MSG" + str(_sat_nr) }) nc_file = (global_data.time_slot.strftime( in_msg.reprojected_data_filename) % { "area": area, "msg": "MSG" + str(_sat_nr) }) ncOutputFile = nc_dir + nc_file # check if output directory exists, if not create it path = dirname(ncOutputFile) if not exists(path): if in_msg.verbose: print('... create output directory: ' + path) makedirs(path) if in_msg.verbose: print("... save reprojected data: ncview " + ncOutputFile + " &") #data.save(ncOutputFile, to_format="netcdf4", compression=False) data.save(ncOutputFile, band_axis=0, concatenate_bands=False) # mask for the cloud depths tests (masked data) #if area == 'ccs4': if area == False: print('... apply convective mask') mask_depth = data.image.mask_clouddepth() #print type(mask_depth.max) #print dir(mask_depth.max) index = where( mask_depth < 5) # less than 5 (of 6) tests successfull -> mask out for rgb in RGBs: if rgb in products.MSG_color: rgb2 = rgb.replace("c", "") data[rgb2].data.mask[index] = True fill_value = data[rgb2].data.fill_value #data["IR_108"].data[index] = fill_value #print "data[IR_108].data.min/max ", data["IR_108"].data.min(), data["IR_108"].data.max() #if rgb == "IR_108c": # print type(data["IR_108"].data) # print dir(data["IR_108"].data) #print data["IR_108"].data.mask # save average values if in_msg.save_statistics: mean_array = zeros(len(RGBs)) #statisticFile = '/data/COALITION2/database/meteosat/ccs4/'+yearS+'/'+monthS+'/'+dayS+'/MSG_'+area+'_'+yearS[2:]+monthS+dayS+'.txt' statisticFile = './' + yearS + '-' + monthS + '-' + dayS + '/MSG_' + area + '_' + yearS[ 2:] + monthS + dayS + '.txt' if in_msg.verbose: print("*** write statistics (average values) to " + statisticFile) f1 = open(statisticFile, 'a') # mode append i_rgb = 0 for rgb in RGBs: if rgb in products.MSG_color: mean_array[i_rgb] = data[rgb.replace("c", "")].data.mean() i_rgb = i_rgb + 1 # create string to write str2write = dateS + ' ' + hourS + ' : ' + minS + ' UTC ' for mm in mean_array: str2write = str2write + ' ' + "%7.2f" % mm str2write = str2write + "\n" f1.write(str2write) f1.close() print("y.shape ", global_data_radar['precip'].data.shape) from numpy import copy y = copy(global_data_radar['precip'].data) y = y.ravel() print("y.shape ", y.shape) if 1 == 0: if 'X' in locals(): del X from numpy import column_stack, append, concatenate for rgb in RGBs: # poor mans parallax correction if rgb in products.MSG_color: rgb2 = rgb.replace("c", "") else: rgb2 = rgb x1 = data[rgb2].data.ravel() if 'X' not in locals(): X = x1 X = [X] else: concatenate((X, [x1]), axis=0) print("X.shape ", X.shape) X = append(X, [[1] * len(x1)], axis=1) print("y.shape ", y.shape) #theta = np.linalg.lstsq(X,y)[0] return ind_gt_1 = y > 1 x = x[ind_gt_1] y = y[ind_gt_1] ind_lt_200 = y < 200 x = x[ind_lt_200] y = y[ind_lt_200] #ind_gt_0 = x>0 #x = x[ind_gt_0] #y = y[ind_gt_0] #X = np.column_stack(x+[[1]*len(x[0])]) #beta_hat = np.linalg.lstsq(X,y)[0] #print beta_hat #X_hat= np.dot(X,theta) #y_hat = X_hat.reshape((640, 710)) # creating plots/images if in_msg.make_plots: ind_cloudy = data['CTH'].data > 0 ind_clear = data['CTH'].data <= 0 ind_cloudy = ind_cloudy.ravel() for rgb in RGBs: if rgb in products.MSG_color: rgb2 = rgb.replace("c", "") else: rgb2 = rgb if rgb == 'ir108': rgb2 = 'IR_108' # poor mans parallax correction if 1 == 0: print("... poor mans parallax correction") data[rgb2].data[25:640, :] = data[rgb2].data[0:615, :] #data[rgb2].data[15:640,:] = data[rgb2].data[0:625,:] data[rgb2].data[:, 0:700] = data[rgb2].data[:, 10:710] # create output filename outputDir = format_name(in_msg.outputDir, data.time_slot, area=area, rgb=rgb, sat_nr=data.number) outputFile = outputDir + format_name(in_msg.outputFile, data.time_slot, area=area, rgb=rgb, sat_nr=data.number) PIL_image = create_PIL_image( rgb, data, in_msg ) # !!! in_msg.colorbar[rgb] is initialized inside (give attention to rgbs) !!! if 1 == 1: y = copy(global_data_radar['precip'].data) ind_gt_300 = y > 300 # replace no rain marker with 0mm/h y[ind_gt_300] = 0 y = y.ravel() print("y.shape ", y.shape) x = copy(data[rgb2].data) x = x.ravel() ## get rid of clear sky x = x[ind_cloudy] y = y[ind_cloudy] #ind_gt_01 = x>0.1 #x = x[ind_gt_01] #y = y[ind_gt_01] # get rid of no rain limits for rainfall ind_gt_01 = y > 0.1 x = x[ind_gt_01] y = y[ind_gt_01] ind_lt_300 = y < 300 x = x[ind_lt_300] y = y[ind_lt_300] plt.figure() plt.title('Scatterplot precipitation - radiance') plt.xlabel(rgb) plt.ylabel('precipitation in mm/h') plt.scatter(x, y) #, s=area, c=colors, alpha=0.5 outputDir = format_name(in_msg.outputDir, data.time_slot, area=area, rgb=rgb, sat_nr=data.number) outputFileScatter = outputDir + format_name( 'scatterplot_%(area)s_%Y%m%d%H%M_%(rgb)s_precip_pc.png', data.time_slot, area=area, rgb=rgb, sat_nr=data.number) #plt.show() from numpy import arange x_line = arange(x.min(), x.max(), 1) print("*** display " + outputFileScatter + " &") from numpy import ones, linalg, array print(x.min(), x.max(), y.min(), y.max()) A = array([x, ones(x.size)]) w = linalg.lstsq(A.T, y)[0] # obtaining the parameters y_line = w[0] * x_line + w[1] # regression line #--- #from scipy import stats #slope, intercept, r_value, p_value, std_err = stats.linregress(x,y) #print "slope, intercept, r_value, p_value, std_err" #print slope, intercept, r_value, p_value, std_err #y_line = slope*x_line + intercept from pylab import plot plot(x_line, y_line, 'r-') plt.savefig(outputFileScatter) y_hat = w[0] * data[rgb2].data + w[1] print("y_hat.shape: ", y_hat.shape) # set clear sky to 0 y_hat[ind_clear] = 0 y_hat = ma.asarray(y_hat) y_hat.mask = (y_hat == 9999.9) | (y_hat <= 0.0001) from trollimage.colormap import RainRate colormap = rainbow min_data = 0.0 #max_data=y_hat.max() max_data = 8 colormap.set_range(min_data, max_data) #colormap = RainRate in_msg.colormap[rgb] = colormap units = 'mm/h' img = trollimage(y_hat, mode="L") img.colorize(in_msg.colormap[rgb]) in_msg.colormap[rgb] = colormap.reverse() PIL_image = img.pil_image() outputFile = outputDir + format_name( 'fit_%(area)s_%Y%m%d%H%M_%(rgb)s_precip.png', data.time_slot, area=area, rgb=rgb, sat_nr=data.number) #PIL_image.save(outputFile) ## add coasts, borders, and rivers, database is heree ## http://www.soest.hawaii.edu/pwessel/gshhs/index.html ## possible resolutions ## f full resolution: Original (full) data resolution. ## h high resolution: About 80 % reduction in size and quality. ## i intermediate resolution: Another ~80 % reduction. ## l low resolution: Another ~80 % reduction. ## c crude resolution: Another ~80 % reduction. if in_msg.add_rivers: if in_msg.verbose: print(" add rivers to image (resolution=" + resolution + ")") cw.add_rivers(PIL_image, area_tuple, outline='blue', resolution=resolution, outline_opacity=127, width=0.5, level=5) # if in_msg.verbose: print(" add lakes to image (resolution=" + resolution + ")") cw.add_coastlines(PIL_image, area_tuple, outline='blue', resolution=resolution, outline_opacity=127, width=0.5, level=2) #, outline_opacity=0 if in_msg.add_borders: if in_msg.verbose: print(" add coastlines to image (resolution=" + resolution + ")") cw.add_coastlines(PIL_image, area_tuple, outline=(255, 0, 0), resolution=resolution, width=1) #, outline_opacity=0 if in_msg.verbose: print(" add borders to image (resolution=" + resolution + ")") cw.add_borders(PIL_image, area_tuple, outline=(255, 0, 0), resolution=resolution, width=1) #, outline_opacity=0 #if area.find("EuropeCanary") != -1 or area.find("ccs4") != -1: dc = DecoratorAGG(PIL_image) # add title to image if in_msg.add_title: PIL_image = add_title(PIL_image, rgb, int(data.number), dateS, hourS, minS, area, dc, in_msg.font_file, in_msg.verbose) # add MeteoSwiss and Pytroll logo if in_msg.add_logos: if in_msg.verbose: print('... add logos') dc.align_right() if in_msg.add_colorscale: dc.write_vertically() dc.add_logo("../logos/meteoSwiss3.jpg", height=60.0) dc.add_logo("../logos/pytroll3.jpg", height=60.0) # add colorscale if in_msg.add_colorscale and in_msg.colormap[rgb] is not None: dc.align_right() dc.write_vertically() font_scale = aggdraw.Font( "black", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif-Bold.ttf", size=16) # get tick marks tick_marks = 20 # default minor_tick_marks = 5 # default if rgb in list(in_msg.tick_marks.keys()): tick_marks = in_msg.tick_marks[rgb] if rgb in list(in_msg.minor_tick_marks.keys()): minor_tick_marks = in_msg.minor_tick_marks[rgb] if rgb.find( "-" ) != -1: # for channel differences use tickmarks of 1 tick_marks = 1 minor_tick_marks = 1 tick_marks = 2 # default minor_tick_marks = 1 # default if in_msg.verbose: print('... add colorscale') dc.add_scale(in_msg.colormap[rgb], extend=True, tick_marks=tick_marks, minor_tick_marks=minor_tick_marks, font=font_scale, line_opacity=100) #, unit='T / K' ## test to plot a wind barb #import matplotlib.pyplot as plt #ax = plt.axes(PIL_image) #ax.barbs(0, 0, 20, 20, length=8, pivot='middle', barbcolor='red') #ax.barbs(8, 46, 20, 20, length=8, pivot='middle', barbcolor='red') # check if output directory exists, if not create it path = dirname(outputFile) if not exists(path): if in_msg.verbose: print('... create output directory: ' + path) makedirs(path) # save file if in_msg.verbose: print('... save final file :' + outputFile) PIL_image.save(outputFile, optimize=True) # optimize -> minimize file size if in_msg.compress_to_8bit: if in_msg.verbose: print('... compress to 8 bit image: display ' + outputFile.replace(".png", "-fs8.png") + ' &') subprocess.call("/usr/bin/pngquant -force 256 " + outputFile + " 2>&1 &", shell=True) # 256 == "number of colors" #if in_msg.verbose: # print " add coastlines to "+outputFile ## alternative: reopen image and modify it (takes longer due to additional reading and saving) #cw.add_rivers_to_file(img, area_tuple, level=5, outline='blue', width=0.5, outline_opacity=127) #cw.add_coastlines_to_file(outputFile, obj_area, resolution=resolution, level=4) #cw.add_borders_to_file(outputFile, obj_area, outline=outline, resolution=resolution) # copy to another place if in_msg.scpOutput: if in_msg.verbose: print("... secure copy " + outputFile + " to " + in_msg.scpOutputDir) subprocess.call("scp " + in_msg.scpID + " " + outputFile + " " + in_msg.scpOutputDir + " 2>&1 &", shell=True) if in_msg.compress_to_8bit: if in_msg.verbose: print("... secure copy " + outputFile.replace(".png", "-fs8.png") + " to " + in_msg.scpOutputDir) subprocess.call( "scp " + in_msg.scpID + " " + outputFile.replace(".png", "-fs8.png") + " " + in_msg.scpOutputDir + " 2>&1 &", shell=True) if rgb not in RGBs_done: RGBs_done.append(rgb) ## start postprocessing if area in in_msg.postprocessing_areas: postprocessing(in_msg, global_data.time_slot, data.number, area) if in_msg.verbose: print(" ") return RGBs_done
def main(): parser = get_parser() args = parser.parse_args() levels = [logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG] logging.basicConfig(level=levels[min(3, args.verbosity)]) if args.output_filename is None: args.output_filename = [x[:-3] + "png" for x in args.input_tiff] else: assert len(args.output_filename) == len(args.input_tiff), "Output filenames must be equal to number of input tiffs" if not (args.add_borders or args.add_coastlines or args.add_grid or args.add_rivers or args.add_colorbar): LOG.error("Please specify one of the '--add-X' options to modify the image") return -1 # we may be dealing with large images that look like decompression bombs # let's turn off the check for the image size in PIL/Pillow Image.MAX_IMAGE_PIXELS = None for input_tiff, output_filename in zip(args.input_tiff, args.output_filename): LOG.info("Creating {} from {}".format(output_filename, input_tiff)) gtiff = gdal.Open(input_tiff) proj4_str = osr.SpatialReference(gtiff.GetProjection()).ExportToProj4() ul_x, res_x, _, ul_y, _, res_y = gtiff.GetGeoTransform() half_pixel_x = res_x / 2. half_pixel_y = res_y / 2. area_extent = ( ul_x - half_pixel_x, # lower-left X ul_y + res_y * gtiff.RasterYSize - half_pixel_y, # lower-left Y ul_x + res_x * gtiff.RasterXSize + half_pixel_x, # upper-right X ul_y + half_pixel_y, # upper-right Y ) img = Image.open(input_tiff).convert('RGB') area_def = (proj4_str, area_extent) cw = ContourWriterAGG(args.shapes_dir) if args.add_coastlines: outline = args.coastlines_outline[0] if len(args.coastlines_outline) == 1 else tuple(int(x) for x in args.coastlines_outline) if args.coastlines_fill: fill = args.coastlines_fill[0] if len(args.coastlines_fill) == 1 else tuple(int(x) for x in args.coastlines_fill) else: fill = None cw.add_coastlines(img, area_def, resolution=args.coastlines_resolution, level=args.coastlines_level, outline=outline, fill=fill) if args.add_rivers: outline = args.rivers_outline[0] if len(args.rivers_outline) == 1 else tuple(int(x) for x in args.rivers_outline) cw.add_rivers(img, area_def, resolution=args.rivers_resolution, level=args.rivers_level, outline=outline) if args.add_borders: outline = args.borders_outline[0] if len(args.borders_outline) == 1 else tuple(int(x) for x in args.borders_outline) cw.add_borders(img, area_def, resolution=args.borders_resolution, level=args.borders_level, outline=outline) if args.add_grid: outline = args.grid_outline[0] if len(args.grid_outline) == 1 else tuple(int(x) for x in args.grid_outline) minor_outline = args.grid_minor_outline[0] if len(args.grid_minor_outline) == 1 else tuple(int(x) for x in args.grid_minor_outline) fill = args.grid_fill[0] if len(args.grid_fill) == 1 else tuple(int(x) for x in args.grid_fill) font_path = find_font(args.grid_font, args.grid_text_size) font = Font(outline, font_path, size=args.grid_text_size) cw.add_grid(img, area_def, args.grid_D, args.grid_d, font, fill=fill, outline=outline, minor_outline=minor_outline, write_text=args.grid_text, lon_placement=args.grid_lon_placement, lat_placement=args.grid_lat_placement) if args.add_colorbar: from pydecorate import DecoratorAGG font_color = args.colorbar_text_color font_color = font_color[0] if len(font_color) == 1 else tuple(int(x) for x in font_color) font_path = find_font(args.colorbar_font, args.colorbar_text_size) # this actually needs an aggdraw font font = Font(font_color, font_path, size=args.colorbar_text_size) band_count = gtiff.RasterCount if band_count not in [1, 2]: raise ValueError("Can't add colorbar to RGB/RGBA image") # figure out what colormap we are dealing with band = gtiff.GetRasterBand(1) cmap = get_colormap(band, band_count) # figure out our limits vmin = args.colorbar_min vmax = args.colorbar_max metadata = gtiff.GetMetadata_Dict() vmin = vmin or metadata.get('min_in') vmax = vmax or metadata.get('max_in') if isinstance(vmin, str): vmin = float(vmin) if isinstance(vmax, str): vmax = float(vmax) if vmin is None or vmax is None: data = gtiff.GetRasterBand(1).ReadAsArray() vmin = vmin or np.iinfo(data.dtype).min vmax = vmax or np.iinfo(data.dtype).max cmap.set_range(vmin, vmax) dc = DecoratorAGG(img) if args.colorbar_align == 'top': dc.align_top() elif args.colorbar_align == 'bottom': dc.align_bottom() elif args.colorbar_align == 'left': dc.align_left() elif args.colorbar_align == 'right': dc.align_right() if args.colorbar_vertical: dc.write_vertically() else: dc.write_horizontally() if args.colorbar_width is None or args.colorbar_height is None: LOG.warning("'--colorbar-width' or '--colorbar-height' were " "not specified. Forcing '--colorbar-extend'.") args.colorbar_extend = True kwargs = {} if args.colorbar_width: kwargs['width'] = args.colorbar_width if args.colorbar_height: kwargs['height'] = args.colorbar_height dc.add_scale(cmap, extend=args.colorbar_extend, font=font, line=font_color, tick_marks=args.colorbar_tick_marks, title=args.colorbar_title, unit=args.colorbar_units, **kwargs) img.save(output_filename)
def main(): parser = get_parser() args = parser.parse_args() levels = [logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG] logging.basicConfig(level=levels[min(3, args.verbosity)]) if args.output_filename is None: args.output_filename = [x[:-3] + "png" for x in args.input_tiff] else: assert len(args.output_filename) == len( args.input_tiff ), "Output filenames must be equal to number of input tiffs" if not (args.add_borders or args.add_coastlines or args.add_grid or args.add_rivers or args.add_colorbar): LOG.error("Please specify one of the '--add-X' options to modify the image") return -1 if args.cache_dir and not os.path.isdir(args.cache_dir): LOG.info(f"Creating cache directory: {args.cache_dir}") os.makedirs(args.cache_dir, exist_ok=True) # we may be dealing with large images that look like decompression bombs # let's turn off the check for the image size in PIL/Pillow Image.MAX_IMAGE_PIXELS = None # gather all options into a single dictionary that we can pass to pycoast pycoast_options = _args_to_pycoast_dict(args) for input_tiff, output_filename in zip(args.input_tiff, args.output_filename): LOG.info("Creating {} from {}".format(output_filename, input_tiff)) img = Image.open(input_tiff) img_bands = img.getbands() num_bands = len(img_bands) # P = palette which we assume to be an RGBA colormap img = img.convert("RGBA" if num_bands in (2, 4) or "P" in img_bands else "RGB") if pycoast_options: area_id = os.path.splitext(input_tiff[0])[0] area_def = get_area_def_from_raster(input_tiff, area_id=area_id) cw = ContourWriterAGG(args.shapes_dir) cw.add_overlay_from_dict(pycoast_options, area_def, background=img) if args.add_colorbar: from pydecorate import DecoratorAGG font_color = args.colorbar_text_color font_color = font_color[0] if len(font_color) == 1 else tuple(int(x) for x in font_color) font_path = find_font(args.colorbar_font, args.colorbar_text_size) # this actually needs an aggdraw font font = Font(font_color, font_path, size=args.colorbar_text_size) if num_bands not in (1, 2): raise ValueError("Can't add colorbar to RGB/RGBA image") # figure out what colormap we are dealing with rio_ds = rasterio.open(input_tiff) input_dtype = np.dtype(rio_ds.meta["dtype"]) rio_ct = _get_rio_colormap(rio_ds, 1) cmap = get_colormap(input_dtype, rio_ct, num_bands) # figure out our limits vmin = args.colorbar_min vmax = args.colorbar_max metadata = rio_ds.tags() vmin = vmin or metadata.get("min_in") vmax = vmax or metadata.get("max_in") if isinstance(vmin, str): vmin = float(vmin) if isinstance(vmax, str): vmax = float(vmax) if vmin is None or vmax is None: vmin = vmin or np.iinfo(input_dtype).min vmax = vmax or np.iinfo(input_dtype).max cmap.set_range(vmin, vmax) dc = DecoratorAGG(img) if args.colorbar_align == "top": dc.align_top() elif args.colorbar_align == "bottom": dc.align_bottom() elif args.colorbar_align == "left": dc.align_left() elif args.colorbar_align == "right": dc.align_right() if args.colorbar_vertical: dc.write_vertically() else: dc.write_horizontally() if args.colorbar_width is None or args.colorbar_height is None: LOG.warning( "'--colorbar-width' or '--colorbar-height' were " "not specified. Forcing '--colorbar-extend'." ) args.colorbar_extend = True kwargs = {} if args.colorbar_width: kwargs["width"] = args.colorbar_width if args.colorbar_height: kwargs["height"] = args.colorbar_height dc.add_scale( cmap, extend=args.colorbar_extend, font=font, line=font_color, tick_marks=args.colorbar_tick_marks, title=args.colorbar_title, unit=args.colorbar_units, **kwargs, ) img.save(output_filename)
#dc.align_right() #dc.align_bottom() #dc.add_logo("logos/pytroll_light_big.png") #dc.add_logo("logos/NASA_Logo.gif") #dc.add_text("This is manually\nplaced text\nover here.",cursor=[400,480]) dc.new_line() dc.add_text("This here is\na new line\nof features") dc.add_logo("logos/pytroll_light_big.png") dc.align_right() dc.write_vertically() dc.add_text("Now writing\nvertically",height=0) dc.add_logo("logos/pytroll_light_big.png") dc.add_logo("logos/NASA_Logo.gif") img.show() exit() #dc.toggle_direction() dc.add_logo("logos/pytroll_light_big.png",height=60) dc.add_logo("logos/NASA_Logo.gif")
def plot_msg(in_msg): # get date of the last SEVIRI observation if in_msg.datetime == None: in_msg.get_last_SEVIRI_date() yearS = str(in_msg.datetime.year) #yearS = yearS[2:] monthS = "%02d" % in_msg.datetime.month dayS = "%02d" % in_msg.datetime.day hourS = "%02d" % in_msg.datetime.hour minS = "%02d" % in_msg.datetime.minute dateS=yearS+'-'+monthS+'-'+dayS timeS=hourS+'-'+minS if in_msg.sat_nr==None: in_msg.sat_nr=choose_msg(in_msg.datetime,in_msg.RSS) if in_msg.datetime.year > 2012: if in_msg.sat_nr == 8: area_loaded = get_area_def("EuropeCanary35") elif in_msg.sat_nr == 9: # rapid scan service satellite area_loaded = get_area_def("EuropeCanary95") elif in_msg.sat_nr == 10: # default satellite area_loaded = get_area_def("met09globeFull") # full disk service, like EUMETSATs NWC-SAF products elif in_msg.sat_nr == 0: # fake satellite for reprojected ccs4 data in netCDF area_loaded = get_area_def("ccs4") # #area_loaded = get_area_def("EuropeCanary") #area_loaded = get_area_def("alps") # new projection of SAM else: print("*** Error, unknown satellite number ", in_msg.sat_nr) area_loaded = get_area_def("hsaf") # else: if in_msg.sat_nr == 8: area_loaded = get_area_def("EuropeCanary95") elif in_msg.sat_nr == 9: # default satellite area_loaded = get_area_def("EuropeCanary") # define contour write for coasts, borders, rivers cw = ContourWriterAGG(in_msg.mapDir) if type(in_msg.sat_nr) is int: sat_nr_str = str(in_msg.sat_nr).zfill(2) elif type(in_msg.sat_nr) is str: sat_nr_str = in_msg.sat_nr else: print("*** Waring, unknown type of sat_nr", type(in_msg.sat_nr)) sat_nr_str = in_msg.sat_nr if in_msg.verbose: print('*** Create plots for ') print(' Satellite/Sensor: '+in_msg.sat + ' ' + sat_nr_str) print(' Date/Time: '+dateS +' '+hourS+':'+minS+'UTC') print(' RGBs: ', in_msg.RGBs) print(' Area: ', in_msg.areas) # check if input data is complete if in_msg.verbose: print("*** check input data") RGBs = check_input(in_msg, in_msg.sat+sat_nr_str, in_msg.datetime) if len(RGBs) != len(in_msg.RGBs): print("*** Warning, input not complete.") print("*** Warning, process only: ", RGBs) # define satellite data object global_data = GeostationaryFactory.create_scene(in_msg.sat, sat_nr_str, "seviri", in_msg.datetime) # print "type(global_data) ", type(global_data) # <class 'mpop.scene.SatelliteInstrumentScene'> # print "dir(global_data)", dir(global_data) [..., '__init__', ... 'area', 'area_def', 'area_id', 'channel_list', 'channels', # 'channels_to_load', 'check_channels', 'fullname', 'get_area', 'image', 'info', 'instrument_name', 'lat', 'load', 'loaded_channels', # 'lon', 'number', 'orbit', 'project', 'remove_attribute', 'satname', 'save', 'set_area', 'time_slot', 'unload', 'variant'] ## define satellite data object one scan before #if in_msg.RSS: # scan_time = 5 # min #else: # scan_time = 15 # min scan_time = 15 # min datetime_m1 = in_msg.datetime - timedelta(minutes=scan_time) global_data_m1 = GeostationaryFactory.create_scene(in_msg.sat, sat_nr_str, "seviri", datetime_m1) if len(RGBs) == 0: return RGBs if in_msg.verbose: print("*** load satellite channels for "+in_msg.sat+sat_nr_str+" ", global_data.fullname) # initialize processed RGBs RGBs_done=[] # load reflectivities, brightness temperatures, NWC-SAF products ... print("*** read ", str(in_msg.datetime)) area_loaded = load_products(global_data, RGBs, in_msg, area_loaded) #print "*** read ", str(datetime_m1) #area_loaded = load_products(global_data_m1, RGBs, in_msg, area_loaded) # check if all prerequisites are loaded #rgb_complete = [] #for rgb in RGBs: # all_loaded = True # if rgb in products.RGBs_buildin or rgb in products.RGB_user: # obj_image = get_image(global_data, rgb) # for pre in obj_image.prerequisites: # if pre not in loaded_channels: # all_loaded = False # elif rgb in products.MSG_color: # if rgb.replace("c","") not in loaded_channels: # all_loaded = False # else: # if rgb not in loaded_channels: # all_loaded = False # if all_loaded: # rgb_complete.append(rgb) #print "rgb_complete", rgb_complete # preprojecting the data to another area # -------------------------------------- for area in in_msg.areas: print("") obj_area = get_area_def(area) # reproject data to new area if obj_area == area_loaded: if in_msg.verbose: print("*** Use data for the area loaded: ", area) #obj_area = area_loaded data = global_data data_m1 = global_data_m1 resolution='l' else: if in_msg.verbose: print("*** Reproject data to area: ", area, "(org projection: ", area_loaded.name, ")") obj_area = get_area_def(area) # PROJECT data to new area data = global_data.project(area, precompute=True) data_m1 = global_data_m1.project(area, precompute=True) resolution='i' loaded_products = [chn.name for chn in data.loaded_channels()] print(loaded_products) #loaded_products_m1 = [chn.name for chn in data_m1.loaded_channels()] #print loaded_products_m1 #for prod in loaded_products: # print "xxx ", prod # print data_m1[prod] # data[prod] = data[prod] - data_m1[prod] # # save reprojected data if area in in_msg.save_reprojected_data: save_reprojected_data(data, area, in_msg) # apply a mask to the data (switched off at the moment) if False: mask_data(data, area) # save average values if in_msg.save_statistics: mean_array = zeros(len(RGBs)) #statisticFile = '/data/COALITION2/database/meteosat/ccs4/'+yearS+'/'+monthS+'/'+dayS+'/MSG_'+area+'_'+yearS[2:]+monthS+dayS+'.txt' statisticFile = './'+yearS+'-'+monthS+'-'+dayS+'/MSG_'+area+'_'+yearS[2:]+monthS+dayS+'.txt' if in_msg.verbose: print("*** write statistics (average values) to "+statisticFile) f1 = open(statisticFile,'a') # mode append i_rgb=0 for rgb in RGBs: if rgb in products.MSG_color: mean_array[i_rgb]=data[rgb.replace("c","")].data.mean() i_rgb=i_rgb+1 # create string to write str2write = dateS +' '+hourS+' : '+minS+' UTC ' for mm in mean_array: str2write = str2write+' '+ "%7.2f" % mm str2write = str2write+"\n" f1.write(str2write) f1.close() # creating plots/images if in_msg.make_plots: # choose map resolution resolution = choose_map_resolution(area, in_msg.mapResolution) # define area proj4_string = obj_area.proj4_string # e.g. proj4_string = '+proj=geos +lon_0=0.0 +a=6378169.00 +b=6356583.80 +h=35785831.0' area_extent = obj_area.area_extent # e.g. area_extent = (-5570248.4773392612, -5567248.074173444, 5567248.074173444, 5570248.4773392612) area_tuple = (proj4_string, area_extent) for rgb in RGBs: PIL_image = create_PIL_image(rgb, data, in_msg) # !!! in_msg.colorbar[rgb] is initialized inside (give attention to rgbs) !!! if in_msg.add_rivers: if in_msg.verbose: print(" add rivers to image (resolution="+resolution+")") cw.add_rivers(PIL_image, area_tuple, outline='blue', resolution=resolution, outline_opacity=127, width=0.5, level=5) # if in_msg.verbose: print(" add lakes to image (resolution="+resolution+")") cw.add_coastlines(PIL_image, area_tuple, outline='blue', resolution=resolution, outline_opacity=127, width=0.5, level=2) #, outline_opacity=0 if in_msg.add_borders: if in_msg.verbose: print(" add coastlines to image (resolution="+resolution+")") cw.add_coastlines(PIL_image, area_tuple, outline=(255, 0, 0), resolution=resolution, width=1) #, outline_opacity=0 if in_msg.verbose: print(" add borders to image (resolution="+resolution+")") cw.add_borders(PIL_image, area_tuple, outline=(255, 0, 0), resolution=resolution, width=1) #, outline_opacity=0 #if area.find("EuropeCanary") != -1 or area.find("ccs4") != -1: dc = DecoratorAGG(PIL_image) # add title to image if in_msg.add_title: add_title(PIL_image, rgb, int(data.number), dateS, hourS, minS, area, dc, in_msg.font_file, in_msg.verbose ) # add MeteoSwiss and Pytroll logo if in_msg.add_logos: if in_msg.verbose: print('... add logos') dc.align_right() if in_msg.add_colorscale: dc.write_vertically() dc.add_logo("../logos/meteoSwiss3.jpg",height=60.0) dc.add_logo("../logos/pytroll3.jpg",height=60.0) # add colorscale if in_msg.add_colorscale and in_msg.colormap[rgb] != None: add_colorscale(dc, rgb, in_msg) # create output filename outputDir = format_name(in_msg.outputDir, data.time_slot, area=area, rgb=rgb, sat_nr=data.number) outputFile = outputDir + format_name(in_msg.outputFile, data.time_slot, area=area, rgb=rgb, sat_nr=data.number) # check if output directory exists, if not create it path= dirname(outputFile) if not exists(path): if in_msg.verbose: print('... create output directory: ' + path) makedirs(path) # save file if in_msg.verbose: print('... save final file :' + outputFile) PIL_image.save(outputFile, optimize=True) # optimize -> minimize file size if in_msg.compress_to_8bit: if in_msg.verbose: print('... compress to 8 bit image: display '+outputFile.replace(".png","-fs8.png")+' &') subprocess.call("/usr/bin/pngquant -force 256 "+outputFile+" 2>&1 &", shell=True) # 256 == "number of colors" #if in_msg.verbose: # print " add coastlines to "+outputFile ## alternative: reopen image and modify it (takes longer due to additional reading and saving) #cw.add_rivers_to_file(img, area_tuple, level=5, outline='blue', width=0.5, outline_opacity=127) #cw.add_coastlines_to_file(outputFile, obj_area, resolution=resolution, level=4) #cw.add_borders_to_file(outputFile, obj_area, outline=outline, resolution=resolution) # copy to another place if in_msg.scpOutput: if in_msg.verbose: print("... secure copy "+outputFile+ " to "+in_msg.scpOutputDir) subprocess.call("scp "+in_msg.scpID+" "+outputFile+" "+in_msg.scpOutputDir+" 2>&1 &", shell=True) if in_msg.compress_to_8bit: if in_msg.verbose: print("... secure copy "+outputFile.replace(".png","-fs8.png")+ " to "+in_msg.scpOutputDir) subprocess.call("scp "+in_msg.scpID+" "+outputFile.replace(".png","-fs8.png")+" "+in_msg.scpOutputDir+" 2>&1 &", shell=True) if rgb not in RGBs_done: RGBs_done.append(rgb) ## start postprocessing if area in in_msg.postprocessing_areas: postprocessing(in_msg, global_data.time_slot, data.number, area) if in_msg.verbose: print(" ") return RGBs_done