def test_presets():
    palettes = ColorPalette.getPresets()
    palettes.sort()
    assert palettes == ['mmi', 'pop', 'shaketopo']

    pop = ColorPalette.fromPreset('pop')
    values = [(0, 1.0), (5, 0.749), (50, 0.623), (100, 0.498), (500, 0.372),
              (1000, 0.247), (5000, 0.1215), (10000, 0.0)]
    for value in values:
        zvalue = value[0]
        expected_red = value[1]
        red = pop.getDataColor(zvalue)[0]
        np.testing.assert_almost_equal(expected_red, red, decimal=2)
    assert pop.vmin == 0
    assert pop.vmax == 50000

    mmi = ColorPalette.fromPreset('mmi')
    values = [(0.5, 1.0), (1.5, 0.874)]
    for value in values:
        zvalue = value[0]
        expected_red = value[1]
        red = mmi.getDataColor(zvalue)[0]
        np.testing.assert_almost_equal(expected_red, red, decimal=2)
    assert mmi.vmin == 0
    assert mmi.vmax == 10

    topo = ColorPalette.fromPreset('shaketopo')
    assert topo.vmin == -100
    assert topo.vmax == 9200
Example #2
0
def make_overlay(adict):
    """
    Make a transparent PNG of intensity and a world file

    Args:
        adict (dict): The usual dictionary for the mapping functions.

    Returns:
        nothing: Nothing.
    """
    mmidict = adict['imtdict']
    mmi_array = mmidict['mean']
    geodict = GeoDict(mmidict['mean_metadata'])
    palette = ColorPalette.fromPreset('mmi')
    mmi_rgb = palette.getDataColor(mmi_array, color_format='array')
    img = Image.fromarray(mmi_rgb)
    pngfile = os.path.join(adict['datadir'], 'intensity_overlay.png')
    img.save(pngfile, "PNG")

    # write out a world file
    # https://en.wikipedia.org/wiki/World_file
    worldfile = os.path.join(adict['datadir'], 'intensity_overlay.pngw')
    with open(worldfile, 'wt') as f:
        f.write('%.4f\n' % geodict.dx)
        f.write('0.0\n')
        f.write('0.0\n')
        f.write('-%.4f\n' % geodict.dy)
        f.write('%.4f\n' % geodict.xmin)
        f.write('%.4f\n' % geodict.ymax)
    return
def test_cpt():
    rm = 100  # number of lines to remove on black end of magma_r
    # how much at the zero end should be *just* white before transitioning to
    # meet colors
    ad = 50
    magma_cpt = cm.get_cmap('magma_r', 512)  # start with magma_r
    white_bit = np.array([255 / 256, 250 / 256, 250 / 256,
                          1])  # create array of white
    slip_cpt = magma_cpt(np.linspace(0, 1, 512))  # initialize slip_cpt
    # move beginning up to remove black end
    slip_cpt[rm:, :] = slip_cpt[0:-rm, :]
    # gradient from white to beginning of new magma
    r_s = np.linspace(white_bit[0], slip_cpt[rm][0], rm - ad)
    g_s = np.linspace(white_bit[1], slip_cpt[rm][1], rm - ad)
    b_s = np.linspace(white_bit[2], slip_cpt[rm][2], rm - ad)
    slip_cpt[ad:rm, :][:, 0] = r_s
    slip_cpt[ad:rm, :][:, 1] = g_s
    slip_cpt[ad:rm, :][:, 2] = b_s
    slip_cpt[:ad, :] = white_bit
    slipmap = ListedColormap(slip_cpt)
    z0 = np.arange(0, 300, 1)
    z1 = np.arange(1, 301, 1)
    ncolors = 64
    resolution = (z1.max() - z0.min()) / ncolors
    name = 'test'
    cpt = ColorPalette.fromColorMap(name,
                                    z0,
                                    z1,
                                    slipmap,
                                    resolution=resolution)
    try:
        tdir = tempfile.mkdtemp()
        tfile = os.path.join(tdir, 'test.cpt')
        cpt.write(tfile)
        cpt2 = ColorPalette.fromFile(tfile)
        np.testing.assert_almost_equal(
            cpt.getDataColor(150)[0],
            cpt2.getDataColor(150)[0])
    except:
        pass
    finally:
        if os.path.isdir(tdir):
            shutil.rmtree(tdir)
def test_colormap():
    viridis = plt.get_cmap('viridis')
    cmap = ColorPalette.fromColorMap('viridis', np.arange(0, 10),
                                     np.arange(1, 11), viridis)
    zero_value = np.array(
        [0.26666666666666666, 0.00392156862745098, 0.32941176470588235, 1.0])
    ten_value = np.array(
        [0.9921568627450981, 0.9058823529411765, 0.1450980392156863, 1.0])
    np.testing.assert_almost_equal(cmap.getDataColor(0), zero_value)
    np.testing.assert_almost_equal(cmap.getDataColor(10), ten_value)

    viridis = plt.get_cmap('viridis')
    cmap = ColorPalette.fromColorMap('viridis',
                                     np.arange(-4, 5),
                                     np.arange(-3, 6),
                                     viridis,
                                     is_log=True)
    dcolor = cmap.getDataColor(np.exp(-4.0))
    tcolor = np.array(
        (0.26666666666666666, 0.00392156862745098, 0.32941176470588235, 1.0))
    np.testing.assert_almost_equal(dcolor, tcolor)
Example #5
0
def create_line_styles():
    """Create line styles for contour KML.

    Args:
    """
    line_styles = {}
    cpalette = ColorPalette.fromPreset('mmi')
    for mmi in np.arange(0, 11, 0.5):
        pid = '%.1f' % mmi
        rgb = cpalette.getDataColor(mmi, color_format='hex')
        line_style = skml.LineStyle(color=flip_rgb(rgb), width=2.0)
        style = skml.Style(linestyle=line_style)
        line_styles[pid] = style
    return line_styles
def test_file():
    try:
        tdir = tempfile.mkdtemp()
        tfile = os.path.join(tdir, 'test.cpt')
        f = open(tfile, 'wt')
        f.write(TEST_FILE)
        f.close()
        cp = ColorPalette.fromFile(tfile)
        assert cp._cdict == TEST_DICT
    except:
        pass
    finally:
        if os.path.isdir(tdir):
            shutil.rmtree(tdir)
Example #7
0
def create_overlay_image(container, filename):
    """Create a semi-transparent PNG image of intensity.

    Args:
        container (ShakeMapOutputContainer): Results of model.conf.
        filename (str): Path to desired output PNG file.
    Returns:
        GeoDict: GeoDict object for the intensity grid.
    """
    # extract the intensity data from the container
    comp = container.getComponents('MMI')
    if len(comp) == 0:
        return None
    comp = comp[0]
    imtdict = container.getIMTGrids('MMI', comp)
    mmigrid = imtdict['mean']
    gd = GeoDict(imtdict['mean_metadata'])
    imtdata = mmigrid.copy()
    rows, cols = imtdata.shape

    # get the intensity colormap
    palette = ColorPalette.fromPreset('mmi')

    # map intensity values into
    # RGBA array
    rgba = palette.getDataColor(imtdata, color_format='array')

    # set the alpha value to 255 wherever we have MMI 0
    rgba[imtdata <= 1.5] = 0

    if 'CALLED_FROM_PYTEST' not in os.environ:
        # mask off the areas covered by ocean
        oceans = shpreader.natural_earth(category='physical',
                                         name='ocean',
                                         resolution='10m')
        bbox = (gd.xmin, gd.ymin, gd.xmax, gd.ymax)
        with fiona.open(oceans) as c:
            tshapes = list(c.items(bbox=bbox))
            shapes = []
            for tshp in tshapes:
                shapes.append(shape(tshp[1]['geometry']))
            if len(shapes):
                oceangrid = Grid2D.rasterizeFromGeometry(shapes, gd,
                                                         fillValue=0.0)
                rgba[oceangrid.getData() == 1] = 0

    # save rgba image as png
    img = Image.fromarray(rgba)
    img.save(filename)
    return gd
Example #8
0
def create_stations(container, datadir, document):
    """Create a KMZ file containing station KML and necessary icons files.

    Args:
        container (ShakeMapOutputContainer): Results of model.conf.
        datadir (str): Path to data directory where output KMZ will be written.
        document (Element): LXML KML Document element.
    Returns:
        str: Path to output KMZ file.
    """
    create_styles(document)

    # get a color palette object to convert intensity values to
    # html colors
    cpalette = ColorPalette.fromPreset('mmi')

    # get the station data from the container
    station_dict = container.getStationDict()

    # Group the MMI and instrumented stations separately
    mmi_folder = etree.SubElement(document, 'Folder')
    mmi_name = etree.SubElement(mmi_folder, 'name')
    mmi_name.text = 'Macroseismic Stations'
    mmi_vis = etree.SubElement(mmi_folder, 'visibility')
    mmi_vis.text = '0'

    ins_folder = etree.SubElement(document, 'Folder')
    ins_name = etree.SubElement(ins_folder, 'name')
    ins_name.text = 'Instrumented Stations'
    ins_vis = etree.SubElement(ins_folder, 'visibility')
    ins_vis.text = '0'
    for station in station_dict['features']:
        if station['properties']['station_type'] == 'seismic':
            make_placemark(ins_folder, station, cpalette)
        else:
            make_placemark(mmi_folder, station, cpalette)

    # we need to find the triangle and circle icons and copy them to
    # the output directory
    this_dir, _ = os.path.split(__file__)
    data_path = os.path.join(this_dir, '..', 'data', 'mapping')
    triangle_file = os.path.join(data_path, TRIANGLE)
    circle_file = os.path.join(data_path, CIRCLE)
    tridest = os.path.join(datadir, TRIANGLE)
    cirdest = os.path.join(datadir, CIRCLE)
    shutil.copyfile(triangle_file, tridest)
    shutil.copyfile(circle_file, cirdest)

    return (tridest, cirdest)
Example #9
0
def create_stations(container, datadir, document):
    """Create a KMZ file containing station KML and necessary icons files.

    Args:
        container (ShakeMapOutputContainer): Results of model.conf.
        datadir (str): Path to data directory where output KMZ will be written.
        document (Element): LXML KML Document element.
    Returns:
        str: Path to output KMZ file.
    """

    # get a color palette object to convert intensity values to
    # html colors
    cpalette = ColorPalette.fromPreset('mmi')

    # get the station data from the container
    station_dict = container.getStationDict()

    # Group the MMI and instrumented stations separately
    mmi_folder = document.newfolder(name="Macroseismic Stations",
                                    visibility=0)
    ins_folder = document.newfolder(name="Instrumented Stations",
                                    visibility=0)

    for station in station_dict['features']:
        intensity = get_intensity(station)
        rgb = cpalette.getDataColor(intensity, color_format='hex')
        color = flip_rgb(rgb)
        if station['properties']['station_type'] == 'seismic':
            style_map = create_styles(document, TRIANGLE, 0.6, 0.8, color)
            make_placemark(ins_folder, station, cpalette, style_map)
        else:
            style_map = create_styles(document, CIRCLE, 0.4, 0.6, color)
            make_placemark(mmi_folder, station, cpalette, style_map)

    # we need to find the triangle and circle icons and copy them to
    # the output directory
    this_dir, _ = os.path.split(__file__)
    data_path = os.path.join(this_dir, '..', 'data', 'mapping')
    triangle_file = os.path.join(data_path, TRIANGLE)
    circle_file = os.path.join(data_path, CIRCLE)
    tridest = os.path.join(datadir, TRIANGLE)
    cirdest = os.path.join(datadir, CIRCLE)
    shutil.copyfile(triangle_file, tridest)
    shutil.copyfile(circle_file, cirdest)

    return (tridest, cirdest)
Example #10
0
def make_pin_thumbnail(adict):
    """Make the artsy-thumbnail for the pin on the USGS webpages.
    """
    imtdict = adict['imtdict']
    grid = imtdict['mean']
    metadata = imtdict['mean_metadata']
    num_pixels = 300
    randx = np.random.rand(num_pixels)
    randy = np.random.rand(num_pixels)
    rx = (randx * metadata['nx']).astype(np.int)
    ry = (randy * metadata['ny']).astype(np.int)
    rvals = np.arange(num_pixels)

    x_grid = np.arange(400)
    y_grid = np.arange(400)

    mx_grid, my_grid = np.meshgrid(x_grid, y_grid)

    grid = griddata(np.hstack(
        [randx.reshape((-1, 1)) * 400,
         randy.reshape((-1, 1)) * 400]),
                    grid[ry, rx], (mx_grid, my_grid),
                    method='nearest')
    grid = (grid * 10 + 0.5).astype(np.int).astype(np.float) / 10.0

    rgrid = griddata(np.hstack(
        [randx.reshape((-1, 1)) * 400,
         randy.reshape((-1, 1)) * 400]),
                     rvals, (mx_grid, my_grid),
                     method='nearest')
    irgrid = rgrid.astype(np.int32)
    mypols = [p[0]['coordinates'] for p in rasterio.features.shapes(irgrid)]

    mmimap = ColorPalette.fromPreset('mmi')
    plt.figure(figsize=(2.75, 2.75), dpi=96, frameon=False)
    plt.axis('off')
    plt.tight_layout()
    plt.imshow(grid, cmap=mmimap.cmap, vmin=1.5, vmax=9.5)
    for pol in mypols:
        mycoords = list(zip(*pol[0]))
        plt.plot(mycoords[0], mycoords[1], color='#cccccc', linewidth=0.2)
    plt.savefig(os.path.join(adict['datadir'], "pin-thumbnail.png"),
                dpi=96,
                bbox_inches=matplotlib.transforms.Bbox([[0.47, 0.39],
                                                        [2.50, 2.50]]),
                pad_inches=0)
def test_simplemap():
    z0 = [0, 1, 2]
    z1 = [1, 2, 3]
    rgb0 = [(0, 0, 0), (85, 85, 85), (170, 170, 170)]
    rgb1 = [(85, 85, 85), (170, 170, 170), (255, 255, 255)]
    nan_color = (0, 0, 0, 0)
    cp = ColorPalette('test', z0, z1, rgb0, rgb1, nan_color=nan_color)
    assert cp.getDataColor(0.5) == (0.16470588235294117, 0.16470588235294117,
                                    0.16470588235294117, 1.0)
    cp.vmin = -1.0
    cp.vmax = 4.0
    assert cp.getDataColor(0.5) == (0.29803921568627451, 0.29803921568627451,
                                    0.29803921568627451, 1.0)
    assert cp.getDataColor(0.5, '255') == (76, 76, 76, 255)
    assert cp.getDataColor(0.5, 'hex') == ('#4C4C4C')
    assert cp._cdict == TEST_DICT
Example #12
0
def create_overlay_image(container, oceanfile, filename):
    """Create a semi-transparent PNG image of intensity.

    Args:
        container (ShakeMapOutputContainer): Results of model.conf.
        oceanfile (str): Path to shapefile containing ocean polygons.
        filename (str): Path to desired output PNG file.
    Returns:
        GeoDict: GeoDict object for the intensity grid.
    """
    # extract the intensity data from the container
    comp = container.getComponents('MMI')[0]
    imtdict = container.getIMTGrids('MMI', comp)
    mmigrid = imtdict['mean']
    gd = mmigrid.getGeoDict()
    imtdata = mmigrid.getData().copy()
    rows, cols = imtdata.shape

    # get the intensity colormap
    palette = ColorPalette.fromPreset('mmi')

    # map intensity values into
    # RGBA array
    rgba = palette.getDataColor(imtdata, color_format='array')

    # set the alpha value to 255 wherever we have MMI 0
    rgba[imtdata <= 1.5] = 0

    # mask off the areas covered by ocean
    bbox = (gd.xmin, gd.ymin, gd.xmax, gd.ymax)
    with fiona.open(oceanfile) as c:
        tshapes = list(c.items(bbox=bbox))
        shapes = []
        for tshp in tshapes:
            shapes.append(shape(tshp[1]['geometry']))
        if len(shapes):
            oceangrid = Grid2D.rasterizeFromGeometry(shapes, gd, fillValue=0.0)
            rgba[oceangrid.getData() == 1] = 0

    # save rgba image as png
    img = Image.fromarray(rgba)
    img.save(filename)
    return gd
Example #13
0
def _create_palette(imtype, levels):
    """Create a ColorPalette object from given levels and IMT type.

    Args:
        imtype (str): One of 'PGV','PGA','SA(0.3)',etc.
        levels (sequence): Sequence of contour levels.
    Returns:
        ColorPalette: ColorPalette using range of input data and IMT_CMAP.
    """
    # this method assumes that levels are in logspace
    if len(levels) > 1:
        if len(levels) % 2:
            levels.append(levels[-1])
        nsteps = 256
        z0 = np.linspace(np.log(levels[0]), np.log(levels[-2]), nsteps)
        z1 = np.linspace(np.log(levels[1]), np.log(levels[-1]), nsteps)
    else:
        z0 = np.array([levels[0], levels[0]*10])
        z1 = np.array([levels[0], levels[0]*10])
    cmap = plt.get_cmap(IMT_CMAP)
    palette = ColorPalette.fromColorMap(imtype, z0, z1, cmap, is_log=True)
    return palette
Example #14
0
def create_line_styles(document):
    """Create line styles for contour KML.

    Args:
        document (Element): LXML KML Document element.
    """
    gxns = 'http://www.google.com/kml/ext/2.2'
    nsmap = {'gx': gxns}
    cpalette = ColorPalette.fromPreset('mmi')
    for mmi in np.arange(0, 11, 0.5):
        pid = 'style_mi_%.1f' % mmi
        style = etree.SubElement(document, 'Style', id=pid)
        linestyle = etree.SubElement(style, 'LineStyle')
        color = etree.SubElement(linestyle, 'color')
        rgb = cpalette.getDataColor(mmi, color_format='hex')
        color.text = flip_rgb(rgb)
        width = etree.SubElement(linestyle, 'width')
        width.text = '2.0'
        # TODO: this doesn't work!
        vis = etree.SubElement(linestyle,
                               '{%s}labelVisibility' % gxns,
                               nsmap=nsmap)
        vis.text = '1'
Example #15
0
def contour(container, imtype, component, filter_size):
    """
    Generate contours of a specific IMT and return as a Shapely
    MultiLineString object.

    Args:
        container (ShakeMapOutputContainer): ShakeMapOutputContainer
            with ShakeMap output data.
        imtype (str): String containing the name of an Intensity
            Measure Type found in container.
        component (str): Intensity Measure component found in container.
        filter_size (int): Integer filter (see
            https://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.ndimage.filters.median_filter.html)
    Returns:
        list: List of dictionaries containing two fields

                - geometry: GeoJSON-like representation of one of the objects
                  in https://toblerity.org/fiona/manual.html#geometry-types
                - properties: Dictionary of properties describing that
                  feature.

    Raises:
        NotImplementedError -- if the user attempts to contour a data file
            with sets of points rather than grids.
    """  # noqa
    intensity_colormap = ColorPalette.fromPreset('mmi')
    imtdict = container.getIMTGrids(imtype, component)
    gridobj = imtdict['mean']
    grid = gridobj.getData()
    metadata = gridobj.getGeoDict().asDict()
    if imtype == 'MMI':
        sgrid = grid
        units = 'mmi'
    elif imtype == 'PGV':
        sgrid = np.exp(grid)
        units = 'cms'
    else:
        sgrid = np.exp(grid) * 100.0
        units = 'pctg'
    if filter_size > 0:
        fgrid = median_filter(sgrid, size=filter_size)
    else:
        fgrid = sgrid

    interval_type = 'log'
    if imtype == 'MMI':
        interval_type = 'linear'
    intervals = getContourLevels(np.min(fgrid),
                                 np.max(fgrid),
                                 itype=interval_type)

    lonstart = metadata['xmin']
    latstart = metadata['ymin']
    lonspan = np.abs(metadata['xmax'] - lonstart)
    latspan = np.abs(metadata['ymax'] - latstart)
    nlon = metadata['nx']
    nlat = metadata['ny']

    line_strings = []  # dictionary of MultiLineStrings and props

    for cval in intervals:
        contours = measure.find_contours(fgrid, cval)
        #
        # Convert coords to geographic coordinates; the coordinates
        # are returned in row, column order (i.e., (y, x))
        #
        new_contours = []
        plot_contours = []
        for ic, coords in enumerate(contours):  # coords is a line segment
            if len(coords) <= 20:  # skipping little contour islands?
                continue

            mylons = coords[:, 1] * lonspan / nlon + lonstart
            mylats = (nlat - coords[:, 0]) * latspan / nlat + latstart
            contours[ic][:, 0] = mylons[:]
            contours[ic][:, 1] = mylats[:]
            plot_contours.append(contours[ic])
            new_contours.append(contours[ic].tolist())

        if len(new_contours):
            mls = MultiLineString(new_contours)
            props = {'value': cval, 'units': units}
            if imtype == 'MMI':
                color_array = np.array(intensity_colormap.getDataColor(cval))
                color_rgb = np.array(color_array[0:3] * 255,
                                     dtype=int).tolist()
                props['color'] = '#%02x%02x%02x' % tuple(color_rgb)
                if (cval * 2) % 2 == 1:
                    props['weight'] = 4
                else:
                    props['weight'] = 2
            line_strings.append({
                'geometry': mapping(mls),
                'properties': props
            })
    return line_strings
Example #16
0
import matplotlib.cm as cm
import matplotlib.colors as colors
import os

# third party imports
from impactutils.colors.cpalette import ColorPalette
import numpy as np
from openquake.hazardlib.geo.geodetic import point_at
from openquake.hazardlib.geo.utils import OrthographicProjection

# local imports
from fault.io.timeseries import read_from_directory
from fault.io.fsp import read_from_file

homedir = os.path.dirname(os.path.abspath(__file__))
COLORS = ColorPalette.fromFile(os.path.join(homedir, 'fault2.cpt'))


class Fault(object):
    """Class for analyzing a fault and associated information."""
    def __init__(self):
        self._event = None
        self._segments = None
        self._timeseries_dict = None

    def autocorrelateSums(self, rows, columns):
        """Return slips summed along each axis and autocorrelated.

        Args:
            rows (nd.array): Array of slips summed along the rows.
            columns (nd.array): Array of slips summed along the columns.
Example #17
0
def contour(imtdict, imtype, filter_size, gmice):
    """
    Generate contours of a specific IMT and return as a Shapely
    MultiLineString object.

    Args:
        container (ShakeMapOutputContainer): ShakeMapOutputContainer
            with ShakeMap output data.
        imtype (str): String containing the name of an Intensity
            Measure Type found in container.
        filter_size (int): Integer filter (see
            https://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.ndimage.filters.median_filter.html)
    Returns:
        list: List of dictionaries containing two fields

                - geometry: GeoJSON-like representation of one of the objects
                  in https://toblerity.org/fiona/manual.html#geometry-types
                - properties: Dictionary of properties describing that
                  feature.

    Raises:
        NotImplementedError -- if the user attempts to contour a data file
            with sets of points rather than grids.
    """  # noqa
    oqimt = imt.from_string(imtype)

    intensity_colormap = ColorPalette.fromPreset('mmi')
    grid = imtdict['mean']
    metadata = imtdict['mean_metadata']
    if imtype == 'MMI':
        sgrid = grid
        units = 'mmi'
    elif imtype == 'PGV':
        sgrid = np.exp(grid)
        units = 'cms'
    else:
        sgrid = np.exp(grid) * 100.0
        units = 'pctg'
    if filter_size > 0:
        fgrid = median_filter(sgrid, size=int(filter_size))
    else:
        fgrid = sgrid

    interval_type = 'log'
    if imtype == 'MMI':
        interval_type = 'linear'

    grid_min = np.nanmin(fgrid)
    grid_max = np.nanmax(fgrid)
    if grid_max - grid_min:
        intervals = getContourLevels(grid_min, grid_max, itype=interval_type)
    else:
        intervals = np.array([])

    lonstart = metadata['xmin']
    latstart = metadata['ymin']

    lonend = metadata['xmax']
    if lonend < lonstart:
        lonstart -= 360

    lonspan = np.abs(lonend - lonstart)
    latspan = np.abs(metadata['ymax'] - latstart)
    nlon = metadata['nx']
    nlat = metadata['ny']

    line_strings = []  # dictionary of MultiLineStrings and props

    for cval in intervals:
        contours = measure.find_contours(fgrid, cval)
        #
        # Convert coords to geographic coordinates; the coordinates
        # are returned in row, column order (i.e., (y, x))
        #
        new_contours = []
        plot_contours = []
        for ic, coords in enumerate(contours):  # coords is a line segment
            #
            # This greatly reduces the number of points in the contours
            # without changing their shape too much
            #
            coords = measure.approximate_polygon(coords, filter_size / 20)

            mylons = np.around(coords[:, 1] * lonspan / nlon + lonstart,
                               decimals=6)
            mylats = np.around(
                (nlat - coords[:, 0]) * latspan / nlat + latstart, decimals=6)

            contours[ic] = np.hstack((mylons[:].reshape(
                (-1, 1)), mylats[:].reshape((-1, 1))))
            plot_contours.append(contours[ic])
            new_contours.append(contours[ic].tolist())

        if len(new_contours):
            mls = MultiLineString(new_contours)
            props = {'value': cval, 'units': units}
            if imtype == 'MMI':
                pass
            elif imtype == 'PGV':
                lcval = np.log(cval)
            else:
                lcval = np.log(cval / 100)
            if gmice:
                mmival = gmice.getMIfromGM(np.array([lcval]), oqimt)[0][0]
            elif imtype == 'MMI':
                mmival = cval
            else:
                mmival = 1
            color_array = np.array(intensity_colormap.getDataColor(mmival))
            color_rgb = np.array(color_array[0:3] * 255, dtype=int).tolist()
            props['color'] = '#%02x%02x%02x' % tuple(color_rgb)
            if imtype == 'MMI':
                if (cval * 2) % 2 == 1:
                    props['weight'] = 4
                else:
                    props['weight'] = 2
            else:
                props['weight'] = 4
            line_strings.append({
                'geometry': mapping(mls),
                'properties': props
            })
    return line_strings
Example #18
0
    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))
Example #19
0
def draw_map(adict, override_scenario=False):
    """If adict['imtype'] is MMI, draw a map of intensity draped over
    topography, otherwise Draw IMT contour lines over hill-shaded topography.

    Args:
        adict (dictionary): A dictionary containing the following keys:
            'imtype' (str): The intensity measure type
            'topogrid' (Grid2d): A topography grid
            'allcities' (Cities): A list of global cities,
            'states_provinces' (Cartopy Feature): States/province boundaries.
            'countries' (Cartopy Feature): Country boundaries.
            'oceans' (Cartopy Feature): Oceans.
            'lakes' (Cartopy Feature): Lakes.
            'roads' (Shapely Feature): Roads.
            'faults' (Shapely Feature): Fault traces
            'datadir' (str): The path into which to deposit products
            'operator' (str): The producer of this shakemap
            'filter_size' (int): The size of the filter used before contouring
            'info' (dictionary): The shakemap info structure
            'component' (str): The intensity measure component being plotted
            'imtdict' (dictionary): Dict containing the IMT grids
            'rupdict' (dictionary): Dict containing the rupture data
            'stationdict' (dictionary): Dict of station data
            'config' (dictionary): The configuration data for this shakemap
            'tdict' (dictionary): The text strings to be printed on the map
                in the user's choice of language.
            'license_text' (str): License text to display at bottom of map
            'license_logo' (str): Path to license logo image to display
                next to license text
        override_scenario (bool): Turn off scenario watermark.

    Returns:
        Tuple of (Matplotlib figure, Matplotlib figure): Objects containing
        the map generated by this function, and the intensity legend,
        respectively. If the imtype of this map is not 'MMI', the second
        element of the tuple will be None.
    """
    imtype = adict['imtype']
    imtdict = adict['imtdict']      # mmidict
    imtdata = np.nan_to_num(imtdict['mean'], nan=0.0) # mmidata
    gd = GeoDict(imtdict['mean_metadata'])
    imtgrid = Grid2D(imtdata, gd)   # mmigrid

    gd = imtgrid.getGeoDict()

    # Retrieve the epicenter - this will get used on the map
    rupture = rupture_from_dict(adict['ruptdict'])
    origin = rupture.getOrigin()
    center_lat = origin.lat
    center_lon = origin.lon

    # load the cities data, limit to cities within shakemap bounds
    cities = adict['allcities'].limitByBounds((gd.xmin, gd.xmax,
                                               gd.ymin, gd.ymax))

    # get the map boundaries and figure size
    bounds, figsize, aspect = _get_map_info(gd)

    # Note: dimensions are: [left, bottom, width, height]
    dim_left = 0.1
    dim_bottom = 0.19
    dim_width = 0.8
    dim_height = dim_width/aspect
    if dim_height > 0.8:
        dim_height = 0.8
        dim_width = 0.8 * aspect
        dim_left = (1.0 - dim_width) / 2

    # Create the MercatorMap object, which holds a separate but identical
    # axes object used to determine collisions between city labels.
    mmap = MercatorMap(
        bounds, figsize, cities, padding=0.5,
        dimensions=[dim_left, dim_bottom, dim_width, dim_height])
    fig = mmap.figure
    ax = mmap.axes
    # this needs to be done here so that city label collision
    # detection will work
    fig.canvas.draw()

    # get the geographic projection object
    geoproj = mmap.geoproj
    # get the mercator projection object
    proj = mmap.proj
    # get the proj4 string - used by Grid2D project() method
    projstr = proj.proj4_init

    # get the projected IMT and topo grids
    pimtgrid, ptopogrid = _get_projected_grids(imtgrid, adict['topogrid'],
                                               projstr)

    # get the projected geodict
    proj_gd = pimtgrid.getGeoDict()

    pimtdata = pimtgrid.getData()
    ptopo_data = ptopogrid.getData()

    mmimap = ColorPalette.fromPreset('mmi')

    if imtype == 'MMI':
        draped_hsv = _get_draped(pimtdata, ptopo_data, mmimap)
    else:
        # get the draped topo data
        topo_colormap = ColorPalette.fromPreset('shaketopo')
        draped_hsv = _get_shaded(ptopo_data, topo_colormap)
        # convert units
        if imtype == 'PGV':
            pimtdata = np.exp(pimtdata)
        else:
            pimtdata = np.exp(pimtdata) * 100

    plt.sca(ax)
    ax.set_xlim(proj_gd.xmin, proj_gd.xmax)
    ax.set_ylim(proj_gd.ymin, proj_gd.ymax)
    img_extent = (proj_gd.xmin, proj_gd.xmax, proj_gd.ymin, proj_gd.ymax)

    plt.imshow(draped_hsv, origin='upper', extent=img_extent,
               zorder=IMG_ZORDER, interpolation='none')

    config = adict['config']
    gmice = get_object_from_config('gmice', 'modeling', config)
    gmice_imts = gmice.DEFINED_FOR_INTENSITY_MEASURE_TYPES
    gmice_pers = gmice.DEFINED_FOR_SA_PERIODS

    oqimt = imt.from_string(imtype)

    if imtype != 'MMI' and (not isinstance(oqimt, tuple(gmice_imts)) or
                            (isinstance(oqimt, imt.SA) and
                             oqimt.period not in gmice_pers)):
        my_gmice = None
    else:
        my_gmice = gmice

    if imtype != 'MMI':
        # call the contour module in plotting to get the vertices of the
        # contour lines
        contour_objects = contour(imtdict, imtype, adict['filter_size'],
                                  my_gmice)

        # get a color palette for the levels we have
        # levels = [c['properties']['value'] for c in contour_objects]

        # cartopy shapely feature has some weird behaviors, so I had to go
        # rogue and draw contour lines/labels myself.

        # To choose which contours to label, we will keep track of the lengths
        # of contours, grouped by isovalue
        contour_lens = defaultdict(lambda: [])
        def arclen(path):
            """
            Compute the arclength of *path*, which should be a list of pairs
            of numbers.
            """
            x0, y0 = [np.array(c) for c in zip(*path)]
            x1, y1 = [np.roll(c, -1) for c in (x0, y0)] # offset by 1
            # don't include first-last vertices as an edge:
            x0, y0, x1, y1 = [c[:-1] for c in (x0, y0, x1, y1)]
            return np.sum(np.sqrt((x0 - x1)**2 + (y0 - y1)**2))

        # draw dashed contours first, the ones over land will be overridden by
        # solid contours
        for contour_object in contour_objects:
            props = contour_object['properties']
            multi_lines = sShape(contour_object['geometry'])
            pmulti_lines = proj.project_geometry(multi_lines, src_crs=geoproj)
            for multi_line in pmulti_lines:
                pmulti_line = mapping(multi_line)['coordinates']
                x, y = zip(*pmulti_line)
                contour_lens[props['value']].append(arclen(pmulti_line))
                # color = imt_cmap.getDataColor(props['value'])
                ax.plot(x, y, color=props['color'], linestyle='dashed',
                        zorder=DASHED_CONTOUR_ZORDER)

        white_box = dict(
            boxstyle="round",
            ec=(0, 0, 0),
            fc=(1., 1, 1),
            color='k'
        )

        # draw solid contours next - the ones over water will be covered by
        # ocean polygon
        for contour_object in contour_objects:
            props = contour_object['properties']
            multi_lines = sShape(contour_object['geometry'])
            pmulti_lines = proj.project_geometry(multi_lines, src_crs=geoproj)

            # only label long contours (relative to others with the same
            # isovalue)
            min_len = np.array(contour_lens[props['value']]).mean()

            for multi_line in pmulti_lines:
                pmulti_line = mapping(multi_line)['coordinates']
                x, y = zip(*pmulti_line)
                # color = imt_cmap.getDataColor(props['value'])
                ax.plot(x, y, color=props['color'], linestyle='solid',
                        zorder=CONTOUR_ZORDER)
                if arclen(pmulti_line) >= min_len:
                    # try to label each segment with black text in a white box
                    xc = x[int(len(x)/3)]
                    yc = y[int(len(y)/3)]
                    if _label_close_to_edge(
                            xc, yc, proj_gd.xmin, proj_gd.xmax,
                            proj_gd.ymin, proj_gd.ymax):
                        continue
                    # TODO: figure out if box is going to go outside the map,
                    # if so choose a different point on the line.

                    # For small values, use scientific notation with 1 sig fig
                    # to avoid multiple contours labelled 0.0:
                    value = props['value']
                    fmt = '%.1g' if abs(value) < 0.1 else '%.1f'
                    ax.text(xc, yc, fmt % value, size=8,
                            ha="center", va="center",
                            bbox=white_box, zorder=AXES_ZORDER-1)

    # make the border thicker
    lw = 2.0
    ax.outline_patch.set_zorder(BORDER_ZORDER)
    ax.outline_patch.set_linewidth(lw)
    ax.outline_patch.set_joinstyle('round')
    ax.outline_patch.set_capstyle('round')

    # Coastlines will get drawn when we draw the ocean edges
    # ax.coastlines(resolution="10m", zorder=COAST_ZORDER, linewidth=3)

    if adict['states_provinces']:
        ax.add_feature(adict['states_provinces'], edgecolor='0.5',
                       zorder=COAST_ZORDER)

    if adict['countries']:
        ax.add_feature(adict['countries'], edgecolor='black',
                       zorder=BORDER_ZORDER)

    if adict['oceans']:
        ax.add_feature(adict['oceans'], edgecolor='black',
                       zorder=OCEAN_ZORDER)

    if adict['lakes']:
        ax.add_feature(adict['lakes'], edgecolor='black',
                       zorder=OCEAN_ZORDER)

    if adict['faults'] is not None:
        ax.add_feature(adict['faults'], edgecolor='firebrick',
                       zorder=ROAD_ZORDER)

    if adict['roads'] is not None:
        ax.add_feature(adict['roads'], edgecolor='dimgray',
                       zorder=ROAD_ZORDER)

    # draw graticules, ticks, tick labels
    _draw_graticules(ax, *bounds)

    # is this event a scenario?
    info = adict['info']
    etype = info['input']['event_information']['event_type']
    is_scenario = etype == 'SCENARIO'

    if is_scenario and not override_scenario:
        plt.text(
            center_lon, center_lat,
            adict['tdict']['title_parts']['scenario'],
            fontsize=72,
            zorder=SCENARIO_ZORDER, transform=geoproj,
            alpha=WATERMARK_ALPHA, color=WATERMARK_COLOR,
            horizontalalignment='center',
            verticalalignment='center',
            rotation=45,
            path_effects=[
                path_effects.Stroke(linewidth=1, foreground='black')]
        )

    # Draw the map scale in the unoccupied lower corner.
    corner = 'll'
    draw_scale(ax, corner, pady=0.05, padx=0.05, zorder=SCALE_ZORDER)

    # draw cities
    mmap.drawCities(shadow=True, zorder=CITIES_ZORDER, draw_dots=True)

    # Draw the epicenter as a black star
    plt.sca(ax)
    plt.plot(center_lon, center_lat, 'k*', markersize=16,
             zorder=EPICENTER_ZORDER, transform=geoproj)

    # draw the rupture polygon(s) in black, if not point rupture
    point_source = True
    if not isinstance(rupture, PointRupture):
        point_source = False
        json_dict = rupture._geojson
        for feature in json_dict['features']:
            for coords in feature['geometry']['coordinates']:
                for pcoords in coords:
                    poly2d = sLineString([xy[0:2] for xy in pcoords])
                    ppoly = proj.project_geometry(poly2d)
                    mppoly = mapping(ppoly)['coordinates']
                    for spoly in mppoly:
                        x, y = zip(*spoly)
                        ax.plot(x, y, 'k', lw=1, zorder=FAULT_ZORDER)

    # draw the station data on the map
    stations = adict['stationdict']
    _draw_stations(ax, stations, imtype, mmimap, geoproj)

    _draw_title(imtype, adict)

    process_time = info['processing']['shakemap_versions']['process_time']
    map_version = int(info['processing']['shakemap_versions']['map_version'])
    if imtype == 'MMI':
        _draw_mmi_legend(fig, mmimap, gmice, process_time,
                         map_version, point_source, adict['tdict'])
        # make a separate MMI legend
        fig2 = plt.figure(figsize=figsize)
        _draw_mmi_legend(fig2, mmimap, gmice, process_time,
                         map_version, point_source, adict['tdict'])

    else:
        _draw_imt_legend(fig, mmimap, imtype, gmice, process_time, map_version,
                         point_source, adict['tdict'])
        plt.draw()
        fig2 = None

    _draw_license(fig, adict)

    return (fig, fig2)
Example #20
0
def plot_regression(event_table,
                    imc,
                    imc_table,
                    imt,
                    filename,
                    distance_metric='EpicentralDistance',
                    colormap='viridis'):
    """Make summary "regression" plot.

    TODO:
      * Add GMPE curve and compute mean/sd for all the observations
        and then also report the standardized residuals.
      * Better definitions of column names and units.

    """
    fig = plt.figure(figsize=(10, 5))
    # ax = plt.subplot(1, 1, 1)
    ax = fig.add_axes([BOTTOM, AX1_LEFT, AX1_WIDTH, AX1_HEIGHT])

    if distance_metric not in imc_table.columns:
        raise KeyError('Distance metric "%s" not found in table' %
                       distance_metric)
    imt = imt.upper()

    # Stupid hack to get units for now. Need a better, more systematic
    # approach
    if imt.startswith("SA") | (imt == "PGA"):
        units = "%g"
    elif imt.startswith('FAS') or imt in ['ARIAS', 'PGV']:
        units = "cm/s"
    else:
        units = 'Unknown units for IMT %s' % imt

    if imt not in imc_table.columns:
        raise KeyError('IMT "%s" not found in table' % imt)
    # get the event information
    # group imt data by event id
    # plot imts by event using colors banded by magnitude
    eventids = event_table['id']
    # set up the color bands
    minmag = event_table['magnitude'].min()
    min_mag = min(np.floor(minmag / DELTA_MAG) * DELTA_MAG, MIN_MAG)
    maxmag = event_table['magnitude'].max()
    max_mag = max(np.ceil(maxmag / DELTA_MAG) * DELTA_MAG, MAX_MAG)
    z0 = np.arange(min_mag, max_mag, 0.5)
    z1 = np.arange(min_mag + DELTA_MAG, max_mag + DELTA_MAG, DELTA_MAG)
    cmap = plt.get_cmap(colormap)
    palette = ColorPalette.fromColorMap('mag', z0, z1, cmap)

    colors = []
    for zval in np.arange(min_mag, max_mag + 0.5, 0.5):
        tcolor = palette.getDataColor(zval, 'hex')
        colors.append(tcolor)
    cmap2 = mpl.colors.ListedColormap(colors)

    for eventid in eventids:
        emag = event_table[event_table['id'] ==
                           eventid].magnitude.to_numpy()[0]
        norm_mag = (emag - min_mag) / (max_mag - min_mag)
        color = cmap2(norm_mag)
        erows = imc_table[imc_table['EarthquakeId'] == eventid]
        distance = erows[distance_metric]
        imtdata = erows[imt]
        ax.loglog(distance,
                  imtdata,
                  mfc=color,
                  mec='k',
                  marker='o',
                  linestyle='None')

    ax.set_xlabel('%s (km)' % distance_metric)
    ax.set_ylabel('%s (%s)' % (imt, units))

    bounds = np.arange(min_mag, max_mag + 1.0, 0.5)
    norm = mpl.colors.BoundaryNorm(bounds, cmap2.N)

    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="3%", pad=0.05)

    mpl.colorbar.ColorbarBase(
        cax,
        cmap=cmap2,
        norm=norm,
        ticks=bounds,  # optional
        spacing='proportional',
        orientation='vertical')

    plt.sca(ax)
    plt.suptitle('%s vs %s (#eqks=%i)' % (distance_metric, imt, len(eventids)))
    plt.title('for component %s' % (imc))

    plt.savefig(filename)
Example #21
0
def draw_contour(shakefile,
                 popfile,
                 oceanfile,
                 cityfile,
                 outfilename,
                 make_png=False):
    """Create a contour map showing population (greyscale) underneath contoured MMI.

    :param shakefile:
      String path to ShakeMap grid.xml file.
    :param popfile:
      String path to GDALGrid-compliant file containing population data.
    :param oceanfile:
      String path to file containing ocean vector data in a format compatible with fiona.
    :param cityfile:
      String path to file containing GeoNames cities data.
    :param outfilename:
      String path containing desired output PDF filename.
    :param make_png:
      Boolean indicating whether a PNG version of the file should also be created in the
      same output folder as the PDF.
    :returns:
      Tuple containing: 
        - Name of PNG file created, or None if PNG output not specified.
        - CartopyCities object containing the cities that were rendered on the contour map.
    """
    #load the shakemap - for the time being, we're interpolating the
    #population data to the shakemap, which would be important
    #if we were doing math with the pop values.  We're not, so I think it's ok.
    shakegrid = ShakeGrid.load(shakefile, adjust='res')
    gd = shakegrid.getGeoDict()

    #retrieve the epicenter - this will get used on the map
    clat = shakegrid.getEventDict()['lat']
    clon = shakegrid.getEventDict()['lon']

    #load the population data, sample to shakemap
    popgrid = GDALGrid.load(popfile, samplegeodict=gd, resample=True)
    popdata = popgrid.getData()

    #smooth the MMI data for contouring
    mmi = shakegrid.getLayer('mmi').getData()
    smoothed_mmi = gaussian_filter(mmi, FILTER_SMOOTH)

    #clip the ocean data to the shakemap
    bbox = (gd.xmin, gd.ymin, gd.xmax, gd.ymax)
    oceanshapes = _clip_bounds(bbox, oceanfile)

    #load the cities data, limit to cities within shakemap bounds
    allcities = CartopyCities.fromDefault()
    cities = allcities.limitByBounds((gd.xmin, gd.xmax, gd.ymin, gd.ymax))

    # Define ocean/land masks to do the contours, since we want different contour line styles over land and water.
    oceangrid = Grid2D.rasterizeFromGeometry(oceanshapes,
                                             gd,
                                             burnValue=1.0,
                                             fillValue=0.0,
                                             mustContainCenter=False,
                                             attribute=None)
    oceanmask = np.ma.masked_where(oceangrid == 1.0, smoothed_mmi)
    landmask = np.ma.masked_where(oceangrid == 0.0, smoothed_mmi)

    # Use our GMT-inspired palette class to create population and MMI colormaps
    popmap = ColorPalette.fromPreset('pop')
    mmimap = ColorPalette.fromPreset('mmi')

    #use the ShakeMap to determine the aspect ratio of the map
    aspect = (gd.xmax - gd.xmin) / (gd.ymax - gd.ymin)
    figheight = FIGWIDTH / aspect
    fig = plt.figure(figsize=(FIGWIDTH, figheight))

    # set up axes object with PlateCaree (non) projection.
    ax = plt.axes([0.02, 0.02, 0.95, 0.95], projection=ccrs.PlateCarree())

    #set the image extent to that of the data
    img_extent = (gd.xmin, gd.xmax, gd.ymin, gd.ymax)
    plt.imshow(popdata,
               origin='upper',
               extent=img_extent,
               cmap=popmap.cmap,
               vmin=popmap.vmin,
               vmax=popmap.vmax,
               zorder=9,
               interpolation='none')

    #define arrays of latitude and longitude we will use to plot MMI contours
    lat = np.linspace(gd.ymin, gd.ymax, gd.ny)
    lon = np.linspace(gd.xmin, gd.xmax, gd.nx)

    #contour the masked land/ocean MMI data at half-integer levels
    plt.contour(lon,
                lat,
                landmask,
                linewidths=3.0,
                linestyles='solid',
                zorder=10,
                cmap=mmimap.cmap,
                vmin=mmimap.vmin,
                vmax=mmimap.vmax,
                levels=np.arange(0.5, 10.5, 1.0))

    plt.contour(lon,
                lat,
                oceanmask,
                linewidths=2.0,
                linestyles='dashed',
                zorder=13,
                cmap=mmimap.cmap,
                vmin=mmimap.vmin,
                vmax=mmimap.vmax,
                levels=np.arange(0.5, 10.5, 1.0))

    #the idea here is to plot invisible MMI contours at integer levels and then label them.
    #labeling part does not currently work.
    cs = plt.contour(lon,
                     lat,
                     landmask,
                     linewidths=0.0,
                     levels=np.arange(0, 11),
                     zorder=10)
    #clabel is not actually drawing anything, but it is blotting out a portion of the contour line.  ??
    ax.clabel(cs, np.arange(0, 11), colors='k', zorder=25)

    #set the extent of the map to our data
    ax.set_extent([lon.min(), lon.max(), lat.min(), lat.max()])

    #draw the ocean data
    if isinstance(oceanshapes[0], mPolygon):
        for shape in oceanshapes[0]:
            ocean_patch = PolygonPatch(shape,
                                       zorder=10,
                                       facecolor=WATERCOLOR,
                                       edgecolor=WATERCOLOR)
            ax.add_patch(ocean_patch)
    else:
        ocean_patch = PolygonPatch(oceanshapes[0],
                                   zorder=10,
                                   facecolor=WATERCOLOR,
                                   edgecolor=WATERCOLOR)
        ax.add_patch(ocean_patch)

    # add coastlines with desired scale of resolution
    ax.coastlines('10m', zorder=11)

    #draw meridians and parallels using Cartopy's functions for that
    gl = ax.gridlines(crs=ccrs.PlateCarree(),
                      draw_labels=True,
                      linewidth=2,
                      color=(0.9, 0.9, 0.9),
                      alpha=0.5,
                      linestyle='-',
                      zorder=20)
    gl.xlabels_top = False
    gl.xlabels_bottom = False
    gl.ylabels_left = False
    gl.ylabels_right = False
    gl.xlines = True
    xlocs = np.arange(np.floor(gd.xmin - 1), np.ceil(gd.xmax + 1))
    ylocs = np.arange(np.floor(gd.ymin - 1), np.ceil(gd.ymax + 1))
    gl.xlocator = mticker.FixedLocator(xlocs)
    gl.ylocator = mticker.FixedLocator(ylocs)
    gl.xformatter = LONGITUDE_FORMATTER
    gl.yformatter = LATITUDE_FORMATTER
    gl.xlabel_style = {'size': 15, 'color': 'black'}
    gl.ylabel_style = {'size': 15, 'color': 'black'}

    #drawing our own tick labels INSIDE the plot, as Cartopy doesn't seem to support this.
    yrange = gd.ymax - gd.ymin
    xrange = gd.xmax - gd.xmin
    for xloc in gl.xlocator.locs:
        outside = xloc < gd.xmin or xloc > gd.xmax
        #don't draw labels when we're too close to either edge
        near_edge = (xloc - gd.xmin) < (xrange * 0.1) or (gd.xmax - xloc) < (
            xrange * 0.1)
        if outside or near_edge:
            continue
        if xloc < 0:
            xtext = r'$%s^\circ$W' % str(abs(int(xloc)))
        else:
            xtext = r'$%s^\circ$E' % str(int(xloc))
        ax.text(xloc,
                gd.ymax - (yrange / 35),
                xtext,
                fontsize=14,
                zorder=20,
                ha='center',
                fontname='Bitstream Vera Sans')

    for yloc in gl.ylocator.locs:
        outside = yloc < gd.ymin or yloc > gd.ymax
        #don't draw labels when we're too close to either edge
        near_edge = (yloc - gd.ymin) < (yrange * 0.1) or (gd.ymax - yloc) < (
            yrange * 0.1)
        if outside or near_edge:
            continue
        if yloc < 0:
            ytext = r'$%s^\circ$S' % str(abs(int(yloc)))
        else:
            ytext = r'$%s^\circ$N' % str(int(yloc))
        thing = ax.text(gd.xmin + (xrange / 100),
                        yloc,
                        ytext,
                        fontsize=14,
                        zorder=20,
                        va='center',
                        fontname='Bitstream Vera Sans')

    #Limit the number of cities we show - we may not want to use the population size
    #filter in the global case, but the map collision filter is a little sketchy right now.
    mapcities = cities.limitByPopulation(25000)
    mapcities = mapcities.limitByGrid()
    mapcities = mapcities.limitByMapCollision(ax, shadow=True)
    mapcities.renderToMap(ax, shadow=True, fontsize=12, zorder=11)

    #Get the corner of the map with the lowest population
    corner_rect, filled_corner = _get_open_corner(popgrid, ax)
    clat = round_to_nearest(clat, 1.0)
    clon = round_to_nearest(clon, 1.0)

    #draw a little globe in the corner showing in small-scale where the earthquake is located.
    proj = ccrs.Orthographic(central_latitude=clat, central_longitude=clon)
    ax2 = fig.add_axes(corner_rect, projection=proj)
    ax2.add_feature(cartopy.feature.OCEAN,
                    zorder=0,
                    facecolor=WATERCOLOR,
                    edgecolor=WATERCOLOR)
    ax2.add_feature(cartopy.feature.LAND, zorder=0, edgecolor='black')
    ax2.plot([clon], [clat],
             'w*',
             linewidth=1,
             markersize=16,
             markeredgecolor='k',
             markerfacecolor='r')
    gh = ax2.gridlines()
    ax2.set_global()
    ax2.outline_patch.set_edgecolor('black')
    ax2.outline_patch.set_linewidth(2)

    #Draw the map scale in the unoccupied lower corner.
    corner = 'lr'
    if filled_corner == 'lr':
        corner = 'll'
    draw_scale(ax, corner, pady=0.05, padx=0.05)

    plt.savefig(outfilename)

    pngfile = None
    if make_png:
        fpath, fname = os.path.split(outfilename)
        fbase, t = os.path.splitext(fname)
        pngfile = os.path.join(fpath, fbase + '.png')
        plt.savefig(pngfile)

    return (pngfile, mapcities)
Example #22
0
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)
Example #23
0
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)
Example #24
0
    def getHistoricalEvents(self, maxmmi, nmmi, ndeaths, clat, clon):
        """Select three earthquakes from internal list that are "representative" and similar to input event.

        First event should be the event "most similar" in exposure, and with the fewest fatalities.
        Second event should also be "similar" in exposure, and with the most fatalities.
        Third event should be the deadliest and/or highest population exposure event.

        :param maxmmi:
          MMI level of maximum exposure.
        :param nmmi:
          Number of people exposure to maxmmi.
        :param ndeaths:
          Number of estimated people killed from shaking.
        :param clat:
          Origin latitude.
        :param clon:
          Origin latitude.
        :returns:
          List of three dictionaries (or three None values), containing fields:
            - EventID  14 character event ID based on time: (YYYYMMDDHHMMSS).
            - Time Pandas Timestamp object.
            - Lat  Event latitude.
            - Lon  Event longitude.
            - Depth  Event depth.
            - Magnitude  Event magnitude.
            - CountryCode  Two letter country code in which epicenter is located.
            - ShakingDeaths Number of fatalities due to shaking.
            - TotalDeaths Number of total fatalities.
            - Injured Number of injured.
            - Fire Integer (0 or 1) indicating if any fires occurred as a result of this earthquake.
            - Liquefaction Integer (0 or 1) indicating if any liquefaction occurred as a result of this earthquake.
            - Tsunami Integer (0 or 1) indicating if any tsunamis occurred as a result of this earthquake.
            - Landslide Integer (0 or 1) indicating if any landslides occurred as a result of this earthquake.
            - MMI1 - Number of people exposed to Mercalli intensity 1.
            - MMI2 - Number of people exposed to Mercalli intensity 2.
            - MMI3 - Number of people exposed to Mercalli intensity 3.
            - MMI4 - Number of people exposed to Mercalli intensity 4.
            - MMI5 - Number of people exposed to Mercalli intensity 5.
            - MMI6 - Number of people exposed to Mercalli intensity 6.
            - MMI7 - Number of people exposed to Mercalli intensity 7.
            - MMI8 - Number of people exposed to Mercalli intensity 8.
            - MMI9+ Number of people exposed to Mercalli intensity 9 and above.
            - MaxMMI  Highest intensity level with at least 1000 people exposed.
            - NumMaxMMI Number of people exposed at MaxMMI.
            - Distance Distance of this event from input event, in km.
            - Color The hex color that should be used for row color in historical events table.
        """
        # get the worst event first
        newdf = self._dataframe.sort_values(
            ['ShakingDeaths', 'MaxMMI', 'NumMaxMMI'], ascending=False)
        if not len(newdf):
            return [None, None, None]
        worst = newdf.iloc[0]
        newdf = newdf.drop(newdf.index[[
            0
        ]])  # get rid of that first row, so we don't re-include the same event
        if not len(newdf):
            less_bad = None
        else:  # get the similar but less bad event
            less_bad, newdf = self.getSimilarEvent(newdf,
                                                   maxmmi,
                                                   nmmi,
                                                   ndeaths,
                                                   go_down=True)

        if not len(newdf):
            more_bad = None
        else:  # get the similar but worse event
            more_bad, newdf = self.getSimilarEvent(newdf,
                                                   maxmmi,
                                                   nmmi,
                                                   ndeaths,
                                                   go_down=False)

        events = []
        colormap = ColorPalette.fromPreset('mmi')
        if less_bad is not None:
            lessdict = to_ordered_dict(less_bad)
            rgbval = colormap.getDataColor(lessdict['MaxMMI'])
            rgb255 = tuple([int(c * 255) for c in rgbval])[0:3]
            lessdict['Color'] = '#%02x%02x%02x' % rgb255
            events.append(lessdict)

        if more_bad is not None:
            moredict = to_ordered_dict(more_bad)
            rgbval = colormap.getDataColor(moredict['MaxMMI'])
            rgb255 = tuple([int(c * 255) for c in rgbval])[0:3]
            moredict['Color'] = '#%02x%02x%02x' % rgb255
            events.append(moredict)

        worstdict = to_ordered_dict(worst)
        rgbval = colormap.getDataColor(worstdict['MaxMMI'])
        rgb255 = tuple([int(c * 255) for c in rgbval])[0:3]
        worstdict['Color'] = '#%02x%02x%02x' % rgb255
        events.append(worstdict)

        return events
Example #25
0
def plot_regression(
    event_table,
    imc,
    imc_table,
    imt,
    filename,
    distance_metric="EpicentralDistance",
    colormap="viridis",
):
    """Make summary "regression" plot.

    TODO:
      * Add GMPE curve and compute mean/sd for all the observations
        and then also report the standardized residuals.
      * Better definitions of column names and units.

    """
    fig = plt.figure(figsize=(10, 5))
    ax = fig.add_axes([BOTTOM, AX1_LEFT, AX1_WIDTH, AX1_HEIGHT])

    if distance_metric not in imc_table.columns:
        raise KeyError(
            f'Distance metric "{distance_metric}" not found in table')
    imt = imt.upper()

    # Stupid hack to get units for now. Need a better, more systematic
    # approach
    if imt.startswith("SA") | (imt == "PGA"):
        units = "%g"
    elif imt.startswith("FAS") or imt in ["ARIAS", "PGV"]:
        units = "cm/s"
    else:
        units = f"Unknown units for IMT {imt}"

    if imt not in imc_table.columns:
        raise KeyError(f'IMT "{imt}" not found in table')
    # get the event information
    # group imt data by event id
    # plot imts by event using colors banded by magnitude
    eventids = event_table["id"]
    # set up the color bands
    minmag = event_table["magnitude"].min()
    min_mag = min(np.floor(minmag / DELTA_MAG) * DELTA_MAG, MIN_MAG)
    maxmag = event_table["magnitude"].max()
    max_mag = max(np.ceil(maxmag / DELTA_MAG) * DELTA_MAG, MAX_MAG)
    z0 = np.arange(min_mag, max_mag, 0.5)
    z1 = np.arange(min_mag + DELTA_MAG, max_mag + DELTA_MAG, DELTA_MAG)
    cmap = plt.get_cmap(colormap)
    palette = ColorPalette.fromColorMap("mag", z0, z1, cmap)

    colors = []
    for zval in np.arange(min_mag, max_mag + 0.5, 0.5):
        tcolor = palette.getDataColor(zval, "hex")
        colors.append(tcolor)
    cmap2 = mpl.colors.ListedColormap(colors)

    for eventid in eventids:
        emag = event_table[event_table["id"] ==
                           eventid].magnitude.to_numpy()[0]
        norm_mag = (emag - min_mag) / (max_mag - min_mag)
        color = cmap2(norm_mag)
        erows = imc_table[imc_table["EarthquakeId"] == eventid]
        distance = erows[distance_metric]
        imtdata = erows[imt]
        ax.loglog(distance,
                  imtdata,
                  mfc=color,
                  mec="k",
                  marker="o",
                  linestyle="None")

    ax.set_xlabel(f"{distance_metric} (km)")
    ax.set_ylabel(f"{imt} ({units})")

    bounds = np.arange(min_mag, max_mag + 1.0, 0.5)
    norm = mpl.colors.BoundaryNorm(bounds, cmap2.N)

    divider = make_axes_locatable(ax)
    cax = divider.append_axes("right", size="3%", pad=0.05)

    mpl.colorbar.ColorbarBase(
        cax,
        cmap=cmap2,
        norm=norm,
        ticks=bounds,  # optional
        spacing="proportional",
        orientation="vertical",
    )

    plt.sca(ax)
    plt.suptitle("%s vs %s (#eqks=%i)" % (distance_metric, imt, len(eventids)))
    plt.title(f"for component {imc}")

    plt.savefig(filename)
Example #26
0
def draw_contour(shakegrid,
                 popgrid,
                 oceanfile,
                 oceangridfile,
                 cityfile,
                 basename,
                 borderfile=None,
                 is_scenario=False):
    """Create a contour map showing MMI contours over greyscale population.

    :param shakegrid:
      ShakeGrid object.
    :param popgrid:
      Grid2D object containing population data.
    :param oceanfile:
      String path to file containing ocean vector data in a format compatible
      with fiona.
    :param oceangridfile:
      String path to file containing ocean grid data .
    :param cityfile:
      String path to file containing GeoNames cities data.
    :param basename:
      String path containing desired output PDF base name, i.e.,
      /home/pager/exposure.  ".pdf" and ".png" files will
      be made.
    :param make_png:
      Boolean indicating whether a PNG version of the file should also be
      created in the same output folder as the PDF.
    :returns:
      Tuple containing:
        - Name of PNG file created, or None if PNG output not specified.
        - Cities object containing the cities that were rendered on the
          contour map.
    """
    gd = shakegrid.getGeoDict()

    # Retrieve the epicenter - this will get used on the map
    center_lat = shakegrid.getEventDict()['lat']
    center_lon = shakegrid.getEventDict()['lon']

    # load the ocean grid file (has 1s in ocean, 0s over land)
    # having this file saves us almost 30 seconds!
    oceangrid = read(oceangridfile,
                     samplegeodict=gd,
                     resample=True,
                     doPadding=True)

    # load the cities data, limit to cities within shakemap bounds
    allcities = Cities.fromDefault()
    cities = allcities.limitByBounds((gd.xmin, gd.xmax, gd.ymin, gd.ymax))

    # define the map
    # first cope with stupid 180 meridian
    height = (gd.ymax - gd.ymin) * DEG2KM
    if gd.xmin < gd.xmax:
        width = (gd.xmax - gd.xmin) * np.cos(np.radians(center_lat)) * DEG2KM
        xmin, xmax, ymin, ymax = (gd.xmin, gd.xmax, gd.ymin, gd.ymax)
    else:
        xmin, xmax, ymin, ymax = (gd.xmin, gd.xmax, gd.ymin, gd.ymax)
        xmax += 360
        width = ((gd.xmax + 360) - gd.xmin) * \
            np.cos(np.radians(center_lat)) * DEG2KM

    aspect = width / height

    # if the aspect is not 1, then trim bounds in x or y direction
    # as appropriate
    if width > height:
        dw = (width - height) / 2.0  # this is width in km
        xmin = xmin + dw / (np.cos(np.radians(center_lat)) * DEG2KM)
        xmax = xmax - dw / (np.cos(np.radians(center_lat)) * DEG2KM)
        width = (xmax - xmin) * np.cos(np.radians(center_lat)) * DEG2KM
    if height > width:
        dh = (height - width) / 2.0  # this is width in km
        ymin = ymin + dh / DEG2KM
        ymax = ymax - dh / DEG2KM
        height = (ymax - ymin) * DEG2KM

    aspect = width / height
    figheight = FIGWIDTH / aspect
    bbox = (xmin, ymin, xmax, ymax)
    bounds = (xmin, xmax, ymin, ymax)
    figsize = (FIGWIDTH, figheight)

    # Create the MercatorMap object, which holds a separate but identical
    # axes object used to determine collisions between city labels.
    mmap = MercatorMap(bounds, figsize, cities, padding=0.5)
    fig = mmap.figure
    ax = mmap.axes
    # this needs to be done here so that city label collision
    # detection will work
    fig.canvas.draw()

    geoproj = mmap.geoproj
    proj = mmap.proj

    # project our population grid to the map projection
    projstr = proj.proj4_init
    popgrid_proj = popgrid.project(projstr)
    popdata = popgrid_proj.getData()
    newgd = popgrid_proj.getGeoDict()

    # Use our GMT-inspired palette class to create population and MMI colormaps
    popmap = ColorPalette.fromPreset('pop')
    mmimap = ColorPalette.fromPreset('mmi')

    # set the image extent to that of the data
    img_extent = (newgd.xmin, newgd.xmax, newgd.ymin, newgd.ymax)
    plt.imshow(popdata,
               origin='upper',
               extent=img_extent,
               cmap=popmap.cmap,
               vmin=popmap.vmin,
               vmax=popmap.vmax,
               zorder=POP_ZORDER,
               interpolation='nearest')

    # draw 10m res coastlines
    ax.coastlines(resolution="10m", zorder=COAST_ZORDER)

    states_provinces = cfeature.NaturalEarthFeature(
        category='cultural',
        name='admin_1_states_provinces_lines',
        scale='50m',
        facecolor='none')

    ax.add_feature(states_provinces, edgecolor='black', zorder=COAST_ZORDER)

    # draw country borders using natural earth data set
    if borderfile is not None:
        borders = ShapelyFeature(
            Reader(borderfile).geometries(), ccrs.PlateCarree())
        ax.add_feature(borders,
                       zorder=COAST_ZORDER,
                       edgecolor='black',
                       linewidth=2,
                       facecolor='none')

    # clip the ocean data to the shakemap
    bbox = (gd.xmin, gd.ymin, gd.xmax, gd.ymax)
    oceanshapes = _clip_bounds(bbox, oceanfile)

    ax.add_feature(ShapelyFeature(oceanshapes, crs=geoproj),
                   facecolor=WATERCOLOR,
                   zorder=OCEAN_ZORDER)

    # So here we're going to project the MMI data to
    # our mercator map, then smooth and contour that
    # projected grid.

    # smooth the MMI data for contouring, themn project
    mmi = shakegrid.getLayer('mmi').getData()
    smoothed_mmi = gaussian_filter(mmi, FILTER_SMOOTH)
    newgd = shakegrid.getGeoDict().copy()
    smooth_grid = Grid2D(data=smoothed_mmi, geodict=newgd)
    smooth_grid_merc = smooth_grid.project(projstr)
    newgd2 = smooth_grid_merc.getGeoDict()

    # project the ocean grid
    oceangrid_merc = oceangrid.project(projstr)

    # create masked arrays using the ocean grid
    data_xmin, data_xmax = newgd2.xmin, newgd2.xmax
    data_ymin, data_ymax = newgd2.ymin, newgd2.ymax
    smooth_data = smooth_grid_merc.getData()
    landmask = np.ma.masked_where(oceangrid_merc._data == 0.0, smooth_data)
    oceanmask = np.ma.masked_where(oceangrid_merc._data == 1.0, smooth_data)

    # contour the data
    contourx = np.linspace(data_xmin, data_xmax, newgd2.nx)
    contoury = np.linspace(data_ymin, data_ymax, newgd2.ny)
    ax.contour(
        contourx,
        contoury,
        np.flipud(oceanmask),
        linewidths=3.0,
        linestyles='solid',
        zorder=1000,
        cmap=mmimap.cmap,
        vmin=mmimap.vmin,
        vmax=mmimap.vmax,
        levels=np.arange(0.5, 10.5, 1.0),
    )

    ax.contour(
        contourx,
        contoury,
        np.flipud(landmask),
        linewidths=2.0,
        linestyles='dashed',
        zorder=OCEANC_ZORDER,
        cmap=mmimap.cmap,
        vmin=mmimap.vmin,
        vmax=mmimap.vmax,
        levels=np.arange(0.5, 10.5, 1.0),
    )

    # the idea here is to plot invisible MMI contours at integer levels
    # and then label them. clabel method won't allow text to appear,
    # which is this case is kind of ok, because it allows us an
    # easy way to draw MMI labels as roman numerals.
    cs_land = plt.contour(
        contourx,
        contoury,
        np.flipud(oceanmask),
        linewidths=0.0,
        levels=np.arange(0, 11),
        alpha=0.0,
        zorder=CLABEL_ZORDER,
    )

    clabel_text = ax.clabel(cs_land,
                            cs_land.cvalues,
                            colors='k',
                            fmt='%.0f',
                            fontsize=40)
    for clabel in clabel_text:
        x, y = clabel.get_position()
        label_str = clabel.get_text()
        roman_label = MMI_LABELS[label_str]
        th = plt.text(x,
                      y,
                      roman_label,
                      zorder=CLABEL_ZORDER,
                      ha='center',
                      va='center',
                      color='black',
                      weight='normal',
                      size=16)
        th.set_path_effects([
            path_effects.Stroke(linewidth=2.0, foreground='white'),
            path_effects.Normal()
        ])

    cs_ocean = plt.contour(
        contourx,
        contoury,
        np.flipud(landmask),
        linewidths=0.0,
        levels=np.arange(0, 11),
        zorder=CLABEL_ZORDER,
    )

    clabel_text = ax.clabel(cs_ocean,
                            cs_ocean.cvalues,
                            colors='k',
                            fmt='%.0f',
                            fontsize=40)
    for clabel in clabel_text:
        x, y = clabel.get_position()
        label_str = clabel.get_text()
        roman_label = MMI_LABELS[label_str]
        th = plt.text(x,
                      y,
                      roman_label,
                      ha='center',
                      va='center',
                      color='black',
                      weight='normal',
                      size=16)
        th.set_path_effects([
            path_effects.Stroke(linewidth=2.0, foreground='white'),
            path_effects.Normal()
        ])

    # draw meridians and parallels using Cartopy's functions for that
    gl = ax.gridlines(draw_labels=True,
                      linewidth=2,
                      color=(0.9, 0.9, 0.9),
                      alpha=0.5,
                      linestyle='-',
                      zorder=GRID_ZORDER)
    gl.xlabels_top = False
    gl.xlabels_bottom = False
    gl.ylabels_left = False
    gl.ylabels_right = False
    gl.xlines = True

    # let's floor/ceil the edges to nearest half a degree
    gxmin = np.floor(xmin * 2) / 2
    gxmax = np.ceil(xmax * 2) / 2
    gymin = np.floor(ymin * 2) / 2
    gymax = np.ceil(ymax * 2) / 2

    xlocs = np.linspace(gxmin, gxmax + 0.5, num=5)
    ylocs = np.linspace(gymin, gymax + 0.5, num=5)

    gl.xlocator = mticker.FixedLocator(xlocs)
    gl.ylocator = mticker.FixedLocator(ylocs)
    gl.xformatter = LONGITUDE_FORMATTER
    gl.yformatter = LATITUDE_FORMATTER
    gl.xlabel_style = {'size': 15, 'color': 'black'}
    gl.ylabel_style = {'size': 15, 'color': 'black'}

    # TODO - figure out x/y axes data coordinates
    # corresponding to 10% from left and 10% from top
    # use geoproj and proj
    dleft = 0.01
    dtop = 0.97
    proj_str = proj.proj4_init
    merc_to_dd = pyproj.Proj(proj_str)

    # use built-in transforms to get from axes units to data units
    display_to_data = ax.transData.inverted()
    axes_to_display = ax.transAxes

    # these are x,y coordinates in projected space
    yleft, t1 = display_to_data.transform(
        axes_to_display.transform((dleft, 0.5)))
    t2, xtop = display_to_data.transform(axes_to_display.transform(
        (0.5, dtop)))

    # these are coordinates in lon,lat space
    yleft_dd, t1_dd = merc_to_dd(yleft, t1, inverse=True)
    t2_dd, xtop_dd = merc_to_dd(t2, xtop, inverse=True)

    # drawing our own tick labels INSIDE the plot, as
    # Cartopy doesn't seem to support this.
    yrange = ymax - ymin
    xrange = xmax - xmin
    ddlabelsize = 12
    for xloc in gl.xlocator.locs:
        outside = xloc < xmin or xloc > xmax
        # don't draw labels when we're too close to either edge
        near_edge = (xloc - xmin) < (xrange * 0.1) or (xmax - xloc) < (xrange *
                                                                       0.1)
        if outside or near_edge:
            continue
        xtext = r'$%.1f^\circ$W' % (abs(xloc))
        ax.text(xloc,
                xtop_dd,
                xtext,
                fontsize=ddlabelsize,
                zorder=GRID_ZORDER,
                ha='center',
                fontname=DEFAULT_FONT,
                transform=ccrs.Geodetic())

    for yloc in gl.ylocator.locs:
        outside = yloc < gd.ymin or yloc > gd.ymax
        # don't draw labels when we're too close to either edge
        near_edge = (yloc - gd.ymin) < (yrange * 0.1) or (gd.ymax - yloc) < (
            yrange * 0.1)
        if outside or near_edge:
            continue
        if yloc < 0:
            ytext = r'$%.1f^\circ$S' % (abs(yloc))
        else:
            ytext = r'$%.1f^\circ$N' % (abs(yloc))
        ax.text(yleft_dd,
                yloc,
                ytext,
                fontsize=ddlabelsize,
                zorder=GRID_ZORDER,
                va='center',
                fontname=DEFAULT_FONT,
                transform=ccrs.Geodetic())

    # draw cities
    mapcities = mmap.drawCities(shadow=True, zorder=CITIES_ZORDER)

    # draw the figure border thickly
    # TODO - figure out how to draw map border
    # bwidth = 3
    # ax.spines['top'].set_visible(True)
    # ax.spines['left'].set_visible(True)
    # ax.spines['bottom'].set_visible(True)
    # ax.spines['right'].set_visible(True)
    # ax.spines['top'].set_linewidth(bwidth)
    # ax.spines['right'].set_linewidth(bwidth)
    # ax.spines['bottom'].set_linewidth(bwidth)
    # ax.spines['left'].set_linewidth(bwidth)

    # Get the corner of the map with the lowest population
    corner_rect, filled_corner = _get_open_corner(popgrid, ax)
    clat2 = round_to_nearest(center_lat, 1.0)
    clon2 = round_to_nearest(center_lon, 1.0)

    # draw a little globe in the corner showing in small-scale
    # where the earthquake is located.
    proj = ccrs.Orthographic(central_latitude=clat2, central_longitude=clon2)
    ax2 = fig.add_axes(corner_rect, projection=proj)
    ax2.add_feature(cfeature.OCEAN,
                    zorder=0,
                    facecolor=WATERCOLOR,
                    edgecolor=WATERCOLOR)
    ax2.add_feature(cfeature.LAND, zorder=0, edgecolor='black')
    ax2.plot([clon2], [clat2],
             'w*',
             linewidth=1,
             markersize=16,
             markeredgecolor='k',
             markerfacecolor='r')
    ax2.gridlines()
    ax2.set_global()
    ax2.outline_patch.set_edgecolor('black')
    ax2.outline_patch.set_linewidth(2)

    # Draw the map scale in the unoccupied lower corner.
    corner = 'lr'
    if filled_corner == 'lr':
        corner = 'll'
    draw_scale(ax, corner, pady=0.05, padx=0.05)

    # Draw the epicenter as a black star
    plt.sca(ax)
    plt.plot(center_lon,
             center_lat,
             'k*',
             markersize=16,
             zorder=EPICENTER_ZORDER,
             transform=geoproj)

    if is_scenario:
        plt.text(center_lon,
                 center_lat,
                 'SCENARIO',
                 fontsize=64,
                 zorder=WATERMARK_ZORDER,
                 transform=geoproj,
                 alpha=0.2,
                 color='red',
                 horizontalalignment='center')

    # create pdf and png output file names
    pdf_file = basename + '.pdf'
    png_file = basename + '.png'

    # save to pdf
    plt.savefig(pdf_file)
    plt.savefig(png_file)

    return (pdf_file, png_file, mapcities)
Example #27
0
def create_twopager(pdata, hazinfo, version_dir):
    """
    :param pdata:
      PagerData object.
    :param hazinfo:
      HazusInfo object.
    :param version_dir:
      Path of event version directory.
    """

    # ---------------------------------------------------------------------------
    # Sort out some paths
    # ---------------------------------------------------------------------------

    # Location of this module
    mod_dir, dummy = os.path.split(__file__)

    # losspager package direcotry
    losspager_dir = os.path.join(mod_dir, '..')

    # Repository root directory
    root_dir = os.path.join(losspager_dir, '..')

    # Logos directory
    logos_dir = os.path.join(losspager_dir, 'logos')

    # twopager latex template file
    template_file = os.path.join(logos_dir, 'twopager.tex')

    # ---------------------------------------------------------------------------
    # Read in pager data, Hazus data, and latex template
    # ---------------------------------------------------------------------------

    json_dir = os.path.join(version_dir, 'json')
    pdict = pdata._pagerdict
    edict = pdata.getEventInfo()

    with open(template_file, 'r') as f:
        template = f.read()

    # ---------------------------------------------------------------------------
    # Fill in template values
    # ---------------------------------------------------------------------------

    # Sort out origin time
    olat = edict['lat']
    olon = edict['lon']
    otime_utc = edict['time']
    date_utc = datetime.strptime(otime_utc, "%Y-%m-%d %H:%M:%S")

    date_local = pdata.local_time
    DoW = date_local.strftime('%a')
    otime_local = date_local.strftime('%H:%M:%S')
    otime_local = DoW + ' ' + otime_local
    template = template.replace("[ORIGTIME]", otime_utc)
    template = template.replace("[LOCALTIME]", otime_local)

    # Some paths
    template = template.replace("[VERSIONFOLDER]", version_dir)
    template = template.replace("[HOMEDIR]", root_dir)

    # Magnitude location string under USGS logo
    magloc = 'M %.1f, %s' % (edict['mag'], texify(edict['location']))
    template = template.replace("[MAGLOC]", magloc)

    # Pager version
    ver = "Version " + str(pdict['pager']['version_number'])
    template = template.replace("[VERSION]", ver)

    # Epicenter location
    lat = edict['lat']
    lon = edict['lon']
    dep = edict['depth']
    if lat > 0:
        hlat = "N"
    else:
        hlat = "S"
    if lon > 0:
        hlon = "E"
    else:
        hlon = "W"
    template = template.replace("[LAT]", '%.4f' % abs(lat))
    template = template.replace("[LON]", '%.4f' % abs(lon))
    template = template.replace("[HEMILAT]", hlat)
    template = template.replace("[HEMILON]", hlon)
    template = template.replace("[DEPTH]", '%.1f' % dep)

    # Tsunami warning? --- need to fix to be a function of tsunamic flag
    if edict['tsunami']:
        template = template.replace(
            "[TSUNAMI]", "FOR TSUNAMI INFORMATION, SEE: tsunami.gov")
    else:
        template = template.replace("[TSUNAMI]", "")

    # Elapsed time
    if pdata.isScenario():
        elapse = ''
    else:
        elapse = "Created: " + \
            pdict['pager']['elapsed_time'] + " after earthquake"
    template = template.replace("[ELAPSED]", elapse)

    # Summary alert color
    template = template.replace("[SUMMARYCOLOR]",
                                pdata.summary_alert.capitalize())
    template = template.replace("[ALERTFILL]", pdata.summary_alert)

    # Summary comment
    template = template.replace("[IMPACT1]",
                                texify(pdict['comments']['impact1']))
    template = template.replace("[IMPACT2]",
                                texify(pdict['comments']['impact2']))

    # Hazus arrow color and relative position
    hazdel = (hazinfo.hazloss) / LOSS_CONV
    if hazdel < 0.1:
        hazdelval = 0.1
    elif hazdel > 1000000:
        hazdelval = 1000000
    else:
        hazdelval = hazdel
    arrowloc = (((6 - log10(hazdelval)) * 0.83) - 0.07)

    # distance (in cm) to the left from right end of the econ histogram
    template = template.replace("[ARROWSHIFT]", '%.2f' % arrowloc)
    shift = arrowloc + 1.75
    # value is ARROWSHIFT plus 1.75
    # white box around the arrow and text to "open" the lines between values
    template = template.replace("[BOXSHIFT]", '%.2f' % shift)
    # color of the Hazus econ loss value using PAGER color scale
    template = template.replace("[HAZUS_SUMMARY]", hazinfo.summary_color)

    # MMI color pal
    pal = ColorPalette.fromPreset('mmi')

    # get all of the tag tables
    (green_tag_table, yellow_tag_table,
     red_tag_table) = hazinfo.createTaggingTables()

    # Building Tags by occupancy
    template = template.replace('[GREEN_TAG_TABLE]', green_tag_table)
    template = template.replace('[YELLOW_TAG_TABLE]', yellow_tag_table)
    template = template.replace('[RED_TAG_TABLE]', red_tag_table)

    # Direct economic losses table
    econ_losses_table = hazinfo.createEconTable()
    template = template.replace('[DEL_TABLE]', econ_losses_table)

    # Non-fatal injuries table
    injuries_table = hazinfo.createInjuryTable()
    template = template.replace('[NFI_TABLE]', injuries_table)

    # Shelter needs table
    shelter_table = hazinfo.createShelterTable()
    template = template.replace('[SHELTER_TABLE]', shelter_table)

    # Earthquake Debris table
    debris_table = hazinfo.createDebrisTable()
    template = template.replace('[DEBRIS_TABLE]', debris_table)

    eventid = edict['eventid']

    # query ComCat for information about this event
    # fill in the url, if we can find it
    try:
        ccinfo = ComCatInfo(eventid)
        eventid, allids = ccinfo.getAssociatedIds()
        event_url = ccinfo.getURL() + '#pager'
    except:
        event_url = DEFAULT_PAGER_URL

    eventid = "Event ID: " + eventid
    template = template.replace("[EVENTID]", texify(eventid))
    template = template.replace("[EVENTURL]", texify(event_url))
    template = template.replace("[HAZUSURL]", texify(DEFAULT_FEMA_URL))

    # Write latex file
    tex_output = os.path.join(version_dir, 'twopager.tex')
    with open(tex_output, 'w') as f:
        f.write(template)

    pdf_output = os.path.join(version_dir, 'twopager.pdf')
    stderr = ''
    try:
        cwd = os.getcwd()
        os.chdir(version_dir)
        cmd = '%s -interaction nonstopmode --output-directory %s %s' % (
            LATEX_TO_PDF_BIN, version_dir, tex_output)
        logging.info('Running %s...' % cmd)
        res, stdout, stderr = get_command_output(cmd)
        os.chdir(cwd)
        if not res:
            if os.path.isfile(pdf_output):
                msg = 'pdflatex created output file with non-zero exit code.'
                return (pdf_output, msg)
            return (None, stderr)
        else:
            if os.path.isfile(pdf_output):
                return (pdf_output, stderr)
            else:
                pass
    except Exception as e:
        pass
    finally:
        os.chdir(cwd)
    return (None, stderr)
Example #28
0
def create_onepager(pdata, version_dir, debug=False):
    """
    :param pdata:
      PagerData object.
    :param version_dir: 
      Path of event version directory.
    :param debug:
      bool for whether or not to add textpos boxes to onepager.
    """

    #---------------------------------------------------------------------------
    # Sort out some paths
    #---------------------------------------------------------------------------

    # Locaiton of this module
    mod_dir, dummy = os.path.split(__file__)

    # losspager package direcotry
    losspager_dir = os.path.join(mod_dir, '..')

    # Repository root directory
    root_dir = os.path.join(losspager_dir, '..')

    # Data directory
    data_dir = os.path.join(losspager_dir, 'data')

    # Onepager latex template file
    template_file = os.path.join(data_dir, 'onepager2.tex')

    #---------------------------------------------------------------------------
    # Read in pager data and latex template
    #---------------------------------------------------------------------------

    json_dir = os.path.join(version_dir, 'json')
    pdict = pdata._pagerdict
    edict = pdata.getEventInfo()

    with open(template_file, 'r') as f:
        template = f.read()

    #---------------------------------------------------------------------------
    # Fill in template values
    #---------------------------------------------------------------------------

    # Sort out origin time
    olat = edict['lat']
    olon = edict['lon']
    otime_utc = edict['time']
    date_utc = datetime.strptime(otime_utc, "%Y-%m-%d %H:%M:%S")

    date_local = pdata.local_time
    DoW = date_local.strftime('%a')
    otime_local = date_local.strftime('%H:%M:%S')
    otime_local = DoW + ' ' + otime_local
    template = template.replace("[ORIGTIME]", otime_utc)
    template = template.replace("[LOCALTIME]", otime_local)

    # Some paths
    template = template.replace("[VERSIONFOLDER]", version_dir)
    template = template.replace("[HOMEDIR]", root_dir)

    # Magnitude location string under USGS logo
    magloc = 'M %.1f, %s' % (edict['mag'], texify(edict['location']))
    template = template.replace("[MAGLOC]", magloc)

    # Pager version
    ver = "Version " + str(pdict['pager']['version_number'])
    template = template.replace("[VERSION]", ver)
    template = template.replace("[VERSIONX]", "2.5")

    # Epicenter location
    lat = edict['lat']
    lon = edict['lon']
    dep = edict['depth']
    if lat > 0:
        hlat = "N"
    else:
        hlat = "S"
    if lon > 0:
        hlon = "E"
    else:
        hlon = "W"
    template = template.replace("[LAT]", '%.4f' % abs(lat))
    template = template.replace("[LON]", '%.4f' % abs(lon))
    template = template.replace("[HEMILAT]", hlat)
    template = template.replace("[HEMILON]", hlon)
    template = template.replace("[DEPTH]", '%.1f' % dep)

    # Tsunami warning? --- need to fix to be a function of tsunamic flag
    if edict['tsunami']:
        template = template.replace(
            "[TSUNAMI]", "FOR TSUNAMI INFORMATION, SEE: tsunami.gov")
    else:
        template = template.replace("[TSUNAMI]", "")

    if pdata.isScenario():
        elapse = ''
    else:
        elapse = "Created: " + pdict['pager'][
            'elapsed_time'] + " after earthquake"
    template = template.replace("[ELAPSED]", elapse)
    template = template.replace("[IMPACT1]",
                                texify(pdict['comments']['impact1']))
    template = template.replace("[IMPACT2]",
                                texify(pdict['comments']['impact2']))
    template = template.replace("[STRUCTCOMMENT]",
                                texify(pdict['comments']['struct_comment']))

    # Summary alert color
    template = template.replace("[SUMMARYCOLOR]",
                                pdata.summary_alert.capitalize())
    template = template.replace("[ALERTFILL]", pdata.summary_alert)

    # fill in exposure values
    max_border_mmi = pdata._pagerdict['population_exposure'][
        'maximum_border_mmi']
    explist = pdata.getTotalExposure()
    pophold = 0
    for mmi in range(1, 11):
        iexp = mmi - 1
        if mmi == 2:
            pophold += explist[iexp]
            continue
        elif mmi == 3:
            pop = explist[iexp] + pophold
            macro = '[MMI2-3]'
        else:
            pop = explist[iexp]
            macro = '[MMI%i]' % mmi
        if pop < 1000:
            pop = round_to_nearest(pop, round_value=1000)
        if max_border_mmi > mmi and mmi <= 4:
            if pop == 0:
                popstr = '--*'
            else:
                if pop < 1000:
                    pop = round_to_nearest(pop, round_value=1000)
                popstr = pop_round_short(pop) + '*'
        else:
            popstr = pop_round_short(pop)
        template = template.replace(macro, popstr)

    # MMI color pal
    pal = ColorPalette.fromPreset('mmi')

    # Historical table
    htab = pdata.getHistoricalTable()
    if htab[0] is None:
        # use pdata.getHistoricalComment()
        htex = pdata.getHistoricalComment()
    else:
        # build latex table
        htex = """
\\begin{tabularx}{7.25cm}{lrc*{1}{>{\\centering\\arraybackslash}X}*{1}{>{\\raggedleft\\arraybackslash}X}}
\hline
\\textbf{Date} &\\textbf{Dist.}&\\textbf{Mag.}&\\textbf{Max}    &\\textbf{Shaking}\\\\
\\textbf{(UTC)}&\\textbf{(km)} &              &\\textbf{MMI(\#)}&\\textbf{Deaths} \\\\
\hline
[TABLEDATA]
\hline
\multicolumn{5}{p{7.2cm}}{\\small [COMMENT]}
\end{tabularx}"""
        comment = pdata._pagerdict['comments']['secondary_comment']
        htex = htex.replace("[COMMENT]", texify(comment))
        tabledata = ""
        nrows = len(htab)
        for i in range(nrows):
            date = htab[i]['Time'].split()[0]
            dist = str(int(htab[i]['Distance']))
            mag = str(htab[i]['Magnitude'])
            mmi = dec_to_roman(np.round(htab[i]['MaxMMI'], 0))
            col = pal.getDataColor(htab[i]['MaxMMI'])
            texcol = "%s,%s,%s" % (col[0], col[1], col[2])
            nmmi = pop_round_short(htab[i]['NumMaxMMI'])
            mmicell = '%s(%s)' % (mmi, nmmi)
            shakedeath = htab[i]['ShakingDeaths']
            if np.isnan(shakedeath):
                death = "--"
            else:
                death = pop_round_short(shakedeath)
            row = '%s & %s & %s & \cellcolor[rgb]{%s} %s & %s \\\\ '\
                  '\n' %(date, dist, mag, texcol, mmicell, death)
            tabledata = tabledata + row
        htex = htex.replace("[TABLEDATA]", tabledata)
    template = template.replace("[HISTORICAL_BLOCK]", htex)

    # City table
    ctex = """
\\begin{tabularx}{7.25cm}{lXr}
\hline
\\textbf{MMI} & \\textbf{City} & \\textbf{Population}  \\\\
\hline
[TABLEDATA]
\hline
\end{tabularx}"""
    ctab = pdata.getCityTable()
    nrows = len(ctab.index)
    tabledata = ""
    for i in range(nrows):
        mmi = dec_to_roman(np.round(ctab['mmi'].iloc[i], 0))
        city = ctab['name'].iloc[i]
        if ctab['pop'].iloc[i] == 0:
            pop = '$<$1k'
        else:
            if ctab['pop'].iloc[i] < 1000:
                popnum = round_to_nearest(ctab['pop'].iloc[i],
                                          round_value=1000)
            else:
                popnum = ctab['pop'].iloc[i]
            pop = pop_round_short(popnum)
        col = pal.getDataColor(ctab['mmi'].iloc[i])
        texcol = "%s,%s,%s" % (col[0], col[1], col[2])
        if ctab['on_map'].iloc[i] == 1:
            if ctab['pop'].iloc[i] == 0:
                pop = '\\boldmath$<$\\textbf{1k}'
                row = '\\rowcolor[rgb]{%s}\\textbf{%s} & \\textbf{%s} & '\
                      '%s\\\\ \n' %(texcol, mmi, city, pop)
            else:
                row = '\\rowcolor[rgb]{%s}\\textbf{%s} & \\textbf{%s} & '\
                      '\\textbf{%s}\\\\ \n' %(texcol, mmi, city, pop)
        else:
            row = '\\rowcolor[rgb]{%s}%s & %s & '\
                  '%s\\\\ \n' %(texcol, mmi, city, pop)
        tabledata = tabledata + row
    ctex = ctex.replace("[TABLEDATA]", tabledata)
    template = template.replace("[CITYTABLE]", ctex)

    eventid = edict['eventid']

    # query ComCat for information about this event
    # fill in the url, if we can find it
    try:
        ccinfo = ComCatInfo(eventid)
        eventid, allids = ccinfo.getAssociatedIds()
        event_url = ccinfo.getURL() + '#pager'
    except:
        event_url = DEFAULT_PAGER_URL

    eventid = "Event ID: " + eventid
    template = template.replace("[EVENTID]", texify(eventid))
    template = template.replace("[EVENTURL]", texify(event_url))

    # Write latex file
    tex_output = os.path.join(version_dir, 'onepager.tex')
    with open(tex_output, 'w') as f:
        f.write(template)

    pdf_output = os.path.join(version_dir, 'onepager.pdf')
    stderr = ''
    try:
        cwd = os.getcwd()
        os.chdir(version_dir)
        cmd = '%s -interaction nonstopmode --output-directory %s %s' % (
            LATEX_TO_PDF_BIN, version_dir, tex_output)
        print('Running %s...' % cmd)
        res, stdout, stderr = get_command_output(cmd)
        os.chdir(cwd)
        if not res:
            return (None, stderr)
        else:
            if os.path.isfile(pdf_output):
                return (pdf_output, stderr)
            else:
                pass
    except Exception as e:
        pass
    finally:
        os.chdir(cwd)
    return (None, stderr)
Example #29
0
    def execute(self):
        """
        Write raster.zip file containing ESRI Raster files of all the IMTs
        in shake_result.hdf.

        Raises:
            NotADirectoryError: When the event data directory does not exist.
            FileNotFoundError: When the the shake_result HDF file does not
                exist.
        """

        install_path, data_path = get_config_paths()
        datadir = os.path.join(data_path, self._eventid, 'current', 'products')
        if not os.path.isdir(datadir):
            raise NotADirectoryError('%s is not a valid directory.' % datadir)
        datafile = os.path.join(datadir, 'shake_result.hdf')
        if not os.path.isfile(datafile):
            raise FileNotFoundError('%s does not exist.' % datafile)

        # Open the ShakeMapOutputContainer and extract the data
        container = ShakeMapOutputContainer.load(datafile)
        if container.getDataType() != 'grid':
            raise NotImplementedError('raster module can only operate on '
                                      'gridded data, not sets of points')

        # create GIS-readable .flt files of imt and uncertainty
        self.logger.debug('Creating GIS grids...')
        layers = container.getIMTs()

        # Package up all of these files into one zip file.
        zfilename = os.path.join(datadir, 'raster.zip')
        zfile = zipfile.ZipFile(zfilename,
                                mode='w',
                                compression=zipfile.ZIP_DEFLATED)

        files_written = []
        for layer in layers:
            _, layer = layer.split('/')
            fileimt = oq_to_file(layer)
            # This is a bit hacky -- we only produce the raster for the
            # first IMC returned. It should work as long as we only have
            # one IMC produced per ShakeMap run.
            imclist = container.getComponents(layer)
            imtdict = container.getIMTGrids(layer, imclist[0])
            mean_grid = Grid2D(imtdict['mean'],
                               GeoDict(imtdict['mean_metadata']))
            std_grid = Grid2D(imtdict['std'], GeoDict(imtdict['std_metadata']))
            mean_gdal = GDALGrid.copyFromGrid(mean_grid)
            std_gdal = GDALGrid.copyFromGrid(std_grid)
            mean_fname = os.path.join(datadir, '%s_mean.flt' % fileimt)
            mean_hdr = os.path.join(datadir, '%s_mean.hdr' % fileimt)
            std_fname = os.path.join(datadir, '%s_std.flt' % fileimt)
            std_hdr = os.path.join(datadir, '%s_std.hdr' % fileimt)
            self.logger.debug('Saving %s...' % mean_fname)
            mean_gdal.save(mean_fname)
            files_written.append(mean_fname)
            files_written.append(mean_hdr)
            self.logger.debug('Saving %s...' % std_fname)
            std_gdal.save(std_fname)
            files_written.append(std_fname)
            files_written.append(std_hdr)
            zfile.write(mean_fname, '%s_mean.flt' % fileimt)
            zfile.write(mean_hdr, '%s_mean.hdr' % fileimt)
            zfile.write(std_fname, '%s_std.flt' % fileimt)
            zfile.write(std_hdr, '%s_std.hdr' % fileimt)

        zfile.close()

        # nuke all of the copies of the files we just put in the zipfile
        for file_written in files_written:
            os.remove(file_written)

        # make a transparent PNG of intensity and a world file
        imclist = container.getComponents('MMI')
        mmidict = container.getIMTGrids('MMI', imclist[0])
        mmi_array = mmidict['mean']
        geodict = GeoDict(mmidict['mean_metadata'])
        palette = ColorPalette.fromPreset('mmi')
        mmi_rgb = palette.getDataColor(mmi_array, color_format='array')
        img = Image.fromarray(mmi_rgb)
        pngfile = os.path.join(datadir, 'intensity_overlay.png')
        img.save(pngfile, "PNG")

        # write out a world file
        # https://en.wikipedia.org/wiki/World_file
        worldfile = os.path.join(datadir, 'intensity_overlay.pngw')
        with open(worldfile, 'wt') as f:
            f.write('%.4f\n' % geodict.dx)
            f.write('0.0\n')
            f.write('0.0\n')
            f.write('-%.4f\n' % geodict.dy)
            f.write('%.4f\n' % geodict.xmin)
            f.write('%.4f\n' % geodict.ymax)
        container.close()