def setCityList(self, dataframe): """Set the city list to an input dataframe. Args: dataframe (DataFrame): Pandas DataFrame whose columns include: - name: Name of the city (required). - lat: Latitude of city (required). - lon: Longitude of city (required). - pop: Population of city (optional). - iscap: Boolean indicating capital status (optional). - placement: String indicating where city label should be placed relative to city coordinates, one of: E, W, N, S, NE, SE, SW, NW. (optional). - xoff: Longitude offset for label relative to city coordinates (optional). - yoff: Latitude offset for label relative to city coordinates (optional). """ self.cities = BasemapCities(dataframe) # may raise exception self.city_rows = None self.city_cols = None self.cities_per_grid = None
def parseMapConfig(config): # Parse config object # ADD PLOTORDER TO CONFIG? OTHER THINGS LIKE COLORMAPS? topofile = None roadfolder = None cityfile = None roadcolor = '6E6E6E' countrycolor = '177F10' watercolor = 'B8EEFF' ALPHA = 0.7 outputdir = None oceanfile = None try: config1 = config['mapdata'] if 'dem' in config1: topofile = config1['dem']['file'] if os.path.exists(topofile) is False: print('DEM not valid - hillshade will not be possible\n') if 'ocean' in config1: oceanfile = config1['ocean']['file'] try: oceanref = config1['ocean']['shortref'] except: oceanref = 'unknown' if 'roads' in config1: roadfolder = config1['roads']['file'] if os.path.exists(roadfolder) is False: print('roadfolder not valid - roads will not be displayed\n') roadfolder = None try: roadref = config1['roads']['shortref'] except: roadref = 'unknown' if 'cities' in config1: cityfile = config1['cities']['file'] try: cityref = config1['cities']['shortref'] except: cityref = 'unknown' if os.path.exists(cityfile): try: #PagerCity(cityfile) BasemapCities.loadFromGeoNames(cityfile=cityfile) except Exception as e: print(e) print('cities file not valid - cities will not be displayed\n') cityfile = None else: print('cities file not valid - cities will not be displayed\n') cityfile = False if 'roadcolor' in config1['colors']: roadcolor = config1['colors']['roadcolor'] if 'countrycolor' in config1['colors']: countrycolor = config1['colors']['countrycolor'] if 'watercolor' in config1['colors']: watercolor = config1['colors']['watercolor'] if 'alpha' in config1['colors']: ALPHA = float(config1['colors']['alpha']) try: outputdir = config['output']['folder'] except: outputdir = None except Exception as e: print(('%s - mapdata missing from or misformatted in config' % e)) countrycolor = '#'+countrycolor watercolor = '#'+watercolor roadcolor = '#'+roadcolor mapin = {'topofile': topofile, 'roadfolder': roadfolder, 'cityfile': cityfile, 'roadcolor': roadcolor, 'countrycolor': countrycolor, 'watercolor': watercolor, 'ALPHA': ALPHA, 'outputdir': outputdir, 'roadref': roadref, 'cityref': cityref, 'oceanfile': oceanfile, 'oceanref': oceanref} return mapin
def modelMap(grids, shakefile=None, suptitle=None, inventory_shapefile=None, plotorder=None, maskthreshes=None, colormaps=None, boundaries=None, zthresh=0, scaletype='continuous', lims=None, logscale=False, ALPHA=0.7, maproads=True, mapcities=True, isScenario=False, roadfolder=None, topofile=None, cityfile=None, oceanfile=None, roadcolor='#6E6E6E', watercolor='#B8EEFF', countrycolor='#177F10', outputdir=None, savepdf=True, savepng=True, showplots=False, roadref='unknown', cityref='unknown', oceanref='unknown', printparam=False, ds=True, dstype='mean', upsample=False): """ This function creates maps of mapio grid layers (e.g. liquefaction or landslide models with their input layers) All grids must use the same bounds TO DO change so that all input layers do not have to have the same bounds, test plotting multiple probability layers, and add option so that if PDF and PNG aren't output, opens plot on screen using plt.show() :param grids: Dictionary of N layers and metadata formatted like: maplayers['layer name']={ 'grid': mapio grid2D object, 'label': 'label for colorbar and top line of subtitle', 'type': 'output or input to model', 'description': 'detailed description of layer for subtitle'}. Layer names must be unique. :type name: Dictionary or Ordered dictionary - import collections; grids = collections.OrderedDict() :param shakefile: optional ShakeMap file (url or full file path) to extract information for labels and folder names :type shakefile: Shakemap Event Dictionary :param suptitle: This will be displayed at the top of the plots and in the figure names :type suptitle: string :param plotorder: List of keys describing the order to plot the grids, if None and grids is an ordered dictionary, it will use the order of the dictionary, otherwise it will choose order which may be somewhat random but it will always put a probability grid first :type plotorder: list :param maskthreshes: N x 1 array or list of lower thresholds for masking corresponding to order in plotorder or order of OrderedDict if plotorder is None. If grids is not an ordered dict and plotorder is not specified, this will not work right. If None (default), nothing will be masked :param colormaps: List of strings of matplotlib colormaps (e.g. cm.autumn_r) corresponding to plotorder or order of dictionary if plotorder is None. The list can contain both strings and None e.g. colormaps = ['cm.autumn', None, None, 'cm.jet'] and None's will default to default colormap :param boundaries: None to show entire study area, 'zoom' to zoom in on the area of action (only works if there is a probability layer) using zthresh as a threshold, or a dictionary defining lats and lons in the form of boundaries.xmin = minlon, boundaries.xmax = maxlon, boundaries.ymin = min lat, boundaries.ymax = max lat :param zthresh: threshold for computing zooming bounds, only used if boundaries = 'zoom' :type zthresh: float :param scaletype: Type of scale for plotting, 'continuous' or 'binned' - will be reflected in colorbar :type scaletype: string :param lims: None or Nx1 list of tuples or numpy arrays corresponding to plotorder defining the limits for saturating the colorbar (vmin, vmax) if scaletype is continuous or the bins to use (clev) if scaletype if binned. The list can contain tuples, arrays, and Nones, e.g. lims = [(0., 10.), None, (0.1, 1.5), np.linspace(0., 1.5, 15)]. When None is specified, the program will estimate the limits, when an array is specified but the scale type is continuous, vmin will be set to min(array) and vmax will be set to max(array) :param lims: None or Nx1 list of Trues and Falses corresponding to plotorder defining whether to use a linear or log scale (log10) for plotting the layer. This will be reflected in the labels :param ALPHA: Transparency for mapping, if there is a hillshade that will plot below each layer, it is recommended to set this to at least 0.7 :type ALPHA: float :param maproads: Whether to show roads or not, default True, but requires that roadfile is specified and valid to work :type maproads: boolean :param mapcities: Whether to show cities or not, default True, but requires that cityfile is specified and valid to work :type mapcities: boolean :param isScenario: Whether this is a scenario (True) or a real event (False) (default False) :type isScenario: boolean :param roadfolder: Full file path to folder containing road shapefiles :type roadfolder: string :param topofile: Full file path to topography grid (GDAL compatible) - this is only needed to make a hillshade if a premade hillshade is not specified :type topofile: string :param cityfile: Full file path to Pager file containing city & population information :type cityfile: string :param roadcolor: Color to use for roads, if plotted, default #6E6E6E :type roadcolor: Hex color or other matplotlib compatible way of defining color :param watercolor: Color to use for oceans, lakes, and rivers, default #B8EEFF :type watercolor: Hex color or other matplotlib compatible way of defining color :param countrycolor: Color for country borders, default #177F10 :type countrycolor: Hex color or other matplotlib compatible way of defining color :param outputdir: File path for outputting figures, if edict is defined, a subfolder based on the event id will be created in this folder. If None, will use current directory :param savepdf: True to save pdf figure, False to not :param savepng: True to save png figure, False to not :param ds: True to allow downsampling for display (necessary when arrays are quite large, False to not allow) :param dstype: What function to use in downsampling, options are 'min', 'max', 'median', or 'mean' :param upsample: True to upsample the layer to the DEM resolution for better looking hillshades :returns: * PDF and/or PNG of map * Downsampled and trimmed version of input grids. If no modification was needed for plotting, this will be identical to grids but without the metadata """ if suptitle is None: suptitle = ' ' plt.ioff() defaultcolormap = cm.jet if shakefile is not None: edict = ShakeGrid.load(shakefile, adjust='res').getEventDict() temp = ShakeGrid.load(shakefile, adjust='res').getShakeDict() edict['eventid'] = temp['shakemap_id'] edict['version'] = temp['shakemap_version'] else: edict = None # Get output file location if outputdir is None: print('No output location given, using current directory for outputs\n') outputdir = os.getcwd() if edict is not None: outfolder = os.path.join(outputdir, edict['event_id']) else: outfolder = outputdir if not os.path.isdir(outfolder): os.makedirs(outfolder) # Get plotting order, if not specified if plotorder is None: plotorder = list(grids.keys()) # Get boundaries to use for all plots cut = True if boundaries is None: cut = False keytemp = list(grids.keys()) boundaries = grids[keytemp[0]]['grid'].getGeoDict() elif boundaries == 'zoom': # Find probability layer (will just take the maximum bounds if there is # more than one) keytemp = list(grids.keys()) key1 = [key for key in keytemp if 'model' in key.lower()] if len(key1) == 0: print('Could not find model layer to use for zoom, using default boundaries') keytemp = list(grids.keys()) boundaries = grids[keytemp[0]]['grid'].getGeoDict() else: lonmax = -1.e10 lonmin = 1.e10 latmax = -1.e10 latmin = 1.e10 for key in key1: # get lat lons of areas affected and add, if no areas affected, # switch to shakemap boundaries temp = grids[key]['grid'] xmin, xmax, ymin, ymax = temp.getBounds() lons = np.linspace(xmin, xmax, temp.getGeoDict().nx) lats = np.linspace(ymax, ymin, temp.getGeoDict().ny) # backwards so it plots right row, col = np.where(temp.getData() > float(zthresh)) lonmin = lons[col].min() lonmax = lons[col].max() latmin = lats[row].min() latmax = lats[row].max() # llons, llats = np.meshgrid(lons, lats) # make meshgrid # llons1 = llons[temp.getData() > float(zthresh)] # llats1 = llats[temp.getData() > float(zthresh)] # if llons1.min() < lonmin: # lonmin = llons1.min() # if llons1.max() > lonmax: # lonmax = llons1.max() # if llats1.min() < latmin: # latmin = llats1.min() # if llats1.max() > latmax: # latmax = llats1.max() boundaries1 = {'dx': 100, 'dy': 100., 'nx': 100., 'ny': 100} # dummy fillers, only really care about bounds if xmin < lonmin-0.15*(lonmax-lonmin): boundaries1['xmin'] = lonmin-0.1*(lonmax-lonmin) else: boundaries1['xmin'] = xmin if xmax > lonmax+0.15*(lonmax-lonmin): boundaries1['xmax'] = lonmax+0.1*(lonmax-lonmin) else: boundaries1['xmax'] = xmax if ymin < latmin-0.15*(latmax-latmin): boundaries1['ymin'] = latmin-0.1*(latmax-latmin) else: boundaries1['ymin'] = ymin if ymax > latmax+0.15*(latmax-latmin): boundaries1['ymax'] = latmax+0.1*(latmax-latmin) else: boundaries1['ymax'] = ymax boundaries = GeoDict(boundaries1, adjust='res') else: # SEE IF BOUNDARIES ARE SAME AS BOUNDARIES OF LAYERS keytemp = list(grids.keys()) tempgdict = grids[keytemp[0]]['grid'].getGeoDict() if np.abs(tempgdict.xmin-boundaries['xmin']) < 0.05 and \ np.abs(tempgdict.ymin-boundaries['ymin']) < 0.05 and \ np.abs(tempgdict.xmax-boundaries['xmax']) < 0.05 and \ np.abs(tempgdict.ymax - boundaries['ymax']) < 0.05: print('Input boundaries are almost the same as specified boundaries, no cutting needed') boundaries = tempgdict cut = False else: try: if boundaries['xmin'] > boundaries['xmax'] or \ boundaries['ymin'] > boundaries['ymax']: print('Input boundaries are not usable, using default boundaries') keytemp = list(grids.keys()) boundaries = grids[keytemp[0]]['grid'].getGeoDict() cut = False else: # Build dummy GeoDict boundaries = GeoDict({'xmin': boundaries['xmin'], 'xmax': boundaries['xmax'], 'ymin': boundaries['ymin'], 'ymax': boundaries['ymax'], 'dx': 100., 'dy': 100., 'ny': 100., 'nx': 100.}, adjust='res') except: print('Input boundaries are not usable, using default boundaries') keytemp = list(grids.keys()) boundaries = grids[keytemp[0]]['grid'].getGeoDict() cut = False # Pull out bounds for various uses bxmin, bxmax, bymin, bymax = boundaries.xmin, boundaries.xmax, boundaries.ymin, boundaries.ymax # Determine if need a single panel or multi-panel plot and if multi-panel, # how many and how it will be arranged fig = plt.figure() numpanels = len(grids) if numpanels == 1: rowpan = 1 colpan = 1 # create the figure and axes instances. fig.set_figwidth(5) elif numpanels == 2 or numpanels == 4: rowpan = np.ceil(numpanels/2.) colpan = 2 fig.set_figwidth(13) else: rowpan = np.ceil(numpanels/3.) colpan = 3 fig.set_figwidth(15) if rowpan == 1: fig.set_figheight(rowpan*6.0) else: fig.set_figheight(rowpan*5.3) # Need to update naming to reflect the shakemap version once can get # getHeaderData to work, add edict['version'] back into title, maybe # shakemap id also? fontsizemain = 14. fontsizesub = 12. fontsizesmallest = 10. if rowpan == 1.: fontsizemain = 12. fontsizesub = 10. fontsizesmallest = 8. if edict is not None: if isScenario: title = edict['event_description'] else: timestr = edict['event_timestamp'].strftime('%b %d %Y') title = 'M%.1f %s v%i - %s' % (edict['magnitude'], timestr, edict['version'], edict['event_description']) plt.suptitle(title+'\n'+suptitle, fontsize=fontsizemain) else: plt.suptitle(suptitle, fontsize=fontsizemain) clear_color = [0, 0, 0, 0.0] # Cut all of them and release extra memory xbuff = (bxmax-bxmin)/10. ybuff = (bymax-bymin)/10. cutxmin = bxmin-xbuff cutymin = bymin-ybuff cutxmax = bxmax+xbuff cutymax = bymax+ybuff if cut is True: newgrids = collections.OrderedDict() for k, layer in enumerate(plotorder): templayer = grids[layer]['grid'] try: newgrids[layer] = {'grid': templayer.cut(cutxmin, cutxmax, cutymin, cutymax, align=True)} except Exception as e: print(('Cutting failed, %s, continuing with full layers' % e)) newgrids = grids continue del templayer gc.collect() else: newgrids = grids tempgdict = newgrids[list(grids.keys())[0]]['grid'].getGeoDict() # Upsample layers to same as topofile if desired for better looking hillshades if upsample is True and topofile is not None: try: topodict = GDALGrid.getFileGeoDict(topofile) if topodict.dx >= tempgdict.dx or topodict.dy >= tempgdict.dy: print('Upsampling not possible, resolution of results already smaller than DEM') pass else: tempgdict1 = GeoDict({'xmin': tempgdict.xmin-xbuff, 'ymin': tempgdict.ymin-ybuff, 'xmax': tempgdict.xmax+xbuff, 'ymax': tempgdict.ymax+ybuff, 'dx': topodict.dx, 'dy': topodict.dy, 'nx': topodict.nx, 'ny': topodict.ny}, adjust='res') tempgdict2 = tempgdict1.getBoundsWithin(tempgdict) for k, layer in enumerate(plotorder): newgrids[layer]['grid'] = newgrids[layer]['grid'].subdivide(tempgdict2) except: print('Upsampling failed, continuing') # Downsample all of them for plotting, if needed, and replace them in # grids (to save memory) tempgrid = newgrids[list(grids.keys())[0]]['grid'] xsize = tempgrid.getGeoDict().nx ysize = tempgrid.getGeoDict().ny inchesx, inchesy = fig.get_size_inches() divx = int(np.round(xsize/(500.*inchesx))) divy = int(np.round(ysize/(500.*inchesy))) xmin, xmax, ymin, ymax = tempgrid.getBounds() gdict = tempgrid.getGeoDict() # Will be replaced if downsampled del tempgrid gc.collect() if divx <= 1: divx = 1 if divy <= 1: divy = 1 if (divx > 1. or divy > 1.) and ds: if dstype == 'max': func = np.nanmax elif dstype == 'min': func = np.nanmin elif dstype == 'med': func = np.nanmedian else: func = np.nanmean for k, layer in enumerate(plotorder): layergrid = newgrids[layer]['grid'] dat = block_reduce(layergrid.getData().copy(), block_size=(divy, divx), cval=float('nan'), func=func) if k == 0: lons = block_reduce(np.linspace(xmin, xmax, layergrid.getGeoDict().nx), block_size=(divx,), func=np.mean, cval=float('nan')) if math.isnan(lons[-1]): lons[-1] = lons[-2] + (lons[1]-lons[0]) lats = block_reduce(np.linspace(ymax, ymin, layergrid.getGeoDict().ny), block_size=(divy,), func=np.mean, cval=float('nan')) if math.isnan(lats[-1]): lats[-1] = lats[-2] + (lats[1]-lats[0]) gdict = GeoDict({'xmin': lons.min(), 'xmax': lons.max(), 'ymin': lats.min(), 'ymax': lats.max(), 'dx': np.abs(lons[1]-lons[0]), 'dy': np.abs(lats[1]-lats[0]), 'nx': len(lons), 'ny': len(lats)}, adjust='res') newgrids[layer]['grid'] = Grid2D(dat, gdict) del layergrid, dat else: lons = np.linspace(xmin, xmax, xsize) lats = np.linspace(ymax, ymin, ysize) # backwards so it plots right side up #make meshgrid llons1, llats1 = np.meshgrid(lons, lats) # See if there is an oceanfile for masking bbox = PolygonSH(((cutxmin, cutymin), (cutxmin, cutymax), (cutxmax, cutymax), (cutxmax, cutymin))) if oceanfile is not None: try: f = fiona.open(oceanfile) oc = next(f) f.close shapes = shape(oc['geometry']) # make boundaries into a shape ocean = shapes.intersection(bbox) except: print('Not able to read specified ocean file, will use default ocean masking') oceanfile = None if inventory_shapefile is not None: try: f = fiona.open(inventory_shapefile) invshp = list(f.items(bbox=(bxmin, bymin, bxmax, bymax))) f.close() inventory = [shape(inv[1]['geometry']) for inv in invshp] except: print('unable to read inventory shapefile specified, will not plot inventory') inventory_shapefile = None # # Find cities that will be plotted if mapcities is True and cityfile is not None: try: mycity = BasemapCities.loadFromGeoNames(cityfile=cityfile) bcities = mycity.limitByBounds((bxmin, bxmax, bymin, bymax)) #bcities = bcities.limitByPopulation(40000) bcities = bcities.limitByGrid(nx=4, ny=4, cities_per_grid=2) except: print('Could not read in cityfile, not plotting cities') mapcities = False cityfile = None # Load in topofile if topofile is not None: try: topomap = GDALGrid.load(topofile, resample=True, method='linear', samplegeodict=gdict) except: topomap = GMTGrid.load(topofile, resample=True, method='linear', samplegeodict=gdict) topodata = topomap.getData().copy() # mask oceans if don't have ocean shapefile if oceanfile is None: topodata = maskoceans(llons1, llats1, topodata, resolution='h', grid=1.25, inlands=True) else: print('no hillshade is possible\n') topomap = None topodata = None # Load in roads, if needed if maproads is True and roadfolder is not None: try: roadslist = [] for folder in os.listdir(roadfolder): road1 = os.path.join(roadfolder, folder) shpfiles = glob.glob(os.path.join(road1, '*.shp')) if len(shpfiles): shpfile = shpfiles[0] f = fiona.open(shpfile) shapes = list(f.items(bbox=(bxmin, bymin, bxmax, bymax))) for shapeid, shapedict in shapes: roadslist.append(shapedict) f.close() except: print('Not able to plot roads') roadslist = None val = 1 for k, layer in enumerate(plotorder): layergrid = newgrids[layer]['grid'] if 'label' in list(grids[layer].keys()): label1 = grids[layer]['label'] else: label1 = layer try: sref = grids[layer]['description']['name'] except: sref = None ax = fig.add_subplot(rowpan, colpan, val) val += 1 clat = bymin + (bymax-bymin)/2.0 clon = bxmin + (bxmax-bxmin)/2.0 # setup of basemap ('lcc' = lambert conformal conic). # use major and minor sphere radii from WGS84 ellipsoid. m = Basemap(llcrnrlon=bxmin, llcrnrlat=bymin, urcrnrlon=bxmax, urcrnrlat=bymax, rsphere=(6378137.00, 6356752.3142), resolution='l', area_thresh=1000., projection='lcc', lat_1=clat, lon_0=clon, ax=ax) x1, y1 = m(llons1, llats1) # get projection coordinates axsize = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted()) if k == 0: wid, ht = axsize.width, axsize.height if colormaps is not None and \ len(colormaps) == len(newgrids) and \ colormaps[k] is not None: palette = colormaps[k] else: # Find preferred default color map for each type of layer if 'prob' in layer.lower() or 'pga' in layer.lower() or \ 'pgv' in layer.lower() or 'cohesion' in layer.lower() or \ 'friction' in layer.lower() or 'fs' in layer.lower(): palette = cm.jet elif 'slope' in layer.lower(): palette = cm.gnuplot2 elif 'precip' in layer.lower(): palette = cm2.s3pcpn else: palette = defaultcolormap if topodata is not None: if k == 0: ptopo = m.transform_scalar( np.flipud(topodata), lons+0.5*gdict.dx, lats[::-1]-0.5*gdict.dy, np.round(300.*wid), np.round(300.*ht), returnxy=False, checkbounds=False, order=1, masked=False) #use lightsource class to make our shaded topography ls = LightSource(azdeg=135, altdeg=45) ls1 = LightSource(azdeg=120, altdeg=45) ls2 = LightSource(azdeg=225, altdeg=45) intensity1 = ls1.hillshade(ptopo, fraction=0.25, vert_exag=1.) intensity2 = ls2.hillshade(ptopo, fraction=0.25, vert_exag=1.) intensity = intensity1*0.5 + intensity2*0.5 #hillshm_im = m.transform_scalar(np.flipud(hillshm), lons, lats[::-1], np.round(300.*wid), np.round(300.*ht), returnxy=False, checkbounds=False, order=0, masked=False) #m.imshow(hillshm_im, cmap='Greys', vmin=0., vmax=3., zorder=1, interpolation='none') # vmax = 3 to soften colors to light gray #m.pcolormesh(x1, y1, hillshm, cmap='Greys', linewidth=0., rasterized=True, vmin=0., vmax=3., edgecolors='none', zorder=1); # plt.draw() # Get the data dat = layergrid.getData().copy() # mask out anything below any specified thresholds # Might need to move this up to before downsampling...might give illusion of no hazard in places where there is some that just got averaged out if maskthreshes is not None and len(maskthreshes) == len(newgrids): if maskthreshes[k] is not None: dat[dat <= maskthreshes[k]] = float('NaN') dat = np.ma.array(dat, mask=np.isnan(dat)) if logscale is not False and len(logscale) == len(newgrids): if logscale[k] is True: dat = np.log10(dat) label1 = r'$log_{10}$(' + label1 + ')' if scaletype.lower() == 'binned': # Find order of range to know how to scale order = np.round(np.log(np.nanmax(dat) - np.nanmin(dat))) if order < 1.: scal = 10**-order else: scal = 1. if lims is None or len(lims) != len(newgrids): clev = (np.linspace(np.floor(scal*np.nanmin(dat)), np.ceil(scal*np.nanmax(dat)), 10))/scal else: if lims[k] is None: clev = (np.linspace(np.floor(scal*np.nanmin(dat)), np.ceil(scal*np.nanmax(dat)), 10))/scal else: clev = lims[k] # Adjust to colorbar levels dat[dat < clev[0]] = clev[0] for j, level in enumerate(clev[:-1]): dat[(dat >= clev[j]) & (dat < clev[j+1])] = clev[j] # So colorbar saturates at top dat[dat > clev[-1]] = clev[-1] #panelhandle = m.contourf(x1, y1, datm, clev, cmap=palette, linewidth=0., alpha=ALPHA, rasterized=True) vmin = clev[0] vmax = clev[-1] else: if lims is not None and len(lims) == len(newgrids): if lims[k] is None: vmin = np.nanmin(dat) vmax = np.nanmax(dat) else: vmin = lims[k][0] vmax = lims[k][-1] else: vmin = np.nanmin(dat) vmax = np.nanmax(dat) # Mask out cells overlying oceans or block with a shapefile if available if oceanfile is None: dat = maskoceans(llons1, llats1, dat, resolution='h', grid=1.25, inlands=True) else: #patches = [] if type(ocean) is PolygonSH: ocean = [ocean] for oc in ocean: patch = getProjectedPatch(oc, m, edgecolor="#006280", facecolor=watercolor, lw=0.5, zorder=4.) #x, y = m(oc.exterior.xy[0], oc.exterior.xy[1]) #xy = zip(x, y) #patch = Polygon(xy, facecolor=watercolor, edgecolor="#006280", lw=0.5, zorder=4.) ##patches.append(Polygon(xy, facecolor=watercolor, edgecolor=watercolor, zorder=500.)) ax.add_patch(patch) ##ax.add_collection(PatchCollection(patches)) if inventory_shapefile is not None: for in1 in inventory: if 'point' in str(type(in1)): x, y = in1.xy x = x[0] y = y[0] m.scatter(x, y, c='m', s=50, latlon=True, marker='^', zorder=100001) else: x, y = m(in1.exterior.xy[0], in1.exterior.xy[1]) xy = list(zip(x, y)) patch = Polygon(xy, facecolor='none', edgecolor='k', lw=0.5, zorder=10.) #patches.append(Polygon(xy, facecolor=watercolor, edgecolor=watercolor, zorder=500.)) ax.add_patch(patch) palette.set_bad(clear_color, alpha=0.0) # Plot it up dat_im = m.transform_scalar( np.flipud(dat), lons+0.5*gdict.dx, lats[::-1]-0.5*gdict.dy, np.round(300.*wid), np.round(300.*ht), returnxy=False, checkbounds=False, order=0, masked=True) if topodata is not None: # Drape over hillshade #turn data into an RGBA image cmap = palette #adjust data so scaled between vmin and vmax and between 0 and 1 dat1 = dat_im.copy() dat1[dat1 < vmin] = vmin dat1[dat1 > vmax] = vmax dat1 = (dat1 - vmin)/(vmax-vmin) rgba_img = cmap(dat1) maskvals = np.dstack((dat1.mask, dat1.mask, dat1.mask)) rgb = np.squeeze(rgba_img[:, :, 0:3]) rgb[maskvals] = 1. draped_hsv = ls.blend_hsv(rgb, np.expand_dims(intensity, 2)) m.imshow(draped_hsv, zorder=3., interpolation='none') # This is just a dummy layer that will be deleted to make the # colorbar look right panelhandle = m.imshow(dat_im, cmap=palette, zorder=0., vmin=vmin, vmax=vmax) else: panelhandle = m.imshow(dat_im, cmap=palette, zorder=3., vmin=vmin, vmax=vmax, interpolation='none') #panelhandle = m.pcolormesh(x1, y1, dat, linewidth=0., cmap=palette, vmin=vmin, vmax=vmax, alpha=ALPHA, rasterized=True, zorder=2.); #panelhandle.set_edgecolors('face') # add colorbar cbfmt = '%1.1f' if vmax is not None and vmin is not None: if (vmax - vmin) < 1.: cbfmt = '%1.2f' elif vmax > 5.: # (vmax - vmin) > len(clev): cbfmt = '%1.0f' #norm = mpl.colors.Normalize(vmin=vmin, vmax=vmax) if scaletype.lower() == 'binned': cbar = fig.colorbar(panelhandle, spacing='proportional', ticks=clev, boundaries=clev, fraction=0.036, pad=0.04, format=cbfmt, extend='both') #cbar1 = ColorbarBase(cbar.ax, cmap=palette, norm=norm, spacing='proportional', ticks=clev, boundaries=clev, fraction=0.036, pad=0.04, format=cbfmt, extend='both', extendfrac='auto') else: cbar = fig.colorbar(panelhandle, fraction=0.036, pad=0.04, extend='both', format=cbfmt) #cbar1 = ColorbarBase(cbar.ax, cmap=palette, norm=norm, fraction=0.036, pad=0.04, extend='both', extendfrac='auto', format=cbfmt) if topodata is not None: panelhandle.remove() cbar.set_label(label1, fontsize=10) cbar.ax.tick_params(labelsize=8) parallels = m.drawparallels(getMapLines(bymin, bymax, 3), labels=[1, 0, 0, 0], linewidth=0.5, labelstyle='+/-', fontsize=9, xoffset=-0.8, color='gray', zorder=100.) m.drawmeridians(getMapLines(bxmin, bxmax, 3), labels=[0, 0, 0, 1], linewidth=0.5, labelstyle='+/-', fontsize=9, color='gray', zorder=100.) for par in parallels: try: parallels[par][1][0].set_rotation(90) except: pass #draw roads on the map, if they were provided to us if maproads is True and roadslist is not None: try: for road in roadslist: try: xy = list(road['geometry']['coordinates']) roadx, roady = list(zip(*xy)) mapx, mapy = m(roadx, roady) m.plot(mapx, mapy, roadcolor, lw=0.5, zorder=9) except: continue except Exception as e: print(('Failed to plot roads, %s' % e)) #add city names to map if mapcities is True and cityfile is not None: try: fontname = 'Arial' fontsize = 8 if k == 0: # Only need to choose cities first time and then apply to rest fcities = bcities.limitByMapCollision( m, fontname=fontname, fontsize=fontsize) ctlats, ctlons, names = fcities.getCities() cxis, cyis = m(ctlons, ctlats) for ctlat, ctlon, cxi, cyi, name in zip(ctlats, ctlons, cxis, cyis, names): m.scatter(ctlon, ctlat, c='k', latlon=True, marker='.', zorder=100000) ax.text(cxi, cyi, name, fontname=fontname, fontsize=fontsize, zorder=100000) except Exception as e: print('Failed to plot cities, %s' % e) #draw star at epicenter plt.sca(ax) if edict is not None: elat, elon = edict['lat'], edict['lon'] ex, ey = m(elon, elat) plt.plot(ex, ey, '*', markeredgecolor='k', mfc='None', mew=1.0, ms=15, zorder=10000.) m.drawmapboundary(fill_color=watercolor) m.fillcontinents(color=clear_color, lake_color=watercolor) m.drawrivers(color=watercolor) ##m.drawcoastlines() #draw country boundaries m.drawcountries(color=countrycolor, linewidth=1.0) #add map scale m.drawmapscale((bxmax+bxmin)/2., (bymin+(bymax-bymin)/9.), clon, clat, np.round((((bxmax-bxmin)*111)/5)/10.)*10, barstyle='fancy', zorder=10) # Add border autoAxis = ax.axis() rec = Rectangle((autoAxis[0]-0.7, autoAxis[2]-0.2), (autoAxis[1]-autoAxis[0])+1, (autoAxis[3]-autoAxis[2])+0.4, fill=False, lw=1, zorder=1e8) rec = ax.add_patch(rec) rec.set_clip_on(False) plt.draw() if sref is not None: label2 = '%s\nsource: %s' % (label1, sref) # '%s\n' % label1 + r'{\fontsize{10pt}{3em}\selectfont{}%s}' % sref # else: label2 = label1 plt.title(label2, axes=ax, fontsize=fontsizesub) #draw scenario watermark, if scenario if isScenario: plt.sca(ax) cx, cy = m(clon, clat) plt.text(cx, cy, 'SCENARIO', rotation=45, alpha=0.10, size=72, ha='center', va='center', color='red') #if ds: # Could add this to print "downsampled" on map # plt.text() if k == 1 and rowpan == 1: # adjust single level plot axsize = ax.get_window_extent().transformed(fig.dpi_scale_trans.inverted()) ht2 = axsize.height fig.set_figheight(ht2*1.6) else: plt.tight_layout() # Make room for suptitle - tight layout doesn't account for it plt.subplots_adjust(top=0.92) if printparam is True: try: fig = plt.gcf() dictionary = grids['model']['description']['parameters'] paramstring = 'Model parameters: ' halfway = np.ceil(len(dictionary)/2.) for i, key in enumerate(dictionary): if i == halfway and colpan == 1: paramstring += '\n' paramstring += ('%s = %s; ' % (key, dictionary[key])) print(paramstring) fig.text(0.01, 0.015, paramstring, fontsize=fontsizesmallest) plt.draw() except: print('Could not display model parameters') if edict is not None: eventid = edict['eventid'] else: eventid = '' time1 = datetime.datetime.utcnow().strftime('%d%b%Y_%H%M') outfile = os.path.join(outfolder, '%s_%s_%s.pdf' % (eventid, suptitle, time1)) pngfile = os.path.join(outfolder, '%s_%s_%s.png' % (eventid, suptitle, time1)) if savepdf is True: print('Saving map output to %s' % outfile) plt.savefig(outfile, dpi=300) if savepng is True: print('Saving map output to %s' % pngfile) plt.savefig(pngfile) if showplots is True: plt.show() else: plt.close(fig) return newgrids
def parseMapConfig(config, fileext=None): """ Parse config for mapping options. Args: config (ConfigObj): ConfigObj object. fileext (str): File extension to add to relative filepaths, will be prepended to any file paths in config. Returns: dict: Dictionary of map options pulled from config file. """ topofile = None roadfolder = None cityfile = None roadcolor = '6E6E6E' countrycolor = '177F10' watercolor = 'B8EEFF' ALPHA = 0.7 oceanfile = None #oceanref = None #roadref = None #cityref = None if fileext is None: fileext = '.' if 'dem' in config: topofile = os.path.join(fileext, config['dem']['file']) if os.path.exists(topofile) is False: print('DEM not valid - hillshade will not be possible\n') if 'ocean' in config: oceanfile = os.path.join(fileext, config['ocean']['file']) #try: # oceanref = config['ocean']['shortref'] #except: # oceanref = 'unknown' if 'roads' in config: roadfolder = os.path.join(fileext, config['roads']['file']) if os.path.exists(roadfolder) is False: print('roadfolder not valid - roads will not be displayed\n') roadfolder = None #try: # roadref = config['roads']['shortref'] #except: # roadref = 'unknown' if 'cities' in config: cityfile = os.path.join(fileext, config['cities']['file']) #try: # cityref = config['cities']['shortref'] #except: # cityref = 'unknown' if os.path.exists(cityfile): try: BasemapCities.loadFromGeoNames(cityfile=cityfile) except Exception as e: print(e) print('cities file not valid - cities will not be displayed\n') cityfile = None else: print('cities file not valid - cities will not be displayed\n') cityfile = None if 'roadcolor' in config['colors']: roadcolor = config['colors']['roadcolor'] if 'countrycolor' in config['colors']: countrycolor = config['colors']['countrycolor'] if 'watercolor' in config['colors']: watercolor = config['colors']['watercolor'] if 'alpha' in config['colors']: ALPHA = float(config['colors']['alpha']) countrycolor = '#'+countrycolor watercolor = '#'+watercolor roadcolor = '#'+roadcolor mapin = {'topofile': topofile, 'roadfolder': roadfolder, 'cityfile': cityfile, 'roadcolor': roadcolor, 'countrycolor': countrycolor, 'watercolor': watercolor, 'ALPHA': ALPHA, 'oceanfile': oceanfile} # 'roadref': roadref, 'cityref': cityref, 'oceanref': oceanref return mapin
def test(): cityfile = os.path.join(homedir,'data','cities1000.txt') print('Test loading geonames cities file from the web...') cities = BasemapCities.loadFromGeoNames(cityfile=cityfile) #load from the web print('Passed loading geonames cities file from the web.') print('Test limiting cities using California bounds...') ymin,ymax = 32.394, 42.062 xmin,xmax = -125.032, -114.002 bcities = cities.limitByBounds((xmin,xmax,ymin,ymax)) print('Done limiting cities using California bounds.') print('Test removing cities with collisions...') ymin,ymax = 32.394, 42.062 xmin,xmax = -125.032, -114.002 clat = (ymin+ymax)/2.0 clon = (xmin+xmax)/2.0 f = plt.figure(figsize=(8,8)) ax = f.add_axes([0.1,0.1,0.8,0.8]) BASEMAP_RESOLUTION = 'l' m = Basemap(llcrnrlon=xmin,llcrnrlat=ymin,urcrnrlon=xmax,urcrnrlat=ymax, rsphere=(6378137.00,6356752.3142), resolution=BASEMAP_RESOLUTION,projection='merc', lat_0=clat,lon_0=clon,lat_ts=clat,ax=ax) m.drawcoastlines() #have to draw something on map before axis limits are set... bigcities = bcities.limitByPopulation(500000) mapcities = bigcities.limitByMapCollision(m) mapcities.renderToMap(ax) df = mapcities.getDataFrame() boxes = [] for index,row in df.iterrows(): left = row['left'] right = row['right'] left = row['bottom'] right = row['top'] for box in boxes: bleft,bright,bbottom,btop = box #http://gamedevelopment.tutsplus.com/tutorials/collision-detection-using-the-separating-axis-theorem--gamedev-169 width = left - bleft hw_box1 = (right-left)*0.5 hw_box2 = (right-left)*0.5 hgap = length - hw_box1 - hw_box2 height = top - btop hh_box1 = (top-bottom)*0.5 hh_box2 = (btop-bbottom)*0.5 vgap = height - hh_box1 - hh_box2 assert hgap > 0 and vgap > 0 print('Passed test of city collisions...') print('Test all supported font names...') f = plt.figure() ax = f.add_axes([0.1,0.1,0.8,0.8]) plt.plot(1,1) for name in mapcities.getFontList(): plt.text(1,1,name,fontname=name) for name in mapcities.SUGGESTED_FONTS: plt.text(1,1,name,fontname=name) print('Passed test of supported font names.')
def _test_intensity(): datadir = os.path.abspath(os.path.join( homedir, '..', 'data', 'eventdata', 'northridge')) shakefile = os.path.join(datadir, 'northridge_grid.xml') topofile = os.path.join(datadir, 'northridge_topo.grd') faultfile = os.path.join(datadir, 'northridge_fault.txt') cityfile = os.path.join(datadir, 'northridge_cities.txt') coastfile = os.path.join(datadir, 'northridge_coastline.json') countryfile = os.path.join(datadir, 'northridge_countries.json') statefile = os.path.join(datadir, 'northridge_states.json') lakefile = os.path.join(datadir, 'northridge_lakes.json') oceanfile = os.path.join(datadir, 'northridge_ocean.json') stationfile = os.path.join(datadir, 'northridge_stations.db') roadfile = os.path.join(datadir, 'northridge_roads.json') tancptfile = os.path.join(shakedir, 'shakemap', 'mapping', 'tan.cpt') shakecptfile = os.path.join( shakedir, 'shakemap', 'mapping', 'shakecpt.cpt') layerdict = {'coast': coastfile, 'ocean': oceanfile, 'lake': lakefile, 'country': countryfile, 'roads': roadfile, 'state': statefile} tancolormap = ColorPalette.fromPreset('shaketopo') shakecolormap = ColorPalette.fromPreset('mmi') cities = BasemapCities.loadFromCSV(cityfile) shakemap = ShakeGrid.load(shakefile, adjust='res') stations = StationList(stationfile) fault = Fault.readFaultFile(faultfile) edict = shakemap.getEventDict() eventdict = {'lat': edict['lat'], 'lon': edict['lon'], 'depth': edict['depth'], 'mag': edict['magnitude'], 'time': edict['event_timestamp']} source = Source(eventdict, fault) maker = MapMaker(shakemap, topofile, stations, fault, layerdict, source, cities) # draw intensity map outfolder = os.path.expanduser('~') maker.setIntensityLayer('mmi') maker.setIntensityGMTColorMap(shakecolormap) intensity_map = maker.drawIntensityMap(outfolder) print('Intensity map saved as: %s' % intensity_map) # draw contour maps maker.setContourGMTColorMap(tancolormap) # Draw pgv contours maker.setContourLayer('pgv') contour_pgv_map = maker.drawContourMap(outfolder) print('PGV contour map saved as: %s' % contour_pgv_map) # Draw pga contours maker.setContourLayer('pga') contour_pga_map = maker.drawContourMap(outfolder) print('PGA contour map saved as: %s' % contour_pga_map) # Draw psa0.3 contours maker.setContourLayer('psa03') contour_psa03_map = maker.drawContourMap(outfolder) print('PSA0.3 contour map saved as: %s' % contour_psa03_map) # Draw psa1.0 contours maker.setContourLayer('psa10') contour_psa10_map = maker.drawContourMap(outfolder) print('PSA1.0 contour map saved as: %s' % contour_psa10_map) # Draw psa3.0 contours maker.setContourLayer('psa30') contour_psa30_map = maker.drawContourMap(outfolder) print('PSA3.0 contour map saved as: %s' % contour_psa30_map)
def _test_intensity(): datadir = os.path.abspath(os.path.join(homedir, "..", "data", "eventdata", "northridge")) shakefile = os.path.join(datadir, "northridge_grid.xml") topofile = os.path.join(datadir, "northridge_topo.grd") rupturefile = os.path.join(datadir, "northridge_fault.txt") cityfile = os.path.join(datadir, "northridge_cities.txt") coastfile = os.path.join(datadir, "northridge_coastline.json") countryfile = os.path.join(datadir, "northridge_countries.json") statefile = os.path.join(datadir, "northridge_states.json") lakefile = os.path.join(datadir, "northridge_lakes.json") oceanfile = os.path.join(datadir, "northridge_ocean.json") stationfile = os.path.join(datadir, "northridge_stations.db") roadfile = os.path.join(datadir, "northridge_roads.json") tancptfile = os.path.join(shakedir, "shakemap", "mapping", "tan.cpt") shakecptfile = os.path.join(shakedir, "shakemap", "mapping", "shakecpt.cpt") layerdict = { "coast": coastfile, "ocean": oceanfile, "lake": lakefile, "country": countryfile, "roads": roadfile, "state": statefile, } tancolormap = ColorPalette.fromPreset("shaketopo") shakecolormap = ColorPalette.fromPreset("mmi") cities = BasemapCities.loadFromCSV(cityfile) shakemap = ShakeGrid.load(shakefile, adjust="res") stations = StationList(stationfile) rupture = QuadRupture.readRuptureFile(rupturefile) edict = shakemap.getEventDict() eventdict = { "lat": edict["lat"], "lon": edict["lon"], "depth": edict["depth"], "mag": edict["magnitude"], "time": edict["event_timestamp"], } source = Source(eventdict, rupture) maker = MapMaker(shakemap, topofile, stations, rupture, layerdict, source, cities) # draw intensity map outfolder = os.path.expanduser("~") maker.setIntensityLayer("mmi") maker.setIntensityGMTColorMap(shakecolormap) intensity_map = maker.drawIntensityMap(outfolder) print("Intensity map saved as: %s" % intensity_map) # draw contour maps maker.setContourGMTColorMap(tancolormap) # Draw pgv contours maker.setContourLayer("pgv") contour_pgv_map = maker.drawContourMap(outfolder) print("PGV contour map saved as: %s" % contour_pgv_map) # Draw pga contours maker.setContourLayer("pga") contour_pga_map = maker.drawContourMap(outfolder) print("PGA contour map saved as: %s" % contour_pga_map) # Draw psa0.3 contours maker.setContourLayer("psa03") contour_psa03_map = maker.drawContourMap(outfolder) print("PSA0.3 contour map saved as: %s" % contour_psa03_map) # Draw psa1.0 contours maker.setContourLayer("psa10") contour_psa10_map = maker.drawContourMap(outfolder) print("PSA1.0 contour map saved as: %s" % contour_psa10_map) # Draw psa3.0 contours maker.setContourLayer("psa30") contour_psa30_map = maker.drawContourMap(outfolder) print("PSA3.0 contour map saved as: %s" % contour_psa30_map)
def __init__(self, container, topofile, layerdict, cities_file, logger): """Initialize MapMaker object. Args: container (ShakeMapOutputContainer): ShakeMapOutputContainer object containing model results. topofile (str): Path to file containing global topography grid. layerdict (dict): Dictionary containing fields: - coast: Global coastline shapefile. - ocean: Global ocean shapefile. - lake: Global lakes shapefile. - country: Global country boundaries shapefile. - state: Global state (or equivalent) boundaries shapefile. - roads: Global roads directory containing directories with regional shapefiles. cities_file (str): Path to geonames cities1000.txt file. logger (Logger): Python logging instance. Raises: KeyError: When any of layerdict keys are missing. """ req_keys = set(['coast', 'ocean', 'lake', 'country', 'state']) if len(set(layerdict.keys()).intersection(req_keys)) != len(req_keys): raise KeyError( 'layerdict input must have all keys from %s' % str(req_keys)) self.container = container self.topofile = topofile self.layerdict = layerdict cities = BasemapCities.loadFromGeoNames(cities_file) self.cities = cities self.city_cols = CITY_COLS self.city_rows = CITY_ROWS self.cities_per_grid = CITIES_PER_GRID self.intensity_colormap = ColorPalette.fromPreset('mmi') self.contour_colormap = ColorPalette.fromPreset('shaketopo') station_dict = container.getStationDict() self.stations = station_dict rupture_dict = container.getRuptureDict() info_dict = json.loads( container.getString('info.json'))['input']['event_information'] event_dict = { 'eventsourcecode': info_dict['event_id'], 'lat': float(info_dict['latitude']), 'lon': float(info_dict['longitude']), 'depth': float(info_dict['depth']), 'mag': float(info_dict['magnitude']) } origin = Origin(event_dict) if rupture_dict['features'][0]['geometry']['type'] == 'Point': rupture = PointRupture(origin) else: rupture = rupture_from_dict_and_origin(rupture_dict, origin) self.fault = rupture self.fig_width = FIG_WIDTH self.fig_height = FIG_HEIGHT self.logger = logger # clip all the vector data now so that map rendering will be fast t1 = time.time() self._clipBounds() t2 = time.time() self.logger.debug('%.1f seconds to clip vectors.' % (t2 - t1))
class MapMaker(object): """Create intensity raster map and PGV, PGA, and spectral contour maps. """ def __init__(self, container, topofile, layerdict, cities_file, logger): """Initialize MapMaker object. Args: container (ShakeMapOutputContainer): ShakeMapOutputContainer object containing model results. topofile (str): Path to file containing global topography grid. layerdict (dict): Dictionary containing fields: - coast: Global coastline shapefile. - ocean: Global ocean shapefile. - lake: Global lakes shapefile. - country: Global country boundaries shapefile. - state: Global state (or equivalent) boundaries shapefile. - roads: Global roads directory containing directories with regional shapefiles. cities_file (str): Path to geonames cities1000.txt file. logger (Logger): Python logging instance. Raises: KeyError: When any of layerdict keys are missing. """ req_keys = set(['coast', 'ocean', 'lake', 'country', 'state']) if len(set(layerdict.keys()).intersection(req_keys)) != len(req_keys): raise KeyError( 'layerdict input must have all keys from %s' % str(req_keys)) self.container = container self.topofile = topofile self.layerdict = layerdict cities = BasemapCities.loadFromGeoNames(cities_file) self.cities = cities self.city_cols = CITY_COLS self.city_rows = CITY_ROWS self.cities_per_grid = CITIES_PER_GRID self.intensity_colormap = ColorPalette.fromPreset('mmi') self.contour_colormap = ColorPalette.fromPreset('shaketopo') station_dict = container.getStationDict() self.stations = station_dict rupture_dict = container.getRuptureDict() info_dict = json.loads( container.getString('info.json'))['input']['event_information'] event_dict = { 'eventsourcecode': info_dict['event_id'], 'lat': float(info_dict['latitude']), 'lon': float(info_dict['longitude']), 'depth': float(info_dict['depth']), 'mag': float(info_dict['magnitude']) } origin = Origin(event_dict) if rupture_dict['features'][0]['geometry']['type'] == 'Point': rupture = PointRupture(origin) else: rupture = rupture_from_dict_and_origin(rupture_dict, origin) self.fault = rupture self.fig_width = FIG_WIDTH self.fig_height = FIG_HEIGHT self.logger = logger # clip all the vector data now so that map rendering will be fast t1 = time.time() self._clipBounds() t2 = time.time() self.logger.debug('%.1f seconds to clip vectors.' % (t2 - t1)) def _selectRoads(self, roads_folder, bbox): """Select road shapes from roads directory. Args: roads_folder (str): Path to folder containing global roads data. bbox (tuple): Tuple of map bounds (xmin,ymin,xmax,ymax). Returns: list: list of Shapely geometries. """ vshapes = [] xmin, ymin, xmax, ymax = bbox bboxpoly = sPolygon([(xmin, ymax), (xmax, ymax), (xmax, ymin), (xmin, ymin), (xmin, ymax)]) for root, dirs, files in os.walk(roads_folder): for fname in files: if fname.endswith('.shp'): filename = os.path.join(root, fname) with fiona.open(filename, 'r') as f: shapes = f.items(bbox=bbox) for shapeidx, shape in shapes: tshape = sShape(shape['geometry']) intshape = tshape.intersection(bboxpoly) vshapes.append(intshape) return vshapes def _clipBounds(self): """ Clip input vector data to bounds of map. """ # returns a list of GeoJSON-like mapping objects comp = self.container.getComponents('MMI')[0] imtdict = self.container.getIMTGrids('MMI', comp) geodict = imtdict['mean'].getGeoDict() xmin, xmax, ymin, ymax = (geodict.xmin, geodict.xmax, geodict.ymin, geodict.ymax) bbox = (xmin, ymin, xmax, ymax) bboxpoly = sPolygon([(xmin, ymax), (xmax, ymax), (xmax, ymin), (xmin, ymin), (xmin, ymax)]) self.vectors = {} for key, value in self.layerdict.items(): vshapes = [] f = fiona.open(value, 'r') shapes = f.items(bbox=bbox) for shapeidx, shape in shapes: tshape = sShape(shape['geometry']) try: intshape = tshape.intersection(bboxpoly) # except TopologicalError as te: except Exception as te: self.logger.warn('Failure to grab %s segment: "%s"' % (key, str(te))) continue vshapes.append(intshape) self.logger.debug('Filename is %s' % value) f.close() self.vectors[key] = vshapes def setCityGrid(self, nx=2, ny=2, cities_per_grid=10): """Define grid fused to limit the number of cities plotted on the map. Args: nx (int): Number of columns in grid. ny (int): Number of rows in grid. cities_per_grid (int): Maximum number of cities to plot in each grid cell. """ self.city_cols = nx self.city_rows = ny self.cities_per_grid = cities_per_grid def setFigureSize(self, figwidth, figheight): """Set the figure size in inches. Args: figwidth (float): Figure width in inches. figheight (float): Figure height in inches. """ self.fig_width = figwidth self.fig_height = figheight def setCityList(self, dataframe): """Set the city list to an input dataframe. Args: dataframe (DataFrame): Pandas DataFrame whose columns include: - name: Name of the city (required). - lat: Latitude of city (required). - lon: Longitude of city (required). - pop: Population of city (optional). - iscap: Boolean indicating capital status (optional). - placement: String indicating where city label should be placed relative to city coordinates, one of: E, W, N, S, NE, SE, SW, NW. (optional). - xoff: Longitude offset for label relative to city coordinates (optional). - yoff: Latitude offset for label relative to city coordinates (optional). """ self.cities = BasemapCities(dataframe) # may raise exception self.city_rows = None self.city_cols = None self.cities_per_grid = None def _setMap(self, gd): """Define the map extents, figure size, etc. Args: gd (GeoDict): MapIO GeoDict defining bounds/resolution of input ShakeMap. Returns: Basemap: Basemap instance, Mercator projection. """ clon = gd.xmin + (gd.xmax - gd.xmin) / 2.0 clat = gd.ymin + (gd.ymax - gd.ymin) / 2.0 f = plt.figure(figsize=(self.fig_width, self.fig_height)) ax = f.add_axes([0.1, 0.1, 0.8, 0.8]) m = Basemap(llcrnrlon=gd.xmin, llcrnrlat=gd.ymin, urcrnrlon=gd.xmax, urcrnrlat=gd.ymax, rsphere=(6378137.00, 6356752.3142), resolution=BASEMAP_RESOLUTION, projection='merc', lat_0=clat, lon_0=clon, lat_ts=clat, ax=ax, suppress_ticks=True) return m def _projectGrid(self, data, m, gd): """Project 2D array to map projection. Args: data (ndarray): 2D Numpy array to be projected. m (Basemap): Basemap instance. gd (GeoDict): MapIO GeoDict object. Returns: ndarray: Input array projected to map projection. """ # set up meshgrid to project topo and mmi data xmin = gd.xmin if gd.xmax < gd.xmin: xmin -= 360 lons = np.linspace(xmin, gd.xmax, gd.nx) # backwards so it plots right side up lats = np.linspace(gd.ymax, gd.ymin, gd.ny) llons1, llats1 = np.meshgrid(lons, lats) pdata = m.transform_scalar(np.flipud(data), lons, lats[::-1], gd.nx, gd.ny, returnxy=False, checkbounds=False, order=1, masked=False) return pdata def _getDraped(self, data, topodata): """Get array of data "draped" on topography. Args: data (ndarray): 2D Numpy array. topodata (ndarray): 2D Numpy array. Returns: ndarray: Numpy array of data draped on topography. """ maxvalue = self.intensity_colormap.vmax mmisc = data / maxvalue rgba_img = self.intensity_colormap.cmap(mmisc) rgb = np.squeeze(rgba_img[:, :, 0:3]) # use lightsource class to make our shaded topography ls = LightSource(azdeg=135, altdeg=45) # intensity = ls.hillshade(ptopo,fraction=0.25,vert_exag=1.0) ls1 = LightSource(azdeg=120, altdeg=45) ls2 = LightSource(azdeg=225, altdeg=45) intensity1 = ls1.hillshade( topodata, fraction=0.25, vert_exag=VERT_EXAG) intensity2 = ls2.hillshade( topodata, fraction=0.25, vert_exag=VERT_EXAG) intensity = intensity1 * 0.5 + intensity2 * 0.5 draped_hsv = ls.blend_hsv(rgb, np.expand_dims(intensity, 2)) return draped_hsv def _drawBoundaries(self, m): """Draw all country/state boundaries on the map. Args: m (Basemap): Basemap instance. """ allshapes = self.vectors['country'] + self.vectors['state'] for shape in allshapes: # shape is a geojson-like mapping thing try: if hasattr(shape, 'exterior'): blon, blat = zip(*shape.exterior.coords[:]) else: blon, blat = zip(*shape.coords[:]) bx, by = m(blon, blat) m.plot(bx, by, 'k', zorder=BORDER_ZORDER) except NotImplementedError: for tshape in shape: try: blon, blat = zip(*tshape.exterior.coords[:]) bx, by = m(blon, blat) m.plot(bx, by, 'k', zorder=BORDER_ZORDER) except NotImplementedError: continue def _drawRoads(self, m): """Draw all roads on the map. Args: m (Basemap): Basemap instance. """ allshapes = self.vectors['roads'] xmin = 9999999 ymin = xmin xmax = -99999999 ymax = xmax for shape in allshapes: # shape is a shapely geometry if isinstance(shape, (MultiLineString, GeometryCollection)): blon = [] blat = [] for mshape in shape: tlon, tlat = zip(*mshape.coords[:]) blon += tlon blat += tlat else: blon, blat = zip(*shape.coords[:]) if not len(blon): continue if min(blon) < xmin: xmin = min(blon) if min(blat) < ymin: ymin = min(blat) if max(blon) > xmax: xmax = max(blon) if max(blat) > ymax: ymax = max(blat) bx, by = m(blon, blat) m.plot(bx, by, '#808080', zorder=ROAD_ZORDER) def _drawLakes(self, m, gd): """Draw all lakes on the map. Args: m (Basemap): Basemap instance. """ lakes = self.vectors['lake'] for lake in lakes: ppatches = getProjectedPatches(lake, m, edgecolor='k') for ppatch in ppatches: m.ax.add_patch(ppatch) def _drawOceans(self, m, gd): """Draw all oceans on the map. Args: m (Basemap): Basemap instance. """ if len(self.vectors['ocean']): ocean = self.vectors['ocean'][0] # this is one shapely polygon ppatches = getProjectedPatches(ocean, m) for ppatch in ppatches: m.ax.add_patch(ppatch) def _drawMapScale(self, m, gd): """Draw a map scale in the lower left corner of the map. Args: m (Basemap): Basemap instance. gd (GeoDict): MapIO GeoDict instance. """ # where to set the center of the scale bar scalex = gd.xmin + (gd.xmax - gd.xmin) / 5.0 scaley = gd.ymin + (gd.ymax - gd.ymin) / 10.0 # how tall should scale bar be, in map units (km)? yoff = (0.01 * (m.ymax - m.ymin)) # where should scale apply (center of map) clon = (gd.xmin + gd.xmax) / 2.0 clat = (gd.ymin + gd.ymax) / 2.0 # figure out a scalebar length that is approximately 30% of total # width in km map_width = (m.xmax - m.xmin) / 1000 # km lengths = np.array([25, 50, 75, 100, 125, 150, 175, 200, 250]) lfracs = lengths / map_width length = lengths[np.abs(lfracs - 0.3).argmin()] m.drawmapscale(scalex, scaley, clon, clat, length, barstyle='fancy', yoffset=yoff, zorder=SCALE_ZORDER) def _drawCoastlines(self, m, gd): """Draw all coastlines on the map. Args: m (Basemap): Basemap instance. gd (GeoDict): MapIO GeoDict instance. """ coasts = self.vectors['coast'] for coast in coasts: # these are polygons? if isinstance(coast, sPolygon): clon, clat = zip(*coast.exterior.coords[:]) cx, cy = m(clon, clat) m.plot(cx, cy, 'k', zorder=BORDER_ZORDER) elif isinstance(coast, LineString): clon, clat = zip(*coast.coords[:]) cx, cy = m(clon, clat) m.plot(cx, cy, 'k', zorder=BORDER_ZORDER) else: for tshape in coast: clon, clat = zip(*tshape.coords[:]) cx, cy = m(clon, clat) m.plot(cx, cy, 'k', zorder=BORDER_ZORDER) def _drawGraticules(self, m, gd): """Draw meridian/parallels on the map. Args: m (Basemap): Basemap instance. gd (GeoDict): MapIO GeoDict instance. """ par = np.arange(np.ceil(gd.ymin), np.floor(gd.ymax) + 1, 1.0) mer = np.arange(np.ceil(gd.xmin), np.floor(gd.xmax) + 1, 1.0) merdict = m.drawmeridians(mer, labels=[0, 0, 0, 1], fontsize=10, linewidth=0.5, color='gray', zorder=GRATICULE_ZORDER) pardict = m.drawparallels(par, labels=[1, 0, 0, 0], fontsize=10, linewidth=0.5, color='gray', zorder=GRATICULE_ZORDER) # loop over meridian and parallel dicts, change/increase font, draw # ticks xticks = [] for merkey, mervalue in merdict.items(): merline, merlablist = mervalue merlabel = merlablist[0] merlabel.set_family('sans-serif') merlabel.set_fontsize(12.0) xticks.append(merline[0].get_xdata()[0]) yticks = [] for parkey, parvalue in pardict.items(): parline, parlablist = parvalue parlabel = parlablist[0] parlabel.set_family('sans-serif') parlabel.set_fontsize(12.0) yticks.append(parline[0].get_ydata()[0]) # plt.tick_params(axis='both',color='k',direction='in') plt.xticks(xticks, ()) plt.yticks(yticks, ()) m.ax.tick_params(direction='out') def _drawTitle(self, imt): """Draw the map title. Args: imt (str): IMT that is being drawn on the map ('MMI', 'PGV', 'PGA', 'SA(x.y)'). isContour (bool): If true, use input imt, otherwise use MMI. """ # Add a title origin = self.fault.getOrigin() hlon = origin.lon hlat = origin.lat edict = json.loads(self.container.getString( 'info.json'))['input']['event_information'] eloc = edict['event_description'] etime = datetime.strptime( edict['origin_time'], '%Y-%m-%d %H:%M:%S') timestr = etime.strftime('%b %d, %Y %H:%M:%S') mag = origin.mag if hlon < 0: lonstr = 'W%.2f' % np.abs(hlon) else: lonstr = 'E%.2f' % hlon if hlat < 0: latstr = 'S%.2f' % np.abs(hlat) else: latstr = 'N%.2f' % hlat dep = origin.depth eid = edict['event_id'] tpl = (timestr, mag, latstr, lonstr, dep, eid) fmt = ('USGS ShakeMap (%s): %s\n %s UTC M%.1f %s %s ' 'Depth: %.1fkm ID:%s') tstr = fmt % (imt, eloc, timestr, mag, latstr, lonstr, dep, eid) # plt.suptitle('USGS ShakeMap (%s): %s' % (layername, eloc), # fontsize=14, verticalalignment='bottom', y=0.95) # plt.title('%s UTC M%.1f %s %s Depth: %.1fkm ID:%s' % # tpl, fontsize=10, verticalalignment='bottom') # plt.rc('text', usetex=True) # matplotlib.rcParams['text.latex.preamble']=[r"\usepackage{amsmath}"] plt.title(tstr, fontsize=10, verticalalignment='bottom') # plt.title(r"\TeX\ is Number " # r"$\displaystyle\sum_{n=1}^\infty\frac{-e^{i\pi}}{2^n}$!", # fontsize=16, color='gray') def _drawStations(self, m, fill=False, imt='PGA'): """Draw station locations on the map. Args: m (Basemap): Basemap instance. fill (bool): Whether or not to fill symbols. imt (str): One of ('MMI', 'PGA', 'PGV', or 'SA(x.y') """ dimt = imt.lower() # get the locations and values of the MMI observations mmi_dict = {'lat': [], 'lon': [], 'mmi': []} inst_dict = {'lat': [], 'lon': [], dimt: []} # get the locations and values of the observed/instrumented # observations for feature in self.stations['features']: lon, lat = feature['geometry']['coordinates'] net = feature['properties']['network'].lower() if net in ['dyfi', 'mmi', 'intensity', 'ciim']: channel = feature['properties']['channels'][0] for amplitude in channel['amplitudes']: if amplitude['name'] != 'mmi': continue mmi_dict['mmi'].append(float(amplitude['value'])) mmi_dict['lat'].append(lat) mmi_dict['lon'].append(lon) else: channel = feature['properties']['channels'][0] for amplitude in channel['amplitudes']: if amplitude['name'] != dimt: continue inst_dict[dimt].append(float(amplitude['value'])) inst_dict['lat'].append(lat) inst_dict['lon'].append(lon) mmidf = pd.DataFrame(mmi_dict) instdf = pd.DataFrame(inst_dict) if not fill: # plot MMI as small circles mmilat = mmidf['lat'].as_matrix() mmilon = mmidf['lon'].as_matrix() m.plot(mmilon, mmilat, 'ko', latlon=True, fillstyle='none', markersize=4, zorder=STATIONS_ZORDER) # plot MMI as slightly larger triangles instlat = instdf['lat'].as_matrix() instlon = instdf['lon'].as_matrix() m.plot(instlon, instlat, 'k^', latlon=True, fillstyle='none', markersize=6, zorder=STATIONS_ZORDER) else: for idx, value in enumerate(mmidf['lat']): mlat = mmidf['lat'][idx] mlon = mmidf['lon'][idx] mmi = mmidf['mmi'][idx] mcolor = self.intensity_colormap.getDataColor(mmi) m.plot(mlon, mlat, 'o', latlon=True, markerfacecolor=mcolor, markeredgecolor='k', markersize=4, zorder=STATIONS_ZORDER) for idx, value in enumerate(instdf['lat']): mlat = instdf['lat'][idx] mlon = instdf['lon'][idx] # # TODO: Make the fill color correspond to the mmi # obtained from the IMT. # # dmmi = instdf[dimt][idx] # mcolor = self.intensity_colormap.getDataColor(dmmi) m.plot(mlon, mlat, '^', latlon=True, markerfacecolor='w', markeredgecolor='k', markersize=6, zorder=STATIONS_ZORDER) def _drawFault(self, m): """Draw fault rupture on the map. Args: m (Basemap): Basemap instance. """ lats = self.fault.lats lons = self.fault.lons x, y = m(lons, lats) m.plot(x, y, 'k', lw=2, zorder=FAULT_ZORDER) def drawIntensityMap(self, outfolder): """ Render the MMI data as intensity draped over topography, with oceans, coastlines, etc. Args: outfolder (str): Path to directory where output map should be saved. Returns: str: Path to output intensity map. """ t0 = time.time() # resample shakemap to topogrid # get the geodict for the topo file topodict = GMTGrid.getFileGeoDict(self.topofile)[0] # get the geodict for the ShakeMap comp = self.container.getComponents('MMI')[0] imtdict = self.container.getIMTGrids('MMI', comp) mmigrid = imtdict['mean'] smdict = mmigrid.getGeoDict() # get a geodict that is aligned with topo, but inside shakemap sampledict = topodict.getBoundsWithin(smdict) mmigrid = mmigrid.interpolateToGrid(sampledict) gd = mmigrid.getGeoDict() # establish the basemap object m = self._setMap(gd) # get topo layer and project it topogrid = GMTGrid.load( self.topofile, samplegeodict=sampledict, resample=False) topodata = topogrid.getData().copy() ptopo = self._projectGrid(topodata, m, gd) # get intensity layer and project it imtdata = mmigrid.getData().copy() pimt = self._projectGrid(imtdata, m, gd) # get the draped intensity data draped_hsv = self._getDraped(pimt, ptopo) # where will 10.0 come from # draw the draped intensity data m.imshow(draped_hsv, interpolation='none', zorder=IMG_ZORDER) # draw country/state boundaries self._drawBoundaries(m) # draw whatever road data is available # self.logger.debug('Drawing roads...') # self._drawRoads(m) # self.logger.debug('Done drawing roads...') # draw lakes self._drawLakes(m, gd) # draw oceans (pre-processed with islands taken out) t1 = time.time() self._drawOceans(m, gd) t2 = time.time() self.logger.debug('%.1f seconds to render oceans.' % (t2 - t1)) # draw coastlines self._drawCoastlines(m, gd) # draw meridians, parallels, labels, ticks self._drawGraticules(m, gd) # draw map scale self._drawMapScale(m, gd) # draw fault polygon, if present self._drawFault(m) # get the fault loaded # draw epicenter origin = self.fault.getOrigin() hlon = origin.lon hlat = origin.lat m.plot(hlon, hlat, 'k*', latlon=True, fillstyle='none', markersize=22, mew=1.2, zorder=EPICENTER_ZORDER) # draw cities # reduce the number of cities to those whose labels don't collide # set up cities if self.city_cols is not None: self.cities = self.cities.limitByBounds( (gd.xmin, gd.xmax, gd.ymin, gd.ymax)) self.cities = self.cities.limitByGrid( nx=self.city_cols, ny=self.city_rows, cities_per_grid=self.cities_per_grid) # self.logger.debug("Available fonts: ", self.cities._fontlist) if 'Times New Roman' in self.cities._fontlist: font = 'Times New Roman' else: font = 'DejaVu Sans' self.cities = self.cities.limitByMapCollision(m, fontname=font) self.cities.renderToMap(m.ax, zorder=CITIES_ZORDER) # draw title and supertitle self._drawTitle('MMI') # draw station and macroseismic locations self._drawStations(m) # need stationlist object # save plot to file plt.draw() outfile = os.path.join(outfolder, 'intensity.pdf') plt.savefig(outfile) tn = time.time() self.logger.debug('%.1f seconds to render entire map.' % (tn - t0)) return outfile def _getShaded(self, ptopo): """Get shaded topography. Args: ptopo (ndarray): Numpy array of projected topography data. Returns: ndarray: Numpy array of light-shaded topography. """ maxvalue = self.contour_colormap.vmax ls1 = LightSource(azdeg=120, altdeg=45) ls2 = LightSource(azdeg=225, altdeg=45) intensity1 = ls1.hillshade(ptopo, fraction=0.25, vert_exag=VERT_EXAG) intensity2 = ls2.hillshade(ptopo, fraction=0.25, vert_exag=VERT_EXAG) intensity = intensity1 * 0.5 + intensity2 * 0.5 ptoposc = ptopo / maxvalue rgba = self.contour_colormap.cmap(ptoposc) rgb = np.squeeze(rgba) draped_hsv = ls1.blend_hsv(rgb, np.expand_dims(intensity, 2)) return draped_hsv def round_to(self, n, precision): """Round number to nearest level desired precision. Example: round_to(22.1,10) => 20. Args: n (float): Input number to round. precision (int): Desired precision. Returns: int: Rounded value. """ correction = 0.5 if n >= 0 else -0.5 return int(n / precision + correction) * precision def getContourLevels(self, dmin, dmax, imt): """Get contour levels given min/max values and desired IMT. Args: dmin (float): Minimum value of data to contour. dmax (float): Maximum value of data to contour. imt (str): String IMT (one of PGV,PGA, etc.) Returns: ndarray: Numpy array of contour levels. """ # groupings taken from table on # https://en.wikipedia.org/wiki/Peak_ground_acceleration if imt == 'PGV': # table of minimum dmax and dinc levels dmax_dinc = OrderedDict([(1.1, 0.1), (3.4, 0.25), (8.1, 0.5), (16.0, 2.0), (31.0, 5.0), (60.0, 10.0), (116.0, 10.0), (200.0, 25.0)]) keys = np.array(list(dmax_dinc.keys())) didx = np.where(keys < dmax)[0].max() dinc = dmax_dinc[keys[didx]] newdmin = self.round_to(dmin, dinc) newdmax = self.round_to(dmax, dinc) else: dmax_dinc = OrderedDict([(0.0017 * 100, 0.1), (0.014 * 100, 0.1), (0.039 * 100, 0.5), (0.092 * 100, 1.0), (0.18 * 100, 2.5), (0.34 * 100, 5.0), (0.65 * 100, 10.0), (1.24 * 100, 15.0), (3.0 * 100, 37.5)]) keys = np.array(list(dmax_dinc.keys())) didx = np.where(keys < dmax)[0].max() dinc = dmax_dinc[keys[didx]] newdmin = self.round_to(dmin, dinc) newdmax = self.round_to(dmax, dinc) levels = np.arange(newdmin, newdmax + dinc, dinc) return levels def drawContourMap(self, imt, outfolder, cmin=None, cmax=None): """ Render IMT data as contours over topography, with oceans, coastlines, etc. Args: outfolder (str): Path to directory where output map should be saved. Returns: str: Path to output IMT map. """ if self.contour_colormap is None: raise Exception('MapMaker.setGMTColormap() has not been called.') t0 = time.time() # resample shakemap to topogrid # get the geodict for the topo file topodict = GMTGrid.getFileGeoDict(self.topofile)[0] # get the geodict for the ShakeMap comp = self.container.getComponents(imt)[0] imtdict = self.container.getIMTGrids(imt, comp) imtgrid = imtdict['mean'] smdict = imtgrid.getGeoDict() # get a geodict that is aligned with topo, but inside shakemap sampledict = topodict.getBoundsWithin(smdict) imtgrid = imtgrid.interpolateToGrid(sampledict) gd = imtgrid.getGeoDict() # establish the basemap object m = self._setMap(gd) # get topo layer and project it topogrid = GMTGrid.load( self.topofile, samplegeodict=sampledict, resample=False) topodata = topogrid.getData().copy() ptopo = self._projectGrid(topodata, m, gd) # get contour layer and project it1 imtdata = imtgrid.getData().copy() # convert units if necessary if imt == 'MMI': pass elif imt == 'PGV': imtdata = np.exp(imtdata) else: imtdata = np.exp(imtdata) * 100 pimt = self._projectGrid(imtdata, m, gd) # get the draped intensity data hillshade = self._getShaded(ptopo) # draw the draped intensity data m.imshow(hillshade, interpolation='none', zorder=IMG_ZORDER) # draw the contours of imt data xmin = gd.xmin if gd.xmax < gd.xmin: xmin -= 360 lons = np.linspace(xmin, gd.xmax, gd.nx) # backwards so it plots right side up lats = np.linspace(gd.ymax, gd.ymin, gd.ny) x, y = m(*np.meshgrid(lons, lats)) pimt = gaussian_filter(pimt, 5.0) dmin = pimt.min() dmax = pimt.max() levels = self.getContourLevels(dmin, dmax, imt) cs = m.contour(x, y, np.flipud(pimt), colors='w', cmap=None, levels=levels, zorder=CONTOUR_ZORDER) clabels = plt.clabel(cs, colors='k', fmt='%.1f', fontsize=8.0, zorder=CONTOUR_ZORDER) for cl in clabels: bbox = dict(boxstyle="round", facecolor='white', edgecolor='w') cl.set_bbox(bbox) cl.set_zorder(CONTOUR_ZORDER) # draw country/state boundaries self._drawBoundaries(m) # draw lakes self._drawLakes(m, gd) # draw oceans (pre-processed with islands taken out) t1 = time.time() self._drawOceans(m, gd) t2 = time.time() self.logger.debug('%.1f seconds to render oceans.' % (t2 - t1)) # draw coastlines self._drawCoastlines(m, gd) # draw meridians, parallels, labels, ticks self._drawGraticules(m, gd) # draw filled symbols for MMI and instrumented measures self._drawStations(m, fill=True, imt=imt) # draw map scale self._drawMapScale(m, gd) # draw fault polygon, if present self._drawFault(m) # get the fault loaded # draw epicenter origin = self.fault.getOrigin() hlon = origin.lon hlat = origin.lat m.plot(hlon, hlat, 'k*', latlon=True, fillstyle='none', markersize=22, mew=1.2, zorder=EPICENTER_ZORDER) # draw cities # reduce the number of cities to those whose labels don't collide # set up cities if self.city_cols is not None: self.cities = self.cities.limitByBounds( (gd.xmin, gd.xmax, gd.ymin, gd.ymax)) self.cities = self.cities.limitByGrid( nx=self.city_cols, ny=self.city_rows, cities_per_grid=self.cities_per_grid) if 'Times New Roman' in self.cities._fontlist: font = 'Times New Roman' else: font = 'DejaVu Sans' self.cities = self.cities.limitByMapCollision(m, fontname=font) self.cities.renderToMap(m.ax, zorder=CITIES_ZORDER) # draw title and supertitle self._drawTitle(imt) # save plot to file fileimt = oq_to_file(imt) plt.draw() outfile = os.path.join(outfolder, 'contour_%s.pdf' % (fileimt)) plt.savefig(outfile) tn = time.time() self.logger.debug('%.1f seconds to render entire map.' % (tn - t0)) return outfile
def _test_intensity(): datadir = os.path.abspath( os.path.join(homedir, '..', 'data', 'eventdata', 'northridge')) shakefile = os.path.join(datadir, 'northridge_grid.xml') topofile = os.path.join(datadir, 'northridge_topo.grd') faultfile = os.path.join(datadir, 'northridge_fault.txt') cityfile = os.path.join(datadir, 'northridge_cities.txt') coastfile = os.path.join(datadir, 'northridge_coastline.json') countryfile = os.path.join(datadir, 'northridge_countries.json') statefile = os.path.join(datadir, 'northridge_states.json') lakefile = os.path.join(datadir, 'northridge_lakes.json') oceanfile = os.path.join(datadir, 'northridge_ocean.json') stationfile = os.path.join(datadir, 'northridge_stations.db') roadfile = os.path.join(datadir, 'northridge_roads.json') tancptfile = os.path.join(shakedir, 'shakemap', 'mapping', 'tan.cpt') shakecptfile = os.path.join(shakedir, 'shakemap', 'mapping', 'shakecpt.cpt') layerdict = { 'coast': coastfile, 'ocean': oceanfile, 'lake': lakefile, 'country': countryfile, 'roads': roadfile, 'state': statefile } tancolormap = GMTColorMap.loadFromCPT(tancptfile) shakecolormap = GMTColorMap.loadFromCPT(shakecptfile) cities = BasemapCities.loadFromCSV(cityfile) shakemap = ShakeGrid.load(shakefile, adjust='res') stations = StationList(stationfile) fault = Fault.readFaultFile(faultfile) edict = shakemap.getEventDict() eventdict = { 'lat': edict['lat'], 'lon': edict['lon'], 'depth': edict['depth'], 'mag': edict['magnitude'], 'time': edict['event_timestamp'] } source = Source(eventdict, fault) maker = MapMaker(shakemap, topofile, stations, fault, layerdict, source, cities) # draw intensity map outfolder = os.path.expanduser('~') maker.setIntensityLayer('mmi') maker.setIntensityGMTColorMap(shakecolormap) intensity_map = maker.drawIntensityMap(outfolder) print('Intensity map saved as: %s' % intensity_map) # draw contour maps maker.setContourGMTColorMap(tancolormap) # Draw pgv contours maker.setContourLayer('pgv') contour_pgv_map = maker.drawContourMap(outfolder) print('PGV contour map saved as: %s' % contour_pgv_map) # Draw pga contours maker.setContourLayer('pga') contour_pga_map = maker.drawContourMap(outfolder) print('PGA contour map saved as: %s' % contour_pga_map) # Draw psa0.3 contours maker.setContourLayer('psa03') contour_psa03_map = maker.drawContourMap(outfolder) print('PSA0.3 contour map saved as: %s' % contour_psa03_map) # Draw psa1.0 contours maker.setContourLayer('psa10') contour_psa10_map = maker.drawContourMap(outfolder) print('PSA1.0 contour map saved as: %s' % contour_psa10_map) # Draw psa3.0 contours maker.setContourLayer('psa30') contour_psa30_map = maker.drawContourMap(outfolder) print('PSA3.0 contour map saved as: %s' % contour_psa30_map)