Is there's a way to get the indices properly from a Pymel/Maya API function?
I know Pymel has a function called getEdges() however according to their docs this get's them from the selected face, however I just need them from the selected edges.
Is this possible?
While your answer will work theodox, I did find a much simpler resolution, after some serious digging!
Turns out, hiding and not very well documented, was a function ironically called indices(), I did search for this but nothing came up in the docs.
Pymel
selection[0].indices()[0]
The above will give us the integer of the selected edge. Simple and elegant!
Do you mean you just the expanded list of selected edges? That's just FilterExpand -sm 32 or cmds.filterExpand(sm=32) or pm.filterExpand(sm=32) on an edge selection. Those commands are always strings, you grab the indices out them with a regular expression:
# where objs is a list of edges, for example cmds.ls(sl=True) on an edge selection
cList = "".join(cmds.filterExpand( *objs, sm=32))
outList = set(map ( int, re.findall('\[([0-9]+)\]', cList ) ) )
which will give you a set containing the integer indices of the edges (I use sets so its easy to do things like find edges common to two groups without for loops or if tests)
Related
I tried to create a LP model by using pyomo.environ. However, I'm having a hard time on creating sets. For my problem, I have to create two sets. One set is from a bunch of nodes, and the other one is from several arcs between nodes. I create a network by using Networkx to store my nodes and arcs.
The node data is saved like (Longitude, Latitude) in tuple form. The arcs are saved as (nodeA, nodeB), where nodeA and nodeB are both coordinates in tuple.
So, a node is something like:
(-97.97516252657978, 30.342243012086083)
And, an arc is something like:
((-97.97516252657978, 30.342243012086083),
(-97.976196300350608, 30.34247219922803))
The way I tried to create a set is as following:
# import pyomo.envrion as pe
# create a model m
m = pe.ConcreteModel()
# network is an object I created by Networkx module
m.node_set = pe.Set(initialize= self.network.nodes())
m.arc_set = pe.Set(initialize= self.network.edges())
However, I kept getting an error message on arc_set.
ValueError: The value=(-97.97516252657978, 30.342243012086083,
-97.976196300350608, 30.34247219922803) does not have dimension=2,
which is needed for set=arc_set
I found it's weird that somehow my arc_set turned into one tuple instead of two. Then I tried to convert my nodes and arcs into string but still got the error.
Could somebody show me some hint? Or how do delete this bug?
Thanks!
Underneath the hood, Pyomo "flattens" all indexing sets. That is, it removes nested tuples so that each set member is a single tuple of scalar values. This is generally consistent with other algebraic modeling languages, and helps to make sure that we can consistently (and correctly) retrieve component members regardless of how the user attempted to query them.
In your case, Pyomo will want each member of the the arc set as a single 4-member tuple. There is a utility in PyUtilib that you can use to flatten your tuples when constructing the set:
from pyutilib.misc import flatten
m.arc_set = pe.Set(initialize=(tuple(flatten(x)) for x in self.network.edges())
You can also perform some error checking, in this case to make sure that all edges start and end at known nodes:
from pyutilib.misc import flatten
m.node_set = pe.Set( initialize=self.network.nodes() )
m.arc_set = pe.Set(
within=m.node_set*m.node_set,
initialize=(tuple(flatten(x)) for x in self.network.edges() )
This is particularly important for models like this where you are using floating point numbers as indices, and subtle round-off errors can produce indices that are nearly the same but not mathematically equal.
There has been some discussion among the developers to support both structured and flattened indices, but we have not quite reached consensus on how to best support it in a backwards compatible manner.
I'm writing a function that receives a graph as input.
The very first thing I need to do is determine the order of the graph (that is, the number of vertices in the graph).
I mean, I could use g.summary() (which returns a string that includes the number of vertices), but then I'd have parse the string to get at the number of vertices -- and that's just nasty.
To get the number of edges I'm using len(g.get_edgelist()), which works. But there is no g.get_vertexlist(), so I can't use the same method.
Surely there is an easy way to do this that doesn't involve parsing strings.
g.vcount() is a dedicated function in igraph that returns the number of vertices. Similarly, g.ecount() returns the number of edges, and it is way faster than len(g.get_edgelist()) as it does not have to construct the full edge list in advance.
As some functions in igraph have been renamed in meantime, I found the answers here out of date. What the docs suggest now is calling
gorder(g)
which works for me. Analogy for ecount is
gsize(g) # vcount(g) still works, but not g.vcount()
It's useful to note that help pages are cleverly redirected, so
?vcount
brings you to gorder docs etc.
g.vs should return the sequence of vertices as an igraph.VertexSeq object:
>>> from igraph import Graph
>>> g = Graph.Formula("A-B")
>>> g.vs["name"]
['A', 'B']
>>> len(g.vs)
2
>>> g.vcount()
2
Edit: As #Tamas mentions below, g.vcount() will also return the number of vertices. Example edited to account for this.
I have a 2D part in Abaqus with many partitions and I therefore want to select many edges with the getByBoundingBox command to create a surface set. This is the bit of code I have:
p = mdb.models['Model-1'].parts['Plate']
s = p.edges
edges = s.getByBoundingBox((0,0.02,0,0.003,0.04,0))
p.Surface(side1Edges=edges, name='r1')
But it gives me the following error: "edges = s.getByBoundingBox((0,0.02,0,0.003,0.04,0)) TypeError: arg1; found tuple, expecting float".
Any advice much appreciated.
The corners of the bounding box should be provided as 6 separate numbers and not as a single tuple. The solution is very simple, just change the leading "((" and trailing "))" to single "(" and ")". So the call looks like this s.getByBoundingBox(0,0.02,0,0.003,0.04,0).
this comes quite late but in case anyone enters and has the same doubt:
When telling to Abaqus which edge/face/element you are actually selecting, sometimes you need to specify the "ID" of that object, that's why it's asking for a float instead of a tuple in the error message. This can be solved as:
You select the edge/face/node/element you want:
edge = s.getByBoundingBox((0,0.02,0,0.003,0.04,0))
Create a intermediate variable to know the "ID" of the element:
edge_id = edge.id
You now can refenciate it in the dialog for creating surfaces:
p.Surface(side1Edges=p.edges[edge_id], name='r1')
In this case, you're telling Abaqus to select the edge with the id "edge_id" from all the edges that your part "p" has.
This happens many times and you've to be aware what Abaqus is expecting from the code. Sometimes can be the object itselft, a tuple of elements or simply a float expressed as a tupple e.g: edge = (number, )
Regards
I tried the modified code on a 2D plate with the following code
p = mdb.models['Model-1'].parts['Plate']
s = p.edges
edges=s.getByBoundingBox(0,0,0,25,25,1)
And it does not crash. But its not really clear how you can create a surface using this. You need to use a different strategy to achieve what you want. You can find create a surface using the 'pointOn' method.
I got the code working like this until i realized that the vertex index changes for geometry with over 100 vertices...
I assumed i could just split the string and everything would be dandy
import maya.cmds as mc
selPoints = mc.ls(sl = True) # list of names of selected vertices
objName = (str(selPoints[0]))[:-9]
print selPoints
print objName
Heres what it returned:
[u'pCylinder25.vtx[4]', u'pCylinder25.vtx[24]']
pCylinder
I'm trying to hack off the portion with '.vtx[integer]'
I may be going about this completely wrong, and there may be a dead simple way to do this.
Thanks
You can get the object from any valid selection string with the -o flag:
cmds.ls("pCube1.vtx[0]", o=True)
# pCubeShape1
Note that will be the shape, not the transform -- that's Maya being pedantic but it is correct. The transform would be
cmds.listRelatives(cmds.ls("pCube1.vtx[0]", o=True), p=True)
You may also find it helpful to split the components using partition:
object, _, component = "pCube1.vtx[0]".partition(".")
where the _ is python slang for 'ignore me'.
Wouldn't it be awesome if it were easy to get the object from Maya? From experience, I know it can be frustrating since MEL/maya.cmds doesn't use an object-oriented approach.
Anyhow, you should refer to the documentation often for more info on the variety of string methods you can use. Really comes in handy all the time!
To answer your question, you can use .split or .find, whichever you prefer.
print selPoints[0].split('.vtx')[0]
print selPoints[0][0:selPoints[0].find('.vtx')]
The split method returns a list of strings created by the delimiter string '.vtx'. Then, taking the first element from that list will always be the object name.
The find method returns the index of the substring '.vtx', so the second example simply uses slicing syntax to return the correct string.
just for stuff, using vanilla maya commands:
as mentioned with ls:
cm.ls("pCube1.vtx[0]", o=1) # will return shape pCubeShape1
with plugNode (opposite plugAttr):
cm.plugNode("pCube1.vtx[0]") # will return transform pCube1
Since I'm pretty new this question'll certainly sound stupid but I have no idea about how to approach this.
I'm trying take a list of nodes and for each of the nodes I want to create an array of predecessors and successors in the ordered array of all nodes.
Currently my code looks like this:
nodes = self.peers.keys()
nodes.sort()
peers = {}
numPeers = len(nodes)
for i in nodes:
peers[i] = [self.coordinator]
for i in range(0,len(nodes)):
peers[nodes[i%numPeers]].append(nodes[(i+1)%numPeers])
peers[nodes[(i+1)%numPeers]].append(nodes[i%numPeers])
# peers[nodes[i%numPeers]].append(nodes[(i+4)%numPeers])
# peers[nodes[(i+4)%numPeers]].append(nodes[i%numPeers])
The last two lines should later be used to create a skip graph, but that's not really important. The problem is that it doesn't really work reliably, sometimes a predecessor or a successor is skipped, and instead the next one is used, and so forth. Is this correct at all or is there a better way to do this? Basically I need to get the array indices with certain offsets from each other.
Any ideas?
I would almost bet that when the error occurs, the values in nodes have duplicates, which would cause your dictionary in peers to get mixed up. Your code assumes the values in nodes are unique.