Exemplo n.º 1
0
def init_lambert_azimuthal_equal_area_projection(standard_latitude_deg=None,
                                                 central_latitude_deg=None,
                                                 central_longitude_deg=None):
    """Initializes Lambert azimuthal equal-area projection.

    :param standard_latitude_deg: Standard latitude (latitude of true scale)
        (deg N).
    :param central_latitude_deg: Central latitude (deg N).
    :param central_longitude_deg: Central longitude (deg E).
    :return: projection_object: object created by `pyproj.Proj`, specifying the
        Lambert azimuthal equal-area projection.
    """

    error_checking.assert_is_valid_latitude(standard_latitude_deg)
    error_checking.assert_is_valid_latitude(central_latitude_deg)
    central_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        central_longitude_deg, allow_nan=False)

    return Proj(proj='laea',
                lat_ts=standard_latitude_deg,
                lat_0=central_latitude_deg,
                lon_0=central_longitude_deg)
Exemplo n.º 2
0
def get_center_of_grid(nw_grid_point_lat_deg, nw_grid_point_lng_deg,
                       lat_spacing_deg, lng_spacing_deg, num_grid_rows,
                       num_grid_columns):
    """Finds center of radar grid.

    :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.
    :param num_grid_rows: Number of rows (unique grid-point latitudes).
    :param num_grid_columns: Number of columns (unique grid-point longitudes).
    :return: center_latitude_deg: Latitude (deg N) at center of grid.
    :return: center_longitude_deg: Longitude (deg E) at center of grid.
    """

    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.)
    error_checking.assert_is_integer(num_grid_rows)
    error_checking.assert_is_greater(num_grid_rows, 1)
    error_checking.assert_is_integer(num_grid_columns)
    error_checking.assert_is_greater(num_grid_columns, 1)

    min_latitude_deg = nw_grid_point_lat_deg - (
        (num_grid_rows - 1) * lat_spacing_deg)
    max_longitude_deg = nw_grid_point_lng_deg + (
        (num_grid_columns - 1) * lng_spacing_deg)

    return (numpy.mean(numpy.array([min_latitude_deg, nw_grid_point_lat_deg])),
            numpy.mean(numpy.array([nw_grid_point_lng_deg,
                                    max_longitude_deg])))
Exemplo n.º 3
0
def plot_parallels(basemap_object=None,
                   axes_object=None,
                   bottom_left_lat_deg=None,
                   upper_right_lat_deg=None,
                   parallel_spacing_deg=DEFAULT_PARALLEL_SPACING_DEG,
                   line_width=DEFAULT_PARALLEL_MERIDIAN_WIDTH,
                   line_colour=DEFAULT_PARALLEL_MERIDIAN_COLOUR):
    """Draws parallels (lines of equal latitude).

    :param basemap_object: Instance of `mpl_toolkits.basemap.Basemap`.
    :param axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`.
    :param bottom_left_lat_deg: Latitude at bottom-left corner (deg N).
    :param upper_right_lat_deg: Latitude at upper-right corner (deg N).
    :param parallel_spacing_deg: Spacing between successive parallels (deg N).
    :param line_width: Line width (real positive number).
    :param line_colour: Colour (in any format accepted by `matplotlib.colors`).
    """

    error_checking.assert_is_valid_latitude(bottom_left_lat_deg)
    error_checking.assert_is_valid_latitude(upper_right_lat_deg)
    error_checking.assert_is_greater(upper_right_lat_deg, bottom_left_lat_deg)
    error_checking.assert_is_greater(parallel_spacing_deg, 0)

    min_parallel_deg = rounder.ceiling_to_nearest(bottom_left_lat_deg,
                                                  parallel_spacing_deg)
    max_parallel_deg = rounder.floor_to_nearest(upper_right_lat_deg,
                                                parallel_spacing_deg)
    num_parallels_deg = int(1 + (max_parallel_deg - min_parallel_deg) /
                            parallel_spacing_deg)
    parallels_deg = numpy.linspace(min_parallel_deg,
                                   max_parallel_deg,
                                   num=num_parallels_deg)
    basemap_object.drawparallels(parallels_deg,
                                 color=line_colour,
                                 linewidth=line_width,
                                 labels=[True, False, False, False],
                                 ax=axes_object,
                                 zorder=Z_ORDER_MERIDIANS_AND_PARALLELS)
Exemplo n.º 4
0
def init_cylindrical_equidistant_projection(central_latitude_deg,
                                            central_longitude_deg,
                                            true_scale_latitude_deg):
    """Initializes cylindrical equidistant projection.

    :param central_latitude_deg: Central latitude (deg N).
    :param central_longitude_deg: Central longitude (deg E).
    :param true_scale_latitude_deg: Latitude of true scale (deg N).
    :return: projection_object: Instance of `pyproj.Proj`.
    """

    error_checking.assert_is_valid_latitude(central_latitude_deg)
    error_checking.assert_is_valid_latitude(true_scale_latitude_deg)
    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='eqc',
                lat_0=central_latitude_deg,
                lon_0=central_longitude_deg,
                lat_ts=true_scale_latitude_deg,
                rsphere=EARTH_RADIUS_METRES,
                ellps='sphere')
Exemplo n.º 5
0
def _check_basemap_args(min_latitude_deg, max_latitude_deg, min_longitude_deg,
                        max_longitude_deg, resolution_string):
    """Error-checks input args for creating basemap.

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

    Both output values are in deg E, with positive values (180-360) in the
    western hemisphere.  The inputs may be positive or negative in WH.

    :param min_latitude_deg: Minimum latitude in map (bottom-left corner).
    :param max_latitude_deg: Max latitude in map (top-right corner).
    :param min_longitude_deg: Minimum longitude in map (bottom-left corner).
    :param max_longitude_deg: Max longitude in map (top-right corner).
    :param resolution_string: Resolution of boundaries (political borders,
        lakes, rivers, etc.) in basemap.  Options are "c" for crude, "l" for
        low, "i" for intermediate, "h" for high, and "f" for full.
    :return: min_longitude_deg: Minimum longitude (deg E, positive in western
        hemisphere).
    :return: max_longitude_deg: Max longitude (deg E, positive in western
        hemisphere).
    """

    error_checking.assert_is_valid_latitude(min_latitude_deg)
    error_checking.assert_is_valid_latitude(max_latitude_deg)
    error_checking.assert_is_greater(max_latitude_deg, min_latitude_deg)

    min_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        min_longitude_deg)
    max_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        max_longitude_deg)

    error_checking.assert_is_greater(max_longitude_deg, min_longitude_deg)

    error_checking.assert_is_string(resolution_string)

    return min_longitude_deg, max_longitude_deg
Exemplo n.º 6
0
def get_latlng_grid_points_in_radius(
        test_latitude_deg, test_longitude_deg, effective_radius_metres,
        grid_point_latitudes_deg=None, grid_point_longitudes_deg=None,
        grid_point_dict=None):
    """Finds lat-long grid points within radius of test point.

    One of the following sets of input args must be specified:

    - grid_point_latitudes_deg and grid_point_longitudes_deg
    - grid_point_dict

    M = number of rows (unique grid-point latitudes)
    N = number of columns (unique grid-point longitudes)
    K = number of grid points within radius of test point

    :param test_latitude_deg: Latitude (deg N) of test point.
    :param test_longitude_deg: Longitude (deg E) of test point.
    :param effective_radius_metres: Effective radius (will find all grid points
        within this radius of test point).
    :param grid_point_latitudes_deg: length-M numpy array with latitudes (deg N)
        of grid points.
    :param grid_point_longitudes_deg: length-N numpy array with longitudes
        (deg E) of grid points.
    :param grid_point_dict: Dictionary created by a previous run of this method
        (see output documentation).
    :return: rows_in_radius: length-K numpy array with row indices of grid
        points near test point.
    :return: columns_in_radius: Same but for columns.
    :return: grid_point_dict: Dictionary with the following keys.
    grid_point_dict['grid_point_x_matrix_metres']: M-by-N numpy array with
        x-coordinates of grid points.
    grid_point_dict['grid_point_y_matrix_metres']: M-by-N numpy array with
        y-coordinates of grid points.
    grid_point_dict['projection_object']: Instance of `pyproj.Proj`, which can
        be used to convert future test points from lat-long to x-y coordinates.
    """

    if grid_point_dict is None:
        (grid_point_lat_matrix_deg, grid_point_lng_matrix_deg
        ) = latlng_vectors_to_matrices(
            unique_latitudes_deg=grid_point_latitudes_deg,
            unique_longitudes_deg=grid_point_longitudes_deg)

        projection_object = projections.init_azimuthal_equidistant_projection(
            central_latitude_deg=numpy.mean(grid_point_latitudes_deg),
            central_longitude_deg=numpy.mean(grid_point_longitudes_deg))

        (grid_point_x_matrix_metres, grid_point_y_matrix_metres
        ) = projections.project_latlng_to_xy(
            latitudes_deg=grid_point_lat_matrix_deg,
            longitudes_deg=grid_point_lng_matrix_deg,
            projection_object=projection_object)

        grid_point_dict = {
            GRID_POINT_X_MATRIX_KEY: grid_point_x_matrix_metres,
            GRID_POINT_Y_MATRIX_KEY: grid_point_y_matrix_metres,
            PROJECTION_OBJECT_KEY: projection_object
        }

    error_checking.assert_is_valid_latitude(test_latitude_deg)
    error_checking.assert_is_geq(effective_radius_metres, 0.)
    test_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        longitudes_deg=numpy.array([test_longitude_deg]), allow_nan=False)[0]

    (test_x_coords_metres, test_y_coords_metres
    ) = projections.project_latlng_to_xy(
        latitudes_deg=numpy.array([test_latitude_deg]),
        longitudes_deg=numpy.array([test_longitude_deg]),
        projection_object=grid_point_dict[PROJECTION_OBJECT_KEY])
    test_x_coord_metres = test_x_coords_metres[0]
    test_y_coord_metres = test_y_coords_metres[0]

    valid_x_flags = numpy.absolute(
        grid_point_dict[GRID_POINT_X_MATRIX_KEY] - test_x_coord_metres
    ) <= effective_radius_metres
    valid_y_flags = numpy.absolute(
        grid_point_dict[GRID_POINT_Y_MATRIX_KEY] - test_y_coord_metres
    ) <= effective_radius_metres
    rows_to_try, columns_to_try = numpy.where(numpy.logical_and(
        valid_x_flags, valid_y_flags))

    distances_to_try_metres = numpy.sqrt(
        (grid_point_dict[GRID_POINT_X_MATRIX_KEY][rows_to_try, columns_to_try] -
         test_x_coord_metres) ** 2 +
        (grid_point_dict[GRID_POINT_Y_MATRIX_KEY][rows_to_try, columns_to_try] -
         test_y_coord_metres) ** 2)
    valid_indices = numpy.where(
        distances_to_try_metres <= effective_radius_metres)[0]

    return (rows_to_try[valid_indices], columns_to_try[valid_indices],
            grid_point_dict)
Exemplo n.º 7
0
    def test_assert_is_valid_latitude_nan_not_allowed(self):
        """Checks assert_is_valid_latitude; input = NaN, allow_nan = False."""

        with self.assertRaises(ValueError):
            error_checking.assert_is_valid_latitude(numpy.nan, allow_nan=False)
Exemplo n.º 8
0
    def test_assert_is_valid_latitude_nan_allowed(self):
        """Checks assert_is_valid_latitude; input = NaN, allow_nan = True."""

        error_checking.assert_is_valid_latitude(numpy.nan, allow_nan=True)
Exemplo n.º 9
0
    def test_assert_is_valid_latitude_true(self):
        """Checks assert_is_valid_latitude when latitude is valid."""

        error_checking.assert_is_valid_latitude(SINGLE_LATITUDE_DEG)
Exemplo n.º 10
0
    def test_assert_is_valid_latitude_false(self):
        """Checks assert_is_valid_latitude when latitude is invalid."""

        with self.assertRaises(ValueError):
            error_checking.assert_is_valid_latitude(SINGLE_LAT_INVALID_DEG)
def plot_parallels(basemap_object,
                   axes_object,
                   min_latitude_deg=None,
                   max_latitude_deg=None,
                   num_parallels=DEFAULT_NUM_PARALLELS,
                   font_size=FONT_SIZE,
                   line_width=DEFAULT_GRID_LINE_WIDTH,
                   line_colour=DEFAULT_GRID_LINE_COLOUR,
                   z_order=DEFAULT_GRID_LINE_Z_ORDER):
    """Plots parallels (grid lines for latitude).

    If `min_latitude_deg` and `max_latitude_deg` are both None, this method will
    take plotting limits from `basemap_object`.

    :param basemap_object: See doc for `plot_countries`.
    :param axes_object: Same.
    :param min_latitude_deg: Minimum latitude for grid lines.
    :param max_latitude_deg: Max latitude for grid lines.
    :param num_parallels: Number of parallels.
    :param font_size: Font size for tick labels.
    :param line_width: See doc for `plot_countries`.
    :param line_colour: Same.
    :param z_order: Same.
    """

    if min_latitude_deg is None or max_latitude_deg is None:
        latitude_limits_deg = _basemap_to_latlng_limits(basemap_object)[0]
        min_latitude_deg = latitude_limits_deg[0]
        max_latitude_deg = latitude_limits_deg[1]

    error_checking.assert_is_valid_latitude(min_latitude_deg)
    error_checking.assert_is_valid_latitude(max_latitude_deg)
    error_checking.assert_is_greater(max_latitude_deg, min_latitude_deg)

    error_checking.assert_is_integer(num_parallels)
    error_checking.assert_is_geq(num_parallels, 2)

    parallel_spacing_deg = ((max_latitude_deg - min_latitude_deg) /
                            (num_parallels - 1))

    if parallel_spacing_deg < 1.:
        parallel_spacing_deg = number_rounding.round_to_nearest(
            parallel_spacing_deg, 0.1)
    else:
        parallel_spacing_deg = numpy.round(parallel_spacing_deg)

    min_latitude_deg = number_rounding.ceiling_to_nearest(
        min_latitude_deg, parallel_spacing_deg)
    max_latitude_deg = number_rounding.floor_to_nearest(
        max_latitude_deg, parallel_spacing_deg)
    num_parallels = 1 + int(
        numpy.round(
            (max_latitude_deg - min_latitude_deg) / parallel_spacing_deg))
    latitudes_deg = numpy.linspace(min_latitude_deg,
                                   max_latitude_deg,
                                   num=num_parallels)

    basemap_object.drawparallels(latitudes_deg,
                                 color=colour_from_numpy_to_tuple(line_colour),
                                 fontsize=font_size,
                                 linewidth=line_width,
                                 labels=[True, False, False, False],
                                 ax=axes_object,
                                 zorder=z_order)
Exemplo n.º 12
0
def init_lambert_conformal_map(
        standard_latitudes_deg=None,
        central_longitude_deg=None,
        fig_width_inches=DEFAULT_FIG_WIDTH_INCHES,
        fig_height_inches=DEFAULT_FIG_HEIGHT_INCHES,
        resolution_string=DEFAULT_BOUNDARY_RESOLUTION_STRING,
        min_latitude_deg=None,
        max_latitude_deg=None,
        min_longitude_deg=None,
        max_longitude_deg=None):
    """Initializes map with LCC (Lambert conformal conic) projection.

    :param standard_latitudes_deg: length-2 numpy array of standard parallels
        (deg N).  standard_latitudes_deg[i] is the (i + 1)th standard parallel.
    :param central_longitude_deg: Central meridian (deg E).
    :param fig_width_inches: Figure width.
    :param fig_height_inches: Figure height.
    :param resolution_string: Resolution for boundaries (e.g., coastlines and
        political borders).  Options are "c" for crude, "l" for low, "i" for
        intermediate, "h" for high, and "f" for full.  Keep in mind that higher-
        resolution boundaries take much longer to draw.
    :param min_latitude_deg: Latitude at bottom-left corner (deg N).
    :param max_latitude_deg: Latitude at upper-right corner (deg N).
    :param min_longitude_deg: Longitude at bottom-left corner (deg E).
    :param max_longitude_deg: Longitude at upper-right corner (deg E).
    :return: figure_object: Instance of `matplotlib.figure.Figure`.
    :return: axes_object: Instance of `matplotlib.axes._subplots.AxesSubplot`.
    :return: basemap_object: Instance of `mpl_toolkits.basemap.Basemap`.
    """

    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)

    error_checking.assert_is_greater(fig_width_inches, 0)
    error_checking.assert_is_greater(fig_height_inches, 0)
    error_checking.assert_is_string(resolution_string)
    error_checking.assert_is_valid_latitude(min_latitude_deg)
    error_checking.assert_is_valid_latitude(max_latitude_deg)

    error_checking.assert_is_non_array(max_longitude_deg)
    error_checking.assert_is_non_array(min_longitude_deg)
    min_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        min_longitude_deg)
    max_longitude_deg = lng_conversion.convert_lng_positive_in_west(
        max_longitude_deg)

    figure_object, axes_object = pyplot.subplots(1,
                                                 1,
                                                 figsize=(fig_width_inches,
                                                          fig_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,
                             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
Exemplo n.º 13
0
def create_equidistant_grid(min_latitude_deg,
                            max_latitude_deg,
                            min_longitude_deg,
                            max_longitude_deg,
                            x_spacing_metres,
                            y_spacing_metres,
                            azimuthal=True):
    """Creates equidistant grid.

    M = number of rows
    N = number of columns

    :param min_latitude_deg: Minimum latitude (deg N) in grid.
    :param max_latitude_deg: Max latitude (deg N) in grid.
    :param min_longitude_deg: Minimum longitude (deg E) in grid.
    :param max_longitude_deg: Max longitude (deg E) in grid.
    :param x_spacing_metres: Spacing between grid points in adjacent columns.
    :param y_spacing_metres: Spacing between grid points in adjacent rows.
    :param azimuthal: Boolean flag.  If True, will create azimuthal equidistant
        grid.  If False, will create Lambert conformal grid.
    :return: grid_dict: Dictionary with the following keys.
    grid_dict['grid_point_x_coords_metres']: length-N numpy array with unique
        x-coordinates at grid points.
    grid_dict['grid_point_y_coords_metres']: length-M numpy array with unique
        y-coordinates at grid points.
    grid_dict['projection_object']: Instance of `pyproj.Proj` (used to convert
        between lat-long coordinates and the x-y coordinates of the grid).
    """

    # Check input args.
    error_checking.assert_is_valid_latitude(min_latitude_deg)
    error_checking.assert_is_valid_latitude(max_latitude_deg)
    error_checking.assert_is_greater(max_latitude_deg, min_latitude_deg)
    error_checking.assert_is_greater(x_spacing_metres, 0.)
    error_checking.assert_is_greater(y_spacing_metres, 0.)
    error_checking.assert_is_boolean(azimuthal)

    min_longitude_deg = lng_conversion.convert_lng_negative_in_west(
        min_longitude_deg, allow_nan=False)
    max_longitude_deg = lng_conversion.convert_lng_negative_in_west(
        max_longitude_deg, allow_nan=False)
    error_checking.assert_is_greater(max_longitude_deg, min_longitude_deg)

    # Create lat-long grid.
    num_grid_rows = 1 + int(
        numpy.round((max_latitude_deg - min_latitude_deg) /
                    DUMMY_LATITUDE_SPACING_DEG))
    num_grid_columns = 1 + int(
        numpy.round((max_longitude_deg - min_longitude_deg) /
                    DUMMY_LONGITUDE_SPACING_DEG))

    unique_latitudes_deg, unique_longitudes_deg = get_latlng_grid_points(
        min_latitude_deg=min_latitude_deg,
        min_longitude_deg=min_longitude_deg,
        lat_spacing_deg=DUMMY_LATITUDE_SPACING_DEG,
        lng_spacing_deg=DUMMY_LONGITUDE_SPACING_DEG,
        num_rows=num_grid_rows,
        num_columns=num_grid_columns)

    latitude_matrix_deg, longitude_matrix_deg = latlng_vectors_to_matrices(
        unique_latitudes_deg=unique_latitudes_deg,
        unique_longitudes_deg=unique_longitudes_deg)

    # Create projection.
    central_latitude_deg = 0.5 * (min_latitude_deg + max_latitude_deg)
    central_longitude_deg = 0.5 * (min_longitude_deg + max_longitude_deg)

    if azimuthal:
        projection_object = projections.init_azimuthal_equidistant_projection(
            central_latitude_deg=central_latitude_deg,
            central_longitude_deg=central_longitude_deg)
    else:
        projection_object = projections.init_lcc_projection(
            standard_latitudes_deg=numpy.full(2, central_latitude_deg),
            central_longitude_deg=central_longitude_deg)

    # Convert lat-long grid to preliminary x-y grid.
    prelim_x_matrix_metres, prelim_y_matrix_metres = (
        projections.project_latlng_to_xy(latitudes_deg=latitude_matrix_deg,
                                         longitudes_deg=longitude_matrix_deg,
                                         projection_object=projection_object))

    # Find corners of preliminary x-y grid.
    x_min_metres = numpy.min(prelim_x_matrix_metres)
    x_max_metres = numpy.max(prelim_x_matrix_metres)
    y_min_metres = numpy.min(prelim_y_matrix_metres)
    y_max_metres = numpy.max(prelim_y_matrix_metres)

    # Find corners of final x-y grid.
    x_min_metres = number_rounding.floor_to_nearest(x_min_metres,
                                                    x_spacing_metres)
    x_max_metres = number_rounding.ceiling_to_nearest(x_max_metres,
                                                      x_spacing_metres)
    y_min_metres = number_rounding.floor_to_nearest(y_min_metres,
                                                    y_spacing_metres)
    y_max_metres = number_rounding.ceiling_to_nearest(y_max_metres,
                                                      y_spacing_metres)

    # Create final x-y grid.
    num_grid_rows = 1 + int(
        numpy.round((y_max_metres - y_min_metres) / y_spacing_metres))
    num_grid_columns = 1 + int(
        numpy.round((x_max_metres - x_min_metres) / x_spacing_metres))

    unique_x_coords_metres, unique_y_coords_metres = get_xy_grid_points(
        x_min_metres=x_min_metres,
        y_min_metres=y_min_metres,
        x_spacing_metres=x_spacing_metres,
        y_spacing_metres=y_spacing_metres,
        num_rows=num_grid_rows,
        num_columns=num_grid_columns)

    return {
        X_COORDS_KEY: unique_x_coords_metres,
        Y_COORDS_KEY: unique_y_coords_metres,
        PROJECTION_KEY: projection_object
    }
Exemplo n.º 14
0
def subset_tornadoes(tornado_table,
                     min_time_unix_sec=None,
                     max_time_unix_sec=None,
                     min_latitude_deg=None,
                     max_latitude_deg=None,
                     min_longitude_deg=None,
                     max_longitude_deg=None):
    """Subsets tornadoes by time, latitude, and/or longitude.

    :param tornado_table: See doc for `write_processed_file`.
    :param min_time_unix_sec: Minimum time.
    :param max_time_unix_sec: Max time.
    :param min_latitude_deg: Minimum latitude (deg N).
    :param max_latitude_deg: Max latitude (deg N).
    :param min_longitude_deg: Minimum longitude (deg E).
    :param max_longitude_deg: Max longitude (deg E).
    :return: tornado_table: Same as input but maybe with fewer rows.
    """

    # TODO(thunderhoser): Needs unit tests.

    if min_time_unix_sec is not None or max_time_unix_sec is not None:
        error_checking.assert_is_integer(min_time_unix_sec)
        error_checking.assert_is_integer(max_time_unix_sec)
        error_checking.assert_is_greater(max_time_unix_sec, min_time_unix_sec)

        good_start_flags = numpy.logical_and(
            tornado_table[START_TIME_COLUMN].values >= min_time_unix_sec,
            tornado_table[START_TIME_COLUMN].values <= max_time_unix_sec)

        good_end_flags = numpy.logical_and(
            tornado_table[END_TIME_COLUMN].values >= min_time_unix_sec,
            tornado_table[END_TIME_COLUMN].values <= max_time_unix_sec)

        invalid_flags = numpy.invert(
            numpy.logical_or(good_start_flags, good_end_flags))

        invalid_rows = numpy.where(invalid_flags)[0]
        tornado_table.drop(tornado_table.index[invalid_rows],
                           axis=0,
                           inplace=True)

    if min_latitude_deg is not None or max_latitude_deg is not None:
        error_checking.assert_is_valid_latitude(min_latitude_deg)
        error_checking.assert_is_valid_latitude(max_latitude_deg)
        error_checking.assert_is_greater(max_latitude_deg, min_latitude_deg)

        good_start_flags = numpy.logical_and(
            tornado_table[START_LAT_COLUMN].values >= min_latitude_deg,
            tornado_table[START_LAT_COLUMN].values <= max_latitude_deg)

        good_end_flags = numpy.logical_and(
            tornado_table[END_LAT_COLUMN].values >= min_latitude_deg,
            tornado_table[END_LAT_COLUMN].values <= max_latitude_deg)

        invalid_flags = numpy.invert(
            numpy.logical_or(good_start_flags, good_end_flags))

        invalid_rows = numpy.where(invalid_flags)[0]
        tornado_table.drop(tornado_table.index[invalid_rows],
                           axis=0,
                           inplace=True)

    if min_longitude_deg is not None or max_longitude_deg is not None:
        longitude_limits_deg = lng_conversion.convert_lng_positive_in_west(
            longitudes_deg=numpy.array([min_longitude_deg, max_longitude_deg]),
            allow_nan=False)

        min_longitude_deg = longitude_limits_deg[0]
        max_longitude_deg = longitude_limits_deg[1]
        error_checking.assert_is_greater(max_longitude_deg, min_longitude_deg)

        good_start_flags = numpy.logical_and(
            tornado_table[START_LNG_COLUMN].values >= min_longitude_deg,
            tornado_table[START_LNG_COLUMN].values <= max_longitude_deg)

        good_end_flags = numpy.logical_and(
            tornado_table[END_LNG_COLUMN].values >= min_longitude_deg,
            tornado_table[END_LNG_COLUMN].values <= max_longitude_deg)

        invalid_flags = numpy.invert(
            numpy.logical_or(good_start_flags, good_end_flags))

        invalid_rows = numpy.where(invalid_flags)[0]
        tornado_table.drop(tornado_table.index[invalid_rows],
                           axis=0,
                           inplace=True)

    return tornado_table