Setting in-built curve properties via Scripting

It is probably (definitely) easier to do this via the Graph Editor but please bear in mind that I am starting out learning Python in Blender so it could end up being just a valuable learning experience rather than a better way of doing things.

I am trying to write a script that will create a cube and add a built in modifier - the default in the Graph Editor is a sine curve. The code below does that. However, I would like to change the Amplitude, Phase Multiplier, Phase Offset and Value Offset. And maybe even the curve type to something else - it would be good to know how.

Standard approach so far has been to copy code from the Info window and try in the Console. When I alter Amplitude in the Graph Editor, for example, the code generated is:

bpy.data.actions[ā€œCubeAction.008ā€].(null) = 10

This throws up a syntax error because .(null) is invalid when used in Console. Looking at the available options (by pressing TAB after ā€œ].ā€ hasnā€™t helped.

Incidentally, it doesnā€™t matter what property I change in the Graph Editor, the .(null) thing pops up for all of them in the Info window which is very odd.

Iā€™ve tried using several options. Iā€™ve tried putting that line after the ui_type change in the Text Editor just incase it was down to a context error but that did not work.

After two hours and several cups of tea Iā€™ve come to you chaps for help :slight_smile:

#090522
#Creates cube, adds keyframe, changes ui.type to add built in sine curve in graph editor
import bpy

bpy.ops.mesh.primitive_cube_add(size=2, enter_editmode=False, align=ā€˜WORLDā€™, location=(0, 0, 0), scale=(1, 1, 1))

mycube = bpy.data.objects[0]

mycube.keyframe_insert(data_path = ā€œlocationā€, frame = 1)

bpy.context.area.ui_type = ā€˜FCURVESā€™
bpy.ops.graph.fmodifier_add(type=ā€˜FNGENERATORā€™, only_active=True)
bpy.context.area.ui_type = ā€˜TEXT_EDITORā€™

PS:
I have been messing with the following line from sozap who helped with an answer to an earlier question. But Iā€™m not making progress not matter how I modify it
bpy.context.selected_objects[0].animation_data.action.fcurves[0].data_path


I tried adding (via scripting) a vertical sinusoidal motion to each object with a phase offset so they kind of ripple around the edge of a circle. The idea being that this is scalable and easily modified in terms of just tiny alterations in the code (eg number of objects). Nearly had it: except that the interpolation type makes the sin wave really funky (see image). So: I need help!!! :slight_smile: I cannot code the alteration of the interpolation type and I have made no progress with the question above. I know it is two questions - the answer to just one would be COOOOOOL.

Not an excessive amount of commenting in this but it should point you in the right direction for your original post.

import bpy


# just for flexibility
def add_item(item_type="primitive_cube_add"):
    primitives = ["primitive_plane_add",
        "primitive_cube_add",
        "primitive_circle_add",
        "primitive_uv_sphere_add",
        "primitive_ico_sphere_add",
        "primitive_cylinder_add",
        "primitive_cone_add",
        "primitive_torus_add",
        "primitive_monkey_add",
        ]
    if item_type not in primitives:
        return {'CANCELLED'}
    eval(f"bpy.ops.mesh.{item_type}()")
    return bpy.context.object

# add a primitive and store a reference in my_obj
my_obj = add_item("primitive_uv_sphere_add")

# insert a keyframe
my_obj.keyframe_insert(data_path = "location", frame = 1)

# convenience variable
fcs = my_obj.animation_data.action.fcurves

x_axis = fcs[0]
y_axis = fcs[1]
z_axis = fcs[2]

# add a modifier to x axis
my_mod1 = x_axis.modifiers.new(type='FNGENERATOR')

# modify the amplitude of the function
my_mod1.amplitude = 5
1 Like

GENIUS!!! Thank you so much. Now I can do exactly what I want! Although I am going to take some time to properly understand rather than just copy - but itā€™s perfect.

I have just one question - how did you learn or find out how to do this?

1st recommendation:
Get only visible details and properties of a node in python - Coding / Python Support - Blender Artists Community

Enabling feedback to show what the python commands are for most items (in your specific example this got you to the:

bpy.data.actions[ā€œCubeAction.008ā€].(null) point of the code.

2nd recommendation:
Just spending time using commands in the console.
since you know your keyframe is an fcurve try to find it in the object data block

3rd recommendation:
Continue to search and post on forums. Given Blendersā€™s increasing user base; someone somewhere is bound to have either stumbled there way through it previously, or just be too stubborn a person to not know themselves and fumble through an answer.

2 Likes

I know this is a really old thread, but Iā€™m a bit confused by this line of code. I thought eval() just returned a string in python. What is it doing here if the resulting string isnā€™t assigned to anything?

if you hit ā€œeval(ā€ in the console and the TAB you will get:

it just executes the command which you generated by the string.

more info: https://www.programiz.com/python-programming/methods/built-in/eval

hope that helps

1 Like

Thanks for getting back to me so quickly! So Iā€™m guessing the reason you chose to execute the code this way is because you can use the flexibility of f-strings to format your code?

i guess thatā€™s why he did it that way. :wink:

1 Like