dictionary help

78 views
Skip to first unread message

kevco...@gmail.com

unread,
Oct 8, 2014, 10:14:40 AM10/8/14
to python_in...@googlegroups.com
Hey Guys,

I'll admit, dictionaries are not my strong point, and I could use a little help ;)

I'm looping through a dictionaries values, to find a particular value. If it doesn't find the value, okay fine. But if it does find the value, I need the key the value belongs to.

#=============================
import pymel.core as pm
from itertools import chain

sel = pm.ls(sl=1, fl=True)

connectedVertGroups = {}
vertGroups = {}
for i, vtx in enumerate(sel):

if vtx not in chain( *connectedVertGroups.values() ):
connectedVerts = [ vert for vert in vtx.connectedVertices() ]
connectedVerts.append(vtx)
connectedVertGroups["group_{0}".format(i)] = connectedVerts
vertGroups["group_{0}".format(i)] = vtx

else:
'''
TODO - Get the Key in connectedVertGroups that vtx belongs to, and add connected verts to it if they're not already in it. verify it's also in the correct vertGroup key.
'''
connectedVerts = [ vert for vert in vtx.connectedVertices() if vert not in connectedVertGroups.values() ]
#===========================


Thx
Kev

Jack Straw

unread,
Oct 8, 2014, 12:10:57 PM10/8/14
to python_in...@googlegroups.com, kevco...@gmail.com
This is how I generally go about searching the values in a dict; 

my_key = next((key for key, value in dict.iteritems() if value == 'what im testing against'), None)

my_key will be None if the condition is never True.

kevco...@gmail.com

unread,
Oct 8, 2014, 12:56:42 PM10/8/14
to python_in...@googlegroups.com, kevco...@gmail.com
Hi jack, thx for helping me.

I think this works for me:

vtxKey = next((key for key, value in connectedVertGroups.iteritems() if value == vtx), None)

The only problem I'm having is that my dictionary values are a list of vertices, and I need to check for a vertex within those lists.

Do you have any suggestions for getting passed that? I was able to use chain(*) when checking the dictionary values directly, but it doesn't seem to work when I'm using dict.iteritems(). chain(*dict.iteritems()) or chain(*dict.items()) - too many items to unpack.

Kev

Marcus Ottosson

unread,
Oct 8, 2014, 1:05:45 PM10/8/14
to python_in...@googlegroups.com, kevin cortez

How about a loop?

awesome_verts = list()
for name, group in connectedVertGroups.iteritems():
    for vertex in group:
         if vertex is 'Awesome':
              awesome_verts.append(vertex)


Kev

--
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/7246e089-a231-4297-9e81-27e676b1dfb6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

Jack Straw

unread,
Oct 8, 2014, 1:11:14 PM10/8/14
to python_in...@googlegroups.com, kevin cortez
import pymel.core as pm

sel = pm.ls(sl=1, fl=True)

connectedVertGroups = {}
vertGroups = {}
for i, vtx in enumerate(sel):
    vtxKey = next((key for key, vtx_list in connectedVertGroups.iteritems() if vtx in vtx_list), None)
    if vtxKey is None:
        connectedVerts = [ vert for vert in vtx.connectedVertices() ]
        connectedVerts.append(vtx)
        connectedVertGroups["group_{0}".format(i)] = connectedVerts
        vertGroups["group_{0}".format(i)] = vtx

--
You received this message because you are subscribed to a topic in the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/python_inside_maya/_K5kHFAEXjo/unsubscribe.
To unsubscribe from this group and all its topics, 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/CAFRtmOAXxCMuYbPfbvX_%3D0BM-pKVciXSXr51V5qqenU2cKDNKA%40mail.gmail.com.

kevco...@gmail.com

unread,
Oct 8, 2014, 1:48:12 PM10/8/14
to python_in...@googlegroups.com, kevco...@gmail.com
okay, now we're getting somewhere ;)

I feel so useless, but this is really helping me understand dictionaries. I was figuring those loops could be reduced.

I'll admit I'm kinda lost now in the code. It seems that "vtxKey" is returning a vertex, and not the dictionary key.

What i'll need to do is if that vtx does exist in the list of vertices that are my values in the keys of connectedVertGroups. append the vtx to the the same dictionary key, value list in vertGroups.

in the end, the keys for vertGroups, will contain all the vertices in my selection that are connected to eachother.

i.e If I select verts 1,2,3,4,5,50,51,52,53,54

vertGroups will have two keys. the first key's value would be [1,2,3,4,5] and the second key's value woud be [50,51,52,53,54]

kevco...@gmail.com

unread,
Oct 8, 2014, 2:07:51 PM10/8/14
to python_in...@googlegroups.com, kevco...@gmail.com
so something kinda like this, except I'm getting an error: "MeshVertex" object has no attribute append, as I'm not quite sure how to do that bit.


import pymel.core as pm

sel = pm.ls(sl=1, fl=True)

connectedVertGroups = {}
vertGroups = {}
for i, vtx in enumerate(sel):

vtxKey = next((key for key, vtx_list in connectedVertGroups.iteritems() if vtx in vtx_list), None)

connectedVerts = [ vert for vert in vtx.connectedVertices() ]
connectedVerts.append(vtx)

if vtxKey is None:


connectedVertGroups["group_{0}".format(i)] = connectedVerts
vertGroups["group_{0}".format(i)] = vtx

else:
connectedVertGroups[vtxKey] = connectedVertGroups[vtxKey].append( connectedVerts )
vertGroups[vtxKey] = vertGroups[vtxKey].append( vtx )

Justin Israel

unread,
Oct 8, 2014, 3:07:02 PM10/8/14
to python_in...@googlegroups.com, kevin cortez
Here is a little tip about itertools.chain... If you already have an iterable of sequences (the values of a dict being a list of verts), you can use chain.from_iterable()

d['a'] = range(5)
d['b'] = range(5)
d['c'] = range(5)
chained = chain.from_iterable(d.itervalues())

The benefit is that you don't have to expand out all of your lists in temporary memory, if you have a lot or large lists. You are just passing in generators, and chain won't have to expand every list if you don't iterate the whole thing. 

When you do this: chain( *connectedVertGroups.values() )
You are first building out a list of lists, and then expanding them into args to pass to chain()




--
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.

kevco...@gmail.com

unread,
Oct 8, 2014, 3:14:02 PM10/8/14
to python_in...@googlegroups.com, kevco...@gmail.com
okay, I think I get it, get the value of the key, append the vtx to the list, then set that list as the value for the key. And from the looks of it, it seems as though everything should work now. So why doesn't it work :(

#==============================
import pymel.core as pm

sel = pm.ls(sl=1, fl=True)

connectedVertGroups = {}
vertGroups = {}
for i, vtx in enumerate(sel):

vtxKey = next((key for key, vtx_list in connectedVertGroups.iteritems() if vtx in vtx_list), None)

connectedVerts = [ vert for vert in vtx.connectedVertices() ]
connectedVerts.append(vtx)

if vtxKey is None:


connectedVertGroups["group_{0}".format(i)] = connectedVerts
vertGroups["group_{0}".format(i)] = vtx

else:
connectedVertList = connectedVertGroups.get(vtxKey)
connectedVertList.append( connectedVerts )

vertList = list(vertGroups.get(vtxKey))
vertList.append( vtx )

connectedVertGroups[vtxKey] = connectedVertList
vertGroups[vtxKey] = vertList

#=============================

kevco...@gmail.com

unread,
Oct 8, 2014, 3:23:57 PM10/8/14
to python_in...@googlegroups.com, kevco...@gmail.com
Thx Justin,

I'm gonna have to think about that one for a while. I can't say I fully understand what chain does. All I know is that sometimes, when I have nested lists or what not, it works for me. haha. I guess it's time to get smarter. You can laugh ;)

Cheers!

kevco...@gmail.com

unread,
Oct 8, 2014, 3:45:18 PM10/8/14
to python_in...@googlegroups.com, kevco...@gmail.com
Ah-ha. I was appending a list to the list of connectedVerts.

I still need to test it a bit, but I think this gets me what I'm after. Thanks guys for holding my hand through it.

btw, how are you guys nicely formatting your code? are there no <code> tags?


#=================================


import pymel.core as pm
from itertools import chain

sel = pm.ls(sl=1, fl=True)

connectedVertGroups = {}
vertGroups = {}
for i, vtx in enumerate(sel):

vtxKey = next((key for key, vtx_list in connectedVertGroups.iteritems() if vtx in vtx_list), None)

connectedVerts = [ vert for vert in vtx.connectedVertices() ]
connectedVerts.append(vtx)

if vtxKey is None:

connectedVertGroups["group_{0}".format(i)] = connectedVerts
vertGroups["group_{0}".format(i)] = vtx

else:

connectedVertList = list( set( connectedVertGroups.get(vtxKey) ) )
connectedVertList = connectedVertList + [ vert for vert in connectedVerts ]



vertList = list(vertGroups.get(vtxKey))
vertList.append( vtx )

connectedVertGroups[vtxKey] = connectedVertList
vertGroups[vtxKey] = vertList

#===============================


Kev

Justin Israel

unread,
Oct 8, 2014, 5:03:39 PM10/8/14
to python_in...@googlegroups.com, kevin cortez
On Thu, Oct 9, 2014 at 8:45 AM, <kevco...@gmail.com> wrote:
Ah-ha.  I was appending a list to the list of connectedVerts.

I still need to test it a bit, but I think this gets me what I'm after.  Thanks guys for holding my hand through it.

btw, how are you guys nicely formatting your code? are there no <code> tags?

Marcus shared a cool browser plugin a little while ago that some of us started using:
 


#=================================
import pymel.core as pm
from itertools import chain

sel = pm.ls(sl=1, fl=True)

connectedVertGroups = {}
vertGroups = {}
for i, vtx in enumerate(sel):

    vtxKey = next((key for key, vtx_list in connectedVertGroups.iteritems() if vtx in vtx_list), None)
    connectedVerts = [ vert for vert in vtx.connectedVertices() ]
    connectedVerts.append(vtx)

    if vtxKey is None:

        connectedVertGroups["group_{0}".format(i)] = connectedVerts
        vertGroups["group_{0}".format(i)] = vtx

    else:
        connectedVertList = list( set( connectedVertGroups.get(vtxKey) ) )
        connectedVertList = connectedVertList + [ vert for vert in connectedVerts ]

        vertList = list(vertGroups.get(vtxKey))
        vertList.append( vtx )

        connectedVertGroups[vtxKey] = connectedVertList
        vertGroups[vtxKey] = vertList

#===============================


Kev

--
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.

Jack Straw

unread,
Oct 9, 2014, 1:22:09 PM10/9/14
to python_in...@googlegroups.com, kevin cortez

I now understand what you are trying to achieve. You want to group selections of vertices that are connected.

The approach you were using had the caveat that you would need to select the verts in connected order otherwise it was possible to have orphaned ones that should be grouped (I fixed your code, tried it out and found this).

Here is another way of doing it, I basically grab a single selected vert, look if any of the verts around it are in our selection list, if they are, add it to the group and add its connected verts to a list of verts surrounding the group, growing the group one vert at a time. If there aren’t any verts in the selection list that are on the edge of the group we can make a new group.

import pymel.core as pm

unmatched_vtxs = pm.ls(sl=1, fl=True)

vtx_grps = []

while len(unmatched_vtxs) > 0:
    # grab a vertex
    vtx = unmatched_vtxs.pop()
    vtx_grps.append([vtx])

    # create a list that will contain all of the vertices around the edge of the group, starting with all of the connected verts for the start vert
    edge_vtxs = [v for v in vtx.connectedVertices()]
    matched_vtx = vtx
    # continue to try to find more verts to add to the group if we add a new vert, if not we can loop to the creating the next group
    while matched_vtx is not None: 
        matched_vtx = None
        for unmatched_vtx in unmatched_vtxs:
            if unmatched_vtx in edge_vtxs:
                matched_vtx = unmatched_vtx
                # if one of the unmatched verts is on the edge of our group add it to the group
                vtx_grps[-1].append(matched_vtx)
                # remove it from the edge list
                edge_vtxs.remove(matched_vtx)
                # add all of the new matched verts connected verts if they aren't already in the list
                for added_conn_vtx in matched_vtx.connectedVertices():
                    if added_conn_vtx not in edge_vtxs:
                        edge_vtxs.append(added_conn_vtx)
                break
        # remove the matched vert from our list of unmatched ones
        if matched_vtx is not None:
            unmatched_vtxs.remove(matched_vtx)


print vtx_grps



This is pretty slow in python for big selections as it runs in polynomial time, it might be more useful as a command C++ plugin.

Jack.

Marcus Ottosson

unread,
Oct 9, 2014, 1:24:19 PM10/9/14
to python_in...@googlegroups.com, kevin cortez

This is pretty slow in python for big selections as it runs in polynomial time, it might be more useful as a command C++ plugin.

I bet this will see a substantial performance increase if done using maya.cmds. Iterating over large sets isn’t a task well suited for PyMEL.


--
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.

For more options, visit https://groups.google.com/d/optout.



--
Marcus Ottosson
konstr...@gmail.com

kevco...@gmail.com

unread,
Oct 9, 2014, 5:28:41 PM10/9/14
to python_in...@googlegroups.com, kevco...@gmail.com
Hey Jack,

I noticed that yesterday when playing around with it a bit. In certain cases, it would give me some extra groups, depending on how I selected the verts. It makes sense.

I'm gonna have to pick apart your code to understand it a bit better. I had a feeling this stuff was gonna be fairly slow. It will lend itself to a rigging workflow, where someone can select whatever components, and build nulls and whatnot at the computed transform of those vert groups. It shouldn't ever really receive that many components, and the component selections can be simplified to speed it up a bit.

I'd love to see the speed of something similar written with maya.cmds. or even mel. I guess I veered towards pymel, since coming from softimage. Can't say i'd get very far with cmds ;)

Thanks for all your help
Kev

Justin Israel

unread,
Oct 9, 2014, 6:27:13 PM10/9/14
to python_in...@googlegroups.com, kevin cortez
I threw together a cmds version of this code (but someone please confirm my results. Maybe I did this wrong). I didn't really do anything to the actual logic, other than switching from PyMel to cmds, and I also switched to using a set, for an extra bit of performance increase, since the loop is doing a lot of membership testing within the collection.
206 verts, 29 groups, speedup of 18.5x
<function test1 at 0x112031b8> 1.5795 sec, 29 groups
<function test4 at 0x105c1cf8> 0.0841 sec, 29 groups

418 verts, 47 groups, speed of 42.12
<function test1 at 0x11203140> 7.2657 sec, 47 groups
<function test4 at 0x1149eb90> 0.1725 sec, 47 groups
def test4():
    unmatched_vtxs = cmds.ls(sl=True, fl=True)

    vtx_grps = []

    
while len(unmatched_vtxs) > 0:
        # grab a vertex

        vtx = unmatched_vtxs.pop()

        grp = [vtx]
        vtx_grps.append(grp)

        
# create a list that will contain all of the vertices around 

        # the edge of the group, starting with all of the connected 
        # verts for the start vert
        edge_vtxs = set(connectedVertices(vtx))
        matched_vtx = vtx

        
# continue to try to find more verts to add to the group if we 

        # add a new vert, if not we can loop to the creating the next group

        while matched_vtx is not None: 
            matched_vtx = None
            for unmatched_vtx in unmatched_vtxs:
                if unmatched_vtx in edge_vtxs:
                    matched_vtx = unmatched_vtx
                    # if one of the unmatched verts is on the edge of 

                    # our group add it to the group
                    grp.append(matched_vtx)
                    
# remove it from the edge list
                    edge_vtxs.remove(matched_vtx)
                    # add all of the new matched verts connected verts if 

                    # they aren't already in the list
                    for added_conn_vtx in connectedVertices(matched_vtx):
                        if added_conn_vtx not in edge_vtxs:
                            edge_vtxs.add(added_conn_vtx)
                    
break

            # remove the matched vert from our list of unmatched ones
            if matched_vtx is not None
:
                unmatched_vtxs.remove(matched_vtx)

    return vtx_grps

def connectedVertices(vtx):
    edges = cmds.polyListComponentConversion(vtx, fv=True, te=True)
    vtxs = cmds.polyListComponentConversion(edges, fe=True, tv=True)
    return cmds.ls(vtxs, fl=True)

--
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.

kevco...@gmail.com

unread,
Oct 9, 2014, 6:33:35 PM10/9/14
to python_in...@googlegroups.com, kevco...@gmail.com
wow, that's quite a bit faster. Thanks for this! I didn't anticipate that much of an increase. Guess it's time to start using cmds more often.

Kev

Justin Israel

unread,
Oct 9, 2014, 8:48:19 PM10/9/14
to python_in...@googlegroups.com, kevin cortez

Fo' sho'
Anytime you see a for/while loop in there with many inner PyMel calls, it probably could benefit from testing a cmds or api variation

wow, that's quite a bit faster. Thanks for this! I didn't anticipate that much of an increase.  Guess it's time to start using cmds more often.

Kev

--
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.
Reply all
Reply to author
Forward
0 new messages