0
$\begingroup$

I'm trying to delete some specific channels from many objects. I select them but the dope sheet requires me to expand the Action and Transform menus from each object, then selecting each curve and delete. For example, I'd like to delete specifically the "X Location" channel from all selected objects, but from the UI I could only delete all axes from the location or delete a single channel from only one of the objects.

This is really boring, so I thought I'd use Blender's Python API to automate it. However, I'm very new to it and couldn't find how to show the channel's name to the user.

I'm starting with an operator that would scan all selected items' channels and present a list to the user to select which channel to delete from all selected objects. However, the furthest I got was to list those channels by their data_path and array_index. I have this so far:

for ob in bpy.context.selected_objects:
    anim = ob.animation_data
    for group in anim.action.groups:
        for channel in group.channels:
            print("Channel:", channel)
            print("data_path:", channel.data_path, "   array_index:", channel.array_index)
            print(ob.path_resolve(channel.data_path))

However, the array_index is not really user-readable. So, here are two-questions-in-one:

Can I delete a single channel from all selected objects?

and

How can I present an FCurve's user-readable name to the user, if it is possible without hard-coding?

By the way, I remember that Blender is now translatable, and it seems the path should be in that direction, but I couldn't find it yet.

$\endgroup$
1
$\begingroup$

Find and remove

The fcurves collection of an action has a method to find fcurves from data path and index, and a remove method.

The same action can be linked to multiple objects, so will use a set to find all the actions' fcurves.

There really is no need to look at the group, location x keyframes have data path 'location' and array_index 0.

Test code. Since you mention you are going to convert this to an operator have added the context variable context = bpy.context Once test code works, lose this and use the context argument passed to operator/panel methods, when pasting into operator code.

import bpy

context = bpy.context

data_path = "location"
index = 0 # location.x or location[0]

#objects = bpy.data.objects # all
#objects = context.scene.objects # all in scene
objects = context.selected_objects # selected

all_fcurves = set(
    o.animation_data.action.fcurves for o in objects
    if o.animation_data and o.animation_data.action
    )

for fcurves in all_fcurves:
    fcurve = fcurves.find(data_path, index=index)
    if fcurve:
        fcurves.remove(fcurve)

for bones the data path is akin to

'pose.bones["Bone"].location`

in which case to find x location keyframe it could be simpler to replace the find method with

def find(fcurves, data_path, index):
    x = [fc for fc in fcurves 
         if fc.data_path.endswith(datapath) 
         and fc.array_index == index]
    return x.pop() if x else None

Thanks, I can use your answer later, but you missed the exact point of my question. I do not know that the user will delete specifically the X Location channel. Instead, I want to present a list of channels from all selected objects to the user, so that he will select, for example, "I want to delete the Z Location from all selected objects". However, I could not find a way to convert location[2] to "Z Location".

Re-read the question appears to be a pretty good attempt at an answer to part i. Generally the idea is to have one question per question , re part 2

Can get the name of the property via the "RNA" eg if an object has an fcurve with datapath "location" or "rotation_euler"

>>> C.object.bl_rna.properties['location'].name
'Location'

>>> C.object.bl_rna.properties['rotation_euler'].name
'Euler Rotation'

>>> C.object.bl_rna.properties['rotation_euler'].subtype
'EULER'

>>> C.object.bl_rna.properties['location'].subtype
'TRANSLATION'

As for the axis name from index, have asked this question Python RNA getting the names of Vector axes. (eg "g" is color[1])

>>> index = 0
>>> "XYZ"[index]
'X'

and as for your third question, with espanol selected as language.

>>> bpy.app.translations.pgettext("Location")
'Posición'

consult the docs. https://docs.blender.org/api/current/bpy.app.translations.html#module-bpy.app.translations

$\endgroup$
2
  • $\begingroup$ Thanks, I can use your answer later, but you missed the exact point of my question. I do not know that the user will delete specifically the X Location channel. Instead, I want to present a list of channels from all selected objects to the user, so that he will select, for example, "I want to delete the Z Location from all selected objects". However, I could not find a way to convert location[2] to "Z Location". $\endgroup$ – Ronan Paixão Sep 14 '20 at 22:03
  • $\begingroup$ I guess I couldn't get myself understood properly. I treated the two questions as one because I was hoping someone could provide a non-scripting (UI-only) answer that would accomplish what I needed without having to build my own script. But after our initial misunderstanding, your edited answer has everything I need and much more! Even though the answer to your reference question is what I'd consider "hardcoding", that classMap dict is much smaller than I expected and very much acceptable. In fact, this answer is quite informative and will help me a lot. Thank you! $\endgroup$ – Ronan Paixão Sep 16 '20 at 0:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.