I want to individually update nodes for a certain new custom attribute called 'journeys', but am having severe difficulties with it.
Say I have some graph:
import pandas as pd
import networkx as nx
cols = ['node_a','node_b','travel_time','attribute']
data = [['A','B',3,'attribute1'],
['B','C',1,'attribute1'],
[ 'C','D',7,'attribute1'],
['D','E',3,'attribute1'],
['E','F',2,'attribute1'],
['F','G',4,'attribute1'],
['A','L',4,'attribute2'],
['L','D',3,'attribute2']
]
edges = pd.DataFrame(data)
edges.columns = cols
G=nx.convert_matrix.from_pandas_edgelist(edges,'node_a','node_b', ['travel_time','attribute'])
For each node, I want to add an attribute in the form of {direction: [[id,timestamp, set_of_carrying_items]]} where the inner one is a list of lists as i want to add more lists of the form [id,timestamp, carrying_items] to it.
Example: Update a particular node A with
new_attribute = {'A':{'up': [[0, Timestamp('1900-01-01 05:31:00'), set()]]}}}
However, no matter what I try, the node doesnt get updated correctly. nx.get_node_attributes(G, 'A') returns an empty dictionary. But nx.get_node_attributes(G,'up') returns the attribute!!
It seems i'm setting it wrongly but I cant figure out how. Anyone know the proper way?
Using networkx 2.4
Solved it.
nx.get_node_attributes(G,X) returns attributes called X for all nodes. You're looking for G.node['nodeA']
if your attribute is of the form {'nodeA':{'attribute_name': value}}, you'll set value to attribute_name for node nodeA.
For example, in my case:
att = {'nodeA':{'up': [[1, Timestamp('1900-01-01 22:31:00'), set()]]}}}
nx.set_node_attributes(G,att)
works
Related
I have an ox graph, called G_map, with a geo data frame for nodes associated, as the following code.
G_nodes = ox.graph_to_gdfs(G_map,edges=False)
One of the G_nodes attributes is called 'osmid' and it's the ID of the node in open street map, so every single node has a different 'osmid'. My goal here is to plot the G_map graph giving certain nodes different colors, depending on the node ID, e.g., 'osmid'. For instance, if a node has a certain ID i would like for it to be red. I think I will have to use the osmnx function but I don't know how to do it exactly,
osmnx.plot.get_node_colors_by_attr()
I have also tried this:
node_c = ['b' if ('osmid'==25620516 or 'osmid'==25620570) else 'r' for idx in G_nodes(keys=True)]
fig, ax = ox.plot_graph(G_map, node_color=node_c, node_edgecolor='w', node_size=30, node_zorder=3, edge_color=ec, edge_linewidth=3)
But i get an error saying:
TypeError: 'GeoDataFrame' object is not callable
If anyone could help me,
Thank you!
You should be able to simply iterate over the graph and use the attributes of the nodes directly, e.g.:
['b' if (data['osmid']==25620516 or data['osmid']==25620570) else 'r' for node, data in G_map.nodes(data=True)]
I have been stuck on this simple problem for awhile and cant quite figure out the solution. I have a dictionary that is structured like {(node1, node2): weight} called EdgeDictFull. I wanted to create a DiGraph that has the weight stored as an attribute in the graph. I have tried a whole bunch of different ideas but no seem to work. When I run this code....
(weights is just a list of all the weights I want to add to the edges as attributes)
TG = nx.DiGraph()
for x in weights:
TG.add_edges_from(EdgeDictFull.keys(), weight = x)
TG.edges(data = True)
What this does is it will create all the correct edges, but all edges will have the attribute value of the last integer in my weights list. I think I understand why it does that, however, I cant seem to figure out how to fix it. I know it's something really simple. Any advice would be great!
# the problem with your code is that in every iteration of your loop you add
# *all* edges, and all of them get the same weight.
# you can do either of the following:
# zip:
TG = nx.DiGraph()
for edge, weight in zip(EdgeDictFull.keys(), weights):
TG.add_edge(*edge, weight=weight)
# or directly work with the dictionary:
## dummy dictionary:
EdgeDictFull = {(np.random.randint(5),np.random.randint(5)):np.random.rand() for i in range(3)}
TG = nx.DiGraph()
TG.add_weighted_edges_from((a,b,c) for (a,b), c in EdgeDictFull.items())
TG.edges(data = True)
I have overcome the problem of avoiding the creation of duplicate nodes on my DB with the use of merge_one functions which works like that:
t=graph.merge_one("User","ID","someID")
which creates the node with unique ID. My problem is that I can't find a way to add multiple attributes/properties to my node along with the ID which is added automatically (date for example).
I have managed to achieve this the old "duplicate" way but it doesn't work now since merge_one can't accept more arguments! Any ideas???
Graph.merge_one only allows you to specify one key-value pair because it's meant to be used with a uniqueness constraint on a node label and property. Is there anything wrong with finding the node by its unique id with merge_one and then setting the properties?
t = graph.merge_one("User", "ID", "someID")
t['name'] = 'Nicole'
t['age'] = 23
t.push()
I know I am a bit late... but still useful I think
Using py2neo==2.0.7 and the docs (about Node.properties):
... and the latter is an instance of PropertySet which extends dict.
So the following worked for me:
m = graph.merge_one("Model", "mid", MID_SR)
m.properties.update({
'vendor':"XX",
'model':"XYZ",
'software':"OS",
'modelVersion':"",
'hardware':"",
'softwareVesion':"12.06"
})
graph.push(m)
This hacky function will iterate through the properties and values and labels gradually eliminating all nodes that don't match each criteria submitted. The final result will be a list of all (if any) nodes that match all the properties and labels supplied.
def find_multiProp(graph, *labels, **properties):
results = None
for l in labels:
for k,v in properties.iteritems():
if results == None:
genNodes = lambda l,k,v: graph.find(l, property_key=k, property_value=v)
results = [r for r in genNodes(l,k,v)]
continue
prevResults = results
results = [n for n in genNodes(l,k,v) if n in prevResults]
return results
The final result can be used to assess uniqueness and (if empty) create a new node, by combining the two functions together...
def merge_one_multiProp(graph, *labels, **properties):
r = find_multiProp(graph, *labels, **properties)
if not r:
# remove tuple association
node,= graph.create(Node(*labels, **properties))
else:
node = r[0]
return node
example...
from py2neo import Node, Graph
graph = Graph()
properties = {'p1':'v1', 'p2':'v2'}
labels = ('label1', 'label2')
graph.create(Node(*labels, **properties))
for l in labels:
graph.create(Node(l, **properties))
graph.create(Node(*labels, p1='v1'))
node = merge_one_multiProp(graph, *labels, **properties)
I am working with networkx and cant find a list of available attributes for edges or nodes anywhere. I am not interested in what attributes are assigned already, but what I can set/change when i create or edit the node or edge.
Can someone point me to where this is documented?
Thanks!
If you want to query a graph for all the possible attributes that might have been applied across the various nodes (and this, for communally created graphs, or ones that have been edited over time, is more common than you might imagine), then the following does the trick for me:
set(np.array([list(self.graph.node[n].keys()) for n in self.graph.nodes()]).flatten())
This returns all possible attribute names for which there are values attributed to graph-nodes. I've imported numpy as np here in order to use np.flatten for (relative) performance, but I'm sure there are various vanilla python alternatives (e.g. try the following itertools.chain method, if you need to avoid numpy )
from itertools import chain
set(chain(*[(ubrg.graph.node[n].keys()) for n in ubrg.graph.nodes()]))
You can assign a lot of edge or node attributes when you create them. It's up to you to decide what their names will be.
import networkx as nx
G=nx.Graph()
G.add_edge(1,2,weight=5) #G now has nodes 1 and 2 with an edge
G.edges()
#[(1, 2)]
G.get_edge_data(2,1) #note standard graphs don't care about order
#{'weight': 5}
G.get_edge_data(2,1)['weight']
#5
G.add_node('extranode',color='yellow', age = 17, qwerty='dvorak', asdfasdf='lkjhlkjh') #nodes are now 1, 2, and 'extranode'
G.node['extranode']
{'age': 17, 'color': 'yellow', 'qwerty': 'dvorak', 'asdfasdf': 'lkjhlkjh'}
G.node['extranode']['qwerty']
#'dvorak'
Or you can use a dict to define some of the attributes with nx.set_node_attributes and create a dict for all nodes for which a particular attribute is defined with nx.get_node_attributes
tmpdict = {1:'green', 2:'blue'}
nx.set_node_attributes(G,'color', tmpdict)
colorDict = nx.get_node_attributes(G,'color')
colorDict
#{1: 'green', 2: 'blue', 'extranode': 'yellow'}
colorDict[2]
#'blue'
Similarly there is a nx.get_edge_attributes and nx.set_edge_attributes.
More information is here in the networkx tutorial. About halfway down this page under the headings "Node Attributes" and "Edge Attributes". Specific documentation for the set...attributes and get...attributes can be found here under "Attributes".
pydot has a huge number of bound methods for getting and setting every little thing in a dot graph, reading and writing, you-name-it, but I can't seem to find a simple membership test.
>>> d = pydot.Dot()
>>> n = pydot.Node('foobar')
>>> d.add_node(n)
>>> n in d.get_nodes()
False
is just one of many things that didn't work. It appears that nodes, once added to a graph, acquire a new identity
>>> d.get_nodes()[0]
<pydot.Node object at 0x171d6b0>
>>> n
<pydot.Node object at 0x1534650>
Can anyone suggest a way to create a node and test to see if it's in a graph before adding it so you could do something like this:
d = pydot.Dot()
n = pydot.Node('foobar')
if n not in d:
d.add_node(n)
Looking through the source code, http://code.google.com/p/pydot/source/browse/trunk/pydot.py, it seems that node names are unique values, used as the keys to locate the nodes within a graph's node dictionary (though, interestingly, rather than return an error for an existing node, it simply adds the attributes of the new node to those of the existing one).
So unless you want to add an implementation of __contains__() to one of the classes in the pydot.py file that does the following, you can just do the following in your code:
if n.get_name() not in d.obj_dict['nodes'].keys():
d.add_node(n)