Scripting: Shape Keys

Shape Keys are not directly stored in a Key data block. This is a monolithic data block containing the shape keys. The actual shape keys are stored in the key_blocks attribute as Shape Key types.

# Get the list of shape keys
shapekeylist = bpy.context.active_object.data.shape_keys.key_blocks
for shapekey in shapekeylist:
    print(f"Key '{shapekey.name}' value is {shapekey.value}")

The active shape key can be acquired directly from the object (not the object data!):

currKey = obj.active_shape_key
currIndex = obj.active_shape_key_index

Single shape keys can be addressed by ID or by name:

sk=bpy.context.active_object.data.shape_keys.key_blocks[22]
print(sk.name)
sk=bpy.context.active_object.data.shape_keys.key_blocks["Male 002"]
print(sk.name)
#getting the id from name
myObj=bpy.context.scene.objects[0]
first_shape_id = myObj.data.shape_keys.key_blocks.find("Male 001")

A new shape key is created via the bpy.ops.object.shape_key_add operator and you remove them with bpy.ops.object.shape_key_remove.

bpy.ops.object.shape_key_add(from_mix=False)
bpy.ops.object.shape_key_remove(all=False)

The positions of the shape keys is stored in the data block of the shape key

for i, d in enumerate(sk.data):
    print(f"Vertex {i} Pos: {d.co}")

Shape Key Meshes

Meshes are stored in the data part of a Shape Key. It's a list of ShapeKeyPoint, which has the coordinates as a Vector.

sk=bpy.context.active_object.data.shape_keys.key_blocks[22]
print(f"Shapekey {sk.name} first vertex: {sk.data[0].co}")
# <Vector (-0.8453, -0.8453, -0.8453)>

Animation

Shape key derives from bpy_struct, hence keyframes are set via the keyframe_insert method:

sk.value=1
sk.keyframe_insert("value")
sk.value=0
next_frame_number=bpy.context.scene.frame_current+1
sk.keyframe_insert("value", frame=next_frame_number)

Same way it's possible to delete a keyframe:

sk.keyframe_delete("value")
next_frame_number=bpy.context.scene.frame_current+1
sk.keyframe_delete("value", frame=next_frame_number)

Get keyframes and the values via the animation_data:

ad=bpy.context.active_object.data.shape_keys.animation_data
action=ad.action
print("Keyframes:")
for fcu in action.fcurves:
    print()
    print(fcu.data_path, fcu.array_index)
    for kp in fcu.keyframe_points:
        print(f"  Frame {kp.co[0]}: {kp.co[1]}")

print("Frames:")
for fcu in action.fcurves:
    print()
    print(fcu.data_path, fcu.array_index)
    for i in range(1, 6):
        print(f"  Frame {i}: {fcu.evaluate(i):6f}")

Various Examples

# Delete all shapekeys starting with a keystring

import bpy

shapekey_keystring = "frame"
obj = bpy.context.active_object

# Get the list of shape keys
shapekeylist = obj.data.shape_keys.key_blocks
keys = dict(enumerate(shapekeylist))
for sid, shapekey in reversed(keys.items()):
    if shapekey.name.starts_with(shapekey_key):
        obj.active_shape_key_index = sid
        bpy.ops.object.shape_key_remove(all=False)