Draw different color for nodes in networkx based on their node value

后端 未结 2 1081
傲寒
傲寒 2020-12-04 19:36

I have a large graph of nodes and directed edges. Furthermore, I have an additional list of values assigned to each node.

I now want to change the color of each node

相关标签:
2条回答
  • 2020-12-04 19:51
    import networkx as nx
    import numpy as np
    import matplotlib.pyplot as plt
    
    G = nx.Graph()
    G.add_edges_from(
        [('A', 'B'), ('A', 'C'), ('D', 'B'), ('E', 'C'), ('E', 'F'),
         ('B', 'H'), ('B', 'G'), ('B', 'F'), ('C', 'G')])
    
    val_map = {'A': 1.0,
               'D': 0.5714285714285714,
               'H': 0.0}
    
    values = [val_map.get(node, 0.25) for node in G.nodes()]
    
    nx.draw(G, cmap=plt.get_cmap('viridis'), node_color=values, with_labels=True, font_color='white')
    plt.show()
    

    yields


    The numbers in values are associated with the nodes in G.nodes(). That is to say, the first number in values is associated with the first node in G.nodes(), and similarly for the second, and so on.

    0 讨论(0)
  • 2020-12-04 20:17

    For the general case, in which we have a list of values indicating some attribute of a node, and we want to assign a colour to the given node which gives a sense of scale of that attribute (reds to blues for instance), here's one approach:

    import matplotlib as mpl
    from matplotlib import pyplot as plt
    from pylab import rcParams
    import networkx as nx
    
    G = nx.Graph()
    G.add_edges_from([('A', 'D'), ('Z', 'D'), ('F', 'J'), ('A', 'E'), ('E', 'J'),('Z', 'K'), ('B', 'A'), ('B', 'D'), ('A', 'J'), ('Z', 'F'),('Z', 'D'), ('A', 'B'), ('J', 'D'), ('J', 'E'), ('Z', 'J'),('K', 'J'), ('B', 'F'), ('B', 'J'), ('A', 'Z'), ('Z', 'E'),('C', 'Z'), ('C', 'A')])
    

    Say that we have the following dictionary mapping a each node to a given value:

    color_lookup = {k:v for v, k in enumerate(sorted(set(G.nodes())))}
    # {'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'J': 6, 'K': 7, 'Z': 8}
    

    What we could do is to use mpl.colors.Normalize to normalize the values in color_lookup to the range [0,1] based on the minimum and maximum values that the nodes take, and then matplotlib.cm.ScalarMappable to map the normalized values to colours in a colourmap, here I'll be using mpl.cm.coolwarm:

    low, *_, high = sorted(color_lookup.values())
    norm = mpl.colors.Normalize(vmin=low, vmax=high, clip=True)
    mapper = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.coolwarm)
    
    rcParams['figure.figsize'] = 12, 7
    nx.draw(G, 
            nodelist=color_lookup,
            node_size=1000,
            node_color=[mapper.to_rgba(i) 
                        for i in color_lookup.values()], 
            with_labels=True)
    plt.show()
    

    For another colour map we'd just have to change the cmap parameter in mpl.cm.ScalarMappable:

    mapper = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.summer)
    nx.draw(G, 
            nodelist=color_lookup,
            node_size=1000,
            node_color=[mapper.to_rgba(i) 
                        for i in color_lookup.values()], 
            with_labels=True)
    plt.show()
    

    Where we'd get:

    Similarly, we could set the colour of a node based on the degree of a node by defining a dictionary mapping all nodes to their corresponding degree, and taking the same steps as above:

    d = dict(G.degree)
    # {'A': 6, 'D': 4, 'Z': 7, 'F': 3, 'J': 7, 'E': 3, 'K': 2, 'B': 4, 'C': 2}
    low, *_, high = sorted(d.values())
    norm = mpl.colors.Normalize(vmin=low, vmax=high, clip=True)
    mapper = mpl.cm.ScalarMappable(norm=norm, cmap=mpl.cm.coolwarm)
    
    nx.draw(G, 
            nodelist=d,
            node_size=1000,
            node_color=[mapper.to_rgba(i) 
                        for i in d.values()], 
            with_labels=True,
            font_color='white')
    plt.show()
    

    0 讨论(0)
提交回复
热议问题