after various failed attempts to make keyframes work to my liking in my first blender-script work I request your help 🥲

So I am working on a Dataviz:

  1. I load Data into Blender and create an object.
  2. Then I transform the object according to the data.
  3. Now I have 4 different years, Year1 - Year4. I want to show each transformation, for each Year with keyframes (one keyframe shows one year location, scale transformation)
  4. and all of the keyframes of the 150 country-Objects should start and end at the same time.

...But the mechanics of the for-loop are laughing at my face - I got everything working except for the keyframes which drives me mad 🤪 so If I use an offset the transformations for each object are working perfectly, but they don't start at the same time - if I try and use iteration, I have neat keyframes, but no animation (I will only show Year4). How do I get out of this Mess? 😓

See the code for the Iteration-version on github: https://github.com/SaraHeitz/blenderpython

Version with offset: https://www.youtube.com/watch?v=QTyYj4ZKNBA enter image description here enter image description here

Version with iteration: enter image description here enter image description here

So in short I would love for this Dataviz to animate the country for each year, and set a keyframe for the according values, like the youtube animation, but start and end at the same time for every object: https://www.youtube.com/watch?v=QTyYj4ZKNBA

  • 1
    $\begingroup$ can u paste a working example with a small text file you're loading? here read_list it's not defined. $\endgroup$ Jul 25, 2022 at 9:06
  • $\begingroup$ Hello Harry, I made a small github compilation -> github.com/SaraHeitz/blenderpython $\endgroup$
    – sehetz
    Jul 25, 2022 at 9:36
  • $\begingroup$ i'm not sure i understand the problem. can you draw a picture of the result you want? $\endgroup$ Jul 25, 2022 at 9:54
  • $\begingroup$ I would like for this Dataviz to animate the countries as bars for each year, and set a keyframe (at eg. 5, 10, 20, 25) for the years [1850,1900,1950,2000] using the according x,y,z values, similar to this youtube animation, but start and end at the same time for every object: youtube.com/watch?v=QTyYj4ZKNBA So far I could only animate those values with offset, the problem is, that the next Object of the loop won't start at 0, but continue right after the first Object (if it ends at 25, it will start at 30) I also updated the initial Question with screenshots $\endgroup$
    – sehetz
    Jul 25, 2022 at 10:28
  • $\begingroup$ in the end, I want it to work for 150 Countries and 100+ Years, that's why I am so eager about the keyframes (so I don't have to change them manually) Thanks for your Investigation already! $\endgroup$
    – sehetz
    Jul 25, 2022 at 10:31

1 Answer 1


You're using the Blender API okay, your problem is with Python logic.

Let's first group the rows of your .csv into a dict by year, so later we can lookup all rows in a given year.

import csv
import bpy

scn = bpy.context.scene
scn.frame_start = 1

with open ('test.csv') as f:
    rows = list(csv.reader(f))

rows_by_year = {}
for row in rows:
    year = int(row[1])
    rows_by_year.setdefault(year, []).append(row)

Now let's sort all the years we just found. (This isn't necessary for the file you gave but it might be if the rows are in a different order.)

years = list(rows_by_year.keys())

Now we can iterate through and create everything

object_map = {}
for iteration, year in enumerate(years):
    ita = iteration * 10
    frame = scn.frame_start + ita
    scn.frame_end = frame
    for row in rows_by_year[year]:
        name = row[0]
        x = float(row[2])
        y = float(row[3])
        z = float(row[4])

        if name not in object_map:
                location=(1, 1, 1),
                scale=(1, 1, 1),
            object_map[name] = bpy.context.object
            object_map[name].name = name

        cylinder = object_map[name]
        cylinder.location = (x, y, z)
        cylinder.scale = (0.5, 0.5, z)
        cylinder.keyframe_insert(data_path="location", frame=frame)
        cylinder.keyframe_insert(data_path="scale", frame=frame)

We iterate first over the years, then process all rows for that year using rows_by_year. The frame is calculated just once for each year, then all rows for that year will use that frame. Then for each row in that year, we create the cyclinder (if it doesn't exist yet), and set its value and keyframe the same way you were doing.

  • 1
    $\begingroup$ amazing - thank you so much! 👏👏👏 - especially for your analytical and detailed review. It helps me as a beginner a lot to gain a better understanding of Python. ((and the data I'm working with)) Overall the code with your review and alterations works great and I have been able to create and animate the objects for all the 220 years and 150 Countries ☺️ $\endgroup$
    – sehetz
    Jul 25, 2022 at 12:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .