# Query grease pencil strokes from python

I want to "query" grease pencil data from my python script. In some sense, I need to get the points of the sketch and their coordinates to do some curve fitting. Is there a way to do this via python? Also, is there a higher level API that can give me more information about the strokes drawn?

Grease Pencil data is stored globally in bpy.data.grease_pencil. Scenes and objects can reference a Grease Pencil datablock.

Up to Blender 2.72, the active object was used. With no active object (right after object deletion), the active scene was used instead. From 2.73 on, the active scene is chosen all the time. There's legacy support for the object level however. For future use, you should assume the GPencil data to be associated with the active scene:

gp = bpy.context.scene.grease_pencil


The GPencil data is hierarchically organized in layers, frames, strokes and points:

# Get 1st point of 1st stroke on active frame and layer
point = gp.layers.active.active_frame.strokes[0].points[0]

point.co       # 3D Vector location
point.pressure # tablet pressure (1.0 on mouse input)
point.select   # selection state (bool)

layer = gp.layers[0] # first layer (by index)
layer = gp.layers["GP_Layer"] # by name
layer.color # color (fill_color for fill color)
layer.alpha # opacity (fill_alpha for fill opacity)

frame = layer.frames[1] # 2nd frame
frame.frame_number # frame number of that frame object

stroke = frame.strokes[-1] # last stroke
stroke.draw_mode # e.g. '3DSPACE'


You can create new GPencil data from scratch too:

gp = bpy.data.grease_pencil.new("My GPencil")
scene = bpy.context.scene
scene.grease_pencil = gp
scene.frame_set(5) # ensure we'll see the stroke (set to frame 5 below)

layer = gp.layers.new("Name for new layer", set_active=True)
layer.info # note: it's not layer.name!
layer.color = (1, 0.3, 0)

frame = layer.frames.new(5) # frame number 5
stroke = frame.strokes.new()
stroke.draw_mode = '3DSPACE' # either of ('SCREEN', '3DSPACE', '2DSPACE', '2DIMAGE')

#stroke.points[0].co = (..., ..., ...) # set 1st point's location
stroke.points.foreach_set("co", (0,0,0,0,0,4,0,6,4,8,6,4)) # set all at once efficiently

• when I create grease pencil strokes this way, they do not show up until I draw another stroke manually in the 3d view. Is there a datablock I need to update? – patmo141 Nov 19 '17 at 22:46
• I'm not sure, it could actually be a bug. I extended the script to call all possible update methods, and yet you still have to draw a stroke manually to make it visible: hastebin.com/ulisoyivas.py - The only thing that I see changing by that user stroke is, that it actually sets the active frame. layer.active_frame = frame set by the script is completely ignored and the value of active_frame remains None without apparent reason. – CoDEmanX Nov 20 '17 at 1:02
• Im glad the behavior is reproducible. – patmo141 Nov 20 '17 at 11:38
• Retried with Blender 2.79 (5bd8ac9) and it works without problems, even without all the update calls, frame.frame_number = 1 and even layer.active_frame = frame. The stroke appears immediately in the viewport. Which version did you try? – CoDEmanX Nov 20 '17 at 18:42
• 2.78b and c....forgot about 2.79 :) will try asap when I get home – patmo141 Nov 20 '17 at 22:52

Eventhough this one is already answered with Python Script solution, I just wanted to add this Sverchok Node Tree solution, just to help beginner programmer in the future, just in case they are asking the same question and would like to see visually as nodes.

You can setup something like below to observe data blocks and pass on the values for other things.

In case of Grease Pencil Strokes, we can get the Coordinate and Pressure pretty easily by chaining nodes and the result if we generate Curves Output is like this:

And if we are instancing boxes along the Grease Pencil while using the Stroke Pressure and Coordinates, we get this: