Exemple #1
0
def naive_compute_iou_matrix(sorted_detections, ground_truths):
    """Computes the iou scores between all pairs of geometries in a naive fashion.

    Args:
        sorted_detections (ndarray, list) : A ndarray of detections stored as:

                * Bounding boxes for a given class where each row is a detection stored as:
                  ``[BoundingBox, confidence]``
                * Polygons for a given class where each row is a detection stored as:
                  ``[Polygon, confidence]``
                * Points for a given class where each row is a detection stored as:
                  ``[Point, confidence]``

            ground_truths (ndarray,list) : A ndarray of ground truth stored as:

                * Bounding boxes for a given class where each row is a ground truth stored as:
                  ``[BoundingBox]``
                * Polygons for a given class where each row is a ground truth stored as:
                  ``[Polygon]``
                * Points for a given class where each row is a ground truth stored as:
                  ``[Point]``

    Returns:
        ndarray : An IoU matrix (#detections, #ground truth)
    """

    # We prepare the IoU matrix (#detection, #gt)
    iou = np.zeros((sorted_detections.shape[0], len(ground_truths)))

    # Naive iterative IoU matrix construction (Note: we iterate over the sorted detections)
    for k, ground_truth in enumerate(ground_truths):
        for m, detection in enumerate(sorted_detections):
            iou[m, k] = area(intersection(detection[0], ground_truth[0])) / area(union(detection[0], ground_truth[0]))
    return iou
Exemple #2
0
 def _tess(
     self,
     ix,
     enclosure,
     buildings,
     query_inp,
     query_res,
     threshold,
     unique_id,
     **kwargs,
 ):
     poly = enclosure.values.data[ix]
     blg = buildings.iloc[query_res[query_inp == ix]]
     within = blg[
         pygeos.area(pygeos.intersection(blg.geometry.values.data, poly)) >
         (pygeos.area(blg.geometry.values.data) * threshold)]
     if len(within) > 1:
         tess = self._morphological_tessellation(
             within,
             unique_id,
             poly,
             shrink=self.shrink,
             segment=self.segment,
             verbose=False,
             check=False,
         )
         tess[self.enclosure_id] = ix
         return tess
     return gpd.GeoDataFrame({
         self.enclosure_id: ix,
         unique_id: None
     },
                             geometry=[poly],
                             index=[0])
Exemple #3
0
def convex_hull_ratio(collection):
    """
    ratio of the area of the convex hull to the area of the shape itself

    Altman's A_3 measure, from Neimi et al 1991.
    """
    ga = _cast(collection)
    return pygeos.area(ga) / pygeos.area(pygeos.convex_hull(ga))
Exemple #4
0
def remove_tiny_shapes(x, regionalized=False):
    """This function will remove the small shapes of multipolygons. Will reduce the size of the file.
    
    Arguments:
        *x* : a geometry feature (Polygon) to simplify. Countries which are very large will see larger (unhabitated) islands being removed.
    
    Optional Arguments:
        *regionalized*  : Default is **False**. Set to **True** will use lower threshold settings (default: **False**).
        
    Returns:
        *MultiPolygon* : a shapely geometry MultiPolygon without tiny shapes.
        
    """

    # if its a single polygon, just return the polygon geometry
    if pygeos.geometry.get_type_id(x.geometry) == 3:  # 'Polygon':
        return x.geometry

    # if its a multipolygon, we start trying to simplify and remove shapes if its too big.
    elif pygeos.geometry.get_type_id(x.geometry) == 6:  # 'MultiPolygon':

        if regionalized == False:
            area1 = 0.1
            area2 = 250

        elif regionalized == True:
            area1 = 0.01
            area2 = 50

        # dont remove shapes if total area is already very small
        if pygeos.area(x.geometry) < area1:
            return x.geometry
        # remove bigger shapes if country is really big

        if x['GID_0'] in ['CHL', 'IDN']:
            threshold = 0.01
        elif x['GID_0'] in ['RUS', 'GRL', 'CAN', 'USA']:
            if regionalized == True:
                threshold = 0.01
            else:
                threshold = 0.01

        elif pygeos.area(x.geometry) > area2:
            threshold = 0.1
        else:
            threshold = 0.001

        # save remaining polygons as new multipolygon for the specific country
        new_geom = []
        for index_ in range(pygeos.geometry.get_num_geometries(x.geometry)):
            if pygeos.area(pygeos.geometry.get_geometry(x.geometry,
                                                        index_)) > threshold:
                new_geom.append(
                    pygeos.geometry.get_geometry(x.geometry, index_))

        return pygeos.creation.multipolygons(numpy.array(new_geom))
Exemple #5
0
def minimum_bounding_circle_ratio(collection):
    """
    The Reock compactness measure, defined by the ratio of areas between the
    minimum bounding/containing circle of a shape and the shape itself.

    Measure A1 in Altman (1998), cited for Frolov (1974), but earlier from Reock
    (1963)
    """
    ga = _cast(collection)
    mbc = pygeos.minimum_bounding_circle(ga)
    return pygeos.area(ga) / pygeos.area(mbc)
Exemple #6
0
def external_entropy(a, b, balance=0, base=numpy.e):
    """
    The harmonic mean summarizing the overlay entropy of two
    sets of polygons: a onto b and b onto a.

    Called the v-measure in :cite:`nowosad2018`

    Arguments
    ----------
    a : geometry array of polygons
        array of polygons
    b : geometry array of polygons
        array of polygons
    balance:  float
        weight that describing the relative importance of pattern a or pattern b.
        When large and positive, we weight the measure more to ensure polygons in b
        are fully contained by polygons in a. When large and negative,
        we weight the pattern to ensure polygons in A are fully contained
        by polygons in b. Corresponds to the log of beta in {cite}`Nowosad2018`.
    base: float
        base of logarithm to use throughout computation
    Returns
    --------
    (n,) array expressing the entropy of the areal distributions
    of a's splits by partition b.

    Example
    -------

    >>> r1 = geopandas.read_file('tests/regions.zip', layer='regions1')
    >>> r2 = geopandas.read_file('tests/regions.zip', layer='regions2')
    >>> external_entropy(r1, r2)
    """
    a = _cast(a)
    b = _cast(b)
    beta = numpy.exp(balance)
    aix, bix, ab = _overlay(a, b, return_indices=True)
    a_areas = pygeos.area(a)
    b_areas = pygeos.area(b)
    ab_areas = pygeos.area(ab)
    b_onto_a = _overlay_entropy(aix, a_areas, ab_areas, base=base)  # SjZ
    # SZ, as sabre has entropy.empirical(rowSums(xtab), unit='log2')
    b_onto_a /= areal_entropy(areas=b_areas, local=False, base=base)
    a_onto_b = _overlay_entropy(bix, b_areas, ab_areas, base=base)  # SjR
    # SR, as sabre has entropy.empirical(colSums(xtab), unit='log2')
    a_onto_b /= areal_entropy(areas=a_areas, local=False, base=base)

    c = 1 - numpy.average(b_onto_a, weights=a_areas)
    h = 1 - numpy.average(a_onto_b, weights=b_areas)

    return (1 + beta) * h * c / ((beta * h) + c)
Exemple #7
0
def area(gdf, km=True):
    """[summary]

    Args:
        gdf ([type]): [description]
        km (bool, optional): [description]. Defaults to True.

    Returns:
        [type]: [description]
    """
    if km:
        return pygeos.area(convert_crs(gdf)[0]) / 1e6
    else:
        return pygeos.area(convert_crs(gdf)[0])
Exemple #8
0
def isoperimetric_quotient(collection):
    """
    The Isoperimetric quotient, defined as the ratio of a polygon's area to the
    area of the equi-perimeter circle.

    Altman's PA_1 measure

    Construction:
    --------------
    let:
    p_d = perimeter of polygon
    a_d = area of polygon

    a_c = area of the constructed circle
    r = radius of constructed circle

    then the relationship between the constructed radius and the polygon
    perimeter is:
    p_d = 2 \pi r
    p_d / (2 \pi) = r

    meaning the area of the circle can be expressed as:
    a_c = \pi r^2
    a_c = \pi (p_d / (2\pi))^2

    implying finally that the IPQ is:

    pp = (a_d) / (a_c) = (a_d) / ((p_d / (2*\pi))^2 * \pi) = (a_d) / (p_d**2 / (4\PI))
    """
    ga = _cast(collection)
    return (4 * numpy.pi * pygeos.area(ga)) / (pygeos.measurement.length(ga)**
                                               2)
Exemple #9
0
def summarize_by_huc12(units_df):
    print("Calculating overlap with land ownership and protection")

    ownership = gp.read_feather(
        ownership_filename, columns=["geometry", "FEE_ORGTYP", "GAP_STATUS"])

    index_name = units_df.index.name

    df = intersection(units_df, ownership)

    if not len(df):
        return

    df["acres"] = pg.area(df.geometry_right.values.data) * M2_ACRES

    # drop areas that touch but have no overlap
    df = df.loc[df.acres > 0].copy()

    by_owner = (df[["FEE_ORGTYP", "acres"]].groupby(
        [index_name,
         "FEE_ORGTYP"]).acres.sum().astype("float32").round().reset_index())

    by_protection = (df[["GAP_STATUS", "acres"]].groupby(
        [index_name,
         "GAP_STATUS"]).acres.sum().astype("float32").round().reset_index())

    by_owner.to_feather(ownership_results_filename)
    by_protection.to_feather(protection_results_filename)
Exemple #10
0
def summarize_by_huc12(units_df):
    """Calculate spatial join with counties

    Parameters
    ----------
    df : GeoDataFrame
        summary units
    """

    print("Calculating overlap with PARCAs")
    parca = gp.read_feather(parca_filename)

    df = intersection(units_df, parca)
    df["acres"] = pg.area(df.geometry_right.values.data) * M2_ACRES

    # drop areas that touch but have no overlap
    df = df.loc[df.acres > 0].copy()

    # aggregate these back up by ID
    by_parca = (df[[
        "parca_id", "name", "description", "acres"
    ]].groupby(by=[df.index.get_level_values(0), "parca_id"]).agg({
        "name":
        "first",
        "description":
        "first",
        "acres":
        "sum"
    }).reset_index().rename(columns={"level_0": "id"}))
    by_parca.acres = by_parca.acres.astype("float32").round()

    by_parca.to_feather(results_filename)
Exemple #11
0
    def create_final_od_grid(df,height_div):
        height = numpy.sqrt(pygeos.area(df.geometry)/height_div).values[0]
        grid = pd.DataFrame(create_grid(create_bbox(df),height),columns=['geometry'])

        #clip grid of bbox to grid of the actual spatial exterior of the country
        clip_grid = pygeos.intersection(grid,df.geometry)
        clip_grid = clip_grid.loc[~pygeos.is_empty(clip_grid.geometry)]

        # turn to shapely geometries again for zonal stats
        clip_grid.geometry = pygeos.to_wkb(clip_grid.geometry)
        clip_grid.geometry = clip_grid.geometry.apply(loads)
        clip_grid = gpd.GeoDataFrame(clip_grid)

        # get total population per grid cell
        clip_grid['tot_pop'] = clip_grid.geometry.apply(lambda x: zonal_stats(x,world_pop,stats="sum"))
        clip_grid['tot_pop'] = clip_grid['tot_pop'].apply(lambda x: x[0]['sum'])    

        # remove cells in the grid that have no population data
        clip_grid = clip_grid.loc[~pd.isna(clip_grid.tot_pop)]
        clip_grid = clip_grid.loc[clip_grid.tot_pop > 100]
        clip_grid.reset_index(inplace=True,drop=True)
        clip_grid.geometry = clip_grid.geometry.centroid
        clip_grid['GID_0'] = GID_0
        clip_grid['grid_height'] = height

        return clip_grid
Exemple #12
0
def squareness(collection):
    """
    Measures how different is a given shape from an equi-areal square

    The index is close to 0 for highly irregular shapes and to 1.3 for circular shapes.
    It equals 1 for squares.

    .. math::
        \\begin{equation}
        \\frac{
            \\sqrt{A}}{P^{2}}
            \\times
            \\frac{\\left(4 \\sqrt{\\left.A\\right)}^{2}\\right.}{\\sqrt{A}}
            =
            \\frac{\\left(4 \\sqrt{A}\\right)^{2}}{P{ }^{2}}
            =
            \\left(\\frac{4 \\sqrt{A}}{P}\\right)^{2}
        \\end{equation}

    where :math:`A` is the area and :math:`P` is the perimeter.

    Notes
    -----
    Implementation follows :cite:`basaraner2017`.

    """
    ga = _cast(collection)
    return ((numpy.sqrt(pygeos.area(ga)) * 4) / pygeos.length(ga))**2
    def compute_similarity_matrix(self,
                                  detections,
                                  ground_truths,
                                  label_mean_area=None):
        r"""Compute the iou scores between all pairs of geometries with an Rtree on detections to speed up computation.

        Args:
            detections (ndarray, list) : A ndarray of detections stored as:

                * Bounding boxes for a given class where each row is a detection stored as:
                  ``[BoundingBox, confidence]``
                * Polygons for a given class where each row is a detection stored as:
                  ``[Polygon, confidence]``

            ground_truths (ndarray,list) : A ndarray of ground truth stored as:

                * Bounding boxes for a given class where each row is a ground truth stored as:
                  ``[BoundingBox]``
                * Polygons for a given class where each row is a ground truth stored as:
                  ``[Polygon]``

            label_mean_area (float) : Optional, default to ``None``. The mean area for each label in the dataset,
                if given, it is used to match with *iIoU* instead of *IoU* (c.f. :ref:`iiou`)

        Returns:
            ndarray : An IoU matrix (#detections, #ground truth)

        """
        detections = self._sort_detection_by_confidence(detections)
        iou = intersection_over_union(detections[:, 0], ground_truths[:, 0])
        if label_mean_area is not None:
            iou = (label_mean_area / area(ground_truths[:, 0])) * iou

        return iou
    def get_parca(self):
        parca = gp.read_feather(parca_filename)
        df = intersection(pd.DataFrame({"geometry": self.geometry}), parca)

        if not len(df):
            return None

        df["acres"] = pg.area(df.geometry_right.values.data) * M2_ACRES
        df = df.loc[df.acres > 0].copy()

        # aggregate these back up by ID
        by_parca = (df[[
            "parca_id", "name", "description", "acres"
        ]].groupby(by=[df.index.get_level_values(0), "parca_id"]).agg({
            "name":
            "first",
            "description":
            "first",
            "acres":
            "sum"
        }).reset_index().rename(columns={"level_0": "id"}))
        by_parca.acres = by_parca.acres.astype("float32").round()

        return {
            "parca":
            by_parca[["name", "description",
                      "acres"]].to_dict(orient="records")
        }
Exemple #15
0
def moment_of_inertia(collection):
    """
    Computes the moment of inertia of the polygon.

    This treats each boundary point as a point-mass of 1.

    Thus, for constant unit mass at each boundary point,
    the MoI of this pointcloud is

    \sum_i d_{i,c}^2

    where c is the centroid of the polygon

    Altman's OS_1 measure, cited in Boyce and Clark (1964), also used in Weaver
    and Hess (1963).
    """
    ga = _cast(collection)
    coords = pygeos.get_coordinates(ga)
    geom_ixs = numpy.repeat(numpy.arange(len(ga)),
                            pygeos.get_num_coordinates(ga))
    centroids = pygeos.get_coordinates(pygeos.centroid(ga))[geom_ixs]
    squared_euclidean = numpy.sum((coords - centroids)**2, axis=1)
    dists = (pandas.DataFrame.from_dict(
        dict(d2=squared_euclidean,
             geom_ix=geom_ixs)).groupby("geom_ix").d2.sum()).values
    return pygeos.area(ga) / numpy.sqrt(2 * dists)
Exemple #16
0
def country_grid_gdp_filled(trans_network,
                            country,
                            data_path,
                            rough_grid_split=100,
                            from_main_graph=False):
    """[summary]

    Args:
        trans_network ([type]): [description]
        rough_grid_split (int, optional): [description]. Defaults to 100.

    Returns:
        [type]: [description]
    """
    if from_main_graph == True:
        node_df = trans_network.copy()
        envelop = pygeos.envelope(
            pygeos.multilinestrings(node_df.geometry.values))
        height = np.sqrt(pygeos.area(envelop) / rough_grid_split)
    else:
        node_df = trans_network.nodes.copy()
        node_df.geometry, approximate_crs = convert_crs(node_df)
        envelop = pygeos.envelope(
            pygeos.multilinestrings(node_df.geometry.values))
        height = np.sqrt(pygeos.area(envelop) / rough_grid_split)

    gdf_admin = pd.DataFrame(create_grid(create_bbox(node_df), height),
                             columns=['geometry'])

    #load data and convert to pygeos
    country_shape = gpd.read_file(os.path.join(data_path, 'GADM',
                                               'gadm36_levels.gpkg'),
                                  layer=0)
    country_shape = pd.DataFrame(
        country_shape.loc[country_shape.GID_0 == country])
    country_shape.geometry = pygeos.from_shapely(country_shape.geometry)

    gdf_admin = pygeos.intersection(gdf_admin, country_shape.geometry)
    gdf_admin = gdf_admin.loc[~pygeos.is_empty(gdf_admin.geometry)]

    gdf_admin['centroid'] = pygeos.centroid(gdf_admin.geometry)
    gdf_admin['km2'] = area(gdf_admin)
    gdf_admin['gdp'] = get_gdp_values(gdf_admin, data_path)
    gdf_admin = gdf_admin.loc[gdf_admin.gdp > 0].reset_index()
    gdf_admin['gdp_area'] = gdf_admin.gdp / gdf_admin['km2']

    return gdf_admin
 def test_rtree_iou_matrix(self):
     matcher = MatchEngineIoU(0.1, 'coco')
     ref_iou = naive_compute_iou_matrix(sort_detection_by_confidence(detections), gt) * \
         (gt_mean_area / area(gt[:, 0]))
     iou = matcher.compute_similarity_matrix(detections, gt, label_mean_area=gt_mean_area)
     print(iou)
     print(ref_iou)
     assert np.all(iou[np.logical_not(np.isinf(iou))] == ref_iou[np.logical_not(np.isinf(iou))])
Exemple #18
0
def nmi(collection):
    """
    Computes the Normalized Moment of Inertia from Li et al (2013), recognizing
    that it is the relationship between the area of a shape squared divided by
    its second moment of area.
    """
    ga = _cast(collection)
    return pygeos.area(ga)**2 / (2 * second_areal_moment(ga) * numpy.pi)
Exemple #19
0
def rectangularity(collection):
    """
    Ratio of the area of the shape to the area of its minimum bounding rotated rectangle

    Reveals a polygon’s degree of being curved inward.

    .. math::
        \\frac{A}{A_{MBR}}

    where :math:`A` is the area and :math:`A_{MBR}` is the area of minimum bounding
    rotated rectangle.

    Notes
    -----
    Implementation follows :cite:`basaraner2017`.
    """
    ga = _cast(collection)
    return pygeos.area(ga) / pygeos.area(pygeos.minimum_rotated_rectangle(ga))
Exemple #20
0
def overlay_entropy(a, b, standardize=True, local=False, base=numpy.e):
    """
    The entropy of how n zones in a are split by m partitions in b,
    where n is the number of polygons in a and m is the number
    of partitions in b. This is the "overlay entropy", since
    the set of polygons constructed from intersection(a,b) is often
    called the "overlay" of A onto B.


    Larger when zones in a are uniformly split into many even pieces
    by partitions in b, and small when zones in A correspond well to
    zones in B.

    Arguments
    ----------
    a : geometry array of polygons
        a set of polygons (the "target") for whom the areal entropy is calculated
    b : geometry array of polygons
        a set of polygons (the "frame") that splits a

    Returns
    --------
    (n,) array expressing the entropy of the areal distributions
    of a's splits by partition b.

    Example
    -------

    >>> r1 = geopandas.read_file('tests/regions.zip', layer='regions1')
    >>> r2 = geopandas.read_file('tests/regions.zip', layer='regions2')
    >>> overlay_entropy(r1, r2)
    """
    a = _cast(a)
    b = _cast(b)
    aix, bix, ab = _overlay(a, b, return_indices=True)
    a_areas = pygeos.area(a)
    b_areas = pygeos.area(b)
    h = _overlay_entropy(aix, a_areas, pygeos.area(ab), base=base)
    if standardize:
        h /= areal_entropy(None, areas=b_areas, local=False, base=base)
    if local:
        return h
    return h.sum()
Exemple #21
0
def test_polygon_with_none_hole():
    actual = pygeos.polygons(
        pygeos.linearrings(box_tpl(0, 0, 10, 10)),
        [
            pygeos.linearrings(box_tpl(1, 1, 2, 2)),
            None,
            pygeos.linearrings(box_tpl(3, 3, 4, 4)),
        ],
    )
    assert pygeos.area(actual) == 98.0
Exemple #22
0
def isoareal_quotient(collection):
    """
    The Isoareal quotient, defined as the ratio of a polygon's perimeter to the
    perimeter of the equi-areal circle

    Altman's PA_3 measure, and proportional to the PA_4 measure
    """
    ga = _cast(collection)
    return (2 * numpy.pi * numpy.sqrt(
        pygeos.area(ga) / numpy.pi)) / pygeos.measurement.length(ga)
Exemple #23
0
def radii_ratio(collection):
    """
    The Flaherty & Crumplin (1992) index, OS_3 in Altman (1998).

    The ratio of the radius of the equi-areal circle to the radius of the MBC
    """
    ga = _cast(collection)
    r_eac = numpy.sqrt(pygeos.area(ga) / numpy.pi)
    r_mbc = pygeos.minimum_bounding_radius(ga)
    return r_eac / r_mbc
Exemple #24
0
def equivalent_rectangular_index(collection):
    """
    Deviation of a polygon from an equivalent rectangle

    .. math::
        \\frac{\\sqrt{A}}{A_{MBR}}
        \\times
        \\frac{P_{MBR}}{P}

    where :math:`A` is the area, :math:`A_{MBR}` is the area of minimum bounding
    rotated rectangle, :math:`P` is the perimeter, :math:`P_{MBR}` is the perimeter
    of minimum bounding rotated rectangle.

    Notes
    -----
    Implementation follows :cite:`basaraner2017`.
    """
    ga = _cast(collection)
    box = pygeos.minimum_rotated_rectangle(ga)
    return numpy.sqrt(pygeos.area(ga) / pygeos.area(box)) * (
        pygeos.length(box) / pygeos.length(ga))
Exemple #25
0
    def __init__(self, gdf, areas=None):
        self.gdf = gdf

        gdf = gdf.copy()
        if areas is None:
            areas = gdf.geometry.area

        if not isinstance(areas, str):
            gdf["mm_a"] = areas
            areas = "mm_a"
        self.areas = gdf[areas]

        exts = pygeos.area(pygeos.polygons(gdf.geometry.exterior.values.data))

        self.series = pd.Series(exts - gdf[areas], index=gdf.index)
    def get_ownership(self):
        ownership = gp.read_feather(ownership_filename)
        df = intersection(pd.DataFrame({"geometry": self.geometry}), ownership)

        if not len(df):
            return None

        df["acres"] = pg.area(df.geometry_right.values.data) * M2_ACRES
        df = df.loc[df.acres > 0].copy()

        if not len(df):
            return None

        results = dict()

        by_owner = (df[[
            "FEE_ORGTYP", "acres"
        ]].groupby(by="FEE_ORGTYP").acres.sum().astype("float32").to_dict())
        # use the native order of OWNERSHIP to drive order of results
        results["ownership"] = [{
            "label": value["label"],
            "acres": by_owner[key]
        } for key, value in OWNERSHIP.items() if key in by_owner]

        by_protection = (df[[
            "GAP_STATUS", "acres"
        ]].groupby(by="GAP_STATUS").acres.sum().astype("float32").to_dict())
        # use the native order of PROTECTION to drive order of results
        results["protection"] = [{
            "label": value["label"],
            "acres": by_protection[key]
        } for key, value in PROTECTION.items() if key in by_protection]

        by_area = (df[["AREA_NAME", "FEE_OWNER", "acres"]].groupby(
            by=[df.index.get_level_values(0), "AREA_NAME", "FEE_OWNER"
                ]).acres.sum().astype("float32").round().reset_index().rename(
                    columns={
                        "level_0": "id",
                        "AREA_NAME": "name",
                        "FEE_OWNER": "owner"
                    }).sort_values(by="acres", ascending=False))
        # drop very small areas, these are not helpful
        by_area = by_area.loc[by_area.acres >= 1].copy()

        results["protected_areas"] = by_area.head(25).to_dict(orient="records")
        results["num_protected_areas"] = len(by_area)

        return results
def summarize_by_aoi(df, analysis_acres, total_acres):
    """Calculate ranks and areas of overlap within Caribbean Priority Watersheds.

    Parameters
    ----------
    df : GeoDataframe
        area of interest
    analysis_acres : float
        area in acres of area of interest less any area outside SE Blueprint
    total_acres : float
        area in acres of area of interest

        dict
        {
            "priorities": [...],
            "legend": [...],
            "analysis_notes": <analysis_notes>
        }
    """

    car_df = gp.read_feather(caribbean_filename,
                             columns=["geometry", "carrank"])
    df = intersection(df, car_df)
    df["acres"] = pg.area(df.geometry_right.values.data) * M2_ACRES

    # aggregate totals by rank
    by_rank = (df[["carrank", "acres"]].groupby(
        by="carrank").acres.sum().astype("float32").reset_index().sort_values(
            by="carrank"))

    priorities = []
    for ix, row in by_rank.iterrows():
        value = get_rank_value(row.carrank)
        value["acres"] = row.acres
        value["percent"] = 100 * row.acres / analysis_acres

        priorities.append(value)

    # Note: input area remainder deliberately omitted, since all
    # areas outside but close to this input are outside SE Blueprint
    return {
        "priorities": priorities,
        "legend": LEGEND,
        "analysis_notes": get_analysis_notes(),
        "analysis_acres": analysis_acres,
        "total_acres": total_acres,
    }
Exemple #28
0
def areal_entropy(polygons=None, areas=None, local=False, base=numpy.e):
    """
    Compute the entropy of the distribution of polygon areas.

    Arguments
    ---------
    polygons: numpy array of geometries
        polygons whose distribution of entropies needs to be computed.
        Should not be provided if areas is provided.
    areas: numpy array
        areas to use to compute entropy. SHould not be provided if
        polygons are provided.
    local: bool (default: False)
        whether to return the total entropy of the areal distribution
        (False), or to return the contribution to entropy made
        by each of area (True).

    Returns
    -------
    Total map entropy or (n,) vector of local entropies.

    Example
    -------

    >>> r1 = geopandas.read_file('tests/regions.zip', layer='regions1')
    >>> r2 = geopandas.read_file('tests/regions.zip', layer='regions2')
    >>> areal_entropy(polygons=r1)
    """
    assert not (
        (polygons is None) & (areas is None)
    ), "either polygons or precomputed areas must be provided"
    assert not (
        (polygons is not None) & (areas is not None)
    ), "only one of polygons or areas should be provided."
    if polygons is None:
        assert areas is not None, "If polygons are not provided, areas should be."
    if areas is None:
        assert polygons is not None, "If areas are not provided, polygons should be."
        polygons = _cast(polygons)
        areas = pygeos.area(polygons)
    result = entr(areas / areas.sum()) / numpy.log(base)
    result[result < 0] = 0
    if local:
        return result
    return result.sum()
Exemple #29
0
def shape_index(collection):
    """
    Schumm’s shape index (Schumm (1956) in MacEachren 1985)

    .. math::
        {\\sqrt{{A} \\over {\\pi}}} \\over {R}

    where :math:`A` is the area and :math:`R` is the radius of the minimum bounding
    circle.

    Notes
    -----
    Implementation follows :cite:`maceachren1985compactness`.

    """
    ga = _cast(collection)
    return numpy.sqrt(
        pygeos.area(ga) / numpy.pi) / pygeos.minimum_bounding_radius(ga)
Exemple #30
0
def completeness(a, b, local=False, base=numpy.e):
    """
    The completeness of the partitions of polygons in a to those in a.
    Closer to 1 when all polygons in a are fully contained within polygons in b.
    From :cite:`nowosad2018`

    Arguments
    ---------
    a : geometry array of polygons
        array of polygons
    b : geometry array of polygons
        array of polygons
    local: bool (default: False)
        whether or not to provide local scores for each polygon. If True, the
        completeness for polygons in a are returned.
    scale: bool (default: None)
        whether to scale the completeness score(s). By default, completeness is
        is scaled for local scores so that the average of the local scores is
        the overall map completeness. If not local, then completeness is returned
        unscaled. You can also set local=True and scale=False to get raw components
        of the completeness, whose sum is the completeness for the entire map.
        Global re-scaled scores (local=False & scale=True) are not supported.
    base: bool (default=None)
        what base to use for the entropy calculations. The default is base e,
        which means entropy is measured in "nats."

    Example
    -------

    >>> r1 = geopandas.read_file('tests/regions.zip', layer='regions1')
    >>> r2 = geopandas.read_file('tests/regions.zip', layer='regions2')
    >>> completeness(r1, r2)
    """
    a = _cast(a)
    b = _cast(b)
    ohi = overlay_entropy(a, b, standardize=True, local=True, base=base)
    a_areas = pygeos.area(a)
    w = a_areas / a_areas.sum()
    ci = (w * (1 - ohi)) / w.sum()
    if local:
        return ci
    return ci.sum()