Given an undirected graph in networkx:
graph=Graph()
graph.add_edge(1,2)
graph.add_edge(2,3)
When querying the edgeset of this graph using the method graph.edges(),the result is returned as a tuple, i.e. a directed view of the edgeset. In the example above, graph.edges() returns:
[(1, 2), (2, 3)]
If I would query all edges incident to vertex 2 (graph.edges(2)) I get a different directed view:
[(2, 1), (2, 3)]
This behavior is problematic if I have for instance an external dict that maps an edge (key) to some other object. For instance:
lookup={edge : some_object(edge) for edge in graph.edges()}
for edge in graph.edges(2):
print(lookup(edge)) #throws key not found exception
The exception is thrown because key (1,2) exists, but (2,1) does not. What would be the best (efficient/pythonic/...) way to get an undirected object when iterating over an undirected graph in networkx? I could associate some_object(edge) with an edge as one of its attributes, but that doesn't really answer the question.
dfs_labeled_edges(G, source) Traverses through the graph using depth first search.
Since dfs_edges stops after reaching every node, it will not always detect every edge. Instead, dfs_labeled_edges can be implemented to obtain all the edge objects in an undirected graph.
Code:
import networkx as nx
from networkx import dfs_labeled_edges
nodes = [1,2,3]
edges = [(1,2), (2,3)]
G = nx.Graph()
G.add_nodes_from(nodes)
G.add_edges_from(edges)
undirectedGraphEdges = []
dfs = list(dfs_labeled_edges(G,1))
for edge in dfs:
if(edge[:2] not in undirectedGraphEdges):
undirectedGraphEdges.append(edge[:2])
if undirectedGraphEdges[0] not in edges:
del undirectedGraphEdges[0]
print(undirectedGraphEdges)
# [(1, 2), (2, 1), (2, 3), (3, 2)]
Related
I would like to get a subgraph around a specific node of a a directed graph based on the out_edges or in_edges only.
# This does not work
H_tmp = nx.ego_graph(G, node_name, 2)
H_tmp.out_edges = []
H = nx.ego_graph(H_tmp, node_name, 2)
I tried using nx.ego_graph twice, but I don't know an efficient way to remove all the out_edges or in_edges. Is there a way to tell ego_graph to use only a specific set of edges?
Using the eco_graph function on an undirected graph extracts the out successors of the node. According to the doc, if you only want the predecessors (in_edges), you can apply the eco_graph function on the reverse of your graph. You'll then need to reverse your subgraph. If you want both successors and predecessors, you can specify undirected=True. See example summarizing this below:
import networkx as nx
import matplotlib.pyplot as plt
H = nx.fast_gnp_random_graph(5, 0.3,directed=True)
plt.figure(figsize=(15,10))
plt.subplot(141)
plt.title('Full graph')
nx.draw(H,with_labels=True)
plt.subplot(142)
plt.title('All neighbors around node 2')
H_all=nx.ego_graph(H, 2, 1,undirected=True)
nx.draw(H_all,with_labels=True)#plot
plt.subplot(143)
plt.title('Out subgraph around node 2')
H_out=nx.ego_graph(H, 2, 1)
nx.draw(H_out,with_labels=True) #plot
plt.subplot(144)
plt.title('In subgraph around node 2')
H_in=nx.ego_graph(H.reverse(), 2, 1) #apply eco_graph to reverse graph to get in_edges
H_in_r=H_in.reverse() #reverse subgraph
nx.draw(H_in_r,with_labels=True) #plot
I am learning the networkx function named "networkx.graph_edit_distance(g2,q)". Actually, GED(g2,q) = 2.If we want to tranform g2 to q, we should do at least 2 graph edit operations"substituing (1,3) whose label is '2' in g2 to (1,3) whose label is '1', inserting (3,4) which is not exsits in g2 to (3,4) whose label
is '1".My code is shown below:
nodes = [(1,{'label':'C1'}),
(2,{'label':'C2'}),
(3,{'label':'C3'}),
(4,{'label':'C4'}),
(5,{'label':'N'})]
edges = [(1,2,{'label':'1'}),
(2,4,{'label':'1'}),
(4,5,{'label':'1'}),
(5,3,{'label':'1'}),
(3,1,{'label':'2'})]
g2 = nx.Graph()
g2.add_nodes_from(nodes)
g2.add_edges_from(edges)
nodes = [(1,{'label':'C1'}),
(2,{'label':'C2'}),
(3,{'label':'C3'}),
(4,{'label':'C4'}),
(5,{'label':'N'})]
edges = [(1,2,{'label':'1'}),
(2,4,{'label':'1'}),
(4,5,{'label':'1'}),
(5,3,{'label':'1'}),
(3,1,{'label':'1'}),
(3,4,{'label':'1'})]
q = nx.Graph()
q.add_nodes_from(nodes)
q.add_edges_from(edges)
GED_q_g2 = nx.graph_edit_distance(g2, q)
But unfortunately, the expected answer is GED =2, but it gives the answer GED_q_g2 = 1.Please how could I get the right answer?
When I look at the defined graph, the edit distance of 1 is correct, because only (3,4) needs to be removed.
The graph that you've drawn displays two edges between 1 and 3, though. I guess you've misunderstood the label functionality: It's just an optional data attribute that you can use for identification or plotting - it has nothing to do with the number of edges or weights.
If you want to use multiple edges between two nodes, have a look at nx.Multigraph.
just use the edge_match.
nx.graph_edit_distance(g1,g2,edge_match=lambda a,b: a['label'] == b['label']))
I've built a simulation model of pedestrians walking on a network using OSMnx and one of the simulation's outputs is a list "Visits" that is corresponding to the nodes in NodesList = list(Graph.nodes).
How can I create an heatmap using those lists and OSMnx?
For example:
NodesList[:5]
Output: [1214630921, 5513510924, 5513510925, 5513510926, 5243527186]
Visits[:5]
Output: [1139, 1143, 1175, 1200, 1226]
P.S.
the type of heatmap is not important (Nodes size, nodes color, etc.)
Since you specified the type of heatmap is not important, I have come up with the following solution.
import osmnx as ox
address_name='Melbourne'
#Import graph
G=ox.graph_from_address(address_name, distance=300)
#Make geodataframes from graph data
nodes, edges = ox.graph_to_gdfs(G, nodes=True, edges=True)
import numpy as np
#Create a new column in the nodes geodataframe with number of visits
#I have filled it up with random integers
nodes['visits'] = np.random.randint(0,1000, size=len(nodes))
#Now make the same graph, but this time from the geodataframes
#This will help retain the 'visits' columns
G = ox.save_load.gdfs_to_graph(nodes, edges)
#Then plot a graph where node size and node color are related to the number of visits
nc = ox.plot.get_node_colors_by_attr(G,'visits',num_bins = 5)
ox.plot_graph(G,fig_height=8,fig_width=8,node_size=nodes['visits'], node_color=nc)
I am trying to compute a per-channel gradient image in PyTorch. To do this, I want to perform a standard 2D convolution with a Sobel filter on each channel of an image. I am using the torch.nn.functional.conv2d function for this
In my minimum working example code below, I get an error:
import torch
import torch.nn.functional as F
filters = torch.autograd.Variable(torch.randn(1,1,3,3))
inputs = torch.autograd.Variable(torch.randn(1,3,10,10))
out = F.conv2d(inputs, filters, padding=1)
RuntimeError: Given groups=1, weight[1, 1, 3, 3], so expected
input[1, 3, 10, 10] to have 1 channels, but got 3 channels instead
This suggests that groups need to be 3. However, when I make groups=3, I get a different error:
import torch
import torch.nn.functional as F
filters = torch.autograd.Variable(torch.randn(1,1,3,3))
inputs = torch.autograd.Variable(torch.randn(1,3,10,10))
out = F.conv2d(inputs, filters, padding=1, groups=3)
RuntimeError: invalid argument 4: out of range at
/usr/local/src/pytorch/torch/lib/TH/generic/THTensor.c:440
When I check that code snippet in the THTensor class, it refers to a bunch of dimension checks, but I don't know where I'm going wrong.
What does this error mean? How can I perform my intended convolution with this conv2d function? I believe I am misunderstanding the groups parameter.
If you want to apply a per-channel convolution then your out-channel should be the same as your in-channel. This is expected, considering each of your input channels creates a separate output channel that it corresponds to.
In short, this will work
import torch
import torch.nn.functional as F
filters = torch.autograd.Variable(torch.randn(3,1,3,3))
inputs = torch.autograd.Variable(torch.randn(1,3,10,10))
out = F.conv2d(inputs, filters, padding=1, groups=3)
whereas, filters of size (2, 1, 3, 3) or (1, 1, 3, 3) will not work.
Additionally, you can also make your out-channel a multiple of in-channel. This works for instances where you want to have multiple convolution filters for each input channel.
However, This only makes sense if it is a multiple. If not, then pytorch falls back to its closest multiple, a number less than what you specified. This is once again expected behavior. For example a filter of size (4, 1, 3, 3) or (5, 1, 3, 3), will result in an out-channel of size 3.
I'm using scala-graph for some graph computations on Scala, and I can't seem to understand how to do one simple thing: how do I update a certain weight?
Let's say I have:
import scalax.collection.Graph
val g = Graph(1~>2 % 1, 2~>3 % 1, 1~>3 % 3)
and now I'd like to create g2 which will be the same as g but with 1~>2 % 2. How do I do that?
There doesn't seem to be any native method to update the weight of an edge. What you can do is to remove an edge and add a new one with a different weight:
scala> g - 1~>3 % 3 + 1~>3 % 1337
res = Graph(1, 2, 3, 1~>2 %1, 1~>3 %1337, 2~>3 %1)
Edit: Note that the weight of the edge that is being removed, 1~>3 % <weight>, can have any value, since edges aren't identified by their weight.
See this thread for more details.