How do you access and set a specific bone animation fcurve in python ? e.g. set pinky02_L z rotation = 8 degrees

I want to access the keyframes for a specific bone in animation_data.action, just so I can reset them to a default value. My main problem is I dont know how to just access a specific bone.

The general purpose of this is to automatically reset the hand positions of bvh animation loaded onto a manuelbastionilab model. The bvh animation loads it in fine, but because there isnt really any hand data, it sets the animation to a default splayed out position. And because it assigns it to the wrong bones, it comes in with a crooked little finger. So I just want a simple python script to reset any animations I load in to a good default.

I think I should be able to get to the animation data for the keyframes with

myaction = bpy.context.active_object.animation_data.action


But I dont know what comes next, I dont know how to access the fcurves for a specific bone like a joint / bone in my little finger called pinky02_L

This seems incredibly basic but Ive spent ages googling it and failed miserably.

I suspect I might have problems with setting the data too ! I am using quaternions and so I want to access say the z rotation quaternion. So how do I access the z rot channel, I think its some array offset for the fcurve or something ? So once I have found the fcurve for pinky02l (pinky02lfcurve = ?), is it something like curve = pinky02lfcurve[6] to access the z rotation channel ? Or have I got it all horribly wrong ?

keyframePoints = curve.keyframe_points
for keyframe in keyframePoints:


And Once I have a keyframe how do I set it to a value like :

keyframe.value = math.radians(8.0)


. Is it that simple ? I bet its not!

Any answers to any parts of this would be great ! p.s. thank you to batFinger and Scott Milner for answering my question about it setting it to the wrong degrees the other day.

So from the post lemon refers too I if I am understanding it correctly if I use:

for curve in pinky02lfcurve
if curve.data_path.endswith('rotation_quaternion')
if curve.array_index == 2 # or is it 3 for z with quaternions ?
keyframePoints = curve.keyframe_points
for keyframe in keyframePoints:


Ok so re writing to take into account batFingers post I think the following should do what I want !

myaction = bpy.context.active_object.animation_data.action
fcurves = myaction.fcurves
rot = Euler(0,0,8)
myquat = rot.to_quaternion()

pinkyb = bpy.data.objects['MyArmature'].pose.bones['pinky02_L']
dpath = pinkyb.path_from_id("rotation_quaternion")
fc = fcurves.find(dpath, index=0)
keyframePoints = fc.keyframe_points
for keyframe in keyframePoints:
keyframe.co[1] = myquat.w

fc = fcurves.find(dpath, index=1)
keyframePoints = fc.keyframe_points
for keyframe in keyframePoints:
keyframe.co[1] = myquat.x

fc = fcurves.find(dpath, index=2)
keyframePoints = fc.keyframe_points
for keyframe in keyframePoints:
keyframe.co[1] = myquat.y

fc = fcurves.find(dpath, index=3)
keyframePoints = fc.keyframe_points
for keyframe in keyframePoints:
keyframe.co[1] = myquat.z


So I hope this should be good apart from the curve control points which are still at their original positions I think. Though I also still need to work out what angle I actually want to set it too ! Thanks again batFinger and lemon.

• – lemon Jun 22 '18 at 14:16
• Thanks lemon, if I am understanding it correctlyif fc.data_path.endswith(('location','rotation_euler','rotation_quaternion' – MajorTom Jun 22 '18 at 17:38
• Didn't used it myself with quaternion (so you'll have to check how it is organized... 4 data rows??). But yes 'rotation_quaternion', it should be. To check that, simply print the curve names. – lemon Jun 22 '18 at 17:56
• Just to say my last comment didnt go quite as planned, I pressed return to add a line break and arrange some code and it submitted the comment, then I deleted all the characters and submitted that and it ignored me and left the comment there ! Anyway I amended the end of my original question, though I think lemon might have replied to the comment that went wrong. So Im still hazy on the usage of data_path.endswith (is it used with curves or fcurves or are they the same thing) and Im still after a way of finding the fcurve(s) associated with pinky02_L. Thanks – MajorTom Jun 22 '18 at 18:47

Some py console code.

Below are some ways to find an fcurve for specific pose bone, and pose bone property. In this example the context pose bone, and rotation_quaternion.

>>> ob = C.object
>>>
>>> action = ob.animation_data.action
>>> pb =  context.active_pose_bone
>>> pb.name
'Bone'

>>> # could query the pose bone  from collection via its name
>>> ob.pose.bones.get(pb.name)
bpy.data.objects['Armature'].pose.bones["Bone"]

>>> print(pb.path_from_id.__doc__)
.. method:: path_from_id(property="")

Returns the data path from the ID to this object (string).

:arg property: Optional property name which can be used if the path is
to a property of this object.
:type property: string
:return: The path from :class:bpy.types.bpy_struct.id_data
to this struct and property (when given).
:rtype: str

# get the path from pb.id_data
>>> dp = pb.path_from_id("rotation_quaternion")
>>> dp
'pose.bones["Bone"].rotation_quaternion'

>>> # could also build this from name
>>> 'pose.bones["%s"].rotation_quaternion' % pb.name
'pose.bones["Bone"].rotation_quaternion'

>>> # use find for one offs
>>> print(action.fcurves.find.__doc__)
ActionFCurves.find(data_path, index=0)
Find an F-Curve. Note that this function performs a linear scan of all F-Curves in the action.
# find rotquot[3] aka rotquot.z
>>> fc = action.fcurves.find(dp, index=3)
>>> fc
bpy.data.actions['ArmatureAction']...FCurve

>>> fc.array_index
3
# use list comp to find them all for for each index
>>> ["%s[%d]" % (dp, fc.array_index) for fc in action.fcurves if fc.data_path == dp]
['pose.bones["Bone"].rotation_quaternion[0]', 'pose.bones["Bone"].rotation_quaternion[1]', 'pose.bones["Bone"].rotation_quaternion[2]', 'pose.bones["Bone"].rotation_quaternion[3]']

>>> # get the value from ob using dp
>>> ob.path_resolve("%s[%d]" % (dp, fc.array_index))
-0.43060973286628723
# ie ob.pose.bones["Bone"].rotation_quaternion[3] = -0.43
>>> pb.id_data.path_resolve("%s[%d]" % (dp, fc.array_index))
-0.43060973286628723


Get bones associated with specific action in python

How can I tell if a bone property has a keyframe on the current frame using python?

How can I access bone's 'animation_data.action'?

On rotations, here is the quaternion for an xyz Euler rotation of degrees (8, 8, 8)

>>> rot = Euler((radians(8) for axis in "xyz"))
>>> rot.to_quaternion()
Quaternion((0.9930493831634521, 0.06456293165683746, 0.07427114993333817, 0.06456293165683746)) # wxyz


To set the defaults to above would set each keyframe.y of keyframes in fcurve fc with array_index=3 to 0.06.. etc.

• Thanks batFinger I think that sort of works, though boy is it confusing. Ill amend my orig post with what I think is working code in a bit. The one prob I still appear to have is that the curve control points are maybe still at their original positions. So despite setting all the points to the same value I dont end up with a straight line ! Getting the data path from the pose bone and using it to find the fcurve in the action doesnt make a lot of sense to me, but it appears to work, so thank you. P.s. thanks for the tip about quaternions as Im not sure I ever did fully understand them :) – MajorTom Jun 22 '18 at 20:32