Results 1 to 10 of 10
  1. #1
    Member pullup's Avatar
    Join Date
    Dec 2012
    Location
    France
    Posts
    19

    Access only visible F-curve in dopesheet/graph editor through API

    Hi everyone.

    EDIT: see BATfinger answer on blender stack exchange

    How can I access F-curves points ONLY for visible Fcurve (when "show_only_selected" is on) in the graph editor ?
    A way to directly iterate on f-curves would be really nice (if not necessary) to apply some script on what the user see/isolate.

    Currently I'm checking in the context of the graph editor if we are looking only at the selection with
    Code:
    context.area.spaces[0].dopesheet.show_only_selected
    then iterating in all action if only selected is On or in the actions of selected objects in scene if it's Off.

    But even if you iterate over selected object's actions only, you still have the problem of unselected bones in selected armatures that aren't showing up in the graph editor and are still affected by your script without the user knowing (and maybe for animated scene properties too) !

    After searching a bit. I found that the great Jacques Luke (animation node creator ) had the same question back in 2015 (see here)
    I asked him if he found a solution since then but it's a negative and he isn't working on this anymore...

    Any Ideas ?
    Last edited by pullup; 16-Oct-17 at 04:21. Reason: Solved



  2. #2
    Member Secrop's Avatar
    Join Date
    Dec 2011
    Location
    Berlin
    Posts
    1,847
    I think the best would be to operate on the object's fcurves directly, instead of doing it through the editor.
    Fcurves are part of the objects, and you can access to everything through them.

    I.e. context.active_object.animation_data.actions.fcurv es



  3. #3
    Member pullup's Avatar
    Join Date
    Dec 2012
    Location
    France
    Posts
    19
    Originally Posted by Secrop View Post
    I think the best would be to operate on the object's fcurves directly, instead of doing it through the editor

    Hi, thank you for your answer Secrop. But that's actually what I'm doing already. I just check the 'show_only_selected' props in the graph editor to know if i have to filter and then take the actions from the objects directly.


    But the problem is (reformulation here ^^) : what you see in the graph editor is not in sync with what you will get by getting actions from objects.


    In the Graph editor, some fcurves might be hided and you can put some filter on (visibility, hided objects, etc). And I want my script to act only on the curve that are showing up for the user.

    Here is what I'm currently doing :
    I send a specific frame/value for the selected keyframe to snap on


    Code:
    def keyset_action_selection(frame, value):
        objs = bpy.context.selected_objects
        actions = []
        #todo : case of bone selection in armature if only selected is on
        for obj in objs:
            if obj.animation_data is not None and obj.animation_data.action is not None:                
                actions.append(obj.animation_data.action)
        if actions:
            print(9*'-', 'selection')
            set_keyframe_values(actions,frame, value)

    That call the 'set_keyframe_values' function


    Code:
    def set_keyframe_values(actions,frame, value):
        '''Get a list of actions with a frame and value to set selected fcurve points'''
        print("actions", actions)#Dbg
        ct = 0
        for action in actions:
            for fcurve in action.fcurves :
                if not fcurve.hide:#avoid hided curve
                    for p in fcurve.keyframe_points :
                        if p.select_control_point:
                            ct += 1
                            print("key {:.2f} {:.2f}".format(p.co[0], p.co[1]) )
                            if frame != None:# 0 must pass
                                p.co.x = frame
                            if value != None:
                                p.co.y = value
    
    
        print(ct, 'points')
        return ct

    Here the selected keyframe on unselected objects aren't affected by the script (what I want).
    But if an armature is selected and some of it's bones are unselected, there are hided in editor but still affected by the script (not cool !)...


    Of course I can go on with this solution and upgrade with a lot of condition to finally affect only visible fcurve. But what I'm asking for here is a completely different approach...
    It would be so much simpler (painless) to act directly on filtered curves...
    Am I being more understandable ?



  4. #4
    Member Secrop's Avatar
    Join Date
    Dec 2011
    Location
    Berlin
    Posts
    1,847
    Unfortunately, I don't know any other workaround..

    For armatures, you need to loop through the bones that are selected:
    Code:
    SelectedBones = [bone for bone in D.objects['Armature'].data.bones if bone.select==True]
    Last edited by Secrop; 11-Oct-17 at 10:19.



  5. #5
    Member batFINGER's Avatar
    Join Date
    Jun 2007
    Location
    Lochiel NSW Australia
    Posts
    1,857
    Secrop, Would need to look at pose bones

    Code:
    selected_bones = [pb for pb in obj.pose.bones if pb.select]
    
    # or 
    
    selected_bones = context.selected_pose_bones
    as for fcurves, what about

    Code:
    context.selected_editable_fcurves
    when run in graph eidtor context?
    Last edited by batFINGER; 12-Oct-17 at 13:07.



  6. #6
    Member Secrop's Avatar
    Join Date
    Dec 2011
    Location
    Berlin
    Posts
    1,847
    Cool... I never wrote scripts for the graph editor, so I'm not familiar with its context... But if that works, great!!



  7. #7
    Member pullup's Avatar
    Join Date
    Dec 2012
    Location
    France
    Posts
    19
    Originally Posted by batFINGER View Post
    Code:
    context.selected_editable_fcurves
    when run in graph eidtor context?
    This look promising but does not work for me, throw an error :
    Code:
    AttributeError: 'Context' object has no attribute 'selected_editable_fcurves'

    With a bunch of functions I made the filter I needed (except for the 'ghost' - show_hidden filter).

    But I don't want to mark the thread as Solved, because even if it's working, it's certainly not THE best solution to get only visible Fcurve (and still incomplete).

    Here for those interested, search for 'Get visible Fcurves' with spacebar in graph editor to print detected fcurves in console (then do whatever you wnt with them in the class):

    Code:
    # coding: utf-8
    import bpy, re
    
    
    ## global compiled regex (for fast use)
    rebone = re.compile(r'(?<=\[\").*?(?=\"\])')
    # get 'sauce' in 'pose.bones["sauce"]["props"]' or pose.bones["sauce"].location
    
    
    def get_fcurves_from_action(actions):
        '''Get a list of actions and return visible Fcurves'''
        # print("actions:", actions)#Dbg
        global rebone
        fcu_list = []
        for obj, action in actions.items():
            for fcu in action.fcurves :
                if not fcu.hide:#avoid hided curve
                    #print("fcurve data_path:", fcu.data_path)#Dbg
                    if fcu.data_path.startswith('pose.bones['):#Case of armature : if either a pose bone or a property attached to a bone
                        bname = rebone.search(fcu.data_path).group()
                        if obj.data.bones[bname].select:#via posebone: pose.bones[bname].bone.select:
                            fcu_list.append(fcu)
                    else:#else dont have the problem of bones filtering so take it directly
                        fcu_list.append(fcu)
    
    
        return fcu_list
    
    
    
    
    def get_fcurves_selection():
        objs = bpy.context.selected_objects
        actions = {}
        for obj in objs:
            if obj.animation_data is not None and obj.animation_data.action is not None:
                actions[obj] = obj.animation_data.action
        if actions:
            print(9*'-', 'selection')
            return get_fcurves_from_action(actions)
    
    
    
    
    
    
    def get_all_fcurves():
        '''get fcurves (expect hided) from all actions'''
        #todo : check if object hided are showing up with the show_hidden (ghost) property of graph editor...
        print(9*'-', "all")
        fcu_list = []
        for action in bpy.data.actions:
            for fcu in action.fcurves :
                if not fcu.hide:#avoid hided curve
                    fcu_list.append(fcu)
    
    
        return fcu_list
    
    
    
    
    class getVisibleFcurves(bpy.types.Operator):
        bl_idname = "animops.get_visible_fcurves"
        bl_label = "Get visible Fcurves"
        bl_description = "print all visible fcurves"
        bl_options = {"REGISTER"}
    
    
        @classmethod
        def poll(cls, context):
            return context.area.type == 'GRAPH_EDITOR'
    
    
        def execute(self, context):
            #check if it's selection only from context
            selection = context.area.spaces[0].dopesheet.show_only_selected
            
            #get fcurves with designated function
            if selection:
                fcurves = get_fcurves_selection()
            else:
                fcurves = get_all_fcurves()
            
            print("fcurves number:", len(fcurves))
            # print("fcurves", fcurves)
            
            #and now do whaterver you want with the fcurve
            return {"FINISHED"}
    
    
    
    
    def register():
        bpy.utils.register_module(__name__)
    
    
    def unregister():
        bpy.utils.unregister_module(__name__)
    
    
    if __name__ == "__main__":
        register()



  8. #8
    Member Secrop's Avatar
    Join Date
    Dec 2011
    Location
    Berlin
    Posts
    1,847
    ...and what would be THE best solution?
    Your question was to find a way to get the visible fcurves, and that's what you get with this last script...
    Unless there's more than you have told us...

    btw, the error is just a matter (as you already noticed and corrected) of defining the poll function.



  9. #9
    Member batFINGER's Avatar
    Join Date
    Jun 2007
    Location
    Lochiel NSW Australia
    Posts
    1,857
    context.selected_editable_fcurves is a new feature in 2.79.1 .. build nightly from GIT, so didn't realize it was so new. https://docs.blender.org/api/master/...itable_fcurves

    Used here https://blender.stackexchange.com/a/92147/15543 to list all visible fcurves.

    You will need to upgrade to 2.79.1 to use.



  10. #10
    Member pullup's Avatar
    Join Date
    Dec 2012
    Location
    France
    Posts
    19
    Originally Posted by batFINGER View Post
    context.selected_editable_fcurves is a new feature in 2.79.1 .. build nightly from GIT, so didn't realize it was so new. https://docs.blender.org/api/master/...itable_fcurves

    Used here https://blender.stackexchange.com/a/92147/15543 to list all visible fcurves.

    You will need to upgrade to 2.79.1 to use.
    Ok now it's Solved



Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •