3

I want to be able to have a lot of nodes have the same label— in my particular case, each node represents a news article, and they should be labelled with their news category. Ultimately, what I really want is a GML file with these labels.

Here's a small sample:

Gtest = nx.Graph()
nodes = [0, 1, 2, 3, 4]
labels = {0:"business", 1:"business",2:"sports", 3:"sports", 4:"politics"}

for node in nodes:
    Gtest.add_node(node)

print Gtest.nodes(data=True) 

""" 
this prints:
[(0, {}), (1, {}), (2, {}), (3, {}), (4, {})]

Which is good, I want 5 nodes.
"""

Gtest = nx.relabel_nodes(Gtest, labels)

print Gtest.nodes(data=True)

"""this prints:

[('business', {}), ('politics', {}), ('sports', {})]

There are only 3 nodes.
"""

nx.write_gml(Gtest, "gml/stackoverflow_test", stringizer = None)

"""
This writes the GML file:

graph [
  name "()"
  node [
    id 0
    label "business"
  ]
  node [
    id 1
    label "politics"
  ]
  node [
    id 2
    label "sports"
  ]
]
"""

Ultimately, I'm trying to end up with the GML file:

graph [
  name "()"
  node [
    id 0
    label "business"
  ]
  node [
    id 1
    label "business"
  ]
  node [
    id 2
    label "sports"
  ]
  node [
    id 3
    label "sports"
  ]
  node [
    id 4
    label "politics"
  ]
]

Is it possible to have the same label for multiple nodes/to generate this output file?

  • What is your question? – DYZ Apr 04 '17 at 00:04
  • Is it possible to have the same label for multiple nodes/to generate this output file? – Dylan Baker Apr 04 '17 at 00:24
  • Why don't you try? (Hint: yes, it is possible.) – DYZ Apr 04 '17 at 00:26
  • 1
    I've been trying for quite a while! I feel like there's something obvious I'm overlooking, maybe I have a gap in understanding about how networkx works? I'm largely confused as to why relabel_nodes is combining nodes with the same label. – Dylan Baker Apr 04 '17 at 00:40

2 Answers2

5

Here's an example of how this can be done:

G = nx.Graph()
G.add_node(1, {'label' : 'foo'})
G.add_node(2, {'label' : 'foo'})
G.nodes(data=True)
#[(1, {'label': 'foo'}), (2, {'label': 'foo'})]
nx.write_gml(G,open("foo.gml","wb"))

graph [
node [
id 0
label 1
]
node [
id 1
label 2
]
]

NB The answer is for networkx-1.1. It does not work in 2.0 or above. Instead, you can set node attrribute:

nx.set_node_attributes(G, {1: 'foo', 2: 'foo'}, 'label')
G.nodes(data=True)
#NodeDataView({1: {'label': 'foo'}, 2: {'label': 'foo'}})
DYZ
  • 55,249
  • 10
  • 64
  • 93
  • Problem is, for me at least, when you want to do this to an existing graph. (For example, I want to use a graph generator _then_ relabel the nodes. relabel_nodes() appears to add_node() using the new label as the first parameter. – RhodriM Apr 15 '19 at 16:21
  • 1
    @RhodriM The answer is given for networkx-1.1. It does not work in 2.0 and above because the versions are not compatible. See the updated answer. – DYZ Apr 15 '19 at 22:30
  • Thanks DYZ, that looks great. Going to ask on the networkx github board about whether relabel_nodes or your original example _should_ (or not) do this in the newer versions. – RhodriM Apr 16 '19 at 11:39
  • Actually, no, this doesn't work. It appears you're adding label to node data. Not updating the label itself, and on writing gml you get the same labels as the ids as always. – RhodriM Apr 17 '19 at 14:47
0

You can do this by passing a custom function as the stringizer argument to the write_gml function.

Here is a code that produces a GML file that you want:

import networkx as nx

class Article:
    def __init__(self, id, category):
        self.id = id
        self.category = category

    def get_category(self):
        return self.category

Gtest = nx.Graph()
nodes = [0, 1, 2, 3, 4]
labels = {0: "business", 1: "business", 2: "sports", 3: "sports", 4: "politics"}

for node in nodes:
    Gtest.add_node(Article(node, labels[node]))

nx.write_gml(Gtest, "articles.gml", stringizer=Article.get_category)

Please note that if the object that you add to the graph in add_node is an int, float, or dict, then the stringizer function will NOT be called. Therefore, the code above uses a custom class for nodes.

astraujums
  • 709
  • 8
  • 20