What format does sp have to have to work with nx.barycenter?

24 Views Asked by At

I'm using networkx to analyse a weighted, undirected graph and ran into a problem determining the barycenter. My graph is not connected, but made out of three components which are connected. Therefore, I use the function on each subgraph individually.

When I run nx.barycenter with the weights of the graphs it works, but if I run it with the shortest paths precalculated, it doesn't. In that case, I get the NetworkXNoPath: Input graph Graph with 6 nodes and 6 edges is disconnected, so every induced subgraph has infinite barycentricity. error.

So apparently this is related to the shortest_paths I'm giving the function.
The documentation says, I need All pairs shortest path lengths as a dictionary of dictionaries, but with the one I get from dict(nx.shortest_path_length(graph, weight = "weight")) it doesn't work.

Do I need to calculate it differently?

My code currently is:

import networkx as nx

def components(graph):
    connected_comps = sorted(list(nx.connected_components(graph)), key=len, reverse=True)
    return connected_comps

def subgraphs(graph):
    subgraphs = [] 
    connected_comps = components(graph)
    for i, comp in enumerate(connected_comps):
        subgraph = graph.subgraph(comp)
        subgraphs.append(subgraph)
    return subgraphs

graph = nx.Graph()

component1 = [387522, 7189, 3337, 5071]
component2 = [1, 2, 3, 4]
component3 = [2861, 3103, 7188, 387511, 387521, 387531]

graph.add_nodes_from(component1)
graph.add_nodes_from(component2)
graph.add_nodes_from(component3)

graph.add_edge(387522, 7189, weight = 0.55)
graph.add_edge(387522, 3337, weight = 0.55)
graph.add_edge(7189, 3337, weight = 0.86)
graph.add_edge(5071, 7189, weight = 0.72)
graph.add_edge(5071, 3337, weight = 0.72)
graph.add_edge(5071, 387522, weight = 0.72)
graph.add_edge(1, 2, weight = 0.78)
graph.add_edge(1, 3, weight = 0.78)
graph.add_edge(1, 4, weight = 0.78)
graph.add_edge(2, 3, weight = 0.78)
graph.add_edge(2, 4, weight = 0.78)
graph.add_edge(3, 4, weight = 0.78)
graph.add_edge(2861, 3103, weight = 0.78)
graph.add_edge(7188, 2861, weight = 0.86)
graph.add_edge(2861, 387511, weight = 0.86)
graph.add_edge(7188, 387521, weight = 0.86)
graph.add_edge(7188, 3103, weight = 0.86)
graph.add_edge(3103, 387531, weight = 0.86)

p = dict(nx.shortest_path_length(graph, weight = "weight"))

shortest_paths = {
    '387522': {'387522': 0, '7189': 0.55, '3337': 0.55, '5071': 0.72},
    '7189': {'7189': 0, '387522': 0.55, '3337': 0.86, '5071': 0.72},
    '3337': {'3337': 0, '387522': 0.55, '7189': 0.86, '5071': 0.72},
    '5071': {'5071': 0, '7189': 0.72, '3337': 0.72, '387522': 0.72},
    '1': {'1': 0, '2': 0.78, '3': 0.78, '4': 0.78},
    '2': {'2': 0, '1': 0.78, '3': 0.78, '4': 0.78},
    '3': {'3': 0, '1': 0.78, '2': 0.78, '4': 0.78},
    '4': {'4': 0, '1': 0.78, '2': 0.78, '3': 0.78},
    '2861': {'2861': 0, '3103': 0.78, '7188': 0.86, '387511': 0.86, '387531': 1.64, '387521': 1.72},
    '3103': {'3103': 0, '2861': 0.78, '7188': 0.86, '387531': 0.86, '387511': 1.64, '387521': 1.72},
    '7188': {'7188': 0, '2861': 0.86, '387521': 0.86, '3103': 0.86, '387511': 1.72, '387531': 1.72},
    '387511': {'387511': 0, '2861': 0.86, '3103': 1.64, '7188': 1.72, '387531': 2.5, '387521': 2.58},
    '387521': {'387521': 0, '7188': 0.86, '2861': 1.72, '3103': 1.72, '387511': 2.58, '387531': 2.58},
    '387531': {'387531': 0, '3103': 0.86, '2861': 1.64, '7188': 1.72, '387511': 2.5, '387521': 2.58}       
}

def find_bary_center(graph, sp=None):
    centers = []
    for subgraph in subgraphs(graph):
        if nx.is_connected(subgraph):
            print("Connected", subgraph)
        center = nx.barycenter(subgraph, sp=sp)
        centers.append(center)
    return centers

bary = find_bary_center(graph, p)
#print(p)

In this case, p has the same format as shortest_paths, but neither work. Both are a dictionary of dictionaries, so they seem like they should work, but they don't.

1

There are 1 best solutions below

0
Paul Brodersen On BEST ANSWER

It appears that the shortest path dict is assumed to only contain nodes that are also in the graph being passed to barycenter.

def find_bary_center(graph, sp=None):
    centers = []
    for subgraph in subgraphs(graph):
        if nx.is_connected(subgraph):
            print("Connected", subgraph)
        if sp is not None:
            center = nx.barycenter(subgraph, sp={node : data for node, data in sp.items() if node in subgraph})
        else:
            center = nx.barycenter(subgraph)
        centers.append(center)
    return centers

bary = find_bary_center(graph, p)
# [[2861, 3103], [387522], [1, 2, 3, 4]]