Getting vertices of a vertex group from within Python


(4096) #1

I’ve been trying to get all the verices from vertex groups from within the Python API. I created a vertex group for the default Cube in 3D view and then entered the following code in the Python console:


>>> a = bpy.data.objects["Cube"]
>>> a
bpy.data.objects['Cube']

>>> a.vertex_groups
bpy.data.objects['Cube'].vertex_groups

>>> a.vertex_groups["Group"]
bpy.data.objects['Cube']...VertexGroup

>>> a.vertex_groups.keys()
['Group']

>>> a.vertex_groups["Group"]
bpy.data.objects['Cube']...VertexGroup

>>> a.vertex_groups["Group"][0]
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
TypeError: this type doesn't support IDProperties

>>> a.vertex_groups["Group"].keys()
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
TypeError: bpy_struct.keys(): this type doesn't support IDProperties

>>> a.vertex_groups["Group"].keys
<built-in method keys of VertexGroup object at 0x000000000AF6CF08>

>>> a.vertex_groups["Group"].keys(0)
Traceback (most recent call last):
  File "<blender_console>", line 1, in <module>
TypeError: keys() takes no arguments (1 given)

I don’t understand why a.vertex_groups.keys returns a message saying that it is a built in method, but when I actually call keys(), I get an error. How do I get a list of vertices of a vertex group from within Python?


(CoDEmanX) #2

you can either access vertex groups via

bpy.context.object.data.vertices[#].groups (use groups[#].group to get the vertex_group[index!])

or via

bpy.context.object.vertex_groups (vertex_groups[0].name for instance, weight can only be looked via the method weight(), which may result in a RuntimeError if the requested vertex isn’t in the group)


(4096) #3

Thanks for the help, but this seems to just get the group itself. I want a list of the vertices in the group.


(4096) #4

I suppose I could do something like the following:


def get_vertices_in_group(a,index):
    # a is a Blender object
    # index is an integer representing the index of the vertex group in a
    vlist = []
    for v in a.data.vertices:
        for g in v.groups:
            if g.group == index:
                vlist.append(v.index)
    return vlist

but it would be more convenient if there was already a function that would get all the vertices of a vertex group.


(CoDEmanX) #5

maybe like this?

ob =  bpy.context.object
group_lookup = {g.index: g.name for g in ob.vertex_groups}
verts = {name: [] for name in group_lookup.values()}
for v in ob.data.vertices:
    for g in v.groups:
        verts[group_lookup[g.group]].append(v.index)

(PKHG) #6

CoDEmanX , this I should have known yesterday … very nice way accessing vertex_groups

With respect to this I have a question:
I have an object with a group op vertices selected and want to assign these to a vertex_group of the object.
The vertex_group is already set to active
(e.g. object.vertex_groups.active_index = to_list.index(to_groep_name) and in edit mode that group is indeed selected)
BUT I can not assign it via Python : bpy.ops.object.vertex_group_assign() seems not to be possible ???
Forgotten by the implementors?
Select and Deselect commands are schown (bpy.ops.object.vertex_group_select()
bpy.ops.object.vertex_group_deselect() )

but presseing Assign or Remove are done but not shown (in the … window of Blender, opened above the View3D) ???


(CoDEmanX) #7

Well, you could do:

import bpy

ob = bpy.context.object
me = ob.data
is_editmode = me.is_editmode
vgroup = ob.vertex_groups["Group"]

if is_editmode:
    ctx = bpy.context.copy()
    ctx["object"] = ob
    bpy.ops.object.editmode_toggle(ctx)
    
vgroup.add([v.index for v in me.vertices if v.select], 1.0, 'REPLACE')

if is_editmode:
    bpy.ops.object.editmode_toggle(ctx)

It’s unfortunately not possible without mode switching.


(PKHG) #8

Thanks CoDEmanX,

Hmm, I see only one mesh: ob. I have two meshes, identical vertices, edges, faces, both with vertex_groups, one filled one yet not filled
Say mesh one has group Head, with assigned vertices, and now I want the same vertices assigned in the other mesh with group say
MyHead …
Have to see if your suggestion will help me, in the ‘vgroup.add’ the list could be computed from mesh one and the vgroup be a vertex_group of the second mesh , named MyHead …
Will try :wink:
Thanks! The hint is the line vgroup.add … with its parameters, am I right?

Yes this gives me the solution!

VERY BIG THANKS.
Peter


(The Voyager) #9

Thank you for directing me here PKHG. I’m new to blender and I think I’m doing something wrong here. When I run this script it’s flipping to object mode and selecting the entire object. Is there a way to use this code to select a given vertex group (Top Group) and have it remain selected in edit mode so that I can modify it? Then along those same lines, select Bottom Group as a secondary command after the Top Group’s modification is complete?


This first image shows what I’d like to select.

This second picture is what I’m currently seeing after running the script.
Thanks so much in advance for any help that will follow.


(PKHG) #10

Hm … in my attempts to use vgroup.add all works like I want.
So put the code you use in code and /code with [ ] around them to see what is not as expected using YOUR code, will have a look at that and trying to …
Greets
PETER


(CoDEmanX) #11

My bad, if you start in edit mode me.is_editmode will be True and script toggles to object mode in order to assign weights. The toggling back at the end of the script won’t work however, because me.is_editmode is checked again, but of course is now False and thus skipped. Updated my script to store initial is_editmode state.


(Graphics_Dev) #12

A lot of work was put into this answer here:

You may be interested…I even added some performance graphs comparing the three methods in the answer.