是否可以用networkx为每个节点绘制多颜色的图形

时间:2023-02-03 09:54:11

I want to color nodes and edges of Karate club graph. But some of nodes have more than one color. Is there any way to color a node with more than one color in python (especially with networkx)? I need something like this:

我想给空手道俱乐部图的节点和边缘上色。但是有些节点有不止一种颜色。在python中,有什么方法可以给一个具有多个颜色的节点上色(特别是在networkx中)?我需要这样的东西:

是否可以用networkx为每个节点绘制多颜色的图形

1 个解决方案

#1


2  

This can be done but it will probably require a lot of work to obtain the exact result you want. You could start with networkx and pygraphviz like this:

这是可以做到的,但它可能需要大量的工作才能得到您想要的确切结果。你可以从networkx和pygraphviz开始:

import networkx as nx

karate = nx.generators.social.karate_club_graph()                        
karate_agr = nx.nx_agraph.to_agraph(karate)

karate_agr.node_attr['style'] = 'filled'
karate_agr.node_attr['shape'] = 'circle'
karate_agr.node_attr['gradientangle'] = 90

for i in karate_agr.nodes():
    n = karate_agr.get_node(i)
    n.attr['fillcolor'] = 'green;0.5:yellow'

karate_agr.draw('karate.png',prog='dot')

Pygraphviz makes use of graphviz which has really a lot of options. Most of them can be set either for individual nodes (or edges) or globally for all of them like in the example above. It is all well explained in the graphviz documentation.

Pygraphviz使用了graphviz,它有很多选项。它们中的大多数可以为单个节点(或边缘)设置,也可以为所有节点设置全局,如上面的示例所示。这在graphviz文档中有很好的解释。

The above snippet only shows how to make the nodes filled half with one color and half with the other. See the result below (not very beautiful, I know).

上面的代码片段只展示了如何使节点一半用一种颜色填充,另一半用另一种颜色填充。看看下面的结果(我知道不是很漂亮)。

是否可以用networkx为每个节点绘制多颜色的图形

EDIT

编辑

Hmm, so this kinda grew on me, and I really wanted to make something more similar to what you posted. This is what I came up with:

嗯,这让我有点受不了,我真的想做一些和你发的更相似的东西。这就是我想到的:

# coding: utf-8
import networkx as nx
import itertools
from collections import Counter


def edge_in_com(nodes, graph):
    edges = []
    for (i, j) in itertools.combinations(nodes, 2):
        if (i, j) in graph.edges():
            edges.append((i, j))
    return edges


karate = nx.generators.social.karate_club_graph()
karate_agr = nx.nx_agraph.to_agraph(karate)

karate_agr.graph_attr['dpi'] = 180
karate_agr.edge_attr.update(
    dir='both', arrowhead='inv', arrowtail='inv', penwidth=2.0)

karate_agr.node_attr.update(
    style='filled',
    fontcolor='white',
    shape='circle',
    color='transparent',
    gradientangle=90)

colors = ['grey', 'pink', 'blue', 'purple']
communities = list(nx.community.asyn_fluidc(karate, 4))

most_edges = []
for n, com in enumerate(communities):
    edges = edge_in_com(com, karate)
    most_edges.extend(edges)
    for edge in edges:
        e = karate_agr.get_edge(*edge)
        e.attr['color'] = colors[n]
    for node in com:
        node = karate_agr.get_node(node)
        node.attr['fillcolor'] = colors[n]

other = [e for e in karate.edges() if e not in most_edges]

for edge in other:
    gn = karate_agr.get_node
    color = gn(edge[0]).attr['fillcolor']
    karate_agr.get_edge(*edge).attr['color'] = color

for n in karate_agr.nodes():
    cls = [e.attr['color'] for e in karate_agr.in_edges(n)]
    cls2 = [e.attr['color'] for e in karate_agr.out_edges(n)]
    cls = set(cls + cls2)
    if len(cls) > 1:
        # if n.attr['fillcolor'] != cls[0]:
        color1 = cls.pop()
        color2 = cls.pop()
        color_mix = ''.join([color1, ';', '0.5:', color2])
        n.attr['fillcolor'] = color_mix

karate_agr.draw('karate.png', prog='neato')

The program definitely can be improved, and I'm still not very happy with the results but maybe you'll find it helpful.

这个程序肯定是可以改进的,我对结果不太满意,但是也许你会发现它很有帮助。

是否可以用networkx为每个节点绘制多颜色的图形

#1


2  

This can be done but it will probably require a lot of work to obtain the exact result you want. You could start with networkx and pygraphviz like this:

这是可以做到的,但它可能需要大量的工作才能得到您想要的确切结果。你可以从networkx和pygraphviz开始:

import networkx as nx

karate = nx.generators.social.karate_club_graph()                        
karate_agr = nx.nx_agraph.to_agraph(karate)

karate_agr.node_attr['style'] = 'filled'
karate_agr.node_attr['shape'] = 'circle'
karate_agr.node_attr['gradientangle'] = 90

for i in karate_agr.nodes():
    n = karate_agr.get_node(i)
    n.attr['fillcolor'] = 'green;0.5:yellow'

karate_agr.draw('karate.png',prog='dot')

Pygraphviz makes use of graphviz which has really a lot of options. Most of them can be set either for individual nodes (or edges) or globally for all of them like in the example above. It is all well explained in the graphviz documentation.

Pygraphviz使用了graphviz,它有很多选项。它们中的大多数可以为单个节点(或边缘)设置,也可以为所有节点设置全局,如上面的示例所示。这在graphviz文档中有很好的解释。

The above snippet only shows how to make the nodes filled half with one color and half with the other. See the result below (not very beautiful, I know).

上面的代码片段只展示了如何使节点一半用一种颜色填充,另一半用另一种颜色填充。看看下面的结果(我知道不是很漂亮)。

是否可以用networkx为每个节点绘制多颜色的图形

EDIT

编辑

Hmm, so this kinda grew on me, and I really wanted to make something more similar to what you posted. This is what I came up with:

嗯,这让我有点受不了,我真的想做一些和你发的更相似的东西。这就是我想到的:

# coding: utf-8
import networkx as nx
import itertools
from collections import Counter


def edge_in_com(nodes, graph):
    edges = []
    for (i, j) in itertools.combinations(nodes, 2):
        if (i, j) in graph.edges():
            edges.append((i, j))
    return edges


karate = nx.generators.social.karate_club_graph()
karate_agr = nx.nx_agraph.to_agraph(karate)

karate_agr.graph_attr['dpi'] = 180
karate_agr.edge_attr.update(
    dir='both', arrowhead='inv', arrowtail='inv', penwidth=2.0)

karate_agr.node_attr.update(
    style='filled',
    fontcolor='white',
    shape='circle',
    color='transparent',
    gradientangle=90)

colors = ['grey', 'pink', 'blue', 'purple']
communities = list(nx.community.asyn_fluidc(karate, 4))

most_edges = []
for n, com in enumerate(communities):
    edges = edge_in_com(com, karate)
    most_edges.extend(edges)
    for edge in edges:
        e = karate_agr.get_edge(*edge)
        e.attr['color'] = colors[n]
    for node in com:
        node = karate_agr.get_node(node)
        node.attr['fillcolor'] = colors[n]

other = [e for e in karate.edges() if e not in most_edges]

for edge in other:
    gn = karate_agr.get_node
    color = gn(edge[0]).attr['fillcolor']
    karate_agr.get_edge(*edge).attr['color'] = color

for n in karate_agr.nodes():
    cls = [e.attr['color'] for e in karate_agr.in_edges(n)]
    cls2 = [e.attr['color'] for e in karate_agr.out_edges(n)]
    cls = set(cls + cls2)
    if len(cls) > 1:
        # if n.attr['fillcolor'] != cls[0]:
        color1 = cls.pop()
        color2 = cls.pop()
        color_mix = ''.join([color1, ';', '0.5:', color2])
        n.attr['fillcolor'] = color_mix

karate_agr.draw('karate.png', prog='neato')

The program definitely can be improved, and I'm still not very happy with the results but maybe you'll find it helpful.

这个程序肯定是可以改进的,我对结果不太满意,但是也许你会发现它很有帮助。

是否可以用networkx为每个节点绘制多颜色的图形