如何在 Python 上获取 Mesa 和 Networkx 节点之间的距离?

How to get the distance between nodes with Mesa and Networkx on Python?

我正在关注使用 Networkx 创建网络图的 Mesa 库中的 example called Virus on Network

这是它筛选节点邻居的功能,试图用病毒感染他们。

def try_to_infect_neighbors(self):
    neighbors_nodes = self.model.grid.get_neighbors(self.pos, include_center=False)
    susceptible_neighbors = [agent for agent in self.model.grid.get_cell_list_contents(neighbors_nodes) if
                             agent.state is State.SUSCEPTIBLE]
    for a in susceptible_neighbors:
        if self.random.random() < self.virus_spread_chance:
            a.state = State.INFECTED

不过,我喜欢获取节点与其邻居之间的距离。 Mesa 的 another example called Sugarscape 似乎就是这样做的。

于是我将代码修改为:

def try_to_infect_neighbors(self):
    neighbors_nodes = self.model.grid.get_neighbors(self.pos, include_center=False)
    susceptible_neighbors = [agent for agent in self.model.grid.get_cell_list_contents(neighbors_nodes) if
                             agent.state is State.SUSCEPTIBLE]                         
    for a in susceptible_neighbors:

        print('Self position:', self.pos, 'Neightbor position:', neighbor_agent.pos)
        # Output: Self position: 52 Neightbor position: 13
        neightbor_distance = get_distance(self.pos, neighbor_agent.pos)
        # TypeError: 'int' object is not iterable
        print(neightbor_distance)

        if neightbor_distance <= 1:
            if self.random.random() < self.virus_spread_chance:
                a.state = State.INFECTED

def get_distance(pos_1, pos_2):
    """ Get the distance between two point
    Args:
        pos_1, pos_2: Coordinate tuples for both points.
    """
    x1, y1 = pos_1
    x2, y2 = pos_2
    dx = x1 - x2
    dy = y1 - y2
    return math.sqrt(dx**2 + dy**2)

在 Sugarscape 示例中,a.pos 给出了 x 和 y 位置的元组。但是在 Virus on Network 中,a.pos 给出了代理的 ID。如何在网络病毒示例中访问代理的 x 和 y 位置?我尝试通过以下变量从 a.model.Ga.model.grid 中搜索它们:self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob)self.grid = NetworkGrid(self.G),但我无法识别它们并且我认为不应该那样隐藏。

这里是一些添加边权重或获取随机节点位置的代码(也许你想缩放它们)。

import networkx as nx
import random

num_nodes = 10
prob = .25

G = nx.erdos_renyi_graph(n=num_nodes, p=prob)

# you need to add this in the __init__ of VirusOnNetwork
for u, v in G.edges():
    # add random weights between 0 and 10
    G[u][v]["weight"] = random.random() * 10
    # you can access these weights in the same way (G[from_node][target_node]["weight"]

print(G.edges(data=True))
# [(0, 5, {'weight': 2.3337749464751454}), (0, 9, {'weight': 6.127630949347937}), (1, 4, {'weight': 9.048896640242369}), (2, 4, {'weight': 1.4236964132196228}), (2, 6, {'weight': 4.749936581386136}), (2, 9, {'weight': 2.037644705935693}), (3, 5, {'weight': 2.296192134297448}), (3, 7, {'weight': 1.5250362478641677}), (3, 9, {'weight': 7.362866019415747}), (4, 6, {'weight': 7.365668938333058}), (5, 6, {'weight': 1.1855367672698724}), (5, 8, {'weight': 3.219373770451519}), (7, 9, {'weight': 4.025563800958256})]


# alternative node positions
# you can store them in the graph or as separate attribute of your model
pos = nx.random_layout(G)

print(pos)
#{0: array([0.8604371 , 0.19834588], dtype=float32), 1: array([0.13099413, 0.97313595], dtype=float32), 2: array([0.30455875, 0.8844262 ], dtype=float32), 3: array([0.575425, 0.517468], dtype=float32), 4: array([0.7437008 , 0.89525336], dtype=float32), 5: array([0.9664812 , 0.21694745], dtype=float32), 6: array([0.89979964, 0.33603832], dtype=float32), 7: array([0.7894464, 0.7614578], dtype=float32), 8: array([0.44350627, 0.9081728 ], dtype=float32), 9: array([0.8049214 , 0.20761919], dtype=float32)}

# you can use this position for visualisation with networkx
nx.draw(G, pos)