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")
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")