Ejemplo n.º 1
0
def test_geometry_length_multilinestring():
    geod = geodesic.Geodesic()
    geom = sgeom.MultiLineString(
        [sgeom.LineString(np.array([lhr, jfk]).T),
         sgeom.LineString(np.array([tul, jfk]).T)])
    expected = pytest.approx(lhr_to_jfk + jfk_to_tul, abs=1)
    assert geod.geometry_length(geom) == expected
Ejemplo n.º 2
0
def geodesy_distance_between_points(p_start, p_end):
    geodesic = cgeo.Geodesic()

    distances, start_azimuth, end_azimuth = geodesic.inverse(p_start,
                                                             p_end).base.T

    return distances
Ejemplo n.º 3
0
def _point_along_line(ax, start, distance, angle=0, tol=0.01):
    """Point at a given distance from start at a given angle.

    Args:
        ax:       CartoPy axes.
        start:    Starting point for the line in axes coordinates.
        distance: Positive physical distance to travel.
        angle:    Anti-clockwise angle for the bar, in radians. Default: 0
        tol:      Relative error in distance to allow. Default: 0.01

    Returns:
        Coordinates of a point (a (2, 1)-shaped NumPy array).
    """
    # Direction vector of the line in axes coordinates.
    direction = np.array([np.cos(angle), np.sin(angle)])

    geodesic = cgeo.Geodesic()

    # Physical distance between points.
    def dist_func(a_axes, b_axes):
        a_phys = _axes_to_lonlat(ax, a_axes)
        b_phys = _axes_to_lonlat(ax, b_axes)

        # Geodesic().inverse returns a NumPy MemoryView like [[distance,
        # start azimuth, end azimuth]].
        return geodesic.inverse(a_phys, b_phys).base[0, 0]

    end = _upper_bound(start, direction, distance, dist_func)

    return _distance_along_line(start, end, distance, dist_func, tol)
Ejemplo n.º 4
0
def tissot(rads_km=None, lons=None, lats=None, n_samples=80, globe=None, ax=None, draw=False, **kwargs):
    import numpy as np
    import cartopy.crs as ccrs
    import cartopy.feature as feature
    import shapely.geometry as sgeom
    from cartopy import geodesic
    import cartopy.mpl.patch as cpatch

    geod = geodesic.Geodesic(radius=globe.semimajor_axis, flattening=globe.flattening)
    geoms = []

    rads_km = np.asarray(rads_km)
    lons = np.asarray(lons)
    lats = np.asarray(lats)

    for i in range(len(lons)):
        circle = geod.circle(lons[i], lats[i], rads_km[i],
                             n_samples=n_samples)
        geoms.append(sgeom.Polygon(circle))

    polys = cpatch.geos_to_path(geoms)

    if draw:
        if ax==None: ax = plt.gca()
        f = feature.ShapelyFeature(geoms, ccrs.Geodetic(globe=globe),
                                       **kwargs)
        ax.add_feature(f)

    return polys
Ejemplo n.º 5
0
    def setUp(self):
        """
        Data sampled from the GeographicLib Test Data for Geodesics at:
        http://geographiclib.sourceforge.net/html/geodesic.html#testgeod

        """
        self.geod = geodesic.Geodesic()

        # Fill a 10 by 7 numpy array with starting lons, lats, azimuths; ending
        # lons, lats and azimuths and distances to travel.

        data = np.array([(0.0000000000, 36.5300423550, 176.1258751622,
                          5.7623446947, -48.1642707791, 175.3343083163,
                          9398502.0434687007),
                         (0.0000000000, 20.8766024619, 6.9012827094,
                          163.9792202999, 64.2764863397, 165.0440144913,
                          10462971.2273696996),
                         (0.0000000000, 59.7405712203, 80.9569174535,
                          80.1969954660, 30.9857449391, 144.4488137288,
                          6549489.1863671001),
                         (0.0000000000, 38.6508883588, 18.3455177945,
                          23.5931524958, 66.3457305181, 37.7145989984,
                          3425212.4767990001),
                         (0.0000000000, 23.2214345509, 165.5720618611,
                          148.3625110902, -68.8453788967, 39.2692310682,
                          14506511.2971898001),
                         (0.0000000000, 31.2989275984, 155.7723493796,
                          93.8764112107, -69.2776346668, 98.5250397385,
                          13370814.5013951007),
                         (0.0000000000, 49.6823298563, 1.0175398481,
                          5.3554086646, 83.8681965431, 6.1667605618,
                          3815028.2543704999),
                         (0.0000000000, 32.7651878215, 98.6494285944,
                          70.3527194957, 2.4777491770, 123.5999412794,
                          8030520.7178932996),
                         (0.0000000000, 46.3648067071, 94.9148631993,
                          56.5676529172, 25.2581951337, 130.4405565458,
                          5485075.9286326999),
                         (0.0000000000, 33.7321188396, 147.9041907517,
                          33.1346935645, -26.3211288531, 150.4502346224,
                          7512675.5414637001)],
                        dtype=[('start_lon', np.float64),
                               ('start_lat', np.float64),
                               ('start_azi', np.float64),
                               ('end_lon', np.float64),
                               ('end_lat', np.float64),
                               ('end_azi', np.float64),
                               ('dist', np.float64)])

        self.data = data.view(np.recarray)

        self.start_pts = np.array([self.data.start_lon, self.data.start_lat]).T
        self.end_pts = np.array([self.data.end_lon, self.data.end_lat]).T
        self.dir_soln = np.array([self.data.end_lon, self.data.end_lat,
                                  self.data.end_azi]).T
        self.inv_soln = np.array([self.data.dist, self.data.start_azi,
                                  self.data.end_azi]).T
Ejemplo n.º 6
0
def narrow(lon='auto', lat='auto', ax=None, lfactor=1, **kwargs):
    """
    Plot north arrow.
    
    Parameters:
        lon: Starting longitude (decimal degrees) for arrow
        lat: Starting latitude (ecimal degrees) for arrow
        ax: Axes on which to plot arrow
        lfactor: Length factor to increase/decrease arrow length
    
    Returns:
        ax: Axes with arrow plotted
    """
    if ax is None:
        ax = plt.gca()

    geodesic = cgeo.Geodesic()  # Set up geodesic calculations

    # Get map projection from axes
    crs = ax.projection

    if (lon == 'auto') & (lat == 'auto'):
        trans = ax.transAxes + ax.transData.inverted()
        sx, sy = trans.transform((0.2, 0.2))
        lon, lat = ccrs.Geodetic().transform_point(sx, sy, src_crs=crs)

    # Get geodetic projection for lat/lon - do not confuse with geodesic
    gdet = ccrs.Geodetic()

    # Get axes extent and convert to lat/lon
    x1, x2, y1, y2 = ax.get_extent()
    tlx, tly = gdet.transform_point(x1, y2, src_crs=crs)
    blx, bly = gdet.transform_point(x1, y1, src_crs=crs)
    diff = abs(bly - tly)  # Get x coverage of plot in decimal degrees

    # Get arrow endpoint scaled by diff and lfactor
    end = geodesic.direct(points=[lon, lat],
                          azimuths=0,
                          distances=lfactor * diff * 2 * 10**4)[0]

    # Transform lat-lon into axes coordinates
    xstart, ystart = crs.transform_point(lon, lat, src_crs=ccrs.Geodetic())

    # Get X-Y coordinates of endpoint
    xend, yend = crs.transform_point(end[0], end[1], src_crs=ccrs.Geodetic())

    # Plot arrow as annotation
    ax.annotate("",
                xy=(xstart, ystart),
                xycoords='data',
                xytext=(xend, yend),
                textcoords='data',
                arrowprops=dict(arrowstyle="<|-", connectionstyle="arc3"))
    # Add N to arrow
    ax.text(xend, yend, 'N', fontsize=7, ha='center')

    return (ax)
Ejemplo n.º 7
0
Archivo: core.py Proyecto: jaard/xcroco
def distance2coast(croco_ds, coast='coastline_rho', **kwargs):
    '''
    Calculate the distance to coast from a coastline
    
    Parameters
    ----------
    croco_ds: xr.Dataset
              Provides the variables coastline_rho, lon_rho, lat_rho
    condition: boolean array the same shape as mask_rho to mask the coastline 
               and i.e. remove islands
    '''

    # apply masking condition (i.e. remove islands)
    cline = croco_ds[coast]
    clon = croco_ds.lon_rho
    clat = croco_ds.lat_rho
    if kwargs and 'condition' in kwargs:
        cline = cline.where(kwargs['condition'], drop=True)
        clon = clon.where(kwargs['condition'], drop=True)
        clat = clat.where(kwargs['condition'], drop=True)

    # flatten coast to one dimension
    coast1D = cline.stack(points=(cline.dims))
    lon1D = clon.stack(points=(cline.dims)).where(coast1D, drop=True)
    lat1D = clat.stack(points=(cline.dims)).where(coast1D, drop=True)
    #lonlim = (lon1D > -84)
    #lon1D = lon1D.where(lonlim,drop=True)
    #lat1D = lat1D.where(lonlim,drop=True)
    coastline_from_mask = np.stack([lon1D.values, lat1D.values]).T
    print('Calculating distances to {} coastal points...'.format(
        coastline_from_mask.shape[0]))
    croco_coords = [
        np.array([lo, la]) for lo, la in zip(
            croco_ds.lon_rho.stack(n=(croco_ds.mask_rho.dims)).values,
            croco_ds.lat_rho.stack(n=(croco_ds.mask_rho.dims)).values)
    ]

    geo = cgeo.Geodesic()
    dist_list = []
    update_progress(0)
    for ind, cro in enumerate(croco_coords):
        dists = geo.inverse(cro, coastline_from_mask).base[:, 0] / 1000
        dist_list.append(np.min(dists))
        if ind % 100 == 0:
            update_progress(ind / len(croco_coords))
    distarray = np.array(dist_list)
    update_progress(1)

    dist2coast = xr.zeros_like(
        croco_ds.mask_rho).stack(n=croco_ds.mask_rho.dims)
    dist2coast.values = distarray.T
    dist2coast = dist2coast.unstack('n')

    return dist2coast
Ejemplo n.º 8
0
def _point_along_line(ax, start, distance, projected=False, verbose=False):
    """Point at a given distance from start at a given angle.

    Args:
        ax:       CartoPy axes.
        start:    Starting point for the line in data coordinates.
        distance: Positive physical distance to travel in meters.
        angle:    Anti-clockwise angle for the bar, in degrees. Default: 0

    Returns:
        (lon,lat) coords of a point (a (2, 1)-shaped NumPy array)
    """

    # Direction vector of the line in axes coordinates.

    if not projected:

        geodesic = cgeo.Geodesic()

        Direct_R = geodesic.direct(start, 90, distance)

        target_longitude, target_latitude, forw_azi = Direct_R.base.T

        target_point = ([target_longitude[0], target_latitude[0]])

        actual_dist = geodesic.inverse(start, target_point).base.ravel()[0]
        if verbose:

            print('Starting point', start)

            print('target point', target_point)
            print('Expected distance between points: ', distance)

            print('Actual distance between points: ', actual_dist)

    if projected:

        longitude, latitude = start

        target_longitude = longitude + distance

        target_point = (target_longitude, latitude)

        if verbose:
            print('Axes is projected? ', projected)
            print('Expected distance between points: ', distance)

            print('Actual distance between points: ',
                  target_longitude - longitude)

    return start, target_point
Ejemplo n.º 9
0
def _point_along_line(ax, start, distance, angle=-90, projected=False):
    """Point at a given distance from start at a given angle.

    Args:
        ax:       CartoPy axes.
        start:    Starting point for the line in axes coordinates.
        distance: Positive physical distance to travel in meters.
        angle:    Anti-clockwise angle for the bar, in degrees. Default: 0

    Returns:
        (lon,lat) coords of a point (a (2, 1)-shaped NumPy array)
    """

    start_coords = _axes_to_lonlat(ax, start, projected)

    # Direction vector of the line in axes coordinates.

    if not projected:
        geodesic = cgeo.Geodesic()

        Direct_R = geodesic.direct(start_coords, angle, distance)

        longitudes, latitudes, forw_azi = Direct_R.base.T

        # print('Distance', distance)
        # print('start_coords: ', start_coords)
        # print('longitudes: ', longitudes)

        # actual_dist = geodesic.inverse(start_coords,
        # target_point).base.ravel()[0]
        # print('Starting point', start_coords)

        # print('Ending point', target_point)

        # print('Expected distance between points: ', distance)

        # print('Actual distance between points: ', actual_dist)

    if projected:
        start_coords

        longitudes, latitudes = start_coords

        longitudes = longitudes + np.sin(np.deg2rad(angle)) * distance

    target_point = (longitudes, latitudes)

    return start_coords, target_point
Ejemplo n.º 10
0
def overplot_craters():
    """Overplot a lunar map with known crater outlines"""

    imdata_small = mio.load_lola_downsampled()
    smalldata = downscale_local_mean(imdata_small, factors=(10, 10))

    moon_globe = ccrs.Globe(ellipse=None,  # can remove after #1588/#564
                            semimajor_axis=Constants.moon_radius,
                            flattening=Constants.moon_flattening)
    moon_crs = ccrs.Robinson(globe=moon_globe)
    moon_transform = ccrs.PlateCarree(globe=moon_globe)

    plt.rc('text', usetex=True)
    fig = plt.figure(figsize=(12, 6), dpi=120)
    ax = plt.axes(projection=moon_crs)
    ax.gridlines(color='#252525', linestyle='dotted')
    im = ax.imshow(smalldata, origin="upper", transform=moon_transform)
    cbar = fig.colorbar(im, orientation='vertical', shrink=0.7)
    cbar.set_label(r'$\mathrm{LOLA~digital~elevation~model~(m)}$')
    ax.set_global()

    # Reference: International Astronomical Union (IAU) Planetary Gazetteer
    # CSV data downloaded from:  https://planetarynames.wr.usgs.gov/
    # Check the page here for all the history behind the moon feature naming:
    # https://the-moon.us/wiki/IAU_nomenclature
    iau_fname = os.path.join(Paths.table_dir, 'iau_approved_craters.csv')
    #iau_fname = os.path.join(Paths.table_dir, 'iau_approved_features.csv')
    iau_lunar_craters = pd.read_csv(iau_fname)
    lons = iau_lunar_craters.Center_Longitude
    lats = iau_lunar_craters.Center_Latitude
    radii_in_meters = iau_lunar_craters.Diameter * 500  # km to m
    moon_geodesic = geodesic.Geodesic(radius=Constants.moon_radius,
                                      flattening=Constants.moon_flattening)
    craters = []
    crater_proj = ccrs.Geodetic(globe=moon_globe)
    for lon, lat, radius in zip(lons, lats, radii_in_meters):
        if not radius:
            continue

        crater = moon_geodesic.circle(lon=lon, lat=lat, radius=radius,
                                      n_samples=15)
        craters.append(crater)
        geom = shapely.geometry.Polygon(crater)
        ax.add_geometries((geom,), crs=crater_proj, alpha=0.6,
                          facecolor='none', edgecolor='white', linewidth=0.5)

    plt.savefig(os.path.join(Paths.fig_dir, "lunar_craters.png"), dpi=120)
Ejemplo n.º 11
0
def _point_along_line(ax, start, distance, angle=0, tol=0.01):
    """Point at a given distance from start at a given angle.

    Parameters
    ----------
    ax : :class:`cartopy.mpl.geoaxes.GeoAxes`
        Cartopy axes.
    start : tuple
        Starting point for the line in axes coordinates.
    distance : float
        Positive physical distance to travel.
    angle : float, optional
        Anti-clockwise angle for the bar, in radians. Default: 0
    tol : float, optional
        Relative error in distance to allow. Default: 0.01

    Returns
    -------
    np.ndarray, shape (2, 1)
        Coordinates of a point

    """

    # Direction vector of the line in axes coordinates.
    direction = np.array([np.cos(angle), np.sin(angle)])

    geodesic = cgeo.Geodesic()

    # Physical distance between points.
    def dist_func(a_axes, b_axes):
        a_phys = _axes_to_lonlat(ax, a_axes)
        b_phys = _axes_to_lonlat(ax, b_axes)

        inv = geodesic.inverse(a_phys, b_phys)
        try:
            # Geodesic().inverse returns a NumPy MemoryView like [[distance,
            # start azimuth, end azimuth]].
            return inv.base[0, 0]
        except TypeError:
            # In newer versions, it is a plain numpy array
            return inv[0, 0]

    end = _upper_bound(start, direction, distance, dist_func)

    return _distance_along_line(start, end, distance, dist_func, tol)
Ejemplo n.º 12
0
 def makeErrCircle(self, lat, lon, radius):
     circle_points = cgeodesic.Geodesic().circle(lon=lon, lat=lat, \
         radius=radius, n_samples=100, endpoint=False)
     return sgeometry.Polygon(circle_points)
Ejemplo n.º 13
0
from h3.h3 import H3Index as Index

import networkx

from database import db
from ecoregions import ECOREGIONS, TC, RESOLUTION

try:
    __file__
except NameError:
    __file__ = 'this'

ArrayIndex = t.Tuple[int, int]

# Define some constants
GEODESIC: geodesic.Geodesic = geodesic.Geodesic()

P = t.TypeVar("P", bound=sgeom.Point)


class Point(sgeom.Point):  # type: ignore
    @classmethod
    def from_h3(cls: t.Type[P], index: Index) -> P:
        lat, lon = h3.h3_to_geo(index)
        return cls(lon, lat)

    def __repr__(self) -> str:
        return f"Point(longitude={self.x:}, latitude={self.y:})"

    @property
    def longitude(self) -> float:
Ejemplo n.º 14
0
land_shp_fname = shpreader.natural_earth(resolution='50m',
                                         category='physical',
                                         name='land')

land_geom = unary_union([
    record.geometry for record in shpreader.Reader(land_shp_fname).records()
    if record.attributes.get('featurecla') != "Null island"
])

LAND = prep(land_geom)

DEFINITELY_INLAND = prep(land_geom.buffer(
    -1 / 60., resolution=4))  # 1 arc minute – 2 km near the equator.
BUFFER_NOT_SEA = prep(land_geom.buffer(1 / 60., resolution=4))

GEODESIC = geodesic.Geodesic()


def is_landlocked(xy):
    return DEFINITELY_INLAND.contains(sgeom.Point(*xy))


if __name__ == "__main__":
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("database")
    parser.add_argument("--start")
    args = parser.parse_args()
    engine, tables = db(args.database)
    t_hex = tables["hex"]
    t_dist = tables["dist"]
Ejemplo n.º 15
0
def test_geometry_length_point():
    geod = geodesic.Geodesic()
    geom = sgeom.Point(lhr)
    with pytest.raises(ValueError):
        geod.geometry_length(geom)
Ejemplo n.º 16
0
def test_geometry_length_polygon():
    geod = geodesic.Geodesic()
    geom = sgeom.Polygon(np.array([lhr, jfk, tul]))
    expected = pytest.approx(lhr_to_jfk + jfk_to_tul + tul_to_lhr, abs=1)
    assert geod.geometry_length(geom) == expected
Ejemplo n.º 17
0
ax.background_patch.set_facecolor('k')

for aa in airports:
    #    print('Processing '+aa+'...')
    row = np.where(dat['iata_code'] == aa)[0][0]
    lat = dat.loc[row, :]['latitude_deg']
    lon = dat.loc[row, :]['longitude_deg']
    ax.plot(lon,
            lat,
            'o',
            color='xkcd:electric pink',
            transform=ccrs.Geodetic(),
            alpha=0.7,
            markersize=3)
# Define the geometry for calculating cumulative distance
myGeod = geodesic.Geodesic()
totDist = 0
# Overlay the routes
for tt in trips:
    source = tt[0]
    dest = tt[1]
    sourceInd = np.where(dat['iata_code'] == source)[0][0]
    destInd = np.where(dat['iata_code'] == dest)[0][0]
    sourceLat = dat.loc[sourceInd, :]['latitude_deg']
    sourceLon = dat.loc[sourceInd, :]['longitude_deg']
    destLat = dat.loc[destInd, :]['latitude_deg']
    destLon = dat.loc[destInd, :]['longitude_deg']
    ax.plot(
        [sourceLon, destLon],
        [sourceLat, destLat],
        color='xkcd:neon green',
Ejemplo n.º 18
0
def test_geometry_length_linestring():
    geod = geodesic.Geodesic()
    geom = sgeom.LineString(np.array([lhr, jfk, lhr]).T)
    expected = pytest.approx(lhr_to_jfk * 2, abs=1)
    assert geod.geometry_length(geom) == expected
Ejemplo n.º 19
0
def find_duplicates(craters,
                    radius=1737.4,
                    k=10,
                    rcd=5.,
                    ddiam=0.25,
                    filter_pairs=False):
    """Finds duplicate pairs within crater catalog.

    Triples or more will show up as multiple pairs.

    Parameters
    ----------
    craters : pandas.DataFrame
        Crater catalogue.
    radius : float, optional
        Radius of the world.
    k : int, optional
        Nearest neighbours to search for duplicates.  Default is 10.
    rcd : float, optional
        Minimum value of min(crater_pair_diameters) / pair_distance to be
        considered a crater pair.  Minimum rather than average is used to help
        weed out satellite craters.  This criterion is asymmetric between
        pairs, and when filter_pairs=False may lead to single pair entries.
    ddiam : float, optional
        Maximum value of abs(diameter1 - diameter2) / avg(diameters) to be
        considered a crater pair.
    filter_pairs : bool, optional
        If `True`, filters data frame and keeps only one entry per crater
        pair.

    Returns
    -------
    outframe : pandas.DataFrame
        Data frame of crater duplicate pairs.
    """

    mgeod = geodesic.Geodesic(radius=radius, flattening=0.)

    # Convert to 3D (<https://en.wikipedia.org/wiki/
    # Spherical_coordinate_system#Cartesian_coordinates>); phi = [-180, 180) is
    # equivalent to [0, 360).
    craters['phi'] = np.pi / 180. * craters['Long']
    craters['theta'] = np.pi / 180. * (90 - craters['Lat'])

    craters['x'] = radius * np.sin(craters['theta']) * np.cos(craters['phi'])
    craters['y'] = radius * np.sin(craters['theta']) * np.sin(craters['phi'])
    craters['z'] = radius * np.cos(craters['theta'])

    # Create tree.
    kdt = kd(craters[["x", "y", "z"]].as_matrix(), leafsize=10)

    # Loop over all craters to find duplicates.  First, find k + 1 nearest
    # neighbours (k + 1 because query will include self).
    Lnn, inn = kdt.query(craters[["x", "y", "z"]].as_matrix(), k=k + 1)
    # Remove crater matching with itself (by checking id).
    Lnn_remove_self = np.empty([Lnn.shape[0], Lnn.shape[1] - 1])
    inn_remove_self = np.empty([Lnn.shape[0], Lnn.shape[1] - 1], dtype=int)
    for i in range(Lnn_remove_self.shape[0]):
        not_self = (inn[i] != i)
        inn_remove_self[i] = inn[i][not_self]
        Lnn_remove_self[i] = Lnn[i][not_self]
    craters['Lnn'] = list(Lnn_remove_self)
    craters['inn'] = list(inn_remove_self)

    # Get radii of nearest neighbors.
    inn_ravel = inn[:, 1:].ravel()
    craters['dnn'] = list(
        craters['Diameter (km)'].as_matrix()[inn_ravel].reshape(-1, 10))
    craters['long_nn'] = list(craters['Long'].as_matrix()[inn_ravel].reshape(
        -1, 10))
    craters['lat_nn'] = list(craters['Lat'].as_matrix()[inn_ravel].reshape(
        -1, 10))
    craters['set_nn'] = list(craters['Dataset'].as_matrix()[inn_ravel].reshape(
        -1, 10))

    # Prepare empty lists.
    dup_id1 = []
    dup_id2 = []
    dup_D1 = []
    dup_D2 = []
    dup_L = []
    dup_LEuclid = []
    dup_ll1 = []
    dup_ll2 = []
    dup_source1 = []
    dup_source2 = []

    # Iterate over craters to determine if any are duplicate pairs.
    for index, row in craters.iterrows():
        # For each pair, record the smaller crater diameter.
        pair_diameter_min = np.array(
            [min(x, row['Diameter (km)']) for x in row['dnn']])
        proper_dist = np.asarray(
            mgeod.inverse(np.array([row['Long'], row['Lat']]),
                          np.vstack([row['long_nn'], row['lat_nn']]).T))[:, 0]
        # Duplicate pair criteria: 1). min(diameter) / distance > rcd; 2).
        # abs(diameter1 - diameter2) / average(diameter) < ddiam - i.e. the
        # separation distance of the centres must be much smaller than either
        # diameter, and the diameters should be very similar.
        rcd_crit = (pair_diameter_min / row['Lnn'] > rcd)
        diam_sim_crit = ((2. * abs(row['dnn'] - row['Diameter (km)']) /
                          (row['dnn'] + row['Diameter (km)'])) < ddiam)
        dup_candidates, = np.where(rcd_crit & diam_sim_crit)
        if dup_candidates.size:
            for i in dup_candidates:
                if index == row['inn'][i]:
                    raise AssertionError("Two craters with identical IDs.")
                dup_id1.append(index)
                dup_id2.append(row['inn'][i])
                dup_D1.append(row['Diameter (km)'])
                dup_D2.append(row['dnn'][i])
                dup_L.append(proper_dist[i])
                dup_LEuclid.append(row['Lnn'][i])
                dup_ll1.append((row['Long'], row['Lat']))
                dup_ll2.append((row['long_nn'][i], row['lat_nn'][i]))
                dup_source1.append(row['Dataset'])
                dup_source2.append(row['set_nn'][i])

    # Multi-index pandas table; see
    # <https://pandas.pydata.org/pandas-docs/stable/advanced.html>.

    outframe = pd.DataFrame(
        {
            'ID1': dup_id1,
            'ID2': dup_id2,
            'Diameter1 (km)': dup_D1,
            'Diameter2 (km)': dup_D2,
            'Separation (km)': dup_L,
            'Euclidean Separation (km)': dup_LEuclid,
            'Lat/Long1': dup_ll1,
            'Lat/Long2': dup_ll2,
            'Dataset1': dup_source1,
            'Dataset2': dup_source2
        },
        columns=('ID1', 'ID2', 'Diameter1 (km)', 'Diameter2 (km)',
                 'Separation (km)', 'Euclidean Separation (km)', 'Lat/Long1',
                 'Lat/Long2', 'Dataset1', 'Dataset2'))

    # Hacky, O(N^2) duplicate entry removal.
    if filter_pairs:
        osub = outframe[["ID1", "ID2"]].as_matrix()
        osub = np.array([set(x) for x in osub])
        indices_to_remove = []
        for i in range(osub.shape[0]):
            if i not in indices_to_remove:
                dups = np.where(osub[i + 1:] == osub[i])[0] + i + 1
                indices_to_remove += list(dups)
        indices_to_remove = list(set(indices_to_remove))
        outframe.drop(indices_to_remove, inplace=True)
        outframe.reset_index(inplace=True, drop=True)

    return outframe
Ejemplo n.º 20
0
    def __init__(
            self,
            sites,
            subset=None,
            crs=None):
        """Convert a set of sites into a network.

        This function converts a set of language locations, with their attributes,
        into a network (graph). If a subset is defined, only those sites in the
        subset go into the network.

        Args:
            sites(dict): a dict of sites with keys "locations", "id"
            subset(list): boolean assignment of sites to subset
        Returns:
            dict: a network

        """
        if crs is not None:
            try:
                from cartopy import crs as ccrs, geodesic
            except ImportError as e:
                print("Using a coordinate reference system (crs) requires the ´cartopy´ library:")
                print("pip install cartopy")
                raise e

        if subset is None:
            # Define vertices and edges
            vertices = sites['id']

            locations = sites['locations']

            # Distance matrix
            self.names = sites['names']
        else:
            sub_idx = np.nonzero(subset)[0]
            vertices = list(range(len(sub_idx)))

            # Delaunay triangulation
            locations = sites['locations'][sub_idx, :]

            # Distance matrix
            self.names = [sites['names'][i] for i in sub_idx]

        # Delaunay triangulation

        delaunay = compute_delaunay(locations)
        v1, v2 = delaunay.toarray().nonzero()
        edges = np.column_stack((v1, v2))

        # Adjacency Matrix
        adj_mat = delaunay.tocsr()

        if crs is None:
            loc = np.asarray(sites['locations'])
            diff = loc[:, None] - loc
            dist_mat = np.linalg.norm(diff, axis=-1)
        else:
            transformer = pyproj.transformer.Transformer.from_crs(
                crs_from=crs, crs_to=pyproj.crs.CRS("epsg:4326"))
            w_locations = np.vstack(
                transformer.transform(locations[:, 0], locations[:, 1])
            ).T
            geod = geodesic.Geodesic()
            dist_mat = np.hstack([geod.inverse(location, w_locations)[:, :2] for location in w_locations])

        self.vertices = vertices
        self.edges = edges
        self.locations = locations
        self.adj_mat = adj_mat
        self.n = len(vertices)
        self.m = edges.shape[0]
        self.dist_mat = dist_mat
Ejemplo n.º 21
0
def test_geometry_length_ndarray():
    geod = geodesic.Geodesic()
    geom = np.array([lhr, jfk, lhr])
    expected = pytest.approx(lhr_to_jfk * 2, abs=1)
    assert geod.geometry_length(geom) == expected
Ejemplo n.º 22
0
def scalebar(length,
             slon='auto',
             slat='auto',
             az=90,
             label=True,
             ax=None,
             **kwargs):
    """
    Plot scalebar of given length in meters.
    
    Parameters:
        length: Length of scalebar in meters
        slon: Starting longitude (decimal degrees) for scalebar
        slat: Starting latitude (decimal degrees) for scalebar
        az = Azimuth of scalebar
        label: Boolean for whether to label length of scalebar in km
        ax: Axes on which to plot scalebar
    
    Return:
        ax: Axes with scalebar plotted
    """
    if ax is None:
        ax = plt.gca()

    geodesic = cgeo.Geodesic()  # Set up geodesic calculations
    # Get map projection from axes
    crs = ax.projection

    if (slon == 'auto') & (slat == 'auto'):
        trans = ax.transAxes + ax.transData.inverted()
        sx, sy = trans.transform((0.1, 0.1))
        slon, slat = ccrs.Geodetic().transform_point(sx, sy, src_crs=crs)

    # Calculate endpoint for given distance
    end = geodesic.direct(points=[slon, slat], azimuths=az,
                          distances=length)[0]
    elon = end[0]
    elat = end[1]
    mid = geodesic.direct(points=[slon, slat],
                          azimuths=az,
                          distances=length / 2)[0]
    clon = mid[0]
    clat = mid[1]

    # Plot line from start to end
    ax.plot([slon, elon], [slat, elat],
            transform=ccrs.Geodetic(),
            **kwargs,
            linewidth=3)

    # Add label with number of km
    if label == True:

        # Transform lat-lon into axes coordinates
        tlon, tlat = crs.transform_point(clon, clat, src_crs=ccrs.Geodetic())

        # Add label as annotation
        ax.annotate(text=str(round(length / 1000, None)) + ' km',
                    xy=(tlon, tlat),
                    xytext=(0, 3),
                    xycoords='data',
                    textcoords='offset points',
                    fontsize=7,
                    ha='center')

    return (ax)