def plot(argv): """Make a plot""" df = pd.read_csv("%s_maxdailyprecip.txt" % (argv[1], ), dtype={'huc12': str}) df.set_index('huc12', inplace=True) pgconn = get_dbconn('idep') huc12df = gpd.GeoDataFrame.from_postgis(""" SELECT huc12, simple_geom as geo from wbd_huc12 WHERE swat_use ORDER by huc12 """, pgconn, index_col='huc12', geom_col='geo') mp = MapPlot( sector='custom', south=34, north=48, west=-98, east=-77, title="%s Max Daily Precipitation" % (argv[1].split("_", 1)[1], ) ) bins = range(0, 201, 20) cmap = stretch_cmap('terrain_r', bins) norm = mpcolors.BoundaryNorm(bins, cmap.N) for huc12, row in huc12df.iterrows(): for poly in row['geo']: arr = np.asarray(poly.exterior) points = mp.ax.projection.transform_points(ccrs.Geodetic(), arr[:, 0], arr[:, 1]) color = cmap(norm([df.at[huc12, 'maxp'], ]))[0] poly = Polygon(points[:, :2], fc=color, ec='None', zorder=2, lw=.1) mp.ax.add_patch(poly) mp.draw_colorbar(bins, cmap, norm, units='mm') mp.postprocess(filename='test.png')
def contourf(self, lons, lats, vals, clevs, **kwargs): """ Contourf Args: ilabel (boolean,optional): Should we label contours iline (boolean,optional): should we draw contour lines Returns: vals (np.array): The values used for plotting, maybe after gridding """ if isinstance(lons, list): lons = np.array(lons) lats = np.array(lats) vals = np.array(vals) if np.array(vals).ndim == 1: # We need to grid, get current plot bounds in display proj # Careful here as a rotated projection may have maxes not in ul xbnds = self.ax.get_xlim() ybnds = self.ax.get_ylim() ll = ccrs.Geodetic().transform_point(xbnds[0], ybnds[0], self.ax.projection) ul = ccrs.Geodetic().transform_point(xbnds[0], ybnds[1], self.ax.projection) ur = ccrs.Geodetic().transform_point(xbnds[1], ybnds[1], self.ax.projection) lr = ccrs.Geodetic().transform_point(xbnds[1], ybnds[0], self.ax.projection) xi = np.linspace(min(ll[0], ul[0]), max(lr[0], ur[0]), 100) yi = np.linspace(min(ll[1], ul[1]), max(ul[1], ur[1]), 100) xi, yi = np.meshgrid(xi, yi) nn = NearestNDInterpolator((lons, lats), vals) vals = nn(xi, yi) lons = xi lats = yi window = np.ones((6, 6)) vals = convolve2d(vals, window / window.sum(), mode='same', boundary='symm') if lons.ndim == 1: lons, lats = np.meshgrid(lons, lats) cmap = stretch_cmap(kwargs.get('cmap'), clevs) norm = mpcolors.BoundaryNorm(clevs, cmap.N) # vals = maskoceans(lons, lats, vals, resolution='h') self.ax.contourf(lons, lats, vals, clevs, cmap=cmap, norm=norm, zorder=Z_FILL, extend='both', transform=ccrs.PlateCarree()) if kwargs.get('iline', True): csl = self.ax.contour(lons, lats, vals, clevs, colors='w', zorder=Z_FILL_LABEL, transform=ccrs.PlateCarree()) if kwargs.get('ilabel', False): self.ax.clabel(csl, fmt=kwargs.get('labelfmt', '%.0f'), colors='k', fontsize=14) if kwargs.get("clip_on", True): self.draw_mask() kwargs.pop('cmap', None) self.draw_colorbar(clevs, cmap, norm, **kwargs) return vals
def polygon_fill(mymap, geo_provider, data, **kwargs): """Generalized function for overlaying filled polygons on the map Args: mymap (MapPlot): The MapPlot instance geo_provider (dict): The dictionary of keys and geometries data (dict): The dictionary of keys and values used for picking colors **kwargs (Optional): Other things needed for mapping ilabel (Optional[bool]): should values be labelled? Defaults to `False` plotmissing (bool): should geometries not included in the `data` be mapped? Defaults to `True` """ bins = kwargs.get('bins', np.arange(0, 101, 10)) cmap = stretch_cmap(kwargs.get('cmap'), bins) ilabel = kwargs.get('ilabel', False) norm = mpcolors.BoundaryNorm(bins, cmap.N) lblformat = kwargs.get('lblformat', '%s') labels = kwargs.get('labels', dict()) plotmissing = kwargs.get('plotmissing', True) for polykey, polydict in geo_provider.items(): # our dictionary is bytes so we need str val = data.get(polykey.decode('utf-8'), None) if val is None: if not plotmissing: continue lbl = labels.get(polykey.decode('utf-8'), '-') c = 'white' else: lbl = labels.get(polykey.decode('utf-8'), lblformat % (val, )) c = cmap(norm([val, ]))[0] # in python3, our dict types are byte arrays for polyi, polygon in enumerate(polydict.get(b'geom', [])): if polygon.exterior is None: continue a = np.asarray(polygon.exterior) for ax in mymap.axes: points = ax.projection.transform_points(ccrs.Geodetic(), a[:, 0], a[:, 1]) p = mpatches.Polygon( points[:, :2], fc=c, ec='k', zorder=reference.Z_FILL, lw=.1) ax.add_patch(p) if ilabel and polyi == 0: txt = ax.text(polydict.get(b'lon', polygon.centroid.x), polydict.get(b'lat', polygon.centroid.y), lbl, zorder=100, clip_on=True, ha='center', va='center', transform=ccrs.PlateCarree()) txt.set_path_effects([ PathEffects.withStroke(linewidth=2, foreground="w")]) kwargs.pop('cmap', None) kwargs.pop('bins', None) mymap.draw_colorbar(bins, cmap, norm, **kwargs)
def hexbin(self, lons, lats, vals, clevs, **kwargs): """ hexbin wrapper """ cmap = stretch_cmap(kwargs.get('cmap'), clevs) norm = mpcolors.BoundaryNorm(clevs, cmap.N) points = self.ax.projection.transform_points(ccrs.PlateCarree(), lons, lats) _hex = self.ax.hexbin(points[:, 0], points[:, 1], C=vals, norm=norm, cmap=cmap, zorder=Z_FILL) kwargs.pop('cmap', None) self.draw_colorbar(clevs, cmap, norm, **kwargs) return _hex
def pcolormesh(self, lons, lats, vals, clevs, **kwargs): """ pcolormesh wrapper """ cmap = stretch_cmap(kwargs.get('cmap'), clevs) norm = mpcolors.BoundaryNorm(clevs, cmap.N) res = self.ax.pcolormesh(lons, lats, vals, norm=norm, cmap=cmap, zorder=Z_FILL, transform=ccrs.PlateCarree()) if kwargs.get("clip_on", True): self.draw_mask() kwargs.pop('cmap', None) self.draw_colorbar(clevs, cmap, norm, **kwargs) return res
def scatter(self, lons, lats, vals, clevs, **kwargs): """Draw points on the map Args: lons (list): longitude values lats (list): latitude values vals (list): Data values for the points to use for colormapping clevs (list): Levels to use for ramp **kwargs: additional options """ cmap = stretch_cmap(kwargs.get('cmap'), clevs) norm = mpcolors.BoundaryNorm(clevs, cmap.N) colors = cmap(norm(vals)) self.ax.scatter(lons, lats, c=colors, edgecolors=colors, transform=ccrs.PlateCarree(), zorder=Z_OVERLAY) kwargs.pop('cmap', None) self.draw_colorbar(clevs, cmap, norm, **kwargs)
def plotter(fdict): """ Go """ ctx = get_autoplot_context(fdict, get_description()) ptype = ctx["ptype"] date = ctx["date"] varname = ctx["var"] csector = ctx["csector"] title = date.strftime("%-d %B %Y") mp = MapPlot( sector=("state" if len(csector) == 2 else csector), state=ctx["csector"], axisbg="white", nocaption=True, title="IEM Reanalysis of %s for %s" % (PDICT.get(varname), title), subtitle="Data derived from various NOAA datasets", ) (west, east, south, north) = mp.ax.get_extent(ccrs.PlateCarree()) i0, j0 = iemre.find_ij(west, south) i1, j1 = iemre.find_ij(east, north) jslice = slice(j0, j1) islice = slice(i0, i1) idx0 = iemre.daily_offset(date) ncfn = iemre.get_daily_ncname(date.year) if not os.path.isfile(ncfn): raise NoDataFound("No Data Found.") with ncopen(ncfn) as nc: lats = nc.variables["lat"][jslice] lons = nc.variables["lon"][islice] cmap = ctx["cmap"] if varname in ["rsds", "power_swdn"]: # Value is in W m**-2, we want MJ multi = (86400.0 / 1000000.0) if varname == "rsds" else 1 data = nc.variables[varname][idx0, jslice, islice] * multi plot_units = "MJ d-1" clevs = np.arange(0, 37, 3.0) clevs[0] = 0.01 clevstride = 1 elif varname in ["wind_speed"]: data = (masked_array( nc.variables[varname][idx0, jslice, islice], units("meter / second"), ).to(units("mile / hour")).m) plot_units = "mph" clevs = np.arange(0, 41, 2) clevs[0] = 0.01 clevstride = 2 elif varname in ["p01d", "p01d_12z", "snow_12z", "snowd_12z"]: # Value is in W m**-2, we want MJ data = (masked_array(nc.variables[varname][idx0, jslice, islice], units("mm")).to(units("inch")).m) plot_units = "inch" clevs = np.arange(0, 0.25, 0.05) clevs = np.append(clevs, np.arange(0.25, 3.0, 0.25)) clevs = np.append(clevs, np.arange(3.0, 10.0, 1)) clevs[0] = 0.01 clevstride = 1 cmap = stretch_cmap(ctx["cmap"], clevs) elif varname in [ "high_tmpk", "low_tmpk", "high_tmpk_12z", "low_tmpk_12z", "avg_dwpk", ]: # Value is in W m**-2, we want MJ data = (masked_array(nc.variables[varname][idx0, jslice, islice], units("degK")).to(units("degF")).m) plot_units = "F" clevs = np.arange(-30, 120, 5) clevstride = 2 elif varname in ["range_tmpk", "range_tmpk_12z"]: vname1 = "high_tmpk%s" % ("_12z" if varname == "range_tmpk_12z" else "", ) vname2 = "low_tmpk%s" % ("_12z" if varname == "range_tmpk_12z" else "", ) d1 = nc.variables[vname1][idx0, jslice, islice] d2 = nc.variables[vname2][idx0, jslice, islice] data = (masked_array(d1, units("degK")).to(units("degF")).m - masked_array(d2, units("degK")).to(units("degF")).m) plot_units = "F" clevs = np.arange(0, 61, 5) clevstride = 2 if np.ma.is_masked(np.max(data)): raise NoDataFound("Data Unavailable") x, y = np.meshgrid(lons, lats) if ptype == "c": # in the case of contour, use the centroids on the grids mp.contourf( x + 0.125, y + 0.125, data, clevs, clevstride=clevstride, units=plot_units, ilabel=True, labelfmt="%.0f", cmap=cmap, ) else: x, y = np.meshgrid(lons, lats) mp.pcolormesh( x, y, data, clevs, clevstride=clevstride, cmap=cmap, units=plot_units, ) return mp.fig
def plotter(fdict): """ Go """ ctx = get_autoplot_context(fdict, get_description()) csector = ctx['csector'] sdate = make_tuesday(ctx['sdate']) edate = make_tuesday(ctx['edate']) dlevel = ctx['d'] griddelta = 0.1 mp = MapPlot(sector=('state' if len(csector) == 2 else csector), state=ctx['csector'], title=('%s at or above "%s" %s - %s') % (PDICT2[ctx['w']], PDICT[dlevel], sdate.strftime("%b %-d, %Y"), edate.strftime("%b %-d, %Y")), subtitle=('based on weekly US Drought Monitor Analysis, ' '%.2f$^\circ$ grid analysis') % (griddelta, ), continentalcolor='white', titlefontsize=14) # compute the affine (west, east, south, north) = mp.ax.get_extent(ccrs.PlateCarree()) raster = np.zeros((int( (north - south) / griddelta), int((east - west) / griddelta))) lons = np.arange(raster.shape[1]) * griddelta + west lats = np.arange(0, 0 - raster.shape[0], -1) * griddelta + north lats = lats[::-1] affine = Affine(griddelta, 0., west, 0., 0 - griddelta, north) # get the geopandas data pgconn = get_dbconn('postgis') df = read_postgis(""" with d as ( select valid, (ST_Dump(st_simplify(geom, 0.01))).geom from usdm where valid >= %s and valid <= %s and dm >= %s and ST_Intersects(geom, ST_GeomFromEWKT('SRID=4326;POLYGON((%s %s, %s %s, %s %s, %s %s, %s %s))')) ) select valid, st_collect(geom) as the_geom from d GROUP by valid """, pgconn, params=(sdate, edate, dlevel, west, south, west, north, east, north, east, south, west, south), geom_col='the_geom') if df.empty: raise NoDataFound("No Data Found, sorry!") # loop over the cached stats czs = CachingZonalStats(affine) czs.compute_gridnav(df['the_geom'], raster) for nav in czs.gridnav: if nav is None: continue grid = np.ones((nav.ysz, nav.xsz)) grid[nav.mask] = 0. jslice = slice(nav.y0, nav.y0 + nav.ysz) islice = slice(nav.x0, nav.x0 + nav.xsz) raster[jslice, islice] += grid maxval = 10 if np.max(raster) < 11 else np.max(raster) ramp = np.linspace(1, maxval + 1, 11, dtype='i') if ctx['w'] == 'percent': ramp = np.arange(0, 101, 10) ramp[0] = 1. ramp[-1] = 100.1 # we add one since we are rectified to tuesdays, so we have an extra # week in there raster = raster / ((edate - sdate).days / 7. + 1.) * 100. # plot cmap = stretch_cmap(ctx['cmap'], ramp) cmap.set_under('white') cmap.set_bad('white') mp.pcolormesh(lons, lats, np.flipud(raster), ramp, cmap=cmap, units='count' if ctx['w'] == 'weeks' else 'Percent') if len(csector) == 2: mp.drawcounties() mp.drawcities() rows = [] for j in range(raster.shape[0]): for i in range(raster.shape[1]): rows.append(dict(lon=lons[i], lat=lats[j], value=raster[j, i])) return mp.fig, pd.DataFrame(rows)
def test_stretch(): """can we do what we hope?""" cmap = stretch_cmap("jet", range(10)) assert cmap is not None cmap = dep_erosion() assert cmap is not None
def fill_ugcs(self, data, bins=None, **kwargs): """Overlay filled UGC geometries The logic for plotting is a bit tricky due to fire zones overlapping forecast zones. In general, provide the zone code if you want it to display on top. Otherwise, I attempt to place forecast zones overtop fire weather zones. Args: data(dict): A dictionary of 6 char UGC code keys and values bins(list, optional): Bins to use for cloropleth, default 0:101:10 plotmissing(bool, optional): Should missing UGC data be plotted? """ if bins is None: bins = np.arange(0, 101, 10) cmap = stretch_cmap(kwargs.get('cmap'), bins) norm = mpcolors.BoundaryNorm(bins, cmap.N) # Figure out if we have zones or counties/parishes counties = True for key in data: if key[2] == 'Z': counties = False break ugcs = load_pickle_geo( "ugcs_county.pickle" if counties else "ugcs_zone.pickle") filter_func = true_filter if self.sector == 'state': filter_func = state_filter elif self.sector == 'cwa': filter_func = cwa_filter ilabel = kwargs.get('ilabel', False) plotmissing = kwargs.get('plotmissing', True) for ugc in ugcs: ugcdict = ugcs[ugc] if not filter_func(self, ugc, ugcdict): continue if data.get(ugc.decode('utf-8')) is None: if not plotmissing: continue # Holy cow, it appears values above 300 are always firewx, # so lets ignore these when we have no data! if not counties and int(ugc[3:]) >= 300: continue c = 'white' val = '-' z = Z_OVERLAY else: val = data[ugc.decode('utf-8')] c = cmap(norm([val, ]))[0] z = Z_OVERLAY2 for polyi, polygon in enumerate(ugcdict.get(b'geom', [])): if polygon.exterior is None: continue arr = np.asarray(polygon.exterior) points = self.ax.projection.transform_points(ccrs.Geodetic(), arr[:, 0], arr[:, 1]) p = Polygon(points[:, :2], fc=c, ec='k', zorder=z, lw=.1) if z == Z_OVERLAY: self.ax.add_patch(p) if z == Z_OVERLAY2: self.ax.add_patch(p) if polyi == 0 and ilabel: mx = polygon.centroid.x my = polygon.centroid.y txt = self.ax.text(mx, my, '%s' % (val,), zorder=100, ha='center', va='center', transform=ccrs.PlateCarree()) txt.set_path_effects([ PathEffects.withStroke(linewidth=2, foreground="w")]) if 'cmap' in kwargs: del kwargs['cmap'] self.draw_colorbar(bins, cmap, norm, **kwargs)
def plotter(fdict): """ Go """ ctx = get_autoplot_context(fdict, get_description()) ptype = ctx['ptype'] date = ctx['date'] varname = ctx['var'] csector = ctx['csector'] title = date.strftime("%-d %B %Y") mp = MapPlot(sector=('state' if len(csector) == 2 else csector), state=ctx['csector'], axisbg='white', nocaption=True, title='IEM Reanalysis of %s for %s' % (PDICT.get(varname), title), subtitle='Data derived from various NOAA datasets') (west, east, south, north) = mp.ax.get_extent(ccrs.PlateCarree()) i0, j0 = iemre.find_ij(west, south) i1, j1 = iemre.find_ij(east, north) jslice = slice(j0, j1) islice = slice(i0, i1) idx0 = iemre.daily_offset(date) with ncopen(iemre.get_daily_ncname(date.year)) as nc: lats = nc.variables['lat'][jslice] lons = nc.variables['lon'][islice] cmap = ctx['cmap'] if varname in ['rsds', 'power_swdn']: # Value is in W m**-2, we want MJ multi = (86400. / 1000000.) if varname == 'rsds' else 1 data = nc.variables[varname][idx0, jslice, islice] * multi units = 'MJ d-1' clevs = np.arange(0, 37, 3.) clevs[0] = 0.01 clevstride = 1 elif varname in [ 'wind_speed', ]: data = speed(nc.variables[varname][idx0, jslice, islice], 'MPS').value('MPH') units = 'mph' clevs = np.arange(0, 41, 2) clevs[0] = 0.01 clevstride = 2 elif varname in ['p01d', 'p01d_12z', 'snow_12z', 'snowd_12z']: # Value is in W m**-2, we want MJ data = distance(nc.variables[varname][idx0, jslice, islice], 'MM').value('IN') units = 'inch' clevs = np.arange(0, 0.25, 0.05) clevs = np.append(clevs, np.arange(0.25, 3., 0.25)) clevs = np.append(clevs, np.arange(3., 10.0, 1)) clevs[0] = 0.01 clevstride = 1 cmap = stretch_cmap(ctx['cmap'], clevs) elif varname in [ 'high_tmpk', 'low_tmpk', 'high_tmpk_12z', 'low_tmpk_12z', 'avg_dwpk' ]: # Value is in W m**-2, we want MJ data = temperature(nc.variables[varname][idx0, jslice, islice], 'K').value('F') units = 'F' clevs = np.arange(-30, 120, 5) clevstride = 2 elif varname in ['range_tmpk', 'range_tmpk_12z']: vname1 = 'high_tmpk%s' % ('_12z' if varname == 'range_tmpk_12z' else '', ) vname2 = 'low_tmpk%s' % ('_12z' if varname == 'range_tmpk_12z' else '', ) d1 = nc.variables[vname1][idx0, jslice, islice] d2 = nc.variables[vname2][idx0, jslice, islice] data = (temperature(d1, 'K').value('F') - temperature(d2, 'K').value('F')) units = 'F' clevs = np.arange(0, 61, 5) clevstride = 2 if np.ma.is_masked(np.max(data)): raise ValueError("Data Unavailable") x, y = np.meshgrid(lons, lats) if ptype == 'c': # in the case of contour, use the centroids on the grids mp.contourf(x + 0.125, y + 0.125, data, clevs, clevstride=clevstride, units=units, ilabel=True, labelfmt='%.0f', cmap=cmap) else: x, y = np.meshgrid(lons, lats) mp.pcolormesh(x, y, data, clevs, clevstride=clevstride, cmap=cmap, units=units) return mp.fig
def test_stretch(): """can we do what we hope?""" cmap = stretch_cmap('jet', range(10)) assert cmap is not None cmap = dep_erosion() assert cmap is not None