Beispiel #1
0
def network_analyze(
    traces: gpd.GeoDataFrame,
    area: gpd.GeoDataFrame,
    name: str,
    coverage_gdf: gpd.GeoDataFrame,
    circle_radius: float,
) -> Tuple[Network, pd.Series]:
    """
    Analyze traces and area for results.
    """
    network = Network(
        trace_gdf=traces,
        area_gdf=area,
        name=name,
        determine_branches_nodes=True,
        snap_threshold=0.001,
    )
    points = network.representative_points()
    if not len(points) == 1:
        raise ValueError("Expected one target area representative point.")
    point = points[0]
    amount_of_coverage = assess_coverage(target_centroid=point,
                                         coverage_gdf=coverage_gdf,
                                         radius=circle_radius)
    describe_df = describe_random_network(
        network=network,
        target_centroid=point,
        name=name,
        amount_of_coverage=amount_of_coverage,
        radius=circle_radius,
    )

    return network, describe_df.iloc[0]
Beispiel #2
0
def test_network_contour_grid(traces, areas, snap_threshold, name,
                              dataframe_regression):
    """
    Test contour_grid with network determined b and n.
    """
    assert isinstance(name, str)
    assert isinstance(traces, gpd.GeoDataFrame)
    assert isinstance(areas, gpd.GeoDataFrame)
    traces = traces.iloc[0:150]
    network = Network(
        trace_gdf=traces,
        area_gdf=areas,
        determine_branches_nodes=True,
        snap_threshold=snap_threshold,
        truncate_traces=True,
        circular_target_area=False,
        name=name,
    )
    sampled_grid = network.contour_grid()
    fig, ax = network.plot_contour(
        parameter=Param.FRACTURE_INTENSITY_P21.value.name,
        sampled_grid=sampled_grid)
    assert isinstance(fig, Figure)
    assert isinstance(ax, Axes)
    plt.close("all")

    assert isinstance(sampled_grid, gpd.GeoDataFrame)
    assert sampled_grid.shape[0] > 0
    assert isinstance(sampled_grid.geometry.values[0], Polygon)

    sampled_grid.sort_index(inplace=True)
    dataframe_regression.check(
        pd.DataFrame(sampled_grid).drop(columns=["geometry"]))
Beispiel #3
0
def save_azimuth_bin_data(network: Network, other_results_path: Path,
                          loc_hash: str):
    """
    Save azimuth bin data from a Network.
    """
    trace_bins, _, _ = network.plot_trace_azimuth()
    branch_bins, _, _ = network.plot_branch_azimuth()
    trace_bin_df, branch_bin_df = bins_to_dataframes(trace_bins, branch_bins)
    utils.save_csv(trace_bin_df, other_results_path / f"trace_{loc_hash}.csv")
    utils.save_csv(branch_bin_df,
                   other_results_path / f"branch_{loc_hash}.csv")
Beispiel #4
0
def test_network_circular_target_area(trace_gdf, area_gdf, name,
                                      data_regression):
    """
    Test network circular_target_area.
    """
    network_circular = Network(
        trace_gdf=trace_gdf,
        area_gdf=area_gdf,
        name=name,
        circular_target_area=True,
        determine_branches_nodes=True,
    )
    network_non_circular = Network(
        trace_gdf=trace_gdf,
        area_gdf=area_gdf,
        name=name,
        circular_target_area=False,
        determine_branches_nodes=False,
    )

    lengths_circular = network_circular.trace_length_array
    lengths_non_circular = network_non_circular.trace_length_array

    lengths_circular_sum = np.sum(lengths_circular)
    lengths_non_circular_sum = np.sum(lengths_non_circular)

    data_regression.check({
        "circular_sum": lengths_circular_sum.item(),
        "non_circular_sum": lengths_non_circular_sum.item(),
    })

    # test both traces and branches for right boundary_intersect_counts
    for boundary_intersect_count, gdf, name in zip(
        (
            # network_circular.trace_boundary_intersect_count,
            # network_circular.branch_boundary_intersect_count,
            network_circular.trace_data.boundary_intersect_count_desc(
                label="Trace"),
            network_circular.branch_data.boundary_intersect_count_desc(
                label="Branch"),
        ),
        (network_circular.trace_gdf, network_circular.branch_gdf),
        ("Trace", "Branch"),
    ):

        assert all(isinstance(val, str) for val in boundary_intersect_count)
        assert all(
            isinstance(val, int) for val in boundary_intersect_count.values())
        assert sum(boundary_intersect_count.values()) == gdf.shape[0]
        assert sum(gdf.geometry.intersects(
            area_gdf.geometry.iloc[0].boundary)) == sum((
                boundary_intersect_count[f"{name} Boundary 1 Intersect Count"],
                boundary_intersect_count[f"{name} Boundary 2 Intersect Count"],
            ))
def test_plaifiny_rose_plot_manual():
    """
    Test plainify_rose_plot.
    """
    network = Network(
        trace_gdf=tests.flato_traces_gdf(),
        area_gdf=tests.flato_area_gdf(),
        snap_threshold=0.001,
        determine_branches_nodes=False,
        truncate_traces=True,
    )

    _, fig, ax = network.plot_trace_azimuth()
    network_scripts.plainify_rose_plot(fig, ax)
def test_empty_numerical_desc_manual():
    """
    Test that all keys are valid.
    """
    network = Network(
        trace_gdf=tests.flato_traces_gdf(),
        area_gdf=tests.flato_area_gdf(),
        snap_threshold=0.001,
        determine_branches_nodes=True,
        truncate_traces=True,
    )
    assert all([
        key in network_scripts.empty_numerical_desc()
        for key in network.numerical_network_description()
    ])
Beispiel #7
0
def test_network_topology_reassignment(
    trace_gdf: gpd.GeoDataFrame,
    area_gdf: gpd.GeoDataFrame,
    tmp_path: Path,
    network_name: str,
    truncate_traces: bool,
    circular_target_area: bool,
    snap_threshold: float,
):
    """
    Test reassignment of Network branch_gdf and node_gdf.
    """
    network_params: Dict[str, Any] = dict(
        trace_gdf=trace_gdf,
        area_gdf=area_gdf,
        name=network_name,
        truncate_traces=truncate_traces,
        circular_target_area=circular_target_area,
        snap_threshold=snap_threshold,
    )
    network = Network(**network_params, determine_branches_nodes=True)

    original_description = network.numerical_network_description()

    # Explicitly name outputs
    branches_name = f"{network_name}_branches.geojson"
    nodes_name = f"{network_name}_nodes.geojson"

    # Save branches and nodes to tmp_path directory
    network.write_branches_and_nodes(
        output_dir_path=tmp_path, branches_name=branches_name, nodes_name=nodes_name
    )

    branches_path = tmp_path / branches_name
    nodes_path = tmp_path / nodes_name

    assert branches_path.exists()
    assert nodes_path.exists()

    branches_gdf = read_geofile(branches_path)
    nodes_gdf = read_geofile(nodes_path)

    assert isinstance(branches_gdf, gpd.GeoDataFrame)
    assert isinstance(nodes_gdf, gpd.GeoDataFrame)

    new_network = Network(
        **network_params,
        determine_branches_nodes=False,
        branch_gdf=branches_gdf,
        node_gdf=nodes_gdf,
    )

    new_description = new_network.numerical_network_description()

    original_df = pd.DataFrame([original_description])
    new_df = pd.DataFrame([new_description])
    assert_frame_equal(original_df, new_df)
    assert_frame_equal(new_network.branch_gdf, branches_gdf)
Beispiel #8
0
def plot_and_save_azimuths(network: Network, other_results_path: Path,
                           name: str):
    """
    Plot azimuth rose plots and save them.
    """
    _, fig, ax = network.plot_trace_azimuth()
    # save normal version
    fig.savefig(other_results_path / f"{name}_trace_azimuths.svg",
                bbox_inches="tight")
    # Make plain version
    plainify_rose_plot(fig, ax)
    # Save plain version
    fig.savefig(
        other_results_path / f"{name}_trace_azimuths_plain.svg",
        bbox_inches="tight",
        transparent=True,
    )
    # Branch version
    _, fig, _ = network.plot_branch_azimuth()
    fig.savefig(other_results_path / f"{name}_branch_azimuths.svg",
                bbox_inches="tight")
Beispiel #9
0
def test_network_kb11_manual():
    """
    Test Network analysis with KB11 data.

    Returns the Network.
    """
    trace_gdf = Helpers.kb11_traces
    area_gdf = Helpers.kb11_area
    network = Network(
        trace_gdf=trace_gdf,
        area_gdf=area_gdf,
        name="KB11 test",
        determine_branches_nodes=True,
        truncate_traces=True,
        snap_threshold=0.001,
        circular_target_area=False,
    )
    return network
Beispiel #10
0
    def random_network_sample(self, determine_branches_nodes=True) -> RandomSample:
        """
        Get random Network sample with a random target area.

        Returns the network, the sample circle centroid and circle radius.
        """
        # Create random Polygon circle within area
        target_circle, target_centroid, radius = self.random_target_circle()

        # Collect into GeoDataFrame and set crs if it exists in input frame
        area_gdf = gpd.GeoDataFrame({GEOMETRY_COLUMN: [target_circle]})
        if self.trace_gdf.crs is not None:
            area_gdf = area_gdf.set_crs(self.trace_gdf.crs)

        try:
            network_maybe: Optional[Network] = Network(
                trace_gdf=self.trace_gdf,
                area_gdf=area_gdf,
                name=self.name,
                determine_branches_nodes=determine_branches_nodes,
                snap_threshold=self.snap_threshold,
                circular_target_area=True,
                truncate_traces=True,
            )
        except ValueError:
            logging.error(
                "Error occurred during creation of random_network_sample.",
                exc_info=True,
                extra=dict(
                    sampler_name=self.name,
                    target_centroid=target_centroid,
                    radius=radius,
                ),
            )
            network_maybe = None

        return RandomSample(
            network_maybe=network_maybe,
            target_centroid=target_centroid,
            radius=radius,
            name=self.name,
        )
Beispiel #11
0
def test_azimuth_set_relationships_regression(
    azimuth_set_ranges: SetRangeTuple, num_regression
):
    """
    Test for azimuth set relationship regression.
    """
    azimuth_set_names: Tuple[str, ...] = ("1", "2", "3")[0 : len(azimuth_set_ranges)]
    relations_df: pd.DataFrame = Network(
        Helpers.kb7_traces,  # type: ignore
        Helpers.kb7_area,  # type: ignore
        name="kb7",
        determine_branches_nodes=True,
        azimuth_set_ranges=azimuth_set_ranges,
        azimuth_set_names=azimuth_set_names,
        snap_threshold=0.001,
        circular_target_area=False,
        truncate_traces=True,
    ).azimuth_set_relationships

    relations_df_dict = relations_df_to_dict(relations_df)

    num_regression.check(relations_df_dict)
Beispiel #12
0
def test_length_set_relationships_regression(num_regression):
    """
    Test for length set relationship regression.
    """
    trace_length_set_ranges: SetRangeTuple = (
        (0, 2),
        (2, 4),
        (4, 6),
    )
    trace_length_set_names: Tuple[str, ...] = ("a", "b", "c")
    relations_df: pd.DataFrame = Network(
        Helpers.kb7_traces,  # type: ignore
        Helpers.kb7_area,  # type: ignore
        name="kb7",
        determine_branches_nodes=True,
        trace_length_set_names=trace_length_set_names,
        trace_length_set_ranges=trace_length_set_ranges,
        snap_threshold=0.001,
        circular_target_area=False,
    ).azimuth_set_relationships

    relations_df_dict = relations_df_to_dict(relations_df)

    num_regression.check(relations_df_dict)
Beispiel #13
0
def network(
    trace_file: Path = typer.Argument(...,
                                      exists=True,
                                      dir_okay=False,
                                      help=TRACE_FILE_HELP),
    area_file: Path = typer.Argument(...,
                                     exists=True,
                                     dir_okay=False,
                                     help=AREA_FILE_HELP),
    snap_threshold: float = typer.Option(0.001, help=SNAP_THRESHOLD_HELP),
    determine_branches_nodes: bool = typer.Option(
        True,
        help=
        "Whether to determine branches and nodes as part of analysis. Recommended.",
    ),
    name: Optional[str] = typer.Option(
        None,
        help="Name for Network. Used when saving outputs and as plot titles."),
    circular_target_area: bool = typer.Option(
        False, help="Is/are target area(s) circles?"),
    truncate_traces: bool = typer.Option(
        True,
        help="Whether to cut traces at target area boundary. Recommended."),
    censoring_area: Optional[Path] = typer.Option(
        None,
        help=
        "Path to area data that delineates censored areas within target areas.",
    ),
    branches_output: Optional[Path] = typer.Option(
        None, help="Where to save branch data."),
    nodes_output: Optional[Path] = typer.Option(
        None, help="Where to save node data."),
    general_output: Optional[Path] = typer.Option(
        None,
        help="Where to save general network analysis outputs e.g. plots."),
    parameters_output: Optional[Path] = typer.Option(
        None, help="Where to save numerical parameter data from analysis."),
):
    """
    Analyze the geometry and topology of trace network.
    """
    network_name = name if name is not None else area_file.stem
    console = Console()

    console.print(
        Text.assemble("Performing network analysis of ",
                      (network_name, "bold green"), "."))

    network = Network(
        trace_gdf=read_geofile(trace_file),
        area_gdf=read_geofile(area_file),
        snap_threshold=snap_threshold,
        determine_branches_nodes=determine_branches_nodes,
        name=network_name,
        circular_target_area=circular_target_area,
        truncate_traces=truncate_traces,
        censoring_area=read_geofile(censoring_area)
        if censoring_area is not None else gpd.GeoDataFrame(),
    )
    (
        general_output_path,
        branches_output_path,
        nodes_output_path,
        parameters_output_path,
    ) = default_network_output_paths(
        network_name=network_name,
        general_output=general_output,
        branches_output=branches_output,
        nodes_output=nodes_output,
        parameters_output=parameters_output,
    )
    # Save branches and nodes
    console.print(
        Text.assemble(
            "Saving branches to ",
            (str(branches_output_path), "bold green"),
            " and nodes to ",
            (str(nodes_output_path), "bold green"),
            ".",
        ))
    network.branch_gdf.to_file(branches_output_path, driver="GPKG")
    network.node_gdf.to_file(nodes_output_path, driver="GPKG")

    console.print(rich_table_from_parameters(network.parameters))

    pd.DataFrame([network.numerical_network_description()
                  ]).to_csv(parameters_output_path)

    console.print(
        Text.assemble(
            "Saving extensive network parameter csv to path:\n",
            (str(parameters_output_path), "bold green"),
        ))

    # Plot ternary XYI-node proportion plot
    fig, _, _ = network.plot_xyi()
    save_fig(fig=fig, results_dir=general_output_path, name="xyi_ternary_plot")

    # Plot ternary branch proportion plot
    fig, _, _ = network.plot_branch()
    save_fig(fig=fig,
             results_dir=general_output_path,
             name="branch_ternary_plot")

    # Plot trace azimuth rose plot
    _, fig, _ = network.plot_trace_azimuth()
    save_fig(fig=fig, results_dir=general_output_path, name="trace_azimuth")

    # Plot trace length distribution plot
    _, fig, _ = network.plot_trace_lengths()
    save_fig(fig=fig,
             results_dir=general_output_path,
             name="trace_length_distribution")
Beispiel #14
0
def network_extensive_testing(
    network: Network,
    traces: gpd.GeoDataFrame,
    area: gpd.GeoDataFrame,
    snap_threshold: float,
):
    """
    Test Network attributes extensively.
    """
    # Test resetting
    copy_trace_gdf = network.trace_data._line_gdf.copy()
    copy_branch_gdf = network.branch_data._line_gdf.copy()

    # Test resetting
    network.reset_length_data()
    assert_frame_equal(copy_trace_gdf, network.trace_data._line_gdf)
    assert_frame_equal(copy_branch_gdf, network.branch_data._line_gdf)

    network_anisotropy = network.anisotropy
    assert isinstance(network_anisotropy, tuple)
    assert isinstance(network_anisotropy[0], np.ndarray)
    assert isinstance(network.trace_length_set_array, np.ndarray)
    assert isinstance(network.branch_length_set_array, np.ndarray)

    # Test passing old branch and node data
    branch_copy = network.branch_gdf.copy()
    network_test = Network(
        trace_gdf=traces,
        area_gdf=area,
        name="teeest_with_old",
        branch_gdf=branch_copy,
        node_gdf=network.node_gdf.copy(),
        determine_branches_nodes=False,
        truncate_traces=True,
        snap_threshold=snap_threshold,
    )

    assert_frame_equal(network_test.branch_gdf, branch_copy)

    # Test plotting
    fig_returns = network.plot_branch()
    assert fig_returns is not None
    fig, ax, tax = fig_returns
    assert isinstance(fig, Figure)
    assert isinstance(ax, Axes)
    assert isinstance(tax, TernaryAxesSubplot)
    plt.close("all")

    # Test plotting
    fig_returns = network.plot_xyi()
    assert fig_returns is not None
    fig, ax, tax = fig_returns
    assert isinstance(fig, Figure)
    assert isinstance(ax, Axes)
    assert isinstance(tax, TernaryAxesSubplot)
    plt.close("all")

    for plot in (
        "plot_parameters",
        "plot_anisotropy",
        "plot_trace_azimuth_set_count",
        "plot_branch_azimuth_set_count",
        "plot_trace_length_set_count",
        "plot_branch_length_set_count",
        "plot_trace_azimuth",
        "plot_branch_azimuth",
        "plot_trace_lengths",
        "plot_branch_lengths",
        "plot_trace_azimuth_set_lengths",
        "plot_branch_azimuth_set_lengths",
    ):
        # Test plotting
        fig_returns = getattr(network, plot)()
        assert fig_returns is not None
        if len(fig_returns) == 2:
            fig, ax = fig_returns
        elif len(fig_returns) == 3 and "length" in plot:
            other, fig, ax = fig_returns
            if not isinstance(other, powerlaw.Fit):
                # assume fits, figs, axes from plot_*_set_lengths
                assert isinstance(other, list)
                assert isinstance(other[0], powerlaw.Fit)
                # Check just the first value of returns
                assert len(other) == len(fig)
                assert len(other) == len(ax)
                assert len(other) == len(network.azimuth_set_names)
                other, fig, ax = other[0], fig[0], ax[0]
        elif len(fig_returns) == 3 and "azimuth" in plot:
            other, fig, ax = fig_returns
            assert isinstance(other, AzimuthBins)
        else:
            raise ValueError("Expected 3 max returns.")
        assert isinstance(fig, Figure)
        assert isinstance(ax, (Axes, PolarAxes))
        plt.close("all")
Beispiel #15
0
def test_network(
    traces,
    area,
    name,
    determine_branches_nodes,
    truncate_traces,
    snap_threshold,
    circular_target_area,
    file_regression,
    data_regression,
):
    """
    Test Network object creation and attributes with general datasets.

    Tests for regression and general assertions.
    """
    network = Network(
        trace_gdf=traces,
        area_gdf=area,
        name=name,
        determine_branches_nodes=determine_branches_nodes,
        truncate_traces=truncate_traces,
        snap_threshold=snap_threshold,
        trace_length_set_names=("a", "b"),
        branch_length_set_names=("A", "B"),
        trace_length_set_ranges=((0.1, 1), (1, 2)),
        branch_length_set_ranges=((0.1, 1), (1, 2)),
        circular_target_area=circular_target_area,
    )

    assert area.shape[0] == len(network.representative_points())
    numerical_description = network.numerical_network_description()
    assert isinstance(numerical_description, dict)
    for key, item in numerical_description.items():
        assert isinstance(key, str)
        if not isinstance(item, (int, float, str)):
            assert isinstance(item.item(), (int, float))

    cut_off = 1.0
    num_description_explicit_cut_offs = network.numerical_network_description(
        trace_lengths_cut_off=cut_off, branch_lengths_cut_off=cut_off
    )
    for label in ("branch", "trace"):
        key = label + (
            " "
            + length_distributions.Dist.POWERLAW.value
            + " "
            + length_distributions.CUT_OFF
        )
        assert num_description_explicit_cut_offs[key] == 1.0

    network_target_areas = network.target_areas
    assert isinstance(network_target_areas, list)
    assert all(
        [isinstance(val, (Polygon, MultiPolygon)) for val in network_target_areas]
    )

    network_attributes = dict()
    for attribute in ("node_counts", "branch_counts"):
        # network_attributes[attribute] = getattr(network, attribute)
        for key, value in getattr(network, attribute).items():
            if not np.isnan(value):
                network_attributes[key] = int(value)

        for key, value in numerical_description.items():
            if isinstance(value, (float, int)):
                network_attributes[key] = round(
                    value.item() if hasattr(value, "item") else value, 2
                )

    data_regression.check(network_attributes)

    if determine_branches_nodes and network.branch_gdf.shape[0] < 500:

        sorted_branch_gdf = network.branch_gdf.sort_index()
        assert isinstance(sorted_branch_gdf, gpd.GeoDataFrame)
        # Do not check massive branch counts
        file_regression.check(sorted_branch_gdf.to_json(indent=1))
        network_extensive_testing(
            network=network, traces=traces, area=area, snap_threshold=snap_threshold
        )

    trace_intersects = network.trace_intersects_target_area_boundary
    assert isinstance(trace_intersects, np.ndarray)
    assert trace_intersects.dtype in ("int32", "int64")
    branch_intersects = network.branch_intersects_target_area_boundary
    assert isinstance(branch_intersects, np.ndarray)
    assert network.branch_intersects_target_area_boundary.dtype in ("int32", "int64")