#! /usr/bin/env python3 import sys import argparse import cairo from xmet.config import Config from xmet.db import Database from xmet.spc import SPCOutlookParser, \ SPCOutlook, \ SPCOutlookMap, \ SPCOutlookType def render_categorical(db: Database, conus: SPCOutlookMap, outlook: SPCOutlook, args): assets = { 'conus': config['map']['conus_dark' if args.dark else 'conus'], 'logo': config['map']['logo_dark' if args.dark else 'logo'] } with cairo.SVGSurface(args.categorical, conus.width, conus.height) as surface: cr = cairo.Context(surface) conus.draw_base_map_from_file(cr, assets['conus']) conus.draw_categories(cr, outlook) if args.cities: conus.draw_cities(cr, db) conus.draw_logo(cr, assets['logo']) conus.draw_legend(cr, SPCOutlookType.CATEGORICAL) if args.dark: cr.set_source_rgb(1, 1, 1) conus.draw_annotation(cr, outlook, SPCOutlookType.CATEGORICAL) def render_probabilistic(db: Database, conus: SPCOutlookMap, outlook: SPCOutlook, hazard: str, path: str, args): assets = { 'conus': config['map']['conus_dark' if args.dark else 'conus'], 'logo': config['map']['logo_dark' if args.dark else 'logo'] } with cairo.SVGSurface(path, conus.width, conus.height) as surface: cr = cairo.Context(surface) conus.draw_base_map_from_file(cr, assets['conus']) conus.draw_probabilities(cr, outlook, hazard.upper()) if args.cities: conus.draw_cities(cr, db) conus.draw_logo(cr, assets['logo']) conus.draw_legend(cr, SPCOutlookType.PROBABILISTIC) if args.dark: cr.set_source_rgb(1, 1, 1) hazard = ' '.join(map(lambda p: p.lower().capitalize(), hazard.split(' '))) conus.draw_annotation(cr, outlook, SPCOutlookType.PROBABILISTIC, hazard) argparser = argparse.ArgumentParser(description='Render graphical SPC outlooks from text file') argparser.add_argument('--dark', action='store_true', help='Output dark mode graphics') argparser.add_argument('--cities', action='store_true', help='Render major cities') argparser.add_argument('--file', type=str, help='Load outlook from file, not database') argparser.add_argument('--valid', type=str, help='Timestamp on or after most recent outlook') argparser.add_argument('--day', type=int, help='Number of days from issuance outlook applies to') argparser.add_argument('--categorical', type=str, help='Output categorical risk graphic file') argparser.add_argument('--any-severe', type=str, help='Output probabilistic severe risk graphic file') argparser.add_argument('--tornado', type=str, help='Output probabilistic hail risk graphic file') argparser.add_argument('--hail', type=str, help='Output probabilistic hail risk graphic file') argparser.add_argument('--wind', type=str, help='Output probabilistic wind risk graphic file') args = argparser.parse_args() config = Config.load() db = Database.from_config(config) conus = SPCOutlookMap(args.dark) if args.file is None: if args.valid is None or args.day is None: print("Must specify either --file or --valid and --day", file=sys.stderr) exit(1) outlook = SPCOutlook.for_timestamp(db, args.valid, args.day) else: with open(args.file, 'r') as fh: parser = SPCOutlookParser() outlook = parser.parse(fh.read()) if args.categorical is not None: render_categorical(db, conus, outlook, args) if args.any_severe is not None: render_probabilistic(db, conus, outlook, 'any severe', args.any_severe, args) if args.tornado is not None: render_probabilistic(db, conus, outlook, 'tornado', args.tornado, args) if args.hail is not None: render_probabilistic(db, conus, outlook, 'hail', args.hail, args) if args.wind is not None: render_probabilistic(db, conus, outlook, 'wind', args.wind, args)