# Distribute nodes of different sizes without overlaps in Node Editor (Python)

I'm trying to write a function for my script that will distribute the standard 5 nodes along the x axis, without overlapping.

My current setup looks like this:

for index, node in enumerate((texCoord, mapping, texture, diffuse, output)):
node.location.x = 200.0 * index


This works well, and will separate the nodes equally at 200 px apart, which is fine normally but the mapping node is a little over-sized, and it covers my image texture.

Like so:

edit: I have tried an if statement, that looked like:

for index, node in enumerate((texCoord, mapping, texture, diffuse, output)):
if node == mapping:
node.location.x = 400.0 * index
else:
node.location.x = 200.0 * index


but that does this:

I also tried adjusting the values, like so:

for index, node in enumerate((texCoord, mapping, texture, diffuse, output)):
if node == mapping:
node.location.x = 100.0 * index
else:
node.location.x = 250.0 * index


But that ends up not moving the texture coordinate enough:

I also tried using a while loop, but that crashes blender.

I feel like there is probably a better way to adjust for this size, but I can't think of anything.

Because nodes are not necessarily in the order we want in the node tree, I made a list of the nodes in their proper order (listing them from left to right). I then loop through that list and get the nodes by name in the node tree, moving them accordingly.

import bpy

nodes = bpy.data.materials['Material'].node_tree.nodes
list = ['Texture Coordinate', 'Mapping', 'Checker Texture','Diffuse BSDF', 'Material Output']
loc = 0
for i in list:
nodes[i].location.x = loc
loc += nodes[i].width + 50
nodes[i].location.y = 0


The script is rather simple. I loop through my list of node names; then simply set the node's x location to the loc variable.
The next line loc += nodes[i].width + 50 is adding the width of the node, plus 50 (the margin around the nodes) to the already tallied widths.
Then next time around the next node will get moved over that amount.

The only important part is that you add the width of the node to the loc variable after the node has been moved.

• Wow! I had no idea that the area around the node was a measured attribute. That is awesome. – Rug Aug 17 '17 at 23:24
• When you access the nodes using node_tree.nodes, it returns the name of each node inside the material as a string? If not, how is the connection between the string name and the node itself established? – Rug Aug 18 '17 at 0:18
• Yep you are right I am storing the nodes' name in my list. node_tree.nodes['Mapping'] is one way to get to the mapping node. However if it was the second mapping node I added to the tree, its name by default would be "Mapping.001" – David Aug 18 '17 at 0:41
• Thats really neat. Lets say we do need 2 mapping nodes, just for the sake of the argument. How might you change that to be more flexible? Or would you just go and hardcode the name "Mapping.001" instead of "Mapping" into a secondary list? – Rug Aug 18 '17 at 1:08
• @Rug well kind of. It would be easy to loop through the nodes and get all "TEX_IMAGE" (node[].type) but then what? Ask yourself: how do you want to sort them? alphabetically wont help any, so you will need some metric, maybe the node connections to get something useful to sort on. – David Aug 18 '17 at 13:14

In order to space it out far enough, I have increased the pixel difference for both the regular index as well as the mapping node. This is my code now:

for index, node in enumerate((texCoord, mapping, texture, diffuse, output)):
if node == mapping:
node.location.x = 200.0 * index
else:
node.location.x = 300.0 * index


I still feel like there must be a more elegant solution, but I will leave this answer for those in the meantime.