How to remove an edge attribute in python-igraph - python

I want to remove an edge attribute from a Graph object in python-igraph. The equivalent igraph R function is cleverly called delete_edge_attr. I haven't been able to find an equivalent function/method in Python... is there one?
If not, is there another way to do it? (I tried a simple g.es['edge_attr']= [] but this didn't work).
Example Code
g = ig.Graph.Tree(10, 2) #Generate random graph
g_betweenness = g.betweenness() #Calculate betweenness for graph
g['betweenness'] = betweenness #Assign betweenness as edge attribute
print(g.attributes())
g['betweenness'] = [] #Attempt to remove betweenness edge attribute (incorrect)
print(g.attributes())
Output
['betweenness']
['betweenness']
Desired output
['betweenness']
[]

You might not be able to set it to an empty array, but your intuition about directly altering the EdgeSequence was already pretty good. You can simply delete the argument with Python's internal del(), I've included a minimal example below:
import igraph
# minimal graph
G = igraph.Graph()
G.add_vertices(2)
G.add_edge(0,1)
# add your property
G.es['betweenness'] = [1]
# print edge attribute (note the difference to your example)
print(G.es.attribute_names())
# output: ['weight']
# delete argument
del(G.es['weight'])
# print again
print(G.es.attribute_names())
# output: []

Related

CadQuery: Selecting an edge by index (Filleting specific edges)

I come from the engineering CAD world and I'm creating some designs in CadQuery. What I want to do is this (pseudocode):
edges = part.edges()
edges[n].fillet(r)
Or ideally have the ability to do something like this (though I can't find any methods for edge properties). Pseudocode:
edges = part.edges()
for edge in edges:
if edge.length() > x:
edge.fillet(a)
else:
edge.fillet(b)
This would be very useful when a design contains non-orthogonal faces. I understand that I can select edges with selectors, but I find them unnecessarily complicated and work best with orthogonal faces. FreeCAD lets you treat edges as a list.
I believe there might be a method to select the closest edge to a point, but I can't seem to track it down.
If someone can provide guidance that would be great -- thank you!
Bonus question: Is there a way to return coordinates of geometry as a list or vector? e.g.:
origin = cq.workplane.center().val
>> [x,y,z]
(or something like the above)
Take a look at this code, i hope this will be helpful.
import cadquery as cq
plane1 = cq.Workplane()
block = plane1.rect(10,12).extrude(10)
edges = block.edges("|Z")
filleted_block = edges.all()[0].fillet(0.5)
show(filleted_block)
For the posterity. To select multiple edges eg. for chamfering you can use newObject() on Workplane. The argument is a list of edges (they have to be cq.occ_impl.shapes.Edge instances, NOT cq.Workplane instances).
import cadquery as cq
model = cq.Workplane().box(10, 10, 5)
edges = model.edges()
# edges.all() returns worplanes, we have to get underlying geometry
selected = list(map(lambda x: x.objects[0], edges.all()))
model_with_chamfer = model.newObject(selected).chamfer(1)
To get edge length you can do something like this:
edge = model.edges().all()[0] # This select one 'random' edge
length = edge.objects[0].Length()
edge.Length() doesn't work since edge is Workplane instance, not geometry instance.
To get edges of certain length you can just create dict with edge geometry and length and filter it using builtin python's filter(). Here is a snippet of my implementation for chamfering short edges on topmost face:
top_edges = model.edges(">Z and #Z")
def get_length(edge):
try:
return edge.vals()[0].Length()
except Exception:
return 0.0
# Inside edges are shorter - filter only those
edge_len_list = list(map(
lambda x: (x.objects[0], get_length(x)),
top_edges.all()))
avg = mean([a for _, a in edge_len_list])
selected = filter(lambda x: x[1] < avg, edge_len_list)
selected = [e for e, _ in selected]
vertical_edges = model.edges("|Z").all()
selected.extend(vertical_edges)
model = model.newObject(selected)
model = model.chamfer(chamfer_size)

Problem with appending a graph object to lists for networkx in Python

I am trying to remove nodes at random from graphs using the networkx package. The first block describes the graph construction and the second block gives me the node lists that I have to remove from my graph H (20%, 50% and 70% removals). I want 3 versions of the base graph H in the end, in a list or any data structure. The code in block 3 gives me objects of type "None". The last block shows that it works for a single case.
I am guessing that the problem is in the append function, which somehow returns objects of type "None". I also feel that the base graph H might be getting altered after every iteration. Is there any way around this? Any help would be appreciated :)
import networkx as nx
import numpy as np
import random
# node removals from Graphs at random
# network construction
H = nx.Graph()
H.add_nodes_from([1,2,3,4,5,6,7,8,9,10])
H.add_edges_from([[1,2],[2,4],[5,6],[7,10],[1,5],[3,6]])
nx.info(H)
nodes_list = list(H.nodes)
# list of nodes to be removed
perc = [.20,.50,.70] # percentage of nodes to be removed
random_sample_list = []
for p in perc:
interior_list = []
random.seed(2) # for replicability
sample = round(p*10)
random_sample = random.sample(nodes_list, sample)
interior_list.append(random_sample)
random_sample_list.append(random_sample)
# applying the list of nodes to be removed to create a list of graphs - not working
graph_list = []
for i in range(len(random_sample_list)):
H1 = H.copy()
graph_list.append(H1.remove_nodes_from(random_sample_list[i]))
# list access - works
H.remove_nodes_from(random_sample_list[1])
nx.info(H)
Final output should look like:
[Graph with 20% removed nodes, Graph with 50% removed nodes, Graph with 7% removed nodes] - eg. list
The function remove_nodes_from does not return the modified graph, but returns None. Consequently, you only need to create the graph with the desired percentage of your nodes and append it to the list:
graph_list = []
for i in range(len(random_sample_list)):
H1 = H.copy()
H1.remove_nodes_from(random_sample_list[i])
graph_list.append(H1)

Assignment means point to address in python?

I am implementing a Hierarchy clustering algorithm(with similarity) using python 3.6, the following doing is basically build new empty graph ,and keep connecting the the group(represent by list here ) with largest similarity on original recursively
the code in position 1 of code ,I want to return the best partition, however the function return is exactly the same as comminity_list,it looks like best_partition = comminity_list. make best_partition point to the address of 'comminity_list' how come it happens, what I got wrong here? how should I fix that ?
def pearson_clustering(G):
H = nx.create_empty_copy(G). # build a empty copy of G(no vetices)
best = 0 #for current modularity
current =0 #for best modualarty
A = nx.adj_matrix(G). #get adjacent matrix
org_deg =deg_dict(A, G.nodes()) # degree of G
org_E = G.number_of_edges(). # number of edges of G
comminity_list = intial_commnity_list(G) # function return a list of lists here
best_partition = None
p_table =pearson_table(G) #pearson_table return a dictionary of each pair Pearson correlation
l = len(comminity_list)
while True:
if(l == 2): break
current = modualratiry(H,org_deg,org_E) #find current modularity
l = len(comminity_list)
p_build_cluster(p_table,H,G,comminity_list) #building clustering on H
if(best < current):
best_partition = comminity_list. #postion1
best = current #find the clustering with largest modularity
return best_partition #postion2
it looks like best_partition = comminity_list. make best_partition point to the address of 'comminity_list' how come it happens, what I got wrong here? how should I fix that ?
That is just python's implicit assignment behaviour. When you do "best_partition = comminity_list" you just assign comminity_list to the same address as best_partition.
If you want to explicitly copy the list you can use this (which replaces the list best_partition with the comminity_list):
best_partition[:] = comminity_list
or the copy function. If comminity_list has sublists you will need the deepcopy function instead, from the same module (otherwise you will get a copy of the original list, but the sublists will still be just address references).
best_partition = comminity_list.copy

Python-IGraph: Find neighbors of a node, only if connecting edges have certain attributes

is there such a function premade in python-igraph (or also networkx, so I could adapt it to work in igraph), or do i have to implement it?
If it doesnt exist yet, I would outlay it like that:
Get the incident edges of the source node,
only keep edges that meet the attribute criteria (for example, only edges with attribute "major")
For the edges from 2., find the target nodes using the target property of the edge as described here
Any improvements welcome!
There's no pre-made function for this in igraph, but you can try something like:
def filtered_neighbors(graph, node, condition):
return [ \
edge.source if edge.target == node else edge.source \
for edge in graph.es[graph.incident(node)] \
if condition(edge)
]
condition must be a Python callable that takes an edge and returns whether the edge can be accepted.
Try a list comprehension.
import networkx as nx
G = nx.Graph()
G.add_edge(1,2,weight=3)
G.add_edge(1,3,weight = 5)
node = 1
weight3_neighbors = [neighbor for neighbor in G.neighbors_iter(node) if G.edge[node][neighbor]['weight']==3]
weight3_neighbors
> [2]

How to add and show weights on edges of a undirected graph using PyGraphviz?

import pygraphviz as pgv
A = pgv.AGraph()
A.add_node('Alice')
A.add_node('Emma')
A.add_node('John')
A.add_edge('Alice', 'Emma')
A.add_edge('Alice', 'John')
A.add_edge('Emma', 'John')
print A.string()
print "Wrote simple.dot"
A.write('simple.dot') # write to simple.dot
B = pgv.AGraph('simple.dot') # create a new graph from file
B.layout() # layout with default (neato)
B.draw('simple.png') # draw png
print 'Wrote simple.png'
I want to add weights to the edges which should also show up on the figure.
You can add attributes to the edges when you create them:
A.add_edge('Alice', 'Emma', weight=5)
or you can set them later with:
edge = A.get_edge('Alice', 'Emma')
edge.attr['weight'] = 5
To add textual information to edges, give them a label attribute instead:
edge = A.get_edge('Alice', 'Emma')
edge.attr['label'] = '5'
All attributes are internally stored as strings but GraphViz interprets these as specific types; see the attribute documentation.

Categories

Resources