def main(): """Go Main""" nt = NetworkTable(['AWOS', 'IA_ASOS']) pgconn = psycopg2.connect(database='mos', host='localhost', user='******', port=5555) df = read_sql(""" select station, avg(pwater) from model_gridpoint where model = 'NAM' and extract(hour from runtime at time zone 'UTC') = 0 and pwater > 0 and pwater < 100 and extract(month from runtime) between 4 and 9 and ftime = runtime GROUP by station ORDER by avg """, pgconn, index_col='station') df['lat'] = None df['lon'] = None df['pwater'] = distance(df['avg'].values, 'MM').value('IN') for station in df.index.values: df.at[station, 'lat'] = nt.sts[station[1:]]['lat'] df.at[station, 'lon'] = nt.sts[station[1:]]['lon'] mp = MapPlot(title=('00z Analysis NAM Warm-Season Average ' 'Precipitable Water [in]'), subtitle=("based on grid point samples " "from 2004-2017 (April-September)")) cmap = plt.get_cmap("plasma_r") cmap.set_under('white') cmap.set_over('black') mp.contourf(df['lon'], df['lat'], df['pwater'], np.arange(0.94, 1.13, 0.03), cmap=cmap, units='inch') mp.drawcounties() mp.drawcities() mp.postprocess(filename='170901.png') mp.close()
def plotter(fdict): """ Go """ import matplotlib matplotlib.use('agg') import matplotlib.pyplot as plt from pyiem.plot.geoplot import MapPlot ctx = util.get_autoplot_context(fdict, get_description()) date = ctx['date'] sector = ctx['sector'] threshold = ctx['threshold'] threshold_mm = distance(threshold, 'IN').value('MM') window_sts = date - datetime.timedelta(days=90) if window_sts.year != date.year: raise Exception('Sorry, do not support multi-year plots yet!') idx0 = iemre.daily_offset(window_sts) idx1 = iemre.daily_offset(date) ncfn = "/mesonet/data/iemre/%s_mw_mrms_daily.nc" % (date.year, ) ncvar = 'p01d' if not os.path.isfile(ncfn): raise Exception("No data for that year, sorry.") nc = netCDF4.Dataset(ncfn, 'r') grid = np.zeros((len(nc.dimensions['lat']), len(nc.dimensions['lon']))) total = np.zeros((len(nc.dimensions['lat']), len(nc.dimensions['lon']))) for i, idx in enumerate(range(idx1, idx1-90, -1)): total += nc.variables[ncvar][idx, :, :] grid = np.where(np.logical_and(grid == 0, total > threshold_mm), i, grid) lon = np.append(nc.variables['lon'][:], [-80.5]) lat = np.append(nc.variables['lat'][:], [49.]) nc.close() mp = MapPlot(sector='state', state=sector, titlefontsize=14, subtitlefontsize=12, title=("NOAA MRMS Q3: Number of Recent Days " "till Accumulating %s\" of Precip" ) % (threshold, ), subtitle=("valid %s: based on per calendar day " "estimated preciptation, GaugeCorr and " "RadarOnly products" ) % (date.strftime("%-d %b %Y"), )) x, y = np.meshgrid(lon, lat) cmap = plt.get_cmap('terrain') cmap.set_over('k') cmap.set_under('white') mp.pcolormesh(x, y, grid, np.arange(0, 81, 10), cmap=cmap, units='days') mp.drawcounties() mp.drawcities() return mp.fig
def plotter(fdict): """ Go """ ctx = util.get_autoplot_context(fdict, get_description()) ptype = ctx["ptype"] sdate = ctx["sdate"] edate = ctx["edate"] src = ctx["src"] opt = ctx["opt"] usdm = ctx["usdm"] if sdate.year != edate.year: raise NoDataFound("Sorry, do not support multi-year plots yet!") days = (edate - sdate).days sector = ctx["sector"] x0 = 0 x1 = -1 y0 = 0 y1 = -1 state = None if len(sector) == 2: state = sector sector = "state" title = compute_title(src, sdate, edate) if src == "mrms": ncfn = iemre.get_daily_mrms_ncname(sdate.year) clncfn = iemre.get_dailyc_mrms_ncname() ncvar = "p01d" source = "MRMS Q3" subtitle = "NOAA MRMS Project, GaugeCorr and RadarOnly" elif src == "iemre": ncfn = iemre.get_daily_ncname(sdate.year) clncfn = iemre.get_dailyc_ncname() ncvar = "p01d_12z" source = "IEM Reanalysis" subtitle = "IEM Reanalysis is derived from various NOAA datasets" else: ncfn = "/mesonet/data/prism/%s_daily.nc" % (sdate.year, ) clncfn = "/mesonet/data/prism/prism_dailyc.nc" ncvar = "ppt" source = "OSU PRISM" subtitle = ("PRISM Climate Group, Oregon State Univ., " "http://prism.oregonstate.edu, created 4 Feb 2004.") mp = MapPlot( sector=sector, state=state, axisbg="white", nocaption=True, title="%s:: %s Precip %s" % (source, title, PDICT3[opt]), subtitle="Data from %s" % (subtitle, ), titlefontsize=14, ) idx0 = iemre.daily_offset(sdate) idx1 = iemre.daily_offset(edate) + 1 if not os.path.isfile(ncfn): raise NoDataFound("No data for that year, sorry.") with util.ncopen(ncfn) as nc: if state is not None: x0, y0, x1, y1 = util.grid_bounds( nc.variables["lon"][:], nc.variables["lat"][:], state_bounds[state], ) elif sector in SECTORS: bnds = SECTORS[sector] x0, y0, x1, y1 = util.grid_bounds( nc.variables["lon"][:], nc.variables["lat"][:], [bnds[0], bnds[2], bnds[1], bnds[3]], ) lats = nc.variables["lat"][y0:y1] lons = nc.variables["lon"][x0:x1] if sdate == edate: p01d = mm2inch(nc.variables[ncvar][idx0, y0:y1, x0:x1]) elif (idx1 - idx0) < 32: p01d = mm2inch( np.sum(nc.variables[ncvar][idx0:idx1, y0:y1, x0:x1], 0)) else: # Too much data can overwhelm this app, need to chunk it for i in range(idx0, idx1, 10): i2 = min([i + 10, idx1]) if idx0 == i: p01d = mm2inch( np.sum(nc.variables[ncvar][i:i2, y0:y1, x0:x1], 0)) else: p01d += mm2inch( np.sum(nc.variables[ncvar][i:i2, y0:y1, x0:x1], 0)) if np.ma.is_masked(np.max(p01d)): raise NoDataFound("Data Unavailable") plot_units = "inches" cmap = get_cmap(ctx["cmap"]) cmap.set_bad("white") if opt == "dep": # Do departure work now with util.ncopen(clncfn) as nc: climo = mm2inch( np.sum(nc.variables[ncvar][idx0:idx1, y0:y1, x0:x1], 0)) p01d = p01d - climo [maxv] = np.percentile(np.abs(p01d), [99]) clevs = np.around(np.linspace(0 - maxv, maxv, 11), decimals=2) elif opt == "per": with util.ncopen(clncfn) as nc: climo = mm2inch( np.sum(nc.variables[ncvar][idx0:idx1, y0:y1, x0:x1], 0)) p01d = p01d / climo * 100.0 cmap.set_under("white") cmap.set_over("black") clevs = [1, 10, 25, 50, 75, 100, 125, 150, 200, 300, 500] plot_units = "percent" else: p01d = np.where(p01d < 0.001, np.nan, p01d) cmap.set_under("white") clevs = [0.01, 0.1, 0.3, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 8, 10] if days > 6: clevs = [0.01, 0.3, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 7, 8, 10, 15, 20] if days > 29: clevs = [0.01, 0.5, 1, 2, 3, 4, 5, 6, 8, 10, 15, 20, 25, 30, 35] if days > 90: clevs = [0.01, 1, 2, 3, 4, 5, 6, 8, 10, 15, 20, 25, 30, 35, 40] x2d, y2d = np.meshgrid(lons, lats) if ptype == "c": mp.contourf(x2d, y2d, p01d, clevs, cmap=cmap, units=plot_units, iline=False) else: res = mp.pcolormesh(x2d, y2d, p01d, clevs, cmap=cmap, units=plot_units) res.set_rasterized(True) if sector != "midwest": mp.drawcounties() mp.drawcities() if usdm == "yes": mp.draw_usdm(edate, filled=False, hatched=True) return mp.fig
def plotter(fdict): """ Go """ ctx = util.get_autoplot_context(fdict, get_description()) ptype = ctx['ptype'] sdate = ctx['sdate'] edate = ctx['edate'] src = ctx['src'] opt = ctx['opt'] usdm = ctx['usdm'] if sdate.year != edate.year: raise NoDataFound('Sorry, do not support multi-year plots yet!') days = (edate - sdate).days sector = ctx['sector'] if sdate == edate: title = sdate.strftime("%-d %B %Y") else: title = "%s to %s (inclusive)" % (sdate.strftime("%-d %b"), edate.strftime("%-d %b %Y")) x0 = 0 x1 = -1 y0 = 0 y1 = -1 state = None if len(sector) == 2: state = sector sector = 'state' if src == 'mrms': ncfn = iemre.get_daily_mrms_ncname(sdate.year) clncfn = iemre.get_dailyc_mrms_ncname() ncvar = 'p01d' source = 'MRMS Q3' subtitle = 'NOAA MRMS Project, GaugeCorr and RadarOnly' elif src == 'iemre': ncfn = iemre.get_daily_ncname(sdate.year) clncfn = iemre.get_dailyc_ncname() ncvar = 'p01d_12z' source = 'IEM Reanalysis' subtitle = 'IEM Reanalysis is derived from various NOAA datasets' else: ncfn = "/mesonet/data/prism/%s_daily.nc" % (sdate.year, ) clncfn = "/mesonet/data/prism/prism_dailyc.nc" ncvar = 'ppt' source = 'OSU PRISM' subtitle = ('PRISM Climate Group, Oregon State Univ., ' 'http://prism.oregonstate.edu, created 4 Feb 2004.') mp = MapPlot(sector=sector, state=state, axisbg='white', nocaption=True, title='%s:: %s Precip %s' % (source, title, PDICT3[opt]), subtitle='Data from %s' % (subtitle, ), titlefontsize=14) idx0 = iemre.daily_offset(sdate) idx1 = iemre.daily_offset(edate) + 1 if not os.path.isfile(ncfn): raise NoDataFound("No data for that year, sorry.") with util.ncopen(ncfn) as nc: if state is not None: x0, y0, x1, y1 = util.grid_bounds(nc.variables['lon'][:], nc.variables['lat'][:], state_bounds[state]) elif sector in SECTORS: bnds = SECTORS[sector] x0, y0, x1, y1 = util.grid_bounds( nc.variables['lon'][:], nc.variables['lat'][:], [bnds[0], bnds[2], bnds[1], bnds[3]]) lats = nc.variables['lat'][y0:y1] lons = nc.variables['lon'][x0:x1] if sdate == edate: p01d = distance(nc.variables[ncvar][idx0, y0:y1, x0:x1], 'MM').value('IN') elif (idx1 - idx0) < 32: p01d = distance( np.sum(nc.variables[ncvar][idx0:idx1, y0:y1, x0:x1], 0), 'MM').value('IN') else: # Too much data can overwhelm this app, need to chunk it for i in range(idx0, idx1, 10): i2 = min([i + 10, idx1]) if idx0 == i: p01d = distance( np.sum(nc.variables[ncvar][i:i2, y0:y1, x0:x1], 0), 'MM').value('IN') else: p01d += distance( np.sum(nc.variables[ncvar][i:i2, y0:y1, x0:x1], 0), 'MM').value('IN') if np.ma.is_masked(np.max(p01d)): raise NoDataFound("Data Unavailable") units = 'inches' cmap = plt.get_cmap(ctx['cmap']) cmap.set_bad('white') if opt == 'dep': # Do departure work now with util.ncopen(clncfn) as nc: climo = distance( np.sum(nc.variables[ncvar][idx0:idx1, y0:y1, x0:x1], 0), 'MM').value('IN') p01d = p01d - climo [maxv] = np.percentile(np.abs(p01d), [ 99, ]) clevs = np.around(np.linspace(0 - maxv, maxv, 11), decimals=2) elif opt == 'per': with util.ncopen(clncfn) as nc: climo = distance( np.sum(nc.variables[ncvar][idx0:idx1, y0:y1, x0:x1], 0), 'MM').value('IN') p01d = p01d / climo * 100. cmap.set_under('white') cmap.set_over('black') clevs = [1, 10, 25, 50, 75, 100, 125, 150, 200, 300, 500] units = 'percent' else: p01d = np.where(p01d < 0.001, np.nan, p01d) cmap.set_under('white') clevs = [0.01, 0.1, 0.3, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 8, 10] if days > 6: clevs = [0.01, 0.3, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 7, 8, 10, 15, 20] if days > 29: clevs = [0.01, 0.5, 1, 2, 3, 4, 5, 6, 8, 10, 15, 20, 25, 30, 35] if days > 90: clevs = [0.01, 1, 2, 3, 4, 5, 6, 8, 10, 15, 20, 25, 30, 35, 40] x2d, y2d = np.meshgrid(lons, lats) if ptype == 'c': mp.contourf(x2d, y2d, p01d, clevs, cmap=cmap, units=units, iline=False) else: res = mp.pcolormesh(x2d, y2d, p01d, clevs, cmap=cmap, units=units) res.set_rasterized(True) if sector != 'midwest': mp.drawcounties() mp.drawcities() if usdm == 'yes': mp.draw_usdm(edate, filled=False, hatched=True) return mp.fig
def plotter(fdict): """ Go """ ctx = util.get_autoplot_context(fdict, get_description()) date = ctx['date'] sector = ctx['sector'] threshold = ctx['threshold'] threshold_mm = distance(threshold, 'IN').value('MM') window_sts = date - datetime.timedelta(days=90) if window_sts.year != date.year: raise NoDataFound('Sorry, do not support multi-year plots yet!') # idx0 = iemre.daily_offset(window_sts) idx1 = iemre.daily_offset(date) ncfn = iemre.get_daily_mrms_ncname(date.year) if not os.path.isfile(ncfn): raise NoDataFound("No data found.") ncvar = 'p01d' # Get the state weight df = gpd.GeoDataFrame.from_postgis(""" SELECT the_geom from states where state_abbr = %s """, util.get_dbconn('postgis'), params=(sector, ), index_col=None, geom_col='the_geom') czs = CachingZonalStats(iemre.MRMS_AFFINE) with util.ncopen(ncfn) as nc: czs.gen_stats( np.zeros((nc.variables['lat'].size, nc.variables['lon'].size)), df['the_geom']) jslice = None islice = None for nav in czs.gridnav: # careful here as y is flipped in this context jslice = slice(nc.variables['lat'].size - (nav.y0 + nav.ysz), nc.variables['lat'].size - nav.y0) islice = slice(nav.x0, nav.x0 + nav.xsz) grid = np.zeros( (jslice.stop - jslice.start, islice.stop - islice.start)) total = np.zeros( (jslice.stop - jslice.start, islice.stop - islice.start)) for i, idx in enumerate(range(idx1, idx1 - 90, -1)): total += nc.variables[ncvar][idx, jslice, islice] grid = np.where(np.logical_and(grid == 0, total > threshold_mm), i, grid) lon = nc.variables['lon'][islice] lat = nc.variables['lat'][jslice] mp = MapPlot(sector='state', state=sector, titlefontsize=14, subtitlefontsize=12, title=("NOAA MRMS Q3: Number of Recent Days " "till Accumulating %s\" of Precip") % (threshold, ), subtitle=("valid %s: based on per calendar day " "estimated preciptation, GaugeCorr and " "RadarOnly products") % (date.strftime("%-d %b %Y"), )) x, y = np.meshgrid(lon, lat) cmap = plt.get_cmap(ctx['cmap']) cmap.set_over('k') cmap.set_under('white') mp.pcolormesh(x, y, grid, np.arange(0, 81, 10), cmap=cmap, units='days') mp.drawcounties() mp.drawcities() return mp.fig
def plotter(fdict): """ Go """ pgconn = get_dbconn("postgis") ctx = get_autoplot_context(fdict, get_description()) utcvalid = ctx.get("valid") wfo = ctx["wfo"] tzname = ctx["_nt"].sts[wfo]["tzname"] p1 = ctx["phenomenav"][:2] s1 = ctx["significancev"][:1] etn = int(ctx["etn"]) year = int(ctx["year"]) table = "warnings_%s" % (year, ) df = read_postgis( """ SELECT w.ugc, simple_geom, u.name, issue at time zone 'UTC' as issue, expire at time zone 'UTC' as expire, init_expire at time zone 'UTC' as init_expire, 1 as val, status from """ + table + """ w JOIN ugcs u on (w.gid = u.gid) WHERE w.wfo = %s and eventid = %s and significance = %s and phenomena = %s ORDER by issue ASC """, pgconn, params=(wfo[-3:], etn, s1, p1), index_col="ugc", geom_col="simple_geom", ) if df.empty: raise NoDataFound("VTEC Event was not found, sorry.") table = "sbw_%s" % (year, ) sbwdf = read_postgis( """ SELECT status, geom, polygon_begin at time zone 'UTC' as polygon_begin, polygon_end at time zone 'UTC' as polygon_end from """ + table + """ WHERE wfo = %s and eventid = %s and significance = %s and phenomena = %s ORDER by polygon_begin ASC """, pgconn, params=(wfo[-3:], etn, s1, p1), geom_col="geom", ) if utcvalid is None: utcvalid = df["issue"].max() else: # hack for an assumption below utcvalid = pd.Timestamp(utcvalid.replace(tzinfo=None)) def m(valid): """Convert to our local timestamp.""" return (valid.tz_localize(pytz.UTC).astimezone( pytz.timezone(tzname)).strftime(TFORMAT)) df["color"] = vtec.NWS_COLORS.get("%s.%s" % (p1, s1), "#FF0000") if not sbwdf.empty: df["color"] = "tan" bounds = df["simple_geom"].total_bounds buffer = 0.4 mp = MapPlot( subtitle="Map Valid: %s, Event: %s to %s" % (m(utcvalid), m(df["issue"].min()), m(df["expire"].max())), title="%s %s %s %s (%s.%s) #%s" % ( year, wfo, vtec.VTEC_PHENOMENA.get(p1, p1), vtec.VTEC_SIGNIFICANCE.get(s1, s1), p1, s1, etn, ), sector="custom", west=bounds[0] - buffer, south=bounds[1] - buffer, east=bounds[2] + buffer, north=bounds[3] + buffer, nocaption=True, ) mp.sector = "cwa" mp.cwa = wfo[-3:] # CAN statements come here with time == expire :/ df2 = df[(df["issue"] <= utcvalid) & (df["expire"] > utcvalid)] if df2.empty: mp.ax.text( 0.5, 0.5, "Event No Longer Active", zorder=1000, transform=mp.ax.transAxes, fontsize=24, ha="center", ) else: mp.fill_ugcs( df2["val"].to_dict(), color=df2["color"].to_dict(), nocbar=True, labels=df2["name"].to_dict(), missingval="", ilabel=(len(df2.index) <= 10), labelbuffer=5, ) if not sbwdf.empty: color = vtec.NWS_COLORS.get("%s.%s" % (p1, s1), "#FF0000") poly = sbwdf.iloc[0]["geom"] df2 = sbwdf[(sbwdf["polygon_begin"] <= utcvalid) & (sbwdf["polygon_end"] > utcvalid)] if not df2.empty: # draw new mp.ax.add_geometries( [poly], ccrs.PlateCarree(), facecolor="None", edgecolor="k", zorder=Z_OVERLAY2 - 1, ) poly = df2.iloc[0]["geom"] mp.ax.add_geometries( [poly], ccrs.PlateCarree(), facecolor=color, alpha=0.5, edgecolor="k", zorder=Z_OVERLAY2, ) if len(df.index) > 10: mp.drawcities() return mp.fig, df.drop("simple_geom", axis=1)
def make_overviewmap(form): """Draw a pretty map of just the HUC.""" huc = form.get("huc") plt.close() projection = EPSG[5070] if huc is None: huclimiter = "" elif len(huc) >= 8: huclimiter = " and substr(huc_12, 1, 8) = '%s' " % (huc[:8],) with get_sqlalchemy_conn("idep") as conn: df = read_postgis( f""" SELECT simple_geom as geom, huc_12, ST_x(ST_Transform(ST_Centroid(geom), 4326)) as centroid_x, ST_y(ST_Transform(ST_Centroid(geom), 4326)) as centroid_y, hu_12_name from huc12 i WHERE i.scenario = 0 {huclimiter} """, conn, geom_col="geom", index_col="huc_12", ) minx, miny, maxx, maxy = df["geom"].total_bounds buf = float(form.get("zoom", 10.0)) * 1000.0 # 10km hucname = "" if huc not in df.index else df.at[huc, "hu_12_name"] subtitle = "The HUC8 is in tan" if len(huc) == 12: subtitle = "HUC12 highlighted in red, the HUC8 it resides in is in tan" m = MapPlot( axisbg="#EEEEEE", logo="dep", sector="custom", south=miny - buf, north=maxy + buf, west=minx - buf, east=maxx + buf, projection=projection, continentalcolor="white", title="DEP HUC %s:: %s" % (huc, hucname), subtitle=subtitle, titlefontsize=20, subtitlefontsize=18, caption="Daily Erosion Project", ) for _huc12, row in df.iterrows(): p = Polygon( row["geom"].exterior.coords, fc="red" if _huc12 == huc else "tan", ec="k", zorder=Z_OVERLAY2, lw=0.1, ) m.ax.add_patch(p) # If this is our HUC, add some text to prevent cities overlay overlap if _huc12 == huc: m.plot_values( [row["centroid_x"]], [row["centroid_y"]], [" . "], color="None", outlinecolor="None", ) if huc is not None: m.drawcounties() m.drawcities() ram = BytesIO() plt.savefig(ram, format="png", dpi=100) plt.close() ram.seek(0) return ram.read(), True
def make_map(huc, ts, ts2, scenario, v, form): """Make the map""" projection = EPSG[5070] plt.close() # suggested for runoff and precip if v in ["qc_precip", "avg_runoff"]: # c = ['#ffffa6', '#9cf26d', '#76cc94', '#6399ba', '#5558a1'] cmap = james() # suggested for detachment elif v in ["avg_loss"]: # c =['#cbe3bb', '#c4ff4d', '#ffff4d', '#ffc44d', '#ff4d4d', '#c34dee'] cmap = dep_erosion() # suggested for delivery elif v in ["avg_delivery"]: # c =['#ffffd2', '#ffff4d', '#ffe0a5', '#eeb74d', '#ba7c57', '#96504d'] cmap = dep_erosion() pgconn = get_dbconn("idep") cursor = pgconn.cursor() title = "for %s" % (ts.strftime("%-d %B %Y"),) if ts != ts2: title = "for period between %s and %s" % ( ts.strftime("%-d %b %Y"), ts2.strftime("%-d %b %Y"), ) if "averaged" in form: title = "averaged between %s and %s (2008-2017)" % ( ts.strftime("%-d %b"), ts2.strftime("%-d %b"), ) # Check that we have data for this date! cursor.execute( "SELECT value from properties where key = 'last_date_0'", ) lastts = datetime.datetime.strptime(cursor.fetchone()[0], "%Y-%m-%d") floor = datetime.date(2007, 1, 1) if ts > lastts.date() or ts2 > lastts.date() or ts < floor: plt.text( 0.5, 0.5, "Data Not Available\nPlease Check Back Later!", fontsize=20, ha="center", ) ram = BytesIO() plt.savefig(ram, format="png", dpi=100) plt.close() ram.seek(0) return ram.read(), False if huc is None: huclimiter = "" elif len(huc) == 8: huclimiter = " and substr(i.huc_12, 1, 8) = '%s' " % (huc,) elif len(huc) == 12: huclimiter = " and i.huc_12 = '%s' " % (huc,) if "iowa" in form: huclimiter += " and i.states ~* 'IA' " if "mn" in form: huclimiter += " and i.states ~* 'MN' " if "averaged" in form: # 11 years of data is standard # 10 years is for the switchgrass one-off with get_sqlalchemy_conn("idep") as conn: df = read_postgis( f""" WITH data as ( SELECT huc_12, sum({v}) / 10. as d from results_by_huc12 WHERE scenario = %s and to_char(valid, 'mmdd') between %s and %s and valid between '2008-01-01' and '2018-01-01' GROUP by huc_12) SELECT simple_geom as geom, coalesce(d.d, 0) * %s as data from huc12 i LEFT JOIN data d ON (i.huc_12 = d.huc_12) WHERE i.scenario = %s {huclimiter} """, conn, params=( scenario, ts.strftime("%m%d"), ts2.strftime("%m%d"), V2MULTI[v], 0, ), geom_col="geom", ) else: with get_sqlalchemy_conn("idep") as conn: df = read_postgis( f""" WITH data as ( SELECT huc_12, sum({v}) as d from results_by_huc12 WHERE scenario = %s and valid between %s and %s GROUP by huc_12) SELECT simple_geom as geom, coalesce(d.d, 0) * %s as data from huc12 i LEFT JOIN data d ON (i.huc_12 = d.huc_12) WHERE i.scenario = %s {huclimiter} """, conn, params=( scenario, ts.strftime("%Y-%m-%d"), ts2.strftime("%Y-%m-%d"), V2MULTI[v], 0, ), geom_col="geom", ) minx, miny, maxx, maxy = df["geom"].total_bounds buf = 10000.0 # 10km m = MapPlot( axisbg="#EEEEEE", logo="dep", sector="custom", south=miny - buf, north=maxy + buf, west=minx - buf, east=maxx + buf, projection=projection, title="DEP %s by HUC12 %s" % (V2NAME[v], title), titlefontsize=16, caption="Daily Erosion Project", ) if ts == ts2: # Daily bins = RAMPS["english"][0] else: bins = RAMPS["english"][1] norm = mpcolors.BoundaryNorm(bins, cmap.N) for _, row in df.iterrows(): p = Polygon( row["geom"].exterior.coords, fc=cmap(norm([row["data"]]))[0], ec="k", zorder=5, lw=0.1, ) m.ax.add_patch(p) label_scenario(m.ax, scenario, pgconn) lbl = [round(_, 2) for _ in bins] if huc is not None: m.drawcounties() m.drawcities() m.draw_colorbar( bins, cmap, norm, units=V2UNITS[v], clevlabels=lbl, spacing="uniform" ) if "progressbar" in form: fig = plt.gcf() avgval = df["data"].mean() fig.text( 0.01, 0.905, "%s: %4.1f T/a" % (ts.year if "averaged" not in form else "Avg", avgval), fontsize=14, ) bar_width = 0.758 # yes, a small one off with years having 366 days proportion = (ts2 - ts).days / 365.0 * bar_width rect1 = Rectangle( (0.15, 0.905), bar_width, 0.02, color="k", zorder=40, transform=fig.transFigure, figure=fig, ) fig.patches.append(rect1) rect2 = Rectangle( (0.151, 0.907), proportion, 0.016, color=cmap(norm([avgval]))[0], zorder=50, transform=fig.transFigure, figure=fig, ) fig.patches.append(rect2) if "cruse" in form: # Crude conversion of T/a to mm depth depth = avgval / 5.0 m.ax.text( 0.9, 0.92, "%.2fmm" % (depth,), zorder=1000, fontsize=24, transform=m.ax.transAxes, ha="center", va="center", bbox=dict(color="k", alpha=0.5, boxstyle="round,pad=0.1"), color="white", ) ram = BytesIO() plt.savefig(ram, format="png", dpi=100) plt.close() ram.seek(0) return ram.read(), True