Delete multiple edges in igraph for Python - python

I have a problem removing multiple edges in igraph using Python.
I have tried this, but it does not work:
for e in g.es:
if e.is_multiple() is True:
g.es.delete(e)
I even tried
for e in g.es:
if e.is_multiple() is True:
helptuple = e.tuple
source = helptuple[0]
target = helptuple[1]
eid = g.get_eid(source, target)
g.delete_edges(eid)
Is there another solution?

Try this:
def simplify(multiple=True, loops=True, combine_edges=None):
it is a function from the API.
multiple -> whether to remove multiple edges.
read more here:
https://igraph.org/python/doc/api/igraph._igraph.GraphBase.html#simplify

Related

Can you use .index for 2D arrays (without using numpy)?

So I've been tring to use .index with 2D arrays just so I can do some tests on my code, but it just comes up with an error saying that the value which is in the list actually isn't.
For example, from one project (where i was trying to revise network layering whilst practicing some coding), I tried doing this but didnt work:
answers = [['Application Layer','HTTP','HTTPS','SMTP','IMAP','FTP'],['Transport Layer','TCP','UDP'],['Network Layer','ARP','IP','ICMP'],['Data Link layer']]
correct = 0
incorrect = 0
qs = answers[randint(0,3)][0]
print(answers.index(qs))
print(qs)
Example from code
As you can see, I'm trying to get back the value of 'qs' by using index but no luck.
I've seen a few other posts saying to use numpy, but how would I do this without using numpy?
You can do it like this.
answers = [['Application Layer','HTTP','HTTPS','SMTP','IMAP','FTP'],['Transport Layer','TCP','UDP'],['Network Layer','ARP','IP','ICMP'],['Data Link layer']]
correct = 0
incorrect = 0
qs = answers[randint(0,3)][0]
for i, answer in enumerate(answers):
if qs in answer:
print(i)
break
print(qs)

Maya python connect to multiple input

I’m really sorry if I’m asking a question that’s been already answered but I couldn’t find an answer.
I’m writing a code that would allow me to connect a translate of several controllers into a blendWeighted node input channels. The amount of the controllers may vary depending on the selection. I’m struggling with the part where they need to connect to a single blendWeighted node input. Could someone tell me how I could connect every new controller to the next input channel of the blendWeighted node?
I’m sorry if my code is a bit childlike, I’m still learning ^^;
sel = mc.ls(sl=True, fl=True)
drvConnect = []
for i in sel:
name = i.split('_Crv')[0]
dGP = mc.createNode('transform', n='%s_Drv'%name, p=i)
drvConnect.append(dGP)
sh = mc.listRelatives(i, shapes=True)[0]
blendX = mc.createNode('blendWeighted', n='%s_X'%name)
blendY = mc.createNode('blendWeighted', n='%s_Y'%name)
blendZ = mc.createNode('blendWeighted', n='%s_Z'%name)
mc.connectAttr(dGP + '.translateX', blendX +'.input')
mc.connectAttr(dGP + '.translateY', blendY +'.input')
mc.connectAttr(dGP + '.translateZ', blendZ +'.input')
I assume you only want to create a single blendWeighted node. If that's the case, consider that the blendWeighted node's input attribute is an array attribute, so if you want to connect multiple items to it you would need to specify the target index.
For example, to connect the three translate outputs of a node to the first three inputs of the blend node you would use something like this:
mc.connectAttr('ctrl.translateX', 'blend.input[0]')
mc.connectAttr('ctrl.translateY', 'blend.input[1]')
mc.connectAttr('ctrl.translateZ', 'blend.input[2]')
(Maya will take care of creating the items in the array)
In our case you could simply keep a counter of the added items while you loop through the selection and the transform components (just a guide - not tested):
sel = mc.ls(sl=True, fl=True)
drvConnect = []
blendNode = mc.createNode('blendWeighted', n='blend_main')
for i in sel:
name = i.split('_Crv')[0]
dGP = mc.createNode('transform', n='%s_Drv'%name, p=i)
drvConnect.append(dGP)
for comp in ('X', 'Y', 'Z'):
mc.connectAttr(
'{}.translate{}'.format(dGP, comp),
'{}.input[{}]'.format(blendNode, blendIndex))
blendIndex += 1

Converting a graphviz Source object to graphviz Graph object

I've got a template schematic made in raw .dot format, but I now want to populate the labels using python.
with the https://pypi.org/project/graphviz/ library I've managed to load the .dot file but don't see how I can edit it. Is it possible to convert a Source object to a Graph object, or otherwise use the methods available to the Graph object?
trying:
from graphviz import Source
src = Source('digraph "the holy hand grenade" { rankdir=LR; 1 -> 2 -> 3 -> lob }')
src.node("foo")
_ = src.render('test.gv', view=False)
Source.from_file('test.gv')
I get the error AttributeError: 'Source' object has no attribute 'node'
Following the great answer of #Ray Ronnaret, this is what worked for me.
I have no comments in my dot file, thus it becomes as simple as follows:
from graphviz import Source, Digraph
s = Source.from_file('viz.dot')
g = Digraph()
source_lines = str(s).splitlines()
# Remove 'digraph tree {'
source_lines.pop(0)
# Remove the closing brackets '}'
source_lines.pop(-1)
# Append the nodes to body
g.body += source_lines
Then, I was able to edit the graph.
g.graph_attr['rankdir'] = 'LR'
g.unflatten(stagger=3).render()
I do parse the grapviz.source eliminate non necessary char and append back. This work for me. Note that this assume first line may be contain comment. Thing remains is to make it be function.
src = Source.from_file('Source.gv')
lst = str(src).splitlines()
HasComment = (lst[0].find('//') != -1)
IsDirectGraph = False
skipIndex = 0
if HasComment:
skipIndex = 1
if lst[skipIndex].find('graph {')!=-1 :
IsDirectGraph= False
else:
if lst[0].find('graph {')!=-1 :
IsDirectGraph= False
if IsDirectGraph:
g = Digraph()
else:
g = Graph()
g.body.clear()
s = str()
for i in range(len(lst)):
if( (i>skipIndex) and (i!=len(lst)-1) ):
if HasComment:
g.comment = lst[0].replace('//','')
g.body.append(lst[i])
print(g.source)
display(g)
https://github.com/xflr6/graphviz/issues/76
answers the question that it is not possible with that library, but other ones are available which can.

Find neighbouring polygons in Python QGIS

I am using code I found and slightly modified for my purposes. The problem is, it is not doing exactly what I want, and I am stuck with what to change to fix it.
I am searching for all neighbouring polygons, that share common borded (a line), that is not a point
My goal: 135/12 is neigbour with 319/2 135/4, 317 but not with 320/1
What I get in my QGIS table after I run my script
NEIGBOURS are the neighbouring polygons,
SUM is the number of neighbouring polygons
The code I use also includes 320/1 as a neighbouring polygon. How to fix it?
from qgis.utils import iface
from PyQt4.QtCore import QVariant
_NAME_FIELD = 'Nr'
_SUM_FIELD = 'calc'
_NEW_NEIGHBORS_FIELD = 'NEIGHBORS'
_NEW_SUM_FIELD = 'SUM'
layer = iface.activeLayer()
layer.startEditing()
layer.dataProvider().addAttributes(
[QgsField(_NEW_NEIGHBORS_FIELD, QVariant.String),
QgsField(_NEW_SUM_FIELD, QVariant.Int)])
layer.updateFields()
feature_dict = {f.id(): f for f in layer.getFeatures()}
index = QgsSpatialIndex()
for f in feature_dict.values():
index.insertFeature(f)
for f in feature_dict.values():
print 'Working on %s' % f[_NAME_FIELD]
geom = f.geometry()
intersecting_ids = index.intersects(geom.boundingBox())
neighbors = []
neighbors_sum = 0
for intersecting_id in intersecting_ids:
intersecting_f = feature_dict[intersecting_id]
if (f != intersecting_f and
not intersecting_f.geometry().disjoint(geom)):
neighbors.append(intersecting_f[_NAME_FIELD])
neighbors_sum += intersecting_f[_SUM_FIELD]
f[_NEW_NEIGHBORS_FIELD] = ','.join(neighbors)
f[_NEW_SUM_FIELD] = neighbors_sum
layer.updateFeature(f)
layer.commitChanges()
print 'Processing complete.'
I have found somewhat a workaround for it. Before using my script, I create a small (for my purposes, 0,01 m was enough) buffer around all joints. Later, I use a Difference tool to remove the buffer areas from my main layer, thus removing not-needed neighbouring polygons. Using the code now works fine

Graph-tool edge_property to string

I've got a graph with edge weights. I looked around and found that I can use edge_properties to represent an edge weight. I do it like this:
edge_weight = g.new_edge_property("double")
for i in range(10):
e = g.add_edge(i, i+1)
edge_weight[e] = i
Now I want to print a graph from this with the given edge weights on the edges. Do you have any ideas how to do this? The only thing that I could come up is this:
edge_weight = g.new_edge_property("double")
edge_str_weight = g.new_edge_property("string")
for i in range(10):
e = g.add_edge(i, i+1)
edge_weight[e] = i
edge_str_weight[e] = str(i)
graph_draw(g, edge_text=edge_str_weight, output="out.png")
It works, but it's quite redundant. Also if it's suggested to store the edge weight in an other structure or something, feel free to comment :)
In principle, there is no need create a different property, since a conversion to string will be made inside graph_draw(). However, graph-tool uses hexadecimal float notation by default, because it allows for a perfect representation. This is ideal for storing the values in a file, but not for displaying them. Therefore your approach is correct. You can perhaps do it more succinctly and efficiently using map_property_values():
label = g.new_edge_property()
map_property_values(edge_weight, label, lambda w: str(w))
graph_draw(g, edge_text=label, output="out.png"))
Maybe it's a typo but the assignment to edge_str_weight should reference the edge e you are currently working with:
edge_str_weight[e] = str(i)
Other than that, working with property maps is generally the best option with graph-tool. If for some reason you want to use a one-time property-map just for plotting purposes, you will again need to create one:
edge_alt_str_weights = g.new_edge_property("string")
for edge in g.edges():
edge_alt_str_weights[edge] = str(edge_weight[edge])
You might also want to define the property maps you plan to keep around as internal in case you want to use them persistently.

Categories

Resources