Beispiel #1
0
def latlng_vectors_to_matrices(unique_latitudes_deg, unique_longitudes_deg):
    """Converts vectors of lat and long coordinates to matrices.

    This method works only for a regular lat-long grid.  Works for coordinates
    of either grid points or grid-cell edges.

    M = number of rows in grid
    N = number of columns in grid

    :param unique_latitudes_deg: length-M numpy array with latitudes (deg N) of
        either grid points or grid-cell edges.
    :param unique_longitudes_deg: length-N numpy array with longitudes (deg E)
        of either grid points or grid-cell edges.
    :return: latitude_matrix_deg: M-by-N numpy array, where
        latitude_matrix_deg[i, *] = unique_latitudes_deg[i].  Each column in
        this matrix is the same.
    :return: longitude_matrix_deg: M-by-N numpy array, where
        longitude_matrix_deg[*, j] = unique_longitudes_deg[j].  Each row in this
        matrix is the same.
    """

    error_checking.assert_is_valid_lat_numpy_array(unique_latitudes_deg)
    error_checking.assert_is_numpy_array(unique_latitudes_deg, num_dimensions=1)
    error_checking.assert_is_numpy_array(unique_longitudes_deg,
                                         num_dimensions=1)
    unique_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        unique_longitudes_deg, allow_nan=False)

    (longitude_matrix_deg, latitude_matrix_deg) = numpy.meshgrid(
        unique_longitudes_deg, unique_latitudes_deg)
    return latitude_matrix_deg, longitude_matrix_deg
Beispiel #2
0
def get_wind_rotation_angles(latitudes_deg, longitudes_deg, model_name=None):
    """Returns wind-rotation angle for each lat-long point.

    These angles may be used in `rotate_winds`.

    :param latitudes_deg: numpy array of latitudes (deg N).
    :param longitudes_deg: equivalent-shape numpy array of longitudes (deg E).
    :param model_name: Name of model.
    :return: rotation_angle_cosines: equivalent-shape numpy array with cosines
        of rotation angles.
    :return: rotation_angle_sines: equivalent-shape numpy array with sines of
        rotation angles.
    """

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg,
                                                   allow_nan=False)

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg, allow_nan=False)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=numpy.asarray(
                                             latitudes_deg.shape))

    standard_latitudes_deg, central_longitude_deg = get_projection_params(
        model_name)

    rotation_angles = (
        numpy.sin(standard_latitudes_deg[0] * DEGREES_TO_RADIANS) *
        (longitudes_deg - central_longitude_deg) * DEGREES_TO_RADIANS)
    return numpy.cos(rotation_angles), numpy.sin(rotation_angles)
def init_lambert_conformal_projection(standard_latitudes_deg,
                                      central_longitude_deg):
    """Initializes Lambert conformal projection.

    :param standard_latitudes_deg: length-2 numpy array with standard parallels
        (deg N).  standard_latitudes_deg[0] is the first standard parallel;
        standard_latitudes_deg[1] is the second standard parallel.
    :param central_longitude_deg: central meridian (deg E).
    :return: projection_object: object created by `pyproj.Proj`, specifying the
        Lambert conformal projection.
    """

    error_checking.assert_is_valid_lat_numpy_array(standard_latitudes_deg)
    error_checking.assert_is_numpy_array(standard_latitudes_deg,
                                         exact_dimensions=numpy.array([2]))

    error_checking.assert_is_non_array(central_longitude_deg)
    central_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        central_longitude_deg, allow_nan=False)

    return Proj(proj='lcc',
                lat_1=standard_latitudes_deg[0],
                lat_2=standard_latitudes_deg[1],
                lon_0=central_longitude_deg,
                rsphere=EARTH_RADIUS_METRES,
                ellps='sphere')
def interp_temperature_sfc_from_nwp(
        radar_grid_point_lats_deg=None, radar_grid_point_lngs_deg=None,
        unix_time_sec=None, temperature_kelvins=None, model_name=None,
        grid_id=None, top_grib_directory_name=None,
        wgrib_exe_name=grib_io.WGRIB_EXE_NAME_DEFAULT,
        wgrib2_exe_name=grib_io.WGRIB2_EXE_NAME_DEFAULT):
    """Interpolates temperature isosurface from NWP model.

    M = number of rows (unique grid-point latitudes) in radar grid
    N = number of columns (unique grid-point longitudes) in radar grid

    :param radar_grid_point_lats_deg: length-M numpy array of grid-point
        latitudes (deg N).
    :param radar_grid_point_lngs_deg: length-N numpy array of grid-point
        longitudes (deg E).
    :param unix_time_sec: Target time.
    :param temperature_kelvins: Target temperature.
    :param model_name: Name of model.
    :param grid_id: String ID for model grid.
    :param top_grib_directory_name: Name of top-level directory with grib files
        for the given model.
    :param wgrib_exe_name: Path to wgrib executable.
    :param wgrib2_exe_name: Path to wgrib2 executable.
    :return: isosurface_height_matrix_m_asl: length-Q numpy array with heights
        of temperature isosurface (metres above sea level).
    """

    error_checking.assert_is_numpy_array(
        radar_grid_point_lats_deg, num_dimensions=1)
    error_checking.assert_is_valid_lat_numpy_array(radar_grid_point_lats_deg)

    error_checking.assert_is_numpy_array(
        radar_grid_point_lngs_deg, num_dimensions=1)
    lng_conversion.convert_lng_positive_in_west(
        radar_grid_point_lngs_deg, allow_nan=False)

    radar_lat_matrix_deg, radar_lng_matrix_deg = (
        grids.latlng_vectors_to_matrices(
            radar_grid_point_lats_deg, radar_grid_point_lngs_deg))

    num_grid_rows = len(radar_grid_point_lats_deg)
    num_grid_columns = len(radar_grid_point_lngs_deg)
    radar_lat_vector_deg = numpy.reshape(
        radar_lat_matrix_deg, num_grid_rows * num_grid_columns)
    radar_lng_vector_deg = numpy.reshape(
        radar_lng_matrix_deg, num_grid_rows * num_grid_columns)

    query_point_dict = {interp.QUERY_LAT_COLUMN: radar_lat_vector_deg,
                        interp.QUERY_LNG_COLUMN: radar_lng_vector_deg}
    query_point_table = pandas.DataFrame.from_dict(query_point_dict)

    isosurface_height_vector_m_asl = interp.interp_temperature_sfc_from_nwp(
        query_point_table, unix_time_sec=unix_time_sec,
        temperature_kelvins=temperature_kelvins, model_name=model_name,
        grid_id=grid_id, top_grib_directory_name=top_grib_directory_name,
        wgrib_exe_name=wgrib_exe_name, wgrib2_exe_name=wgrib2_exe_name,
        raise_error_if_missing=True)

    return numpy.reshape(
        isosurface_height_vector_m_asl, (num_grid_rows, num_grid_columns))
Beispiel #5
0
def get_elevations(latitudes_deg, longitudes_deg, working_dir_name=None):
    """Returns elevation of each point.

    N = number of points

    :param latitudes_deg: length-N numpy array of latitudes (deg N).
    :param longitudes_deg: length-N numpy array of longitudes (deg E).
    :param working_dir_name: See doc for `__init__` in class
        `ElevationFileHandler`.
    :return: elevations_m_asl: length-N numpy array of elevations (metres above
        sea level).
    """

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg)
    error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1)
    num_points = len(latitudes_deg)

    longitudes_deg = lng_conversion.convert_lng_negative_in_west(
        longitudes_deg, allow_nan=False)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    srtm_data_object = None
    elevations_m_asl = numpy.full(num_points, numpy.nan)

    for i in range(num_points):
        elevations_m_asl[i], srtm_data_object = _get_elevation(
            latitude_deg=latitudes_deg[i],
            longitude_deg=longitudes_deg[i],
            srtm_data_object=srtm_data_object,
            working_dir_name=working_dir_name)

    return elevations_m_asl
Beispiel #6
0
    def test_assert_is_valid_lat_numpy_array_true_with_nan_allowed(self):
        """Checks assert_is_valid_lat_numpy_array; all latitudes valid or NaN.

        In this case, allow_nan = True."""

        error_checking.assert_is_valid_lat_numpy_array(
            LAT_NUMPY_ARRAY_WITH_NANS_DEG, allow_nan=True)
def get_wind_rotation_angles(latitudes_deg, longitudes_deg, model_name):
    """Computes wind-rotation angle for each point.

    These angles may be used in `rotate_winds_to_earth_relative` or
    `rotate_winds_to_grid_relative`.

    :param latitudes_deg: numpy array of latitudes (deg N).
    :param longitudes_deg: numpy array of longitudes (deg E) with same shape as
        `latitudes_deg`.
    :param model_name: Model name (must be accepted by `check_model_name`).
    :return: rotation_angle_cosines: numpy array of cosines with same shape as
        `latitudes_deg`.
    :return: rotation_angle_sines: numpy array of sines with same shape as
        `latitudes_deg`.
    """

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg=latitudes_deg,
                                                   allow_nan=False)

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg=longitudes_deg, allow_nan=False)

    these_expected_dim = numpy.array(latitudes_deg.shape, dtype=int)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=these_expected_dim)

    standard_latitudes_deg, central_longitude_deg = get_projection_params(
        model_name)

    rotation_angles = (
        numpy.sin(standard_latitudes_deg[0] * DEGREES_TO_RADIANS) *
        (longitudes_deg - central_longitude_deg) * DEGREES_TO_RADIANS)

    return numpy.cos(rotation_angles), numpy.sin(rotation_angles)
def plot_scattered_points(axes_object=None,
                          basemap_object=None,
                          latitudes_deg=None,
                          longitudes_deg=None,
                          field_values=None,
                          marker_size=DEFAULT_MARKER_SIZE,
                          marker_edge_width=DEFAULT_MARKER_EDGE_WIDTH,
                          colour_map=None,
                          colour_minimum=None,
                          colour_maximum=None):
    """Plots values of a single NWP field at scattered points.

    These may be interpolated values.

    P = number of points

    :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`.
    :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`.
    :param latitudes_deg: length-P numpy array of latitudes (deg N).
    :param longitudes_deg: length-P numpy array of longitudes (deg E).
    :param field_values: length-P numpy array with values of field.
    :param marker_size: Size of each marker (circle).
    :param marker_edge_width: Line width of black edge around each marker
        (circle).
    :param colour_map: Instance of `matplotlib.pyplot.cm`.
    :param colour_minimum: Minimum value for colour map.
    :param colour_maximum: Maximum value for colour map.
    """

    error_checking.assert_is_numpy_array_without_nan(field_values)
    error_checking.assert_is_numpy_array(field_values, num_dimensions=1)
    num_points = len(field_values)

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg)
    error_checking.assert_is_numpy_array(latitudes_deg,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg, allow_nan=False)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    error_checking.assert_is_greater(colour_maximum, colour_minimum)

    x_coords_metres, y_coords_metres = basemap_object(longitudes_deg,
                                                      latitudes_deg)

    axes_object.scatter(x_coords_metres,
                        y_coords_metres,
                        s=marker_size,
                        c=field_values,
                        marker=MARKER_TYPE,
                        edgecolors=MARKER_EDGE_COLOUR,
                        linewidths=marker_edge_width,
                        cmap=colour_map,
                        vmin=colour_minimum,
                        vmax=colour_maximum)
Beispiel #9
0
    def test_assert_is_valid_lat_numpy_array_true_with_nan_banned(self):
        """Checks assert_is_valid_lat_numpy_array; all latitudes valid or NaN.

        In this case, allow_nan = False."""

        with self.assertRaises(ValueError):
            error_checking.assert_is_valid_lat_numpy_array(
                LAT_NUMPY_ARRAY_WITH_NANS_DEG, allow_nan=False)
Beispiel #10
0
def start_points_and_displacements_to_endpoints(start_latitudes_deg,
                                                start_longitudes_deg,
                                                scalar_displacements_metres,
                                                geodetic_bearings_deg):
    """Computes endpoint from each start point and displacement.

    :param start_latitudes_deg: numpy array with latitudes (deg N) of start
        points.
    :param start_longitudes_deg: equivalent-size numpy array with longitudes
        (deg E) of start points.
    :param scalar_displacements_metres: equivalent-size numpy array of scalar
        displacements.
    :param geodetic_bearings_deg: equivalent-size numpy array of geodetic
        bearings (from start point to end point, measured clockwise from due
        north).
    :return: end_latitudes_deg: equivalent-size numpy array with latitudes
        (deg N) of endpoints.
    :return: end_longitudes_deg: equivalent-size numpy array with longitudes
        (deg E) of endpoints.
    """

    error_checking.assert_is_valid_lat_numpy_array(start_latitudes_deg,
                                                   allow_nan=False)

    start_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        start_longitudes_deg, allow_nan=False)
    error_checking.assert_is_numpy_array(start_longitudes_deg,
                                         exact_dimensions=numpy.array(
                                             start_latitudes_deg.shape))

    error_checking.assert_is_geq_numpy_array(scalar_displacements_metres, 0.)
    error_checking.assert_is_numpy_array(scalar_displacements_metres,
                                         exact_dimensions=numpy.array(
                                             start_latitudes_deg.shape))

    error_checking.assert_is_geq_numpy_array(geodetic_bearings_deg, 0.)
    error_checking.assert_is_leq_numpy_array(geodetic_bearings_deg, 360.)
    error_checking.assert_is_numpy_array(geodetic_bearings_deg,
                                         exact_dimensions=numpy.array(
                                             start_latitudes_deg.shape))

    end_latitudes_deg = numpy.full(start_latitudes_deg.shape, numpy.nan)
    end_longitudes_deg = numpy.full(start_latitudes_deg.shape, numpy.nan)
    num_points = start_latitudes_deg.size

    for i in range(num_points):
        this_start_point_object = geopy.Point(start_latitudes_deg.flat[i],
                                              start_longitudes_deg.flat[i])
        this_end_point_object = VincentyDistance(
            meters=scalar_displacements_metres.flat[i]).destination(
                this_start_point_object, geodetic_bearings_deg.flat[i])

        end_latitudes_deg.flat[i] = this_end_point_object.latitude
        end_longitudes_deg.flat[i] = this_end_point_object.longitude

    end_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        end_longitudes_deg, allow_nan=False)
    return end_latitudes_deg, end_longitudes_deg
def project_latlng_to_xy(latitudes_deg,
                         longitudes_deg,
                         projection_object=None,
                         false_easting_metres=0.,
                         false_northing_metres=0.):
    """Converts from lat-long to projection (x-y) coordinates.

    S = shape of coordinate arrays.

    :param latitudes_deg: numpy array of latitudes (deg N) with shape S.
    :param longitudes_deg: numpy array of longitudes (deg E) with shape S.
    :param projection_object: Projection object created by `pyproj.Proj`.
    :param false_easting_metres: False easting.  Will be added to all x-
        coordinates.
    :param false_northing_metres: False northing.  Will be added to all y-
        coordinates.
    :return: x_coords_metres: numpy array of x-coordinates with shape S.
    :return: y_coords_metres: numpy array of y-coordinates with shape S.
    """

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg,
                                                   allow_nan=True)

    shape_of_coord_arrays = latitudes_deg.shape
    error_checking.assert_is_numpy_array(
        longitudes_deg, exact_dimensions=numpy.asarray(shape_of_coord_arrays))
    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg, allow_nan=True)

    error_checking.assert_is_not_nan(false_easting_metres)
    error_checking.assert_is_not_nan(false_northing_metres)

    x_coords_metres, y_coords_metres = projection_object(
        longitudes_deg, latitudes_deg)

    num_points = latitudes_deg.size
    nan_flags = numpy.logical_or(
        numpy.isnan(numpy.reshape(latitudes_deg, num_points)),
        numpy.isnan(numpy.reshape(longitudes_deg, num_points)))
    nan_indices = numpy.where(nan_flags)[0]

    x_coords_metres_flat = numpy.reshape(x_coords_metres, num_points)
    x_coords_metres_flat[nan_indices] = numpy.nan
    x_coords_metres = numpy.reshape(
        x_coords_metres_flat, shape_of_coord_arrays) + false_easting_metres

    y_coords_metres_flat = numpy.reshape(y_coords_metres, num_points)
    y_coords_metres_flat[nan_indices] = numpy.nan
    y_coords_metres = numpy.reshape(
        y_coords_metres_flat, shape_of_coord_arrays) + false_northing_metres

    return x_coords_metres, y_coords_metres
def start_points_and_distances_and_bearings_to_endpoints(
        start_latitudes_deg=None, start_longitudes_deg=None,
        displacements_metres=None, geodetic_bearings_deg=None):
    """Computes endpoint from each start point, displacement, and bearing.

    P = number of start points

    :param start_latitudes_deg: length-P numpy array of beginning latitudes
        (deg N).
    :param start_longitudes_deg: length-P numpy array of beginning longitudes
        (deg E).
    :param displacements_metres: length-P numpy array of displacements.
    :param geodetic_bearings_deg: length-P numpy array of geodetic bearings
        (from start point towards end point, measured clockwise from due north).
    :return: end_latitudes_deg: length-P numpy array of end latitudes (deg N).
    :return: end_longitudes_deg: length-P numpy array of end longitudes (deg E).
    """

    error_checking.assert_is_valid_lat_numpy_array(
        start_latitudes_deg, allow_nan=False)
    error_checking.assert_is_numpy_array(start_latitudes_deg, num_dimensions=1)
    num_points = len(start_latitudes_deg)

    start_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        start_longitudes_deg, allow_nan=False)
    error_checking.assert_is_numpy_array(
        start_longitudes_deg, exact_dimensions=numpy.array([num_points]))

    error_checking.assert_is_geq_numpy_array(displacements_metres, 0.)
    error_checking.assert_is_numpy_array(
        displacements_metres, exact_dimensions=numpy.array([num_points]))

    error_checking.assert_is_geq_numpy_array(geodetic_bearings_deg, 0.)
    error_checking.assert_is_leq_numpy_array(geodetic_bearings_deg, 360.)
    error_checking.assert_is_numpy_array(
        geodetic_bearings_deg, exact_dimensions=numpy.array([num_points]))

    end_latitudes_deg = numpy.full(num_points, numpy.nan)
    end_longitudes_deg = numpy.full(num_points, numpy.nan)
    for i in range(num_points):
        this_start_point_object = geopy.Point(
            start_latitudes_deg[i], start_longitudes_deg[i])
        this_end_point_object = VincentyDistance(
            meters=displacements_metres[i]).destination(
                this_start_point_object, geodetic_bearings_deg[i])

        end_latitudes_deg[i] = this_end_point_object.latitude
        end_longitudes_deg[i] = this_end_point_object.longitude

    return end_latitudes_deg, lng_conversion.convert_lng_positive_in_west(
        end_longitudes_deg, allow_nan=False)
def plot_polyline(latitudes_deg,
                  longitudes_deg,
                  basemap_object,
                  axes_object,
                  front_type=None,
                  line_colour=None,
                  line_width=DEFAULT_LINE_WIDTH,
                  line_style=DEFAULT_LINE_STYLE):
    """Plots either warm front or cold front as polyline.

    P = number of points in polyline

    :param latitudes_deg: length-P numpy array of latitudes (deg N).
    :param longitudes_deg: length-P numpy array of longitudes (deg N).
    :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`.
    :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`.
    :param front_type: Type of front (string).  Used only to determine line
        colour (if `line_colour` is left as None).
    :param line_colour: Colour (in any format accepted by `matplotlib.colors`).
        Defaults to `DEFAULT_WARM_FRONT_COLOUR` or `DEFAULT_COLD_FRONT_COLOUR`.
    :param line_width: Line width (real positive number).
    :param line_style: Line style (in any format accepted by
        `matplotlib.lines`).
    """

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg)
    error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1)
    num_points = len(latitudes_deg)

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    if line_colour is None:
        front_utils.check_front_type(front_type)
        if front_type == front_utils.WARM_FRONT_STRING_ID:
            line_colour = DEFAULT_WARM_FRONT_COLOUR
        else:
            line_colour = DEFAULT_COLD_FRONT_COLOUR

    x_coords_metres, y_coords_metres = basemap_object(longitudes_deg,
                                                      latitudes_deg)
    axes_object.plot(x_coords_metres,
                     y_coords_metres,
                     color=line_colour,
                     linestyle=line_style,
                     linewidth=line_width)
Beispiel #14
0
def write_grid_metafile(grid_point_latitudes_deg, grid_point_longitudes_deg,
                        netcdf_file_name):
    """Writes metadata for grid to NetCDF file.

    This file is needed only if prediction files are split by space (one per
    grid cell).

    M = number of rows in grid
    N = number of columns in grid

    :param grid_point_latitudes_deg: length-M numpy array of latitudes (deg N).
    :param grid_point_longitudes_deg: length-N numpy array of longitudes
        (deg E).
    :param netcdf_file_name: Path to output file.
    """

    # Check input args.
    error_checking.assert_is_numpy_array(grid_point_latitudes_deg,
                                         num_dimensions=1)
    error_checking.assert_is_valid_lat_numpy_array(grid_point_latitudes_deg)

    error_checking.assert_is_numpy_array(grid_point_longitudes_deg,
                                         num_dimensions=1)
    grid_point_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        grid_point_longitudes_deg)

    # Write to NetCDF file.
    file_system_utils.mkdir_recursive_if_necessary(file_name=netcdf_file_name)
    dataset_object = netCDF4.Dataset(netcdf_file_name,
                                     'w',
                                     format='NETCDF3_64BIT_OFFSET')

    dataset_object.createDimension(GRID_ROW_DIMENSION_KEY,
                                   len(grid_point_latitudes_deg))
    dataset_object.createDimension(GRID_COLUMN_DIMENSION_KEY,
                                   len(grid_point_longitudes_deg))

    dataset_object.createVariable(LATITUDES_KEY,
                                  datatype=numpy.float32,
                                  dimensions=GRID_ROW_DIMENSION_KEY)
    dataset_object.variables[LATITUDES_KEY][:] = grid_point_latitudes_deg

    dataset_object.createVariable(LONGITUDES_KEY,
                                  datatype=numpy.float32,
                                  dimensions=GRID_COLUMN_DIMENSION_KEY)
    dataset_object.variables[LONGITUDES_KEY][:] = grid_point_longitudes_deg

    dataset_object.close()
Beispiel #15
0
def latlng_to_rowcol(latitudes_deg, longitudes_deg, nw_grid_point_lat_deg,
                     nw_grid_point_lng_deg, lat_spacing_deg, lng_spacing_deg):
    """Converts radar coordinates from lat-long to row-column.

    P = number of input grid points

    :param latitudes_deg: length-P numpy array with latitudes (deg N) of grid
        points.
    :param longitudes_deg: length-P numpy array with longitudes (deg E) of
        grid points.
    :param nw_grid_point_lat_deg: Latitude (deg N) of northwesternmost grid
        point.
    :param nw_grid_point_lng_deg: Longitude (deg E) of northwesternmost grid
        point.
    :param lat_spacing_deg: Spacing (deg N) between meridionally adjacent grid
        points.
    :param lng_spacing_deg: Spacing (deg E) between zonally adjacent grid
        points.
    :return: grid_rows: length-P numpy array with row indices of grid points
        (increasing from north to south).
    :return: grid_columns: length-P numpy array with column indices of grid
        points (increasing from west to east).
    """

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg,
                                                   allow_nan=True)
    error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1)
    num_points = len(latitudes_deg)

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg, allow_nan=True)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    error_checking.assert_is_valid_latitude(nw_grid_point_lat_deg)
    nw_grid_point_lng_deg = lng_conversion.convert_lng_positive_in_west(
        nw_grid_point_lng_deg, allow_nan=False)

    error_checking.assert_is_greater(lat_spacing_deg, 0.)
    error_checking.assert_is_greater(lng_spacing_deg, 0.)

    grid_columns = rounder.round_to_nearest(
        (longitudes_deg - nw_grid_point_lng_deg) / lng_spacing_deg, 0.5)
    grid_rows = rounder.round_to_nearest(
        (nw_grid_point_lat_deg - latitudes_deg) / lat_spacing_deg, 0.5)
    return grid_rows, grid_columns
def init_lcc_projection(standard_latitudes_deg,
                        central_longitude_deg,
                        ellipsoid_name=SPHERE_NAME,
                        earth_radius_metres=DEFAULT_EARTH_RADIUS_METRES):
    """Initializes LCC (Lambert conformal conic) projection.

    :param standard_latitudes_deg: length-2 numpy array of standard parallels
        (deg N).
    :param central_longitude_deg: Central meridian (deg E).
    :param ellipsoid_name: Ellipsoid (examples are "sphere" and "WGS84").
    :param earth_radius_metres: [used only if ellipsoid_name = "sphere"]
        Earth radius.
    :return: projection_object: Instance of `pyproj.Proj`, specifying the LCC
        projection.
    """

    error_checking.assert_is_valid_lat_numpy_array(standard_latitudes_deg)
    these_expected_dim = numpy.array([2], dtype=int)
    error_checking.assert_is_numpy_array(standard_latitudes_deg,
                                         exact_dimensions=these_expected_dim)

    error_checking.assert_is_non_array(central_longitude_deg)
    central_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        central_longitude_deg, allow_nan=False)

    _check_ellipsoid(ellipsoid_name)

    if ellipsoid_name == SPHERE_NAME:
        error_checking.assert_is_greater(earth_radius_metres, 0.)

        return Proj(proj='lcc',
                    lat_1=standard_latitudes_deg[0],
                    lat_2=standard_latitudes_deg[1],
                    lon_0=central_longitude_deg,
                    rsphere=earth_radius_metres,
                    ellps=ellipsoid_name)

    return Proj(proj='lcc',
                lat_1=standard_latitudes_deg[0],
                lat_2=standard_latitudes_deg[1],
                lon_0=central_longitude_deg,
                ellps=ellipsoid_name)
def _check_boundary(latitudes_deg, longitudes_deg):
    """Error-checks boundary.

    V = number of vertices in boundary

    :param latitudes_deg: length-V numpy array of latitudes (deg N).
    :param longitudes_deg: length-V numpy array of longitudes (deg E).
    :return: longitudes_deg: Same as input but positive in western hemisphere.
    """

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg=longitudes_deg, allow_nan=False)
    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg=latitudes_deg,
                                                   allow_nan=False)

    num_vertices = len(latitudes_deg)
    expected_dim = numpy.array([num_vertices], dtype=int)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=expected_dim)

    return longitudes_deg
Beispiel #18
0
def get_latlng_centroid(latitudes_deg, longitudes_deg, allow_nan=True):
    """Finds centroid of lat-long points.

    P = number of points

    :param latitudes_deg: length-P numpy array of latitudes (deg N).
    :param longitudes_deg: length-P numpy array of longitudes (deg E).
    :param allow_nan: Boolean flag.  If True, input arrays may contain NaN's
        (however, NaN's must occur at the exact same positions in the two
        arrays).
    :return: centroid_lat_deg: Centroid latitude (deg N).
    :return: centroid_lng_deg: Centroid longitude (deg E).
    :raises: ValueError: if allow_nan = True but NaN's do not occur at the same
        positions in the two arrays.
    """

    error_checking.assert_is_boolean(allow_nan)
    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg, allow_nan)
    error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1)
    num_points = len(latitudes_deg)

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg, allow_nan)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    nan_latitude_indices = numpy.where(numpy.isnan(latitudes_deg))[0]
    nan_longitude_indices = numpy.where(numpy.isnan(longitudes_deg))[0]
    if not numpy.array_equal(nan_latitude_indices, nan_longitude_indices):
        error_string = (
            '\nNaN'
            's occur at the following positions in `latitudes_deg`:\n' +
            str(nan_latitude_indices) +
            '\nand the following positions in `longitudes_deg`:\n' +
            str(nan_longitude_indices) + '\nNaN'
            's should occur at the same positions in the two arrays.')
        raise ValueError(error_string)

    return numpy.nanmean(latitudes_deg), numpy.nanmean(longitudes_deg)
Beispiel #19
0
def get_wind_rotation_angles(latitudes_deg, longitudes_deg, model_name):
    """Computes wind-rotation angle for each lat-long point.

    These angles may be used in `rotate_winds_to_earth_relative` or
    `rotate_winds_to_grid_relative`.

    :param latitudes_deg: numpy array of latitudes (deg N).
    :param longitudes_deg: equivalent-shape numpy array of longitudes (deg E).
    :param model_name: Model name (string).  This model must use a Lambert
        conformal grid.
    :return: rotation_angle_cosines: equivalent-shape numpy array with cosines
        of rotation angles.
    :return: rotation_angle_sines: equivalent-shape numpy array with sines of
        rotation angles.
    """

    # TODO(thunderhoser): ensure that the model uses a Lambert conformal grid.
    # For now the models allowed in GewitterGefahr are the NARR, RUC, and RAP --
    # all of which use a Lambert conformal grid.  But this may change.

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg,
                                                   allow_nan=False)

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg, allow_nan=False)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=numpy.asarray(
                                             latitudes_deg.shape))

    standard_latitudes_deg, central_longitude_deg = get_projection_params(
        model_name=model_name)

    rotation_angles = (
        numpy.sin(standard_latitudes_deg[0] * DEGREES_TO_RADIANS) *
        (longitudes_deg - central_longitude_deg) * DEGREES_TO_RADIANS)
    return numpy.cos(rotation_angles), numpy.sin(rotation_angles)
def plot_storm_track(basemap_object=None, axes_object=None, latitudes_deg=None,
                     longitudes_deg=None, line_colour=DEFAULT_TRACK_COLOUR,
                     line_width=DEFAULT_TRACK_WIDTH,
                     line_style=DEFAULT_TRACK_STYLE,
                     start_marker=DEFAULT_TRACK_START_MARKER,
                     end_marker=DEFAULT_TRACK_END_MARKER,
                     start_marker_size=DEFAULT_TRACK_START_MARKER_SIZE,
                     end_marker_size=DEFAULT_TRACK_END_MARKER_SIZE):
    """Plots storm track (path of storm centroid).

    P = number of points in track

    :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`.
    :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`.
    :param latitudes_deg: length-P numpy array of latitudes (deg N).
    :param longitudes_deg: length-P numpy array of longitudes (deg E).
    :param line_colour: Colour (in any format accepted by `matplotlib.colors`).
    :param line_width: Line width (real positive number).
    :param line_style: Line style (in any format accepted by
        `matplotlib.lines`).
    :param start_marker: Marker type for beginning of track (in any format
        accepted by `matplotlib.lines`).  This may also be None.
    :param end_marker: Marker type for end of track (in any format accepted by
        `matplotlib.lines`).  This may also be None.
    :param start_marker_size: Size of marker at beginning of track.
    :param end_marker_size: Size of marker at end of track.
    """

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg)
    error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1)
    num_points = len(latitudes_deg)

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(longitudes_deg)
    error_checking.assert_is_numpy_array(
        longitudes_deg, exact_dimensions=numpy.array([num_points]))

    x_coords_metres, y_coords_metres = basemap_object(
        longitudes_deg, latitudes_deg)
    axes_object.plot(
        x_coords_metres, y_coords_metres, color=line_colour,
        linestyle=line_style, linewidth=line_width)

    if start_marker is not None:
        if start_marker == 'x':
            start_marker_edge_width = 2
        else:
            start_marker_edge_width = 1

        axes_object.plot(
            x_coords_metres[0], y_coords_metres[0], linestyle='None',
            marker=start_marker, markerfacecolor=line_colour,
            markeredgecolor=line_colour, markersize=start_marker_size,
            markeredgewidth=start_marker_edge_width)

    if end_marker is not None:
        if end_marker == 'x':
            end_marker_edge_width = 2
        else:
            end_marker_edge_width = 1

        axes_object.plot(
            x_coords_metres[-1], y_coords_metres[-1], linestyle='None',
            marker=end_marker, markerfacecolor=line_colour,
            markeredgecolor=line_colour, markersize=end_marker_size,
            markeredgewidth=end_marker_edge_width)
def create_map_with_nwp_proj(model_name,
                             grid_name=None,
                             latlng_limit_dict=None,
                             xy_limit_dict=None,
                             figure_width_inches=DEFAULT_FIGURE_WIDTH_INCHES,
                             figure_height_inches=DEFAULT_FIGURE_HEIGHT_INCHES,
                             resolution_string=DEFAULT_RESOLUTION_STRING):
    """Initializes map with same projection as NWP model.

    However, this map will have false easting = false northing = 0 metres.

    If `latlng_limit_dict is not None`, corners of the map will be determined by
    lat-long coords.

    If `xy_limit_dict is not None`, corners of the map will be determined by
    x-y coords.

    If both are None, corners of the map will be x-y corners of model grid.

    :param model_name: See doc for `nwp_model_utils.check_grid_name`.
    :param grid_name: See doc for `nwp_model_utils.check_grid_name`.
    :param latlng_limit_dict: Dictionary with the following keys:
    latlng_limit_dict['min_latitude_deg']: Minimum latitude (deg N) in map.
    latlng_limit_dict['max_latitude_deg']: Max latitude (deg N) in map.
    latlng_limit_dict['min_longitude_deg']: Minimum longitude (deg E) in map.
    latlng_limit_dict['max_longitude_deg']: Max longitude (deg E) in map.

    :param xy_limit_dict: Dictionary with the following keys:
    xy_limit_dict['x_min_metres']: Minimum x-coord in map.
    xy_limit_dict['x_max_metres']: Max x-coord in map.
    xy_limit_dict['y_min_metres']: Minimum y-coord in map.
    xy_limit_dict['y_max_metres']: Max y-coord in map.

    :param figure_width_inches: Figure width.
    :param figure_height_inches: Figure height.
    :param resolution_string: See doc for `create_lambert_conformal_map`.
    :return: figure_object: Same.
    :return: axes_object: Same.
    :return: basemap_object: Same.
    """

    nwp_model_utils.check_grid_name(model_name=model_name, grid_name=grid_name)

    standard_latitudes_deg, central_longitude_deg = (
        nwp_model_utils.get_projection_params(model_name))

    if latlng_limit_dict is None and xy_limit_dict is None:
        all_x_coords_metres, all_y_coords_metres = (
            nwp_model_utils.get_xy_grid_cell_edges(model_name=model_name,
                                                   grid_name=grid_name))

        false_easting_metres, false_northing_metres = (
            nwp_model_utils.get_false_easting_and_northing(
                model_name=model_name, grid_name=grid_name))

        all_x_coords_metres -= false_easting_metres
        all_y_coords_metres -= false_northing_metres

        xy_limit_dict = {
            X_MIN_KEY: numpy.min(all_x_coords_metres),
            X_MAX_KEY: numpy.max(all_x_coords_metres),
            Y_MIN_KEY: numpy.min(all_y_coords_metres),
            Y_MAX_KEY: numpy.max(all_y_coords_metres)
        }

    figure_object, axes_object = pyplot.subplots(
        1, 1, figsize=(figure_width_inches, figure_height_inches))

    if latlng_limit_dict is not None:
        min_latitude_deg = latlng_limit_dict[MIN_LATITUDE_KEY]
        max_latitude_deg = latlng_limit_dict[MAX_LATITUDE_KEY]

        error_checking.assert_is_valid_lat_numpy_array(
            numpy.array([min_latitude_deg, max_latitude_deg]))

        min_longitude_deg = lng_conversion.convert_lng_positive_in_west(
            latlng_limit_dict[MIN_LONGITUDE_KEY])

        max_longitude_deg = lng_conversion.convert_lng_positive_in_west(
            latlng_limit_dict[MAX_LONGITUDE_KEY])

        error_checking.assert_is_greater(max_latitude_deg, min_latitude_deg)
        error_checking.assert_is_greater(max_longitude_deg, min_longitude_deg)

        basemap_object = Basemap(projection='lcc',
                                 lat_1=standard_latitudes_deg[0],
                                 lat_2=standard_latitudes_deg[1],
                                 lon_0=central_longitude_deg,
                                 rsphere=EARTH_RADIUS_METRES,
                                 ellps=ELLIPSOID_NAME,
                                 resolution=resolution_string,
                                 llcrnrlat=min_latitude_deg,
                                 llcrnrlon=min_longitude_deg,
                                 urcrnrlat=max_latitude_deg,
                                 urcrnrlon=max_longitude_deg)
    else:
        x_min_metres = xy_limit_dict[X_MIN_KEY]
        x_max_metres = xy_limit_dict[X_MAX_KEY]
        y_min_metres = xy_limit_dict[Y_MIN_KEY]
        y_max_metres = xy_limit_dict[Y_MAX_KEY]

        error_checking.assert_is_greater(x_max_metres, x_min_metres)
        error_checking.assert_is_greater(y_max_metres, y_min_metres)

        basemap_object = Basemap(projection='lcc',
                                 lat_1=standard_latitudes_deg[0],
                                 lat_2=standard_latitudes_deg[1],
                                 lon_0=central_longitude_deg,
                                 rsphere=EARTH_RADIUS_METRES,
                                 ellps=ELLIPSOID_NAME,
                                 resolution=resolution_string,
                                 llcrnrx=x_min_metres,
                                 urcrnrx=x_max_metres,
                                 llcrnry=y_min_metres,
                                 urcrnry=y_max_metres)

    return figure_object, axes_object, basemap_object
Beispiel #22
0
def plot_wind_barbs(basemap_object,
                    axes_object,
                    latitudes_deg,
                    longitudes_deg,
                    u_winds_m_s01,
                    v_winds_m_s01,
                    barb_length=DEFAULT_BARB_LENGTH,
                    barb_width=DEFAULT_BARB_WIDTH,
                    empty_barb_radius=DEFAULT_EMPTY_BARB_RADIUS,
                    fill_empty_barb=FILL_EMPTY_BARB_DEFAULT,
                    colour_map=DEFAULT_COLOUR_MAP,
                    colour_minimum_kt=DEFAULT_COLOUR_MINIMUM_KT,
                    colour_maximum_kt=DEFAULT_COLOUR_MAXIMUM_KT):
    """Plots wind barbs.

    N = number of wind barbs

    :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`.
    :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`.
    :param latitudes_deg: length-N numpy array with latitudes (deg N) of wind-
        observation points.
    :param longitudes_deg: length-N numpy array with longitudes (deg E) of wind-
        observation points.
    :param u_winds_m_s01: length-N numpy array with zonal wind components
        ("u-winds") at observation points (metres per second).
    :param v_winds_m_s01: length-N numpy array with meridional wind components
        ("v-winds") at observation points (metres per second).
    :param barb_length: Length of wind barb.
    :param barb_width: Width of wind barb.
    :param empty_barb_radius: Radius of "empty" wind barb (which is actually a
        circle, denoting 0 metres per second).
    :param fill_empty_barb: Boolean flag.  If True, "empty" wind barbs (circles)
        will be coloured in.
    :param colour_map: Instance of `matplotlib.pyplot.cm`.
    :param colour_minimum_kt: Minimum wind speed (nautical miles per hour) in
        colour map.
    :param colour_maximum_kt: Max wind speed (nautical miles per hour) in colour
        map.
    """

    error_checking.assert_is_valid_lat_numpy_array(latitudes_deg)
    error_checking.assert_is_numpy_array(latitudes_deg, num_dimensions=1)
    num_points = len(latitudes_deg)

    longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg)
    error_checking.assert_is_numpy_array(longitudes_deg,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    error_checking.assert_is_numpy_array_without_nan(u_winds_m_s01)
    error_checking.assert_is_numpy_array(u_winds_m_s01,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    error_checking.assert_is_numpy_array_without_nan(v_winds_m_s01)
    error_checking.assert_is_numpy_array(v_winds_m_s01,
                                         exact_dimensions=numpy.array(
                                             [num_points]))

    # error_checking.assert_is_geq(colour_minimum_kt, 0.)
    error_checking.assert_is_greater(colour_maximum_kt, colour_minimum_kt)

    x_coords_metres, y_coords_metres = basemap_object(longitudes_deg,
                                                      latitudes_deg)

    size_dict = {'emptybarb': empty_barb_radius}
    colour_limits_kt = numpy.array([colour_minimum_kt, colour_maximum_kt])
    wind_speeds_m_s01 = numpy.sqrt(u_winds_m_s01**2 + v_winds_m_s01**2)

    axes_object.barbs(x_coords_metres,
                      y_coords_metres,
                      u_winds_m_s01 * METRES_PER_SECOND_TO_KT,
                      v_winds_m_s01 * METRES_PER_SECOND_TO_KT,
                      wind_speeds_m_s01 * METRES_PER_SECOND_TO_KT,
                      length=barb_length,
                      sizes=size_dict,
                      fill_empty=fill_empty_barb,
                      rounding=False,
                      cmap=colour_map,
                      clim=colour_limits_kt,
                      linewidth=barb_width)
def plot_front_with_markers(
        line_latitudes_deg,
        line_longitudes_deg,
        axes_object,
        basemap_object,
        marker_spacing_metres=DEFAULT_MARKER_SPACING_METRES,
        marker_type=None,
        front_type_string=None,
        marker_colour=DEFAULT_MARKER_COLOUR,
        marker_size=DEFAULT_MARKER_SIZE):
    """Plots front with markers (instead of a line).

    P = number of points in line

    :param line_latitudes_deg: length-P numpy array of latitudes (deg N).
    :param line_longitudes_deg: length-P numpy array of longitudes (deg E).
    :param axes_object: Front will be plotted on these axes (instance of
        `matplotlib.axes._subplots.AxesSubplot`).
    :param basemap_object: Basemap used to convert lat-long coordinates to x-y
        (instance of `mpl_toolkits.basemap.Basemap`).
    :param marker_spacing_metres: Spacing between successive markers.
    :param marker_type: Marker type (any format accepted by matplotlib).
    :param front_type_string: [used only if `marker_type is None`]
        Front type (determines marker type).
    :param marker_colour: Marker colour (any format accepted by matplotlib).
    :param marker_size: Marker size (any format accepted by matplotlib).
    """

    error_checking.assert_is_valid_lat_numpy_array(line_latitudes_deg)
    error_checking.assert_is_numpy_array(line_latitudes_deg, num_dimensions=1)

    num_points = len(line_latitudes_deg)
    these_expected_dim = numpy.array([num_points], dtype=int)
    error_checking.assert_is_numpy_array(line_longitudes_deg,
                                         exact_dimensions=these_expected_dim)

    line_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        line_longitudes_deg)

    error_checking.assert_is_greater(marker_spacing_metres, 0.)

    if marker_type is None:
        front_utils.check_front_type(front_type_string)

        if front_type_string == front_utils.WARM_FRONT_STRING_ID:
            marker_type = DEFAULT_WF_MARKER_TYPE
        else:
            marker_type = DEFAULT_CF_MARKER_TYPE

    x_coords_metres, y_coords_metres = basemap_object(line_longitudes_deg,
                                                      line_latitudes_deg)

    for i in range(num_points - 1):
        this_x_diff_metres = x_coords_metres[i + 1] - x_coords_metres[i]
        this_y_diff_metres = y_coords_metres[i + 1] - y_coords_metres[i]
        this_distance_metres = numpy.sqrt(this_x_diff_metres**2 +
                                          this_y_diff_metres**2)

        this_num_points = 1 + int(
            numpy.ceil(this_distance_metres / marker_spacing_metres))

        these_x_coords_metres = numpy.linspace(x_coords_metres[i],
                                               x_coords_metres[i + 1],
                                               num=this_num_points)
        these_y_coords_metres = numpy.linspace(y_coords_metres[i],
                                               y_coords_metres[i + 1],
                                               num=this_num_points)

        axes_object.plot(these_x_coords_metres,
                         these_y_coords_metres,
                         linestyle='None',
                         marker=marker_type,
                         markerfacecolor=marker_colour,
                         markeredgecolor=marker_colour,
                         markersize=marker_size,
                         markeredgewidth=0.1)
Beispiel #24
0
    def test_assert_is_valid_lat_numpy_array_all_invalid(self):
        """Checks assert_is_valid_lat_numpy_array; all latitudes invalid."""

        with self.assertRaises(ValueError):
            error_checking.assert_is_valid_lat_numpy_array(
                LAT_NUMPY_ARRAY_INVALID_DEG)
Beispiel #25
0
    def test_assert_is_valid_lat_numpy_array_true(self):
        """Checks assert_is_valid_lat_numpy_array; all latitudes valid."""

        error_checking.assert_is_valid_lat_numpy_array(LAT_NUMPY_ARRAY_DEG)
Beispiel #26
0
def plot_storm_track(basemap_object,
                     axes_object,
                     centroid_latitudes_deg,
                     centroid_longitudes_deg,
                     line_colour=DEFAULT_TRACK_COLOUR,
                     line_width=DEFAULT_TRACK_WIDTH,
                     line_style=DEFAULT_TRACK_STYLE,
                     start_marker=DEFAULT_START_MARKER_TYPE,
                     end_marker=DEFAULT_END_MARKER_TYPE,
                     start_marker_size=DEFAULT_START_MARKER_SIZE,
                     end_marker_size=DEFAULT_END_MARKER_SIZE):
    """Plots storm track (path of centroid).

    P = number of points in track

    :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`.
    :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`.
    :param centroid_latitudes_deg: length-P numpy array with latitudes (deg N)
        of storm centroid.
    :param centroid_longitudes_deg: length-P numpy array with longitudes (deg E)
        of storm centroid.
    :param line_colour: Colour (in any format accepted by `matplotlib.colors`).
    :param line_width: Line width (real positive number).
    :param line_style: Line style (in any format accepted by
        `matplotlib.lines`).
    :param start_marker: Marker type for beginning of track (in any format
        accepted by `matplotlib.lines`).  This may also be None.
    :param end_marker: Marker type for end of track (in any format accepted by
        `matplotlib.lines`).  This may also be None.
    :param start_marker_size: Size of marker at beginning of track.
    :param end_marker_size: Size of marker at end of track.
    """

    # TODO(thunderhoser): Get rid of this method (or clean it up a lot).

    error_checking.assert_is_valid_lat_numpy_array(centroid_latitudes_deg)
    error_checking.assert_is_numpy_array(centroid_latitudes_deg,
                                         num_dimensions=1)

    centroid_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
        centroid_longitudes_deg)

    num_points = len(centroid_latitudes_deg)
    these_expected_dim = numpy.array([num_points], dtype=int)
    error_checking.assert_is_numpy_array(centroid_longitudes_deg,
                                         exact_dimensions=these_expected_dim)

    centroid_x_coords_metres, centroid_y_coords_metres = basemap_object(
        centroid_longitudes_deg, centroid_latitudes_deg)

    line_colour_tuple = plotting_utils.colour_from_numpy_to_tuple(line_colour)

    axes_object.plot(centroid_x_coords_metres,
                     centroid_y_coords_metres,
                     color=line_colour_tuple,
                     linestyle=line_style,
                     linewidth=line_width)

    if start_marker is not None:
        if start_marker == 'x':
            this_edge_width = 2
        else:
            this_edge_width = 1

        axes_object.plot(centroid_x_coords_metres[0],
                         centroid_y_coords_metres[0],
                         linestyle='None',
                         marker=start_marker,
                         markerfacecolor=line_colour_tuple,
                         markeredgecolor=line_colour_tuple,
                         markersize=start_marker_size,
                         markeredgewidth=this_edge_width)

    if end_marker is not None:
        if end_marker == 'x':
            this_edge_width = 2
        else:
            this_edge_width = 1

        axes_object.plot(centroid_x_coords_metres[-1],
                         centroid_y_coords_metres[-1],
                         linestyle='None',
                         marker=end_marker,
                         markerfacecolor=line_colour_tuple,
                         markeredgecolor=line_colour_tuple,
                         markersize=end_marker_size,
                         markeredgewidth=this_edge_width)
def create_lambert_conformal_map(
        min_latitude_deg,
        max_latitude_deg,
        min_longitude_deg,
        max_longitude_deg,
        standard_latitudes_deg=numpy.full(2, 25.),
        central_longitude_deg=265.,
        figure_width_inches=DEFAULT_FIGURE_WIDTH_INCHES,
        figure_height_inches=DEFAULT_FIGURE_HEIGHT_INCHES,
        resolution_string=DEFAULT_RESOLUTION_STRING):
    """Creates Lambert conformal map.

    This method only initializes a map with the Lambert conformal projection.
    It does not plot anything.

    Latitudes must be in deg N, and longitudes must be in deg E.

    :param min_latitude_deg: See doc for `_check_basemap_args`.
    :param max_latitude_deg: Same.
    :param min_longitude_deg: Same.
    :param max_longitude_deg: Same.
    :param standard_latitudes_deg: length-2 numpy array of standard latitudes
        for projection.
    :param central_longitude_deg: Central longitude for projection.
    :param figure_width_inches: Figure width.
    :param figure_height_inches: Figure height.
    :param resolution_string: See doc for `_check_basemap_args`.
    :return: figure_object: Figure handle (instance of
        `matplotlib.figure.Figure`).
    :return: axes_object: Axes handle (instance of
        `matplotlib.axes._subplots.AxesSubplot`).
    :return: basemap_object: Basemap handle (instance of
        `mpl_toolkits.basemap.Basemap`).
    """

    min_longitude_deg, max_longitude_deg = _check_basemap_args(
        min_latitude_deg=min_latitude_deg,
        max_latitude_deg=max_latitude_deg,
        min_longitude_deg=min_longitude_deg,
        max_longitude_deg=max_longitude_deg,
        resolution_string=resolution_string)

    error_checking.assert_is_valid_lat_numpy_array(standard_latitudes_deg)
    error_checking.assert_is_numpy_array(standard_latitudes_deg,
                                         exact_dimensions=numpy.array(
                                             [2], dtype=int))

    error_checking.assert_is_non_array(central_longitude_deg)
    central_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        central_longitude_deg)

    figure_object, axes_object = pyplot.subplots(
        1, 1, figsize=(figure_width_inches, figure_height_inches))

    basemap_object = Basemap(projection='lcc',
                             lat_1=standard_latitudes_deg[0],
                             lat_2=standard_latitudes_deg[1],
                             lon_0=central_longitude_deg,
                             rsphere=EARTH_RADIUS_METRES,
                             ellps=ELLIPSOID_NAME,
                             resolution=resolution_string,
                             llcrnrlat=min_latitude_deg,
                             llcrnrlon=min_longitude_deg,
                             urcrnrlat=max_latitude_deg,
                             urcrnrlon=max_longitude_deg)

    return figure_object, axes_object, basemap_object
def read_highs_and_lows(text_file_name):
    """Reads locations of high- and low-pressure centers.

    :param text_file_name: Path to input file (text file in WPC format).
    :return: high_low_table: pandas DataFrame with the following columns.  Each
        row is one high- or low-pressure center.
    high_low_table.system_type_string: Type of system (either "high" or "low").
    high_low_table.unix_time_sec: Valid time.
    high_low_table.latitude_deg: Latitude (deg N).
    high_low_table.longitude_deg: Longitude (deg E).
    """

    error_checking.assert_file_exists(text_file_name)
    valid_time_unix_sec = _file_name_to_valid_time(text_file_name)

    system_type_strings = []
    latitudes_deg = numpy.array([], dtype=float)
    longitudes_deg = numpy.array([], dtype=float)

    for this_line in open(text_file_name, 'r').readlines():
        these_words = this_line.split()
        if len(these_words) == 0:
            continue

        this_system_type_string = these_words[0].lower()
        if this_system_type_string not in VALID_SYSTEM_TYPE_STRINGS:
            continue

        these_words = these_words[1:]
        these_latitudes_deg = []
        these_longitudes_deg = []

        for this_word in these_words:
            if len(this_word) < 5:
                continue

            this_latitude_deg, this_longitude_deg = _string_to_latlng(
                latlng_string=this_word, raise_error_if_fails=True)

            these_latitudes_deg.append(this_latitude_deg)
            these_longitudes_deg.append(this_longitude_deg)

        these_latitudes_deg = numpy.array(these_latitudes_deg)
        these_longitudes_deg = numpy.array(these_longitudes_deg)

        if numpy.any(numpy.isnan(these_latitudes_deg)):
            continue

        error_checking.assert_is_valid_lat_numpy_array(these_latitudes_deg)
        these_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
            these_longitudes_deg, allow_nan=False)

        system_type_strings += ([this_system_type_string] *
                                len(these_latitudes_deg))

        latitudes_deg = numpy.concatenate((latitudes_deg, these_latitudes_deg))
        longitudes_deg = numpy.concatenate(
            (longitudes_deg, these_longitudes_deg))

    valid_times_unix_sec = numpy.full(len(system_type_strings),
                                      valid_time_unix_sec,
                                      dtype=int)

    high_low_dict = {
        SYSTEM_TYPE_COLUMN: system_type_strings,
        front_utils.TIME_COLUMN: valid_times_unix_sec,
        LATITUDE_COLUMN: latitudes_deg,
        LONGITUDE_COLUMN: longitudes_deg
    }

    return pandas.DataFrame.from_dict(high_low_dict)
def read_fronts_from_file(text_file_name):
    """Reads locations of warm and cold fronts from WPC bulletin.

    Input file should contain positions of cyclones, anticyclones, fronts, etc.
    for a single valid time.

    :param text_file_name: Path to input file (text file in WPC format).
    :return: front_table: pandas DataFrame with the following columns.  Each row
        is one front.
    front_table.front_type: Type of front (examples: "warm", "cold").
    front_table.unix_time_sec: Valid time.
    front_table.latitudes_deg: 1-D numpy array of latitudes (deg N) along front.
    front_table.longitudes_deg: 1-D numpy array of longitudes (deg E) along
        front.
    """

    error_checking.assert_file_exists(text_file_name)
    valid_time_unix_sec = _file_name_to_valid_time(text_file_name)

    front_types = []
    latitudes_2d_list_deg = []
    longitudes_2d_list_deg = []

    for this_line in open(text_file_name, 'r').readlines():
        these_words = this_line.split()  # Need to skip empty lines.
        if not these_words:
            continue

        this_front_type = these_words[0].lower()
        if this_front_type not in VALID_FRONT_TYPES:
            continue

        these_words = these_words[1:]
        this_num_points = len(these_words)
        these_latitudes_deg = numpy.full(this_num_points, numpy.nan)
        these_longitudes_deg = numpy.full(this_num_points, numpy.nan)

        for i in range(this_num_points):
            these_latitudes_deg[i], these_longitudes_deg[
                i] = _string_to_latlng(these_words[i], False)

        if numpy.any(numpy.isnan(these_latitudes_deg)):
            continue

        error_checking.assert_is_valid_lat_numpy_array(these_latitudes_deg)
        these_longitudes_deg = lng_conversion.convert_lng_positive_in_west(
            these_longitudes_deg, allow_nan=False)

        front_types.append(this_front_type)
        latitudes_2d_list_deg.append(these_latitudes_deg)
        longitudes_2d_list_deg.append(these_longitudes_deg)

    num_fronts = len(front_types)
    valid_times_unix_sec = numpy.full(num_fronts,
                                      valid_time_unix_sec,
                                      dtype=int)

    front_dict = {
        front_utils.FRONT_TYPE_COLUMN: front_types,
        front_utils.TIME_COLUMN: valid_times_unix_sec,
        front_utils.LATITUDES_COLUMN: latitudes_2d_list_deg,
        front_utils.LONGITUDES_COLUMN: longitudes_2d_list_deg
    }
    return pandas.DataFrame.from_dict(front_dict)
Beispiel #30
0
def interp_temperature_surface_from_nwp(
        radar_grid_point_latitudes_deg,
        radar_grid_point_longitudes_deg,
        radar_time_unix_sec,
        critical_temperature_kelvins,
        model_name,
        top_grib_directory_name,
        use_all_grids=True,
        grid_id=None,
        wgrib_exe_name=grib_io.WGRIB_EXE_NAME_DEFAULT,
        wgrib2_exe_name=grib_io.WGRIB2_EXE_NAME_DEFAULT):
    """Interpolates temperature (isothermal) surface from NWP model.

    M = number of rows (unique grid-point latitudes) in radar grid
    N = number of columns (unique grid-point longitudes) in radar grid

    :param radar_grid_point_latitudes_deg: length-M numpy array of grid-point
        latitudes (deg N).
    :param radar_grid_point_longitudes_deg: length-N numpy array of grid-point
        longitudes (deg E).
    :param radar_time_unix_sec: Radar time.
    :param critical_temperature_kelvins: Temperature of isosurface.
    :param model_name: See doc for `interp.interp_temperature_surface_from_nwp`.
    :param top_grib_directory_name: Same.
    :param use_all_grids: Same.
    :param grid_id: Same.
    :param wgrib_exe_name: Same.
    :param wgrib2_exe_name: Same.
    :return: isosurface_height_matrix_m_asl: M-by-N numpy array with heights of
        temperature isosurface (metres above sea level).
    """

    error_checking.assert_is_numpy_array(radar_grid_point_latitudes_deg,
                                         num_dimensions=1)
    error_checking.assert_is_valid_lat_numpy_array(
        radar_grid_point_latitudes_deg)

    error_checking.assert_is_numpy_array(radar_grid_point_longitudes_deg,
                                         num_dimensions=1)
    lng_conversion.convert_lng_positive_in_west(
        radar_grid_point_longitudes_deg, allow_nan=False)

    (radar_latitude_matrix_deg,
     radar_longitude_matrix_deg) = grids.latlng_vectors_to_matrices(
         unique_latitudes_deg=radar_grid_point_latitudes_deg,
         unique_longitudes_deg=radar_grid_point_longitudes_deg)

    num_grid_rows = len(radar_grid_point_latitudes_deg)
    num_grid_columns = len(radar_grid_point_longitudes_deg)
    radar_latitude_vector_deg = numpy.reshape(radar_latitude_matrix_deg,
                                              num_grid_rows * num_grid_columns)
    radar_longitude_vector_deg = numpy.reshape(
        radar_longitude_matrix_deg, num_grid_rows * num_grid_columns)

    query_point_dict = {
        interp.QUERY_LAT_COLUMN: radar_latitude_vector_deg,
        interp.QUERY_LNG_COLUMN: radar_longitude_vector_deg
    }
    query_point_table = pandas.DataFrame.from_dict(query_point_dict)

    isosurface_height_vector_m_asl = interp.interp_temperature_surface_from_nwp(
        query_point_table=query_point_table,
        query_time_unix_sec=radar_time_unix_sec,
        critical_temperature_kelvins=critical_temperature_kelvins,
        model_name=model_name,
        top_grib_directory_name=top_grib_directory_name,
        use_all_grids=use_all_grids,
        grid_id=grid_id,
        wgrib_exe_name=wgrib_exe_name,
        wgrib2_exe_name=wgrib2_exe_name,
        raise_error_if_missing=True)

    return numpy.reshape(isosurface_height_vector_m_asl,
                         (num_grid_rows, num_grid_columns))