def test_config_file_points_and_borders_agg(self): from pycoast import ContourWriterAGG from pyresample.geometry import AreaDefinition config_file = os.path.join(os.path.dirname(__file__), 'nh_points_agg.ini') grid_img = Image.open( os.path.join(os.path.dirname(__file__), 'nh_points_agg.png')) grid_data = np.array(grid_img) img = Image.new('RGB', (1024, 1024), (255, 255, 255)) proj4_string = '+proj=laea +lat_0=90 +lon_0=0 +a=6371228.0 +units=m' area_extent = (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625) area_def = AreaDefinition('nh', 'nh', 'nh', proj4_string, 1024, 1024, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_overlay_from_config(config_file, area_def, img) res = np.array(img) self.assertTrue( fft_metric(grid_data, res), 'Add points with agg module from a config file failed')
def test_config_file_coasts_and_grid(self): from pycoast import ContourWriterAGG from pyresample.geometry import AreaDefinition overlay_config = os.path.join(os.path.dirname(__file__), "coasts_and_grid_agg.ini") grid_img = Image.open( os.path.join(os.path.dirname(__file__), 'grid_nh_cfg_agg.png')) grid_data = np.array(grid_img) proj_dict = { 'proj': 'laea', 'lat_0': 90.0, 'lon_0': 0.0, 'a': 6371228.0, 'units': 'm' } area_extent = (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625) area_def = AreaDefinition('nh', 'nh', 'nh', proj_dict, 850, 850, area_extent) cw = ContourWriterAGG(gshhs_root_dir) overlay = cw.add_overlay_from_config(overlay_config, area_def) img = Image.new('RGB', (850, 850), (255, 255, 255)) img.paste(overlay, mask=overlay) res = np.array(img) self.assertTrue(fft_metric(grid_data, res), 'Writing of nh grid failed')
def test_grid_nh_agg(self): from pycoast import ContourWriterAGG import aggdraw grid_img = Image.open( os.path.join(os.path.dirname(__file__), 'grid_nh_agg.png')) grid_data = np.array(grid_img) img = Image.new('RGB', (425, 425)) proj4_string = '+proj=laea +lat_0=90 +lon_0=0 +a=6371228.0 +units=m' area_extent = (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines(img, area_def, resolution='l', level=4) font = aggdraw.Font('blue', os.path.join(os.path.dirname(__file__), 'test_data', 'DejaVuSerif.ttf'), size=10) cw.add_grid(img, area_def, (10.0, 10.0), (2.0, 2.0), font=font, fill='blue', outline='blue', minor_outline='blue', lon_placement='tblr', lat_placement='') res = np.array(img) # NOTE: Experience inconsistency in ttf font writing between systems. # Still trying to figure out why this test sometimes fails to write # correct font markings. self.assertTrue(fft_metric(grid_data, res), 'Writing of nh grid failed for AGG')
def add_overlay(orig, area, coast_dir, color=(0, 0, 0), width=0.5, resolution=None): """Add coastline and political borders to image, using *color* (tuple of integers between 0 and 255). Warning: Loses the masks ! *resolution* is chosen automatically if None (default), otherwise it should be one of: +-----+-------------------------+---------+ | 'f' | Full resolution | 0.04 km | | 'h' | High resolution | 0.2 km | | 'i' | Intermediate resolution | 1.0 km | | 'l' | Low resolution | 5.0 km | | 'c' | Crude resolution | 25 km | +-----+-------------------------+---------+ """ img = orig.pil_image() if area is None: raise ValueError("Area of image is None, can't add overlay.") from satpy.resample import get_area_def if isinstance(area, str): area = get_area_def(area) LOG.info("Add coastlines and political borders to image.") if resolution is None: x_resolution = ((area.area_extent[2] - area.area_extent[0]) / area.x_size) y_resolution = ((area.area_extent[3] - area.area_extent[1]) / area.y_size) res = min(x_resolution, y_resolution) if res > 25000: resolution = "c" elif res > 5000: resolution = "l" elif res > 1000: resolution = "i" elif res > 200: resolution = "h" else: resolution = "f" LOG.debug("Automagically choose resolution " + resolution) from pycoast import ContourWriterAGG cw_ = ContourWriterAGG(coast_dir) cw_.add_coastlines(img, area, outline=color, resolution=resolution, width=width) cw_.add_borders(img, area, outline=color, resolution=resolution, width=width) arr = np.array(img) if len(orig.channels) == 1: orgi.channels[0] = np.ma.array(arr[:, :] / 255.0) else: for idx in range(len(orig.channels)): orig.channels[idx] = np.ma.array(arr[:, :, idx] / 255.0)
def test_europe_agg_file(self): from pycoast import ContourWriterAGG euro_img = Image.open( os.path.join(os.path.dirname(__file__), 'contours_europe_agg.png')) euro_data = np.array(euro_img) proj4_string = '+proj=stere +lon_0=8.00 +lat_0=50.00 +lat_ts=50.00 +ellps=WGS84' area_extent = (-3363403.31, -2291879.85, 2630596.69, 2203620.1) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines_to_file(test_file, area_def, resolution='l', level=4) cw.add_rivers_to_file(test_file, area_def, level=5, outline='blue', width=0.5, outline_opacity=127) cw.add_borders_to_file(test_file, area_def, outline=(255, 0, 0), width=3, outline_opacity=32) img = Image.open(test_file) res = np.array(img) self.failUnless(fft_metric(euro_data, res), 'Writing of contours failed for AGG')
def test_add_shapefile_shapes_agg(self): from pycoast import ContourWriterAGG grid_img = Image.open(os.path.join(os.path.dirname(__file__), 'brazil_shapefiles_agg.png')) grid_data = np.array(grid_img) img = Image.new('RGB', (425, 425)) proj4_string = \ '+proj=merc +lon_0=-60 +lat_ts=-30.0 +a=6371228.0 +units=m' area_extent = (-2000000.0, -5000000.0, 5000000.0, 2000000.0) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines(img, area_def, resolution='l', level=4) cw.add_shapefile_shapes(img, area_def, os.path.join( os.path.dirname(__file__), 'test_data/shapes/Metareas.shp'), outline='red', width=2) cw.add_shapefile_shape(img, area_def, os.path.join(os.path.dirname(__file__), 'test_data/shapes/divisao_politica/BR_Regioes.shp'), 3, outline='blue') cw.add_shapefile_shape(img, area_def, os.path.join(os.path.dirname(__file__), 'test_data/shapes/divisao_politica/BR_Regioes.shp'), 4, outline='blue', fill='green') res = np.array(img) self.assertTrue( fft_metric(grid_data, res), 'Writing of Brazil shapefiles failed')
def generate_image(global_data, filename): """ This function generates an RGB composite directly from a scene with loaded channels and saves to a GeoTiff :param global_data: an mpop scene object with data from IR channels 12.0, 10.8, 8.7 :param filename: a string with the name of the image file to be generated """ # Generate a dust composite with Pytroll inbuilt function img = global_data.image.dust() # Save the image initially so it can be read in as an image object img.save("/ouce-home/students/hert4173/SEVIRI_imagery/" + filename) # Read it back in as an image object img = Image.open("/ouce-home/students/hert4173/SEVIRI_imagery/" + filename) # Define projection parameters proj4_string = '+proj=geos +lon_0=0.0 +a=6378169.00 +b=6356583.80 ' \ '+h=35785831.0' area_extent = (-2000000, 0, 3000000, 4000000) area_def = (proj4_string, area_extent) # ContourWriterAGG here requires the 'aggdraw' package cw = ContourWriterAGG( '/ouce-home/students/hert4173/.conda_envs/virtual_env/lib/python2.7/' 'pycoast/GSHHS_DATA_ROOT') cw.add_coastlines(img, area_def, resolution='i', width=3) cw.add_borders(img, area_def, outline=(255, 255, 255), resolution='i', width=3) img.save("/ouce-home/students/hert4173/SEVIRI_imagery/" + filename)
def test_grid_agg_txt(self): from pycoast import ContourWriterAGG import aggdraw grid_img = Image.open( os.path.join(os.path.dirname(__file__), 'grid_europe_agg_txt.png')) grid_data = np.array(grid_img) img = Image.new('RGB', (640, 480)) proj4_string = '+proj=stere +lon_0=8.00 +lat_0=50.00 +lat_ts=50.00 +ellps=WGS84' area_extent = (-3363403.31, -2291879.85, 2630596.69, 2203620.1) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines(img, area_def, resolution='l', level=4) font = aggdraw.Font('blue', os.path.join(os.path.dirname(__file__), 'test_data', 'DejaVuSerif.ttf'), size=16, opacity=200) cw.add_grid(img, area_def, (10.0, 10.0), (2.0, 2.0), font=font, outline='blue', outline_opacity=255, width=1.0, minor_outline='lightblue', minor_outline_opacity=255, minor_width=0.5, minor_is_tick=False) res = np.array(img) self.failUnless(fft_metric(grid_data, res), 'Writing of grid failed for AGG')
def test_grid_nh(self): from pycoast import ContourWriterAGG import aggdraw grid_img = Image.open( os.path.join(os.path.dirname(__file__), 'grid_nh_agg.png')) grid_data = np.array(grid_img) img = Image.new('RGB', (425, 425)) proj4_string = '+proj=laea +lat_0=90 +lon_0=0 +a=6371228.0 +units=m' area_extent = (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines(img, area_def, resolution='l', level=4) font = aggdraw.Font('blue', os.path.join(os.path.dirname(__file__), 'test_data', 'DejaVuSerif.ttf'), size=10) cw.add_grid(img, area_def, (10.0, 10.0), (2.0, 2.0), font=font, fill='blue', outline='blue', minor_outline='blue', lon_placement='tblr', lat_placement='') res = np.array(img) self.failUnless(fft_metric(grid_data, res), 'Writing of nh grid failed for AGG')
def test_grid_agg_file(self): from pycoast import ContourWriterAGG grid_img = Image.open( os.path.join(os.path.dirname(__file__), 'grid_europe_agg.png')) grid_data = np.array(grid_img) proj4_string = '+proj=stere +lon_0=8.00 +lat_0=50.00 +lat_ts=50.00 +ellps=WGS84' area_extent = (-3363403.31, -2291879.85, 2630596.69, 2203620.1) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines_to_file(grid_file, area_def, resolution='l', level=4) cw.add_grid_to_file(grid_file, area_def, (10.0, 10.0), (2.0, 2.0), write_text=False, outline='blue', outline_opacity=255, width=1.0, minor_outline='lightblue', minor_outline_opacity=255, minor_width=0.5, minor_is_tick=False) img = Image.open(grid_file) res = np.array(img) self.failUnless(fft_metric(grid_data, res), 'Writing of grid failed for AGG')
def add_overlay(orig, area, coast_dir, color=(0, 0, 0), width=0.5, resolution=None, level_coast=1, level_borders=1): """Add coastline and political borders to image, using *color* (tuple of integers between 0 and 255). Warning: Loses the masks ! *resolution* is chosen automatically if None (default), otherwise it should be one of: +-----+-------------------------+---------+ | 'f' | Full resolution | 0.04 km | | 'h' | High resolution | 0.2 km | | 'i' | Intermediate resolution | 1.0 km | | 'l' | Low resolution | 5.0 km | | 'c' | Crude resolution | 25 km | +-----+-------------------------+---------+ """ if area is None: raise ValueError("Area of image is None, can't add overlay.") from pycoast import ContourWriterAGG if isinstance(area, str): area = get_area_def(area) LOG.info("Add coastlines and political borders to image.") if resolution is None: x_resolution = ((area.area_extent[2] - area.area_extent[0]) / area.x_size) y_resolution = ((area.area_extent[3] - area.area_extent[1]) / area.y_size) res = min(x_resolution, y_resolution) if res > 25000: resolution = "c" elif res > 5000: resolution = "l" elif res > 1000: resolution = "i" elif res > 200: resolution = "h" else: resolution = "f" LOG.debug("Automagically choose resolution %s", resolution) img = orig.pil_image() cw_ = ContourWriterAGG(coast_dir) cw_.add_coastlines(img, area, outline=color, resolution=resolution, width=width, level=level_coast) cw_.add_borders(img, area, outline=color, resolution=resolution, width=width, level=level_borders) arr = da.from_array(np.array(img) / 255.0, chunks=CHUNK_SIZE) orig.data = xr.DataArray(arr, dims=['y', 'x', 'bands'], coords={'y': orig.data.coords['y'], 'x': orig.data.coords['x'], 'bands': list(img.mode)})
def layout(self): self.layouter.layout() cw = ContourWriterAGG(self.layouter.shapes) LOGGER.debug("Add coast line layout (resolution %s, level %s)" % (self.resolution, CoastLineLayouter.MAX_LEVEL)) cw.add_coastlines(self.layouter.image, self.layouter.area, resolution=self.resolution, level=1)
def layout(self): self.layouter.layout() cw = ContourWriterAGG(self.layouter.shapes) LOGGER.debug("Add river layout (resolution %s, level %s)" % (self.resolution, RiverLayouter.MAX_LEVEL)) cw.add_rivers(self.layouter.image, self.layouter.area, resolution=self.resolution, level=1)
def _add_coastlines(self, img): x_range, y_range = self._view_extents # coerce into a py-coast format area_extent = (x_range[0], y_range[0], x_range[1], y_range[1]) area_def = (self._proj_str, area_extent) # Get the path to the shape files cur_dir = os.path.dirname(os.path.abspath(__file__)) shape_dir = os.path.realpath(os.path.join(cur_dir, 'gshhg')) cw = ContourWriterAGG(shape_dir) cw.add_coastlines(img, area_def, resolution='h', width=1.0, level=1, outline=(200, 156, 45))
def test_add_points_agg(self): from pycoast import ContourWriterAGG from pyresample.geometry import AreaDefinition font_file = os.path.join(os.path.dirname(__file__), 'test_data', 'DejaVuSerif.ttf') grid_img = Image.open( os.path.join(os.path.dirname(__file__), 'nh_points_agg.png')) grid_data = np.array(grid_img) img = Image.new('RGB', (1024, 1024), (255, 255, 255)) proj4_string = '+proj=laea +lat_0=90 +lon_0=0 +a=6371228.0 +units=m' area_extent = (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625) area_def = AreaDefinition('nh', 'nh', 'nh', proj4_string, 1024, 1024, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines(img, area_def, outline='black', resolution='l', level=4) cw.add_borders(img, area_def, outline='black', width=3, level=1, resolution='c') points_list = [((2.3522, 48.8566), 'Paris'), ((0.1278, 51.5074), 'London')] cw.add_points(img, area_def, points_list=points_list, font_file=font_file, symbol='circle', ptsize=16, outline='black', width=3, fill='red', fill_opacity=128, box_outline='blue', box_linewidth=0.5, box_fill='yellow', box_opacity=200) res = np.array(img) self.assertTrue(fft_metric(grid_data, res), 'Writing of nh points failed')
def test_coastlines_convert_to_rgba_agg(self): from pycoast import ContourWriterAGG proj4_string = \ '+proj=stere +lon_0=8.00 +lat_0=50.00 +lat_ts=50.00 +ellps=WGS84' area_extent = (-3363403.31, -2291879.85, 2630596.69, 2203620.1) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines_to_file(p_file_coasts, area_def, resolution='l', level=4) img = Image.open(p_file_coasts) image_mode = img.mode img.close() self.assertTrue(image_mode == 'RGBA', 'Conversion to RGBA failed.')
def test_geos_agg(self): from pycoast import ContourWriterAGG geos_img = Image.open( os.path.join(os.path.dirname(__file__), 'contours_geos_agg.png')) geos_data = np.array(geos_img) img = Image.new('RGB', (425, 425)) proj4_string = '+proj=geos +lon_0=0.0 +a=6378169.00 +b=6356583.80 +h=35785831.0' area_extent = (-5570248.4773392612, -5567248.074173444, 5567248.074173444, 5570248.4773392612) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines(img, (proj4_string, area_extent), resolution='l', width=0.5) res = np.array(img) self.failUnless(fft_metric(geos_data, res), 'Writing of geos contours failed for AGG')
def test_add_polygon_agg(self): from pycoast import ContourWriterAGG grid_img = Image.open( os.path.join(os.path.dirname(__file__), 'nh_polygons_agg.png')) grid_data = np.array(grid_img) img = Image.new('RGB', (425, 425)) proj4_string = '+proj=laea +lat_0=90 +lon_0=0 +a=6371228.0 +units=m' area_extent = (-5326849.0625, -5326849.0625, 5326849.0625, 5326849.0625) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) polygons = { 'REYKJAVIK_ATC_A': ((-20.0, 73.0), (0.0, 73.0), (0.0, 61.0), (-30.0, 61.0), (-39.0, 63.5), (-20, 70)), 'REYKJAVIK_ATC_B': ((-39, 63.5), (-55 + 4 / 6.0, 63.5), (-57 + 45 / 60.0, 65), (-76, 76), (-75, 78), (-60, 82), (0, 90), (30, 82), (0, 82), (0, 73), (-20, 73), (-20, 70)), 'REYKJAVIK_ATC': ((0.0, 73.0), (0.0, 61.0), (-30.0, 61.0), (-39, 63.5), (-55 + 4 / 6.0, 63.5), (-57 + 45 / 60.0, 65), (-76, 76), (-75, 78), (-60, 82), (0, 90), (30, 82), (0, 82)), 'ICELAND_BOX': ((-25, 62.5), (-25, 67), (-13, 67), (-13, 62.5)) } cw.add_polygon(img, area_def, polygons['REYKJAVIK_ATC'], outline='red', width=2) cw.add_polygon(img, area_def, polygons['ICELAND_BOX'], outline='green', fill='gray', width=2) cw.add_coastlines(img, area_def, resolution='l', level=4) res = np.array(img) self.assertTrue(fft_metric(grid_data, res), 'Writing of nh polygons failed')
def test_grid_geos_agg(self): from pycoast import ContourWriterAGG geos_img = Image.open(os.path.join(os.path.dirname(__file__), 'grid_geos_agg.png')) geos_data = np.array(geos_img) img = Image.new('RGB', (425, 425)) proj4_string = \ '+proj=geos +lon_0=0.0 +a=6378169.00 +b=6356583.80 +h=35785831.0' area_extent = (-5570248.4773392612, -5567248.074173444, 5567248.074173444, 5570248.4773392612) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(gshhs_root_dir) cw.add_coastlines(img, area_def, resolution='l') cw.add_grid(img, area_def, (10.0, 10.0), (2.0, 2.0), fill='blue', outline='blue', minor_outline='blue', write_text=False) res = np.array(img) self.assertTrue( fft_metric(geos_data, res), 'Writing of geos contours failed')
print('*** create the image') img = data.image.hr_overview() #if True: # img.show() #else: # filename=time_slot.strftime('MSG_'+chn+'-'+area+'_%y%m%d%H%M.png') # img.save(filename) PIL_image = img.pil_image() if True: print(" ") print('*** add the map overlap') from pycoast import ContourWriterAGG cw = ContourWriterAGG('/opt/users/common/shapes/') from mpop.projector import get_area_def obj_area = get_area_def(area) # 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) from plot_msg import add_borders_and_rivers ## 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.
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 main(): import argparse parser = argparse.ArgumentParser( description="Create a world map image of PyTroll contributor locations") parser.add_argument('--map-proj', default="+proj=moll", help='PROJ.4 map projection string to use for the output image') parser.add_argument('--output-size', default=(1200, 600), nargs=2, type=int, help='\'width height\' of output image') parser.add_argument('--contributor-color', default=(255, 127, 127), help='Color of dots for each contributor') parser.add_argument('--bg-color', default=None, nargs=3, type=int, help='Background color of image \'R G B\' 0-255 (default: transparent)') parser.add_argument('-o', '--output', default='contributors_map.png', help='Output filename to save the image to') parser.add_argument('-u', '--github-user', required=True, help='github username') args = parser.parse_args() logging.basicConfig(level=logging.INFO) # Check if we have the shapefile we want if not os.path.isfile('ne_110m_admin_0_countries.shp'): # Download the NaturalEarth shapefile we are going to use import urllib.request import shutil import zipfile url = "http://www.naturalearthdata.com/http//www.naturalearthdata.com/download/110m/cultural/ne_110m_admin_0_countries.zip" zip_fn = 'ne_110m_admin_0_countries.zip' LOG.info("Downloading NaturalEarth Shapefile") with urllib.request.urlopen(url) as response, open(zip_fn, 'wb') as out_file: shutil.copyfileobj(response, out_file) zip_ref = zipfile.ZipFile(zip_fn, 'r') zip_ref.extractall('.') zip_ref.close() im = Image.new('RGBA', args.output_size, color=tuple(args.bg_color) if args.bg_color is not None else None) cw = ContourWriterAGG() p = Proj(args.map_proj) a, _ = p(-180, 0) _, b = p(0, -90) c, _ = p(180, 0) _, d = p(0, 90) extents = (a, b, c, d) area_def = (args.map_proj, extents) LOG.info("Getting PyTroll contributors...") contributors = get_all_pytroll_contributors(args.github_user) LOG.info("Getting all PyTroll contributor locations...") all_user_locations = [] for user in contributors.values(): if user.location is None or user.location == '': LOG.info("User location not specified: ID: '{}';\tName: '{}';\tURL: '{}'".format(user.id, user.name, user.url)) continue all_user_locations.append(user.location) all_countries = list(get_country(all_user_locations)) number_contributors = Counter(all_countries) del number_contributors[None] all_countries = list(number_contributors.keys()) def shape_generator(): import shapefile reader = shapefile.Reader("ne_110m_admin_0_countries.shp") name_idx = [idx for idx, f in enumerate(reader.fields) if f[0] == 'name'][0] for sr in reader.shapeRecords(): name = sr.record[name_idx] if not isinstance(name, str): try: name = name.decode() except UnicodeDecodeError: name = name.decode('latin-1') shape_country = list(get_country([name]))[0] if shape_country is not None and shape_country in all_countries: LOG.info("Contributor country: %s, Code: %s, Number of Contributors: %d", name, shape_country, number_contributors[shape_country]) num_cont = min(number_contributors[shape_country], MAX_CONTRIBUTORS) kwargs = { 'fill': args.contributor_color, 'fill_opacity': int((num_cont / 10.) * 55 + 200) } yield sr.shape, kwargs else: LOG.debug("No contributor's from Country: %s, Code: %s", name, shape_country) yield sr.shape, None LOG.info("Applying contributor locations to map image...") cw.add_shapes(im, area_def, 'polygon', shape_generator(), outline=(0, 0, 0), outline_opacity=255, width=1, fill=(127, 127, 127), fill_opacity=127) im.save(args.output, dpi=(300, 300))
def show_swath_pycoast(self, start, period=None): """ A helper method that displays the orbital swath starting at datetime start, for a period number of minutes. If, start is iterable, then the method assumes it is an iterable of datetimes, plotting a number of swaths at those times. """ # test if start is iterable, EAFP style: try: for e in start: pass except TypeError: start = [start] start.sort() from PIL import Image from pycoast import ContourWriterAGG from pydecorate import DecoratorAGG img = Image.new('RGB', (650, 650)) proj4_string = "" for x in self.working_projection: proj4_string += "+%s=%s " % (x, self.working_projection[x]) area_extent = (-6700000.0, -6700000.0, 6700000.0, 6700000.0) area_def = (proj4_string, area_extent) cw = ContourWriterAGG() cw.add_grid(img, area_def, (10.0, 10.0), (2.0, 2.0), fill='blue', outline='gray', outline_opacity=130, minor_outline=None, write_text=False) # Plot granules for t in start: # fetch the coordinates xys_segs = self.swath_working_projection(t, period) for xys in xys_segs: lls = self.proj(xys[0], xys[1], inverse=True) cw.add_polygon(img, area_def, zip(lls[0], lls[1]), outline="blue", fill="blue", fill_opacity=70, width=1) cw.add_coastlines(img, area_def, resolution='l') aoi_coords = zip(*self.aoi) ## TODO: Handle single point case properly if len(aoi_coords) == 1: x, y = aoi_coords[0] d = 0.5 line_coords = [(x - d, y), (x + d, y)] cw.add_line(img, area_def, line_coords, outline="red", fill="red", fill_opacity=100, width=2) elif len(aoi_coords) == 2: cw.add_line(img, area_def, aoi_coords, outline="red", fill="red", fill_opacity=100, width=10) else: cw.add_polygon(img, area_def, aoi_coords, outline="red", fill="red", fill_opacity=100, width=2) # Decorate dc = DecoratorAGG(img) text = "Granules from time: %s + %.2f min." % ( start[0].strftime('%Y.%m.%d %H:%M:%S'), (start[-1] - start[0]).total_seconds() / 60.0) dc.align_bottom() dc.add_text(text, height=0) img.show()
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
"black", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif-Bold.ttf", size=16) colormap_r.set_range(min_data, max_data) dc.add_scale(colormap_r, extend=True, tick_marks=tick_marks, minor_tick_marks=minor_tick_marks, font=font_scale, line_opacity=100, unit=units) # if add_borders: from pycoast import ContourWriterAGG # define contour write for coasts, borders, rivers cw = ContourWriterAGG('/data/OWARNA/hau/maps_pytroll/') # define area from mpop.projector import get_area_def # obj_area = get_area_def('ccs4') 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_def = (proj4_string, area_extent) resolution = 'h' cw.add_borders(PIL_image, area_def, outline=(255, 0, 0), resolution=resolution, width=1) #, outline_opacity=0
print(" shape:") print(" height: " + str(ysize)) print(" width: " + str(xsize)) print(" area_extent:") print(" lower_left_xy: [%f, %f]" % (area_extent[0], area_extent[1])) print(" upper_right_xy: [%f, %f]" % (area_extent[2], area_extent[3])) if args.shapes is None: sys.exit(0) from PIL import Image from pycoast import ContourWriterAGG img = Image.new('RGB', (xsize, ysize)) #proj4_string = '+proj=geos +lon_0=0.0 +a=6378169.00 +b=6356583.80 +h=35785831.0' #area_extent = (-5570248.4773392612, -5567248.074173444, 5567248.074173444, 5570248.4773392612) area_def = (proj4_string, area_extent) cw = ContourWriterAGG(args.shapes) #cw = ContourWriterAGG('/usr/share/gshhg-gmt-shp/') cw.add_coastlines(img, (proj4_string, area_extent), resolution='l', width=0.5) cw.add_grid(img, area_def, (10.0, 10.0), (2.0, 2.0), write_text=False, outline='white', outline_opacity=175, width=1.0, minor_outline='white', minor_outline_opacity=175, minor_width=0.2, minor_is_tick=False)