Exemplo n.º 1
0
def as_iters(dataset_path, field_names, **kwargs):
    """Generate iterables of feature attribute values.

    Notes:
        Use ArcPy cursor token names for object IDs and geometry objects/properties.

    Args:
        dataset_path (str): Path of the dataset.
        field_names (iter): Collection of field names. The order of the names in the
            collection will determine where its value will fall in the generated item.
        **kwargs: Arbitrary keyword arguments. See below.

    Keyword Args:
        dataset_where_sql (str): SQL where-clause for dataset subselection.
        spatial_reference_item: Item from which the spatial reference of the output
            geometry will be derived.
        iter_type: Iterable type to yield. Default is tuple.

    Yields:
        iter.
    """
    kwargs.setdefault("dataset_where_sql")
    kwargs.setdefault("spatial_reference_item")
    kwargs.setdefault("iter_type", tuple)
    meta = {"spatial": spatial_reference_metadata(kwargs["spatial_reference_item"])}
    keys = {"feature": list(contain(field_names))}
    cursor = arcpy.da.SearchCursor(
        in_table=dataset_path,
        field_names=keys["feature"],
        where_clause=kwargs["dataset_where_sql"],
        spatial_reference=meta["spatial"]["object"],
    )
    with cursor:
        for feature in cursor:
            yield kwargs["iter_type"](feature)
Exemplo n.º 2
0
def project(dataset_path, output_path, spatial_reference_item=4326, **kwargs):
    """Project dataset features to a new dataset.

    Args:
        dataset_path (str): Path of the dataset.
        output_path (str): Path of the output dataset.
        spatial_reference_item: Item from which the spatial reference of the output
            geometry will be derived. Default is 4326 (EPSG code for unprojected WGS84).
        **kwargs: Arbitrary keyword arguments. See below.

    Keyword Args:
        dataset_where_sql (str): SQL where-clause for dataset subselection.
        log_level (str): Level to log the function at. Default is "info".

    Returns:
        str: Path of the converted dataset.
    """
    kwargs.setdefault("dataset_where_sql")
    meta = {"spatial": spatial_reference_metadata(spatial_reference_item)}
    log = leveled_logger(LOG, kwargs.setdefault("log_level", "info"))
    log(
        "Start: Project %s to srid=%s in %s.",
        dataset_path,
        meta["spatial"]["object"].factoryCode,
        output_path,
    )
    meta["dataset"] = dataset_metadata(dataset_path)
    """Project tool cannot output to an in-memory workspace (will throw error 000944).
    This is not a bug. Esri"s Project documentation (as of v10.6) specifically states:
    "The in_memory workspace is not supported as a location to write the output
    dataset."
    https://desktop.arcgis.com/en/arcmap/latest/tools/data-management-toolbox/project.htm
    https://pro.arcgis.com/en/pro-app/tool-reference/data-management/project.htm
    To avoid all this ado, using create to clone a (reprojected)
    dataset & insert features into it.
    """
    dataset.create(
        dataset_path=output_path,
        field_metadata_list=meta["dataset"]["user_fields"],
        geometry_type=meta["dataset"]["geometry_type"],
        spatial_reference_item=meta["spatial"]["object"],
        log_level=None,
    )
    features.insert_from_path(
        dataset_path=output_path,
        insert_dataset_path=dataset_path,
        field_names=meta["dataset"]["user_fields"],
        insert_where_sql=kwargs["dataset_where_sql"],
        log_level=None,
    )
    log("End: Project.")
    return output_path
Exemplo n.º 3
0
def table_to_points(
    dataset_path,
    output_path,
    x_field_name,
    y_field_name,
    spatial_reference_item=4326,
    **kwargs
):
    """Convert coordinate table to a new point dataset.

    Args:
        dataset_path (str): Path of the dataset.
        output_path (str): Path of the output dataset.
        x_field_name (str): Name of field with x-coordinate.
        y_field_name (str): Name of field with y-coordinate.
        spatial_reference_item: Item from which the spatial reference of the output
            geometry will be derived. Default is 4326 (EPSG code for unprojected WGS84).
        **kwargs: Arbitrary keyword arguments. See below.

    Keyword Args:
        dataset_where_sql (str): SQL where-clause for dataset subselection.
        z_field_name (str): Name of the field with z-coordinate.
        log_level (str): Level to log the function at. Default is "info".

    Returns:
        str: Path of the converted dataset.
    """
    kwargs.setdefault("dataset_where_sql")
    kwargs.setdefault("z_field_name")
    log = leveled_logger(LOG, kwargs.setdefault("log_level", "info"))
    log("Start: Convert %s to spatial dataset %s.", dataset_path, output_path)
    meta = {"spatial": spatial_reference_metadata(spatial_reference_item)}
    view_name = unique_name()
    arcpy.management.MakeXYEventLayer(
        table=dataset_path,
        out_layer=view_name,
        in_x_field=x_field_name,
        in_y_field=y_field_name,
        in_z_field=kwargs.get("z_field_name"),
        spatial_reference=meta["spatial"]["object"],
    )
    dataset.copy(
        view_name,
        output_path,
        dataset_where_sql=kwargs["dataset_where_sql"],
        log_level=None,
    )
    dataset.delete(view_name, log_level=None)
    log("End: Convert.")
    return output_path
Exemplo n.º 4
0
def id_map(dataset_path, id_field_names, field_names, **kwargs):
    """Return mapping of feature ID to attribute or list of attributes.

    Notes:
        There is no guarantee that the ID value(s) are unique.
        Use ArcPy cursor token names for object IDs and geometry objects/properties.

    Args:
        dataset_path (str): Path of the dataset.
        id_field_names (iter, str): Name(s) of the ID field(s).
        field_names (iter, str): Name(s) of the field(s).
        **kwargs: Arbitrary keyword arguments. See below.

    Keyword Args:
        dataset_where_sql (str): SQL where-clause for dataset subselection.
        spatial_reference_item: Item from which the spatial reference of the output
            geometry will be derived.

    Returns:
        dict.
    """
    kwargs.setdefault("dataset_where_sql")
    kwargs.setdefault("spatial_reference_item")
    meta = {"spatial": spatial_reference_metadata(kwargs["spatial_reference_item"])}
    keys = {
        "id": list(contain(id_field_names)),
        "attribute": list(contain(field_names)),
    }
    cursor = arcpy.da.SearchCursor(
        in_table=dataset_path,
        field_names=keys["id"] + keys["attribute"],
        where_clause=kwargs["dataset_where_sql"],
        spatial_reference=meta["spatial"]["object"],
    )
    id_attributes = {}
    with cursor:
        for feature in cursor:
            value = {
                "id": feature[0]
                if len(keys["id"]) == 1
                else feature[: len(keys["id"])],
                "attributes": (
                    feature[len(keys["id"])]
                    if len(keys["attribute"]) == 1
                    else feature[len(keys["id"]) :]
                ),
            }
            id_attributes[value["id"]] = value["attributes"]
    return id_attributes
Exemplo n.º 5
0
def create(dataset_path, field_metadata_list=None, **kwargs):
    """Create new dataset.

    Args:
        dataset_path (str): Path of the dataset .
        field_metadata_list (iter): Collection of field metadata mappings.
        **kwargs: Arbitrary keyword arguments. See below.

    Keyword Args:
        geometry_type (str): Type of geometry, if a spatial dataset.
        spatial_reference_item: Item from which the spatial reference of the output
            geometry will be derived. Default is 4326 (EPSG code for unprojected WGS84).
        log_level (str): Level to log the function at. Default is "info".

    Returns:
        str: Path of the dataset created.
    """
    kwargs.setdefault("geometry_type")
    kwargs.setdefault("spatial_reference_item", 4326)
    log = leveled_logger(LOG, kwargs.setdefault("log_level", "info"))
    log("Start: Create dataset %s.", dataset_path)
    meta = {
        "spatial": spatial_reference_metadata(kwargs["spatial_reference_item"])
    }
    create_kwargs = {
        "out_path": os.path.dirname(dataset_path),
        "out_name": os.path.basename(dataset_path),
    }
    if kwargs["geometry_type"]:
        exec_create = arcpy.management.CreateFeatureclass
        create_kwargs["geometry_type"] = kwargs["geometry_type"]
        create_kwargs["spatial_reference"] = meta["spatial"]["object"]
    else:
        exec_create = arcpy.management.CreateTable
    exec_create(**create_kwargs)
    if field_metadata_list:
        for field_meta in field_metadata_list:
            add_field_from_metadata(dataset_path, field_meta, log_level=None)
    log("End: Create.")
    return dataset_path
Exemplo n.º 6
0
def as_dicts(dataset_path, field_names=None, **kwargs):
    """Generate mappings of feature attribute name to value.

    Notes:
        Use ArcPy cursor token names for object IDs and geometry objects/properties.

    Args:
        dataset_path (str): Path of the dataset.
        field_names (iter): Collection of field names. Names will be the keys in the
            dictionary mapping to their values. If value is None, all attributes fields
            will be used.
        **kwargs: Arbitrary keyword arguments. See below.

    Keyword Args:
        dataset_where_sql (str): SQL where-clause for dataset subselection.
        spatial_reference_item: Item from which the spatial reference of the output
            geometry will be derived.

    Yields:
        dict.
    """
    kwargs.setdefault("dataset_where_sql")
    kwargs.setdefault("spatial_reference_item")
    meta = {"spatial": spatial_reference_metadata(kwargs["spatial_reference_item"])}
    if field_names is None:
        meta["dataset"] = dataset_metadata(dataset_path)
        keys = {"feature": [key for key in meta["dataset"]["field_names_tokenized"]]}
    else:
        keys = {"feature": list(contain(field_names))}
    cursor = arcpy.da.SearchCursor(
        in_table=dataset_path,
        field_names=keys["feature"],
        where_clause=kwargs["dataset_where_sql"],
        spatial_reference=meta["spatial"]["object"],
    )
    with cursor:
        for feature in cursor:
            yield dict(zip(cursor.fields, feature))
Exemplo n.º 7
0
def update_by_geometry(dataset_path, field_name, geometry_properties, **kwargs):
    """Update attribute values by cascading through geometry properties.

    Args:
        dataset_path (str): Path of the dataset.
        field_name (str): Name of the field.
        geometry_properties (iter): Geometry property names in object-access order to
            retrieve the update value.
        **kwargs: Arbitrary keyword arguments. See below.

    Keyword Args:
        dataset_where_sql (str): SQL where-clause for dataset subselection.
        spatial_reference_item: Item from which the spatial reference for the output
            geometry property will be derived. Default is the update dataset.
        use_edit_session (bool): Updates are done in an edit session if True. If not
            not specified or None, the spatial reference of the dataset is used.
        log_level (str): Level to log the function at. Default is "info".

    Returns:
        collections.Counter: Counts for each feature action.
    """
    kwargs.setdefault("dataset_where_sql")
    kwargs.setdefault("spatial_reference_item")
    kwargs.setdefault("use_edit_session", False)
    log = leveled_logger(LOG, kwargs.setdefault("log_level", "info"))
    log(
        "Start: Update attributes in %s on %s by geometry properties %s.",
        field_name,
        dataset_path,
        geometry_properties,
    )
    meta = {
        "dataset": dataset_metadata(dataset_path),
        "spatial": spatial_reference_metadata(kwargs["spatial_reference_item"]),
    }
    session = Editor(meta["dataset"]["workspace_path"], kwargs["use_edit_session"])
    cursor = arcpy.da.UpdateCursor(
        in_table=dataset_path,
        field_names=["shape@", field_name],
        where_clause=kwargs["dataset_where_sql"],
        spatial_reference=meta["spatial"]["object"],
    )
    update_action_count = Counter()
    with session, cursor:
        for feature in cursor:
            value = {"geometry": feature[0], "old": feature[-1]}
            value["new"] = property_value(
                value["geometry"],
                GEOMETRY_PROPERTY_TRANSFORM,
                *contain(geometry_properties)
            )
            if same_value(value["old"], value["new"]):
                update_action_count["unchanged"] += 1
            else:
                try:
                    cursor.updateRow([value["geometry"], value["new"]])
                    update_action_count["altered"] += 1
                except RuntimeError:
                    LOG.error("Offending value is %s", value["new"])
                    raise

    for action, count in sorted(update_action_count.items()):
        log("%s attributes %s.", count, action)
    log("End: Update.")
    return update_action_count