# How do I create a custom node group for the compositor?

I have made a script that adds a panel, it has buttons that when pressed, nodes are added to the Compositor. I would like to add another button that then adds them to a group.

I have looked around the net and into the Info on Blender and I notice the bpy.ops.node.group_make() which will take the nodes that are selected and then insert them into a group.

I am pretty sure I need this for what I want but the trouble is, I can not find a way to implement that into my script. I also tried this:

tidy_group = bpy.data.node_groups.new('NewGroup', 'CompositorNodeTree')
tidy_group.name = 'Group Name'


It creates a node group in the (ShiftA > Groups) section. However, I have no idea how to properly use it. If someone could help point me how this would work I would greatly appreciate it.

• Hey thanks for sharing!.. I had to change a few things but I think that answer is exactly what I needed!.. I had to change the "Shader" part to compositor but yeah thanks so much!.. – Darkfall Sep 6 '19 at 14:01

## 1 Answer

Converted this script to generate a shader group by @sambler for the Compositor. The script creates a new node group called NewGroup containing three math nodes plugged together properly:

import bpy

# create a group
test_group = bpy.data.node_groups.new('NewGroup', 'CompositorNodeTree')

# create group inputs
group_inputs = test_group.nodes.new('NodeGroupInput')
group_inputs.location = (-350,0)
test_group.inputs.new('NodeSocketFloat','in_to_greater')
test_group.inputs.new('NodeSocketFloat','in_to_less')

# create group outputs
group_outputs = test_group.nodes.new('NodeGroupOutput')
group_outputs.location = (300,0)
test_group.outputs.new('NodeSocketFloat','out_result')

# create three math nodes in a group
node_add = test_group.nodes.new('CompositorNodeMath')
node_add.operation = 'ADD'
node_add.location = (100,0)

node_greater = test_group.nodes.new('CompositorNodeMath')
node_greater.operation = 'GREATER_THAN'
node_greater.label = 'greater'
node_greater.location = (-100,100)

node_less = test_group.nodes.new('CompositorNodeMath')
node_less.operation = 'LESS_THAN'
node_less.label = 'less'
node_less.location = (-100,-100)

# link nodes together
test_group.links.new(node_add.inputs[0], node_greater.outputs[0])
test_group.links.new(node_add.inputs[1], node_less.outputs[0])

# link inputs
test_group.links.new(group_inputs.outputs['in_to_greater'], node_greater.inputs[0])
test_group.links.new(group_inputs.outputs['in_to_less'], node_less.inputs[0])

#link output
test_group.links.new(node_add.outputs[0], group_outputs.inputs['out_result'])


Wrap this up into a function and allow to pass some arguments e.g. a string for the name. Even better, make it a function and add it to an execute() method of an Operator, that way you can use the Search Menu (F3) to add your group. In addition to that, you can display the Operator as a button on any panel like in the Properties Panel N of the Compositor:

import bpy

# Create compositor group
def create_comp_group(context, operator, group_name):
# Create a group
test_group = bpy.data.node_groups.new(group_name, 'CompositorNodeTree')

# Create group inputs
group_inputs = test_group.nodes.new('NodeGroupInput')
group_inputs.location = (-350,0)
test_group.inputs.new('NodeSocketFloat','in_to_greater')
test_group.inputs.new('NodeSocketFloat','in_to_less')

# Create group outputs
group_outputs = test_group.nodes.new('NodeGroupOutput')
group_outputs.location = (300,0)
test_group.outputs.new('NodeSocketFloat','out_result')

# Create three math nodes in a group
node_add = test_group.nodes.new('CompositorNodeMath')
node_add.operation = 'ADD'
node_add.location = (100,0)

node_greater = test_group.nodes.new('CompositorNodeMath')
node_greater.operation = 'GREATER_THAN'
node_greater.label = 'greater'
node_greater.location = (-100,100)

node_less = test_group.nodes.new('CompositorNodeMath')
node_less.operation = 'LESS_THAN'
node_less.label = 'less'
node_less.location = (-100,-100)

# Link nodes together
test_group.links.new(node_add.inputs[0], node_greater.outputs[0])
test_group.links.new(node_add.inputs[1], node_less.outputs[0])

# Link inputs
test_group.links.new(group_inputs.outputs['in_to_greater'], node_greater.inputs[0])
test_group.links.new(group_inputs.outputs['in_to_less'], node_less.inputs[0])

# link output
test_group.links.new(node_add.outputs[0], group_outputs.inputs['out_result'])

# return the group
return test_group

# Operator
class NODE_OT_compGroup(bpy.types.Operator):
"""Tooltip"""
bl_idname = "node.simple_operator"
bl_label = "Add Group (Operator)"

@classmethod
def poll(cls, context):
space = context.space_data
return space.type == 'NODE_EDITOR'

def execute(self, context):

# Create the group
custom_node_name = "my_node"
my_group = create_comp_group(self, context, custom_node_name)
comp_node = context.scene.node_tree.nodes.new('CompositorNodeGroup')
comp_node.node_tree = bpy.data.node_groups[my_group.name]
comp_node.location = 100,0

return {'FINISHED'}

# Panel
class NODE_PT_customPanel(bpy.types.Panel):
bl_idname = "NODE_PT_customPanel"
bl_space_type = 'NODE_EDITOR'
bl_label = "Custom Panel"
bl_region_type = "UI"
bl_category = "Custom Category"

@classmethod
def poll(self,context):
return context.object is not None

def draw(self, context):
layout = self.layout
layout.operator(NODE_OT_compGroup.bl_idname)
layout.separator()

# Register
def register():
bpy.utils.register_class(NODE_OT_compGroup)
bpy.utils.register_class(NODE_PT_customPanel)

def unregister():
bpy.utils.unregister_class(NODE_OT_compGroup)
bpy.utils.unregister_class(NODE_PT_customPanel)

if __name__ == "__main__":
register()


Further reading:

• thanks so much! I went to the link you shared and I figured I had to change that part but it took me ages to realize that.. I am glad you took the time to convert the script!!.. I will be sure to thank you in one of my videos ;) – Darkfall Sep 6 '19 at 14:04
• Cool, I added the button business. What videos? @Darkfall – brockmann Sep 6 '19 at 15:12
• Hey @brockmann Yeah i managed to do all that I just couldn't understand how to implement the whole making of a group but now I am all sorted so thanks!..I know I will have more questions in the future.. I make videos on youtube (darkfall), and when I upload my next video about the Addon I will mention I got some help from you and the Stack Exchange.. If you have a channel, blog or website you post to, I would be happy to point people that way.. – Darkfall Sep 6 '19 at 22:31
• Had some time yesterday and watched two of your "bpy videos". As commented already below one of them (which isn't public for whatever reason), you're doing several beginner mistakes like assigning the object in context using the wrong reference. Don't get me wrong, it's not that bad as kind of walkthrough. However, I don't think it's a good idea teaching beginners that way, programming is especially about detail and language specifics. Don't get me wrong but I think it's too early for you posting a video about bpy. Cheers @Darkfall – brockmann Mar 19 at 12:14
• @brockmann- Which video?. As for "assigning the object in context using the wrong reference", could you be more specific? In order to improve I must understand what you think is wrong?. And several mistakes? Could you again be more specific. There are hardly any videos on this and yeah I may get some things slightly wrong but all the examples work, and I had to stumble through snippets, forums and trial and error, so I know they videos are not perfect and they may not be helpful to you, but others have found them to be so, regardless if they are beginners or have been using python for a while. – Darkfall Mar 20 at 13:52