diff --git a/superblockify/metrics/measures.py b/superblockify/metrics/measures.py index 5e5ebd3..d738bad 100644 --- a/superblockify/metrics/measures.py +++ b/superblockify/metrics/measures.py @@ -229,6 +229,65 @@ def write_relative_increase_to_edges( ) +def write_component_wise_travel_increase( + partitioner, distance_matrix, node_list, measure1, measure2 +): + """Write the component-wise relative travel increase to the Superblocks. + + For every Superblock of the partitioner, calculate the relative travel increase. + This is the mean of the relative travel increase for all pairs of nodes in the + Superblock. Relative travel increase is the percentual increase of the travel + between measure 1 and measure 2. + + Mean of d_1(i, j) / d_2(i, j) if i in the concerning component. + + The mean is written to the `rel_increase` key of the Superblock and to the + `rel_increase_comp` attribute of the edges of the Superblock's subgraph. + + Parameters + ---------- + partitioner : Partitioner + The partitioner to calculate the component-wise travel increase for. + distance_matrix : dict + The distance matrix to calculate the component-wise travel increase for. + node_list : list + The list of nodes the distance matrices are sorted by. + measure1 : str + The name of the first measure. Key for the distance matrix. + measure2 : str + The name of the second measure. Key for the distance matrix. + """ + + rel_incr = rel_increase(distance_matrix[measure1], distance_matrix[measure2]) + + for component in partitioner.get_ltns(): + if component.get("ignore") is True: + continue + # Calculate mean of the relative travel increase: Take all increases from + # inside the component to all other nodes and reverse. All rows and columns + # with indices in the component + nodes_idx = [ + node_list.index(node) + for node in component["subgraph"].nodes + if node not in partitioner.sparsified.nodes + ] + # column from nodes to all other nodes + col = rel_incr[:, nodes_idx] + # row from all other nodes to nodes + row = rel_incr[nodes_idx, :] + # Take the mean of the union where the values are not np.inf + rel_increase_component = np.mean( + np.union1d( + col[~np.isinf(col)], + row[~np.isinf(row)], + ) + ) + component["rel_increase"] = rel_increase_component + # Write this to the edges of the subgraph + for edge in component["subgraph"].edges: + partitioner.graph.edges[edge]["rel_increase_comp"] = rel_increase_component + + @nx.utils.py_random_state(7) def betweenness_centrality( graph, diff --git a/superblockify/metrics/metric.py b/superblockify/metrics/metric.py index 45ce6c5..fb4c495 100644 --- a/superblockify/metrics/metric.py +++ b/superblockify/metrics/metric.py @@ -12,6 +12,7 @@ calculate_global_efficiency, calculate_directness, write_relative_increase_to_edges, + write_component_wise_travel_increase, calculate_coverage, betweenness_centrality, calculate_high_bc_clustering, @@ -330,6 +331,13 @@ def calculate_all( "N", "S", ) + write_component_wise_travel_increase( + partitioner, + self.distance_matrix, + self.node_list, + "N", + "S", + ) add_ltn_means( partitioner.get_ltns(), edge_attr=[ diff --git a/superblockify/metrics/plot.py b/superblockify/metrics/plot.py index 2ee5070..9e23af6 100644 --- a/superblockify/metrics/plot.py +++ b/superblockify/metrics/plot.py @@ -254,19 +254,17 @@ def plot_distance_matrices_pairwise_relative_difference(metric, name=None): def plot_component_wise_travel_increase( partitioner, distance_matrix, node_list, measure1, measure2, unit, **pg_kwargs ): - """Calculate and plot the component-wise travel increase. + """Plot the component-wise travel increase. - For every component of the partitioner, calculate the relative travel increase. - This is the mean of the relative travel increase for all pairs of nodes in the - component. Relative travel increase is the percentual increase of the travel between - measure 1 and measure 2. - - Mean of d_1(i, j) / d_1(i, j) if i in the concerning component. + Plots the relative travel increase per Superblock, as calculated by + :func:`superblockify.metrics.measures.write_component_wise_travel_increase` + and stored in the `rel_increase` key of the Superblocks and the + `rel_increase_comp` edge attribute. Parameters ---------- partitioner : Partitioner - The partitioner to calculate the component-wise travel increase for. + The partitioner to plot the component-wise travel increase for. distance_matrix : dict The distance matrix to calculate the component-wise travel increase for. node_list : list @@ -284,36 +282,13 @@ def plot_component_wise_travel_increase( ------- fig, axes : matplotlib.figure.Figure, matplotlib.axes.Axes The figure and axes of the plot. - """ # pylint: disable=too-many-locals - - partition_nodes = partitioner.get_partition_nodes() - - rel_incr = rel_increase(distance_matrix[measure1], distance_matrix[measure2]) - - for component in partition_nodes: - # Calculate mean of the relative travel increase: Take all increases from inside - # the component to all other nodes and reverse. All rows and columns with - # Indices in the component - nodes_idx = [ - node_list.index(node) - for node in component["subgraph"].nodes - if node not in partitioner.sparsified.nodes - ] - # column from nodes to all other nodes - col = rel_incr[:, nodes_idx] - # row from all other nodes to nodes - row = rel_incr[nodes_idx, :] - # Take the mean of the union where the values are not np.inf - rel_increase_component = np.mean( - np.union1d( - col[~np.isinf(col)], - row[~np.isinf(row)], - ) - ) - component["rel_increase"] = rel_increase_component - # Write this to the edges of the subgraph - for edge in component["subgraph"].edges: - partitioner.graph.edges[edge]["rel_increase_comp"] = rel_increase_component + """ # pylint: disable=unused-argument + + partition_nodes = [ + component + for component in partitioner.get_ltns() + if component.get("ignore") is not True + ] _, axes = plt.subplots(1, 1, figsize=(10, 10)) # Add colorbar diff --git a/superblockify/utils.py b/superblockify/utils.py index 336b9ac..9c5d68d 100644 --- a/superblockify/utils.py +++ b/superblockify/utils.py @@ -379,6 +379,7 @@ def load_graphml_dtypes(filepath=None, attribute_label=None, attribute_dtype=Non "travel_time": float, "travel_time_restricted": float, "rel_increase": float, + "rel_increase_comp": float, "population": float, "area": float, "cell_id": int, diff --git a/tests/metrics/test_metric.py b/tests/metrics/test_metric.py index 6e06b5e..27cf8e5 100644 --- a/tests/metrics/test_metric.py +++ b/tests/metrics/test_metric.py @@ -112,6 +112,15 @@ def test_calculate_metrics( assert component["change_mean_edge_betweenness_length"] is not None assert component["change_mean_edge_betweenness_linear"] is not None + def test_calculate_metrics_without_plots(self, test_city_small_precalculated_copy): + """Test that rel_increase_comp is calculated without make_plots.""" + part = test_city_small_precalculated_copy + part.calculate_metrics(make_plots=False) + for component in part.get_ltns(): + assert "rel_increase" in component + for edge in component["subgraph"].edges: + assert "rel_increase_comp" in part.graph.edges[edge] + @pytest.mark.parametrize("unit", ["time", "distance"]) def test_calculate_metrics_before(self, test_one_city_precalculated_copy, unit): """Test the metric calculation for before partitioning."""