#python #networkx
#python #networkx
Вопрос:
Я хотел бы создать график, в котором узлы имеют разный вес и цвет на основе значений в столбцах.
Образец данных
Узел | Вес | Цвет | Соседи |
---|---|---|---|
1 | 23 | красный | [3,5] |
3 | 18 | Синий | [2] |
4 | 50 | Синий | [] |
5 | 18 | Синий | [1] |
2 | 36 | Зеленый | [3] |
В таблице выше показаны ссылки по узлам:
- узел 1 связан с 3 и 5. Он имеет вес 23 и красный цвет
- узел 2 связан с 3. Он имеет вес 36 и зеленый цвет
- узел 3 связан с 2. Он имеет вес 18 и синий цвет
- узел 4 не имеет ссылок. Он имеет синий цвет и вес 50
- узел 5 связан с 1. Он имеет вес 18 и синий цвет
Для построения сети я сделал следующее
d = dict(df.drop_duplicates(subset=['Node','Colour'])[['Node','Colour']].to_numpy().tolist())
nodes = G.nodes()
plt.figure(figsize=(30,30))
pos = nx.draw(G, with_labels=True,
nodelist=nodes,
node_color=[d.get(i,'lightgreen') for i in nodes],
node_size=1000)
К сожалению, все цвета неверны! Кроме того, у меня возникают трудности с добавлением информации о весах.
Связи между узлами должны иметь присвоенные им веса.
Я пробовал с edge_attr='weight'
помощью in nx.draw
, где 'weight' = df['Weight']
.
Я надеюсь, что вы можете оказать мне некоторую помощь и сообщить, что я сделал не так.
Ответ №1:
node_color=[d.get(i,'lightgreen') for i in nodes],
Этот метод раскраски не сработал, потому что вы назначаете цвета в соответствии с nodes
вместо их цветов.
«Связи между узлами должны иметь присвоенные им веса. Я пробовал использовать edge_attr=’weight’ в nx.draw, где ‘weight’ = df[‘Вес’].»*
Для решения, которое я представляю, только узлы имеют веса, а не ребра. Если вы притворяетесь, что делаете это, добавьте столбец в свой фрейм данных, например:
Узел | Вес | Цвет | Соседи | Edge_Weights |
---|---|---|---|---|
1 | 23 | красный | [3,5] | [w1_3,w1_5] |
3 | 18 | Синий | [2] | [w3_2] |
4 | 50 | Синий | [] | [] |
5 | 18 | Синий | [1] | [w5_1] |
2 | 36 | Зеленый | [3] | [w2_3] |
Затем добавьте вес ребра, используя G.add_edge(n1,n2,wight=w)
, вот некоторая документация.
Поскольку у вас есть несколько атрибутов, которые вы хотите добавить к своим узлам, я бы рекомендовал выполнить итерацию по вашему фрейму данных, используя, например df.itertuples()
.
Вот полный код:
df = pd.DataFrame( data = {'Node': [1, 3, 4, 5, 2],
'Weight': [23, 18 ,50, 18, 36],
'Colour': ["red", "blue", "blue", "blue", "green"],
'Neighbors': [[3,5], [2], [], [1], [3]]
}
)
NROWS = None
def get_graph_from_pandas(df:
G = nx.DiGraph() # assuming the graph is directed since e.g node 1 has
# 3 as neighbour but 3 doesnt have 1 as neighbour
for row in df.itertuples(): # row is the row of the dataframe
n = row.Node # change to row.(name of column with the node names)
w = row.Weight # change to row.(name of column with the node weights)
c = row.Colour # change to row.(name of column with the node colors)
neighbors = row.Neighbors
G.add_node(n, weight = w, colour = c)
for neigh in neighbors:
#add edge weights here, attribute of G.add_edge
G.add_edge(n,neigh)
return G
G = get_graph_from_pandas(df)
print("Done.")
print("Total number of nodes: ", G.number_of_nodes())
print("Total number of edges: ", G.number_of_edges())
pos = nx.draw(G, with_labels=True,
node_color=[node[1]['colour'] for node in G.nodes(data=True)],
node_size=200)
Комментарии:
1. Привет, willcrack, спасибо за ваш ответ. Не могли бы вы, пожалуйста, объяснить мне эту строку кода:
node_color=[node[1]['colour'] for node in G.nodes(data=True)]
я получаю сообщение об ошибке:KeyError: 'colour'
когда я расширяю график на весь набор данных. Большое спасибо2. Привет! Пока вы делаете:
c = row.Colour
,G.add_node(n, weight = w, colour = c)
он не должен возвращать эту ошибку3.
node_color=[node[1]['colour'] for node in G.nodes(data=True)]
Эта строка использует понимание списка , чтобы вернуть список с цветом ваших узлов.4. Я считаю, что создание нового сообщения — лучший вариант
5. Np @Val 😉 рад, что смог помочь