fasted way to search for nodes based on attr, and under hierarchy?

67 views
Skip to first unread message

Gerard v

unread,
Mar 11, 2015, 9:38:18 PM3/11/15
to python_in...@googlegroups.com
Hi all.

I am trying to determine the most efficient way to search for nodes (transforms) of specified types (eg transform of a curve) under a hierarchy (lets call it 'top_node') that have a specific custom (string) attribute.
When potentially dealing with a large number of nodes speed becomes a factor. 

I've approached this in a few ways (two if which are listed below), and I'd appreciate opinions:

Approach1: 
1) Create List1: nodes that have the required attribute via:  cmds.ls('*.customAttrName')  ..not so fast (scene level search..) but somewhat convenient
2) Create List2: transforms of specific node type under the 'top_node'   ..eg: all transforms of curves under the top_node
3) intersect the 2 lists using : list(set(List1) & set(List2))

top_node = 'M_worldMover_crv'
search_string = '*.gvAnim'
gvAnim_list = cmds.ls(search_string, r=1, o=1, l=1)
curves_list = cmds.listRelatives(cmds.ls(top_node, dag=1, type='nurbsCurve',ni=1, o=1, r=1, l=1), p=1, f=1)
final_list = list(set(gvAnim_list) & set(curves_list))
cmds.select(final_list)



Approach2: 
I think this one is a bit faster but not greatly.
1) create List1: transforms of specific node type under the 'top_node' (eg all transforms of meshes).
2) Create List2: iterate through List1 to see if the node contains the custom attribute and append to the list.

top_node = 'M_worldMover_crv'
search_attribute = '.gvAnim'
curves_list = cmds.listRelatives(cmds.ls(top_node, dag=1, type='nurbsCurve',ni=1, o=1, r=1, l=1), p=1, f=1)
final_list = [i for i in curves_list if cmds.ls(i + search_attribute )]
cmds.select(final_list)


I guess my issue would be solved, mostly, if the command ls could take a string argument for attribute, while using the 'dag' flag, and a node to search under:
example:
cmds.ls(top_node, dag=1, type='mesh')   # works to search under a hierarchy
cmds.ls('*.customAttr', o=1)   # works to find all objects in scene with the specified attribute

but.. this obviously doesnt work, unless I'm missing something:

cmds.ls(top_node, '*.customAttr', dag=1, o=1) # but it's sort of what I am trying to do..


Is the API faster? If so is there someone that could point me in the right direction please?
Thanks for any help.

Gerard.

Chris Gardner

unread,
Mar 11, 2015, 9:46:02 PM3/11/15
to python_in...@googlegroups.com
hey gerard,

nice to see you at the pub the other day :)

here's some API code for looking for custom attrs called "tags" and then looking for a string inside that. it's a bunch faster than maya cmds. adapt as necessary. it's filtering on transform nodes currently, but you could change that for your node type you want to target.

import time
import maya.api.OpenMaya as om2


def findByTag(inTag):
    coll = []
   
    sel = om2.MGlobal.getSelectionListByName('*')
    depFn = om2.MFnDependencyNode()
   
    xformType = om2.MTypeId(0x5846524d)
   
    for i in xrange(sel.length()):
        mObj = sel.getDependNode(i)
        depNode = depFn.setObject(mObj)
        if depNode.typeId == xformType:
            if depNode.hasAttribute('tags'):
                plug = depNode.findPlug("tags", False)
                result = plug.asString()
               
                if result:
                    tags = result.split(',')
                    if inTag in tags:
                        coll.append(depNode.name())
    return coll
   

ts = time.time()
coll = findByTag('blah')
te = time.time()

print coll
#cmds.select(coll)

print 'api2 %2.4f sec' % (te - ts)
print len(coll)

cheers,
chrisg

Gerard v

unread,
Mar 11, 2015, 11:01:51 PM3/11/15
to python_in...@googlegroups.com
Hey there Chris. Thanks for the code I'll take a gander. Fuel catchup was great. Haven't seen any of the old team in quite some time.
Cheers.
G.

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAPoKtNfn1sCAivOYEw5NQ2kFpWGzdQVYZcfP8FXBrm53_mm%3DOQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Roy Nieterau

unread,
Mar 12, 2015, 3:16:45 PM3/12/15
to python_in...@googlegroups.com
Just to get geeky and not sure if it's any faster but here's another version. ;)

import maya.cmds as mc
import itertools

def grouper(iterable, n, fillvalue=None):
   
"Collect data into fixed-length chunks or blocks"
   
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args
= [iter(iterable)] * n
   
return itertools.izip_longest(fillvalue=fillvalue, *args)

# search under node for nodes with attr that are of type in allowed_types
root_node
= 'rootNode'
search_attr
= 'testAttr'
allowed_types
= frozenset(['mesh'])
valid_nodes
= [node for node, type in grouper(mc.ls('*.{0}'.format(search_attr), long=True, recursive=True, showType=True, o=True), 2) if type in allowed_types and node.startswith(root_node)]
mc
.select(valid_nodes, r=1)

Note that this version assumes root_node is actually a root node (so has no parent). If you want to allow it to have a parent then you wouldn't do node.startswith() but something like:

import maya.cmds as mc
import itertools

def grouper(iterable, n, fillvalue=None):
   
"Collect data into fixed-length chunks or blocks"
   
# grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx
    args
= [iter(iterable)] * n
   
return itertools.izip_longest(fillvalue=fillvalue, *args)

# search under node for nodes with attr that are of type in allowed_types
root_node
= 'rootNode'
search_attr
= 'testAttr'
allowed_types
= frozenset(['mesh'])

root_node_as_parent
= '{0}|'.format(root_node)
valid_nodes
= [node for node, type in grouper(mc.ls('*.{0}'.format(search_attr), long=True, recursive=True, showType=True, o=True), 2) if type in allowed_types and root_node_as_parent in node]
mc
.select(valid_nodes, r=1)

Sometimes the fastest thing is limiting the amount of commands you run that actually rely on querying something from Maya so this could be fast. Could you provide a heavyweight test scene example? ;)
Both these versions rely on a single maya command query.
Let me know what kind of speeds you get from this. :D

Cheers and /geekout,
Roy
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_maya+unsub...@googlegroups.com.

Gerard Gmail

unread,
Mar 13, 2015, 3:08:22 AM3/13/15
to python_in...@googlegroups.com
This looks interesting Roy. Thanks for the suggestion. Formatting looks crazy on my phone, but I'll test it out on Monday morning when I'm  back on the box. 

Have a great weekend all. 

Gerard. 
Sydney, Australia. 
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/0ffe7f97-9e92-41dd-9149-41c3609223b7%40googlegroups.com.
Reply all
Reply to author
Forward
0 new messages