Как получить расстояние между узлами с Mesa и Networkx на Python?

Я следую этому примеру под названием «Вирус в сети» из библиотеки Mesa, которая создает сетевые графы с помощью Networkx.

Вот его функция, которая проверяет соседей узла, чтобы попытаться заразить их вирусом.

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

Однако мне нравится определять расстояние между узлом и его соседом. А вот еще один пример под названием 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. Но в случае с вирусом в сети a.pos дает идентификатор агента. Как я могу получить доступ к местоположению агента по осям x и y в примере «Вирус в сети»? Я попытался найти их внутри a.model.G и a.model.grid с помощью переменных: self.G = nx.erdos_renyi_graph(n=self.num_nodes, p=prob) и self.grid = NetworkGrid(self.G), но я не смог их идентифицировать и думаю, что это не должно быть так скрыто.


person KubiK888    schedule 07.04.2020    source источник
comment
Модель вируса не имеет координат (x, y), назначенных агентам (см. Реализацию _ 1_). Вы можете просто добавить случайные веса в качестве расстояния до графа или поместить узлы графа на 2D-плоскость (например, с помощью алгоритма рисования и использовать это). Решило бы это вашу проблему?   -  person Sparky05    schedule 09.04.2020
comment
Как разместить узлы на графике? Рабочий пример будет отличным.   -  person KubiK888    schedule 09.04.2020
comment
А также, не могли бы вы объяснить, как я могу назначить вес соединениям узлов?   -  person KubiK888    schedule 10.04.2020


Ответы (1)


Вот код для добавления весов ребер или получения случайных позиций узлов (возможно, вы захотите их масштабировать).

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)
person Sparky05    schedule 10.04.2020
comment
После того, как вы сгенерируете позиции x и y для каждого узла, можно ли переназначить или перерисовать erdos_renyi_graph, чтобы он соответствовал некоторым осям x и y? Если нет, есть ли альтернативный график, который я могу сделать вместе с информацией о сетевом подключении? - person KubiK888; 10.04.2020
comment
Что вы имеете в виду под перерисовкой? Вы имеете в виду только визуализацию? или вы имеете в виду выборку новых ребер? - person Sparky05; 10.04.2020
comment
То, что я имею в виду, взято из моего исходного сообщения, вы упомянули, и похоже, что networkgrid не имеет координат x и y, назначенных агенту. Но мой код был построен на этой схеме отображения, и мне очень нравится, как она показывает узлы и края. В вашем ответе похоже, что вы назначаете случайные x и y в качестве pos каждому узлу. Поэтому мне интересно, если бы я отобразил это как сетевой график, как я могу отобразить это таким образом, чтобы он показывал недавно назначенные позиции x и y. Например, рассматривая самый нижний левый угол как позицию (0, 0). - person KubiK888; 10.04.2020
comment
Сервер вашего примера (github.com/projectmesa/ mesa / blob / master / examples /) не использует рисунок networkx, а использует некоторый javascript. Затем вам нужно будет изменить это и соответствующий файл js (github.com/projectmesa/mesa/blob/) - person Sparky05; 11.04.2020