top of page

AUTO DOT

  • jnietomonco
  • Feb 9, 2023
  • 1 min read

With this code, you can automatically create dots at a perfectly straight angle between the two nodes you have selected. You can align it in X to the top or the bottom node, depending on what you want. It doesn't matter the order of your selection. For X aligned to the bottom node of my selection I use ctrl+., and for X aligned to the top node I use shift+..


ree

This code is particularly useful when you are connecting nodes that are far away in the Node Graph.

Expand Auto Dot

import nuke
        
def lowDot():
    def XYCheck():
        topNode = None
        sideNode = None
        # Check if Y and X positions are the same
        for i in nuke.selectedNodes():
            if topNode is None:
                topNodeName = i['name'].getValue()
                topNode = i['ypos'].getValue() + (i.screenHeight()/2)
            elif i['ypos'].getValue() + (i.screenHeight()/2) < topNode:
                topNodeName = i['name'].getValue()
                topNode = i['ypos'].getValue() + (i.screenHeight()/2)
            elif i['ypos'].getValue() + (i.screenHeight()/2) == topNode:
                nuke.message('Both nodes have the same Y position. No dot created.')
                return
    
            if sideNode is None:
                sideNode = i['xpos'].getValue() + (i.screenWidth()/2)
            elif i['xpos'].getValue() + (i.screenWidth()/2) < sideNode:
                sideNode = i['xpos'].getValue() + (i.screenWidth()/2)
            elif i['xpos'].getValue() + (i.screenWidth()/2) == sideNode:
                nuke.message('Both nodes have the same X position. No dot created.')
                return

        for i in nuke.selectedNodes():
            if i.maxInputs() == 0 and i['name'].getValue() != topNodeName:
                nuke.message('Lowest selected node does not have an input to connect. No dot created.')
                return   
        createLowDot()
    
    def createLowDot():
        topNode = None
        # Check highest Y position
        for i in nuke.selectedNodes():
            if topNode is None:
                topNode = i['ypos'].getValue()
            elif i['ypos'].getValue() < topNode:
                topNode = i['ypos'].getValue()
    
        sel = nuke.selectedNodes()
    
        for i in sel:
            # If it is the lowest in Y
            if not i['ypos'].getValue() == topNode:
                # We will connect the dot here, so we save its
                # name and Y position for later.
                dotOutput = i['name'].getValue()
                sideNodePos = i['ypos'].getValue()
    
            i['selected'].setValue(False)
            # If the node is the highest in Y
            if i['ypos'].getValue() == topNode:
                # Check if it is connected to the lowest one
                existingConnections = []
                topNodeXPos = i['xpos'].getValue()
                i['selected'].setValue(True)
                # Save the name of the node for later
                dotInput = i['name'].getValue()
                for conn in nuke.selectedNode().dependent():
                    connName = conn['name'].getValue()
                    existingConnections.append(connName)
                i['selected'].setValue(False)
    
        # We store some sizes and positions that we will use later to
        # move the dot to an approximate position.
        dotSize = nuke.toNode('preferences').knob('dot_node_scale').value()
        dotCenter = (12*dotSize)/2 # 12 is width and height by default
        dotOutWidthCenter = nuke.toNode(str(dotOutput)).screenWidth() / 2
        topNodeXPos = topNodeXPos + (dotOutWidthCenter - dotCenter)
        dotOutHeightCenter = nuke.toNode(str(dotOutput)).screenHeight() / 2
        dotInWidthCenter = nuke.toNode(str(dotInput)).screenWidth() / 2
        if not nuke.toNode(str(dotOutput)).Class() == 'Dot':
            sideNodePos = sideNodePos + (dotOutHeightCenter - dotCenter)
        else:
            topNodeXPos = topNodeXPos + (dotInWidthCenter - dotCenter)
        if nuke.toNode(str(dotInput)).Class() == 'Dot':
            topNodeXPos = topNodeXPos - (dotOutWidthCenter - dotCenter)
    
        # If we found both high and low nodes are connected
        if existingConnections != []:
            nuke.toNode(dotOutput)['selected'].setValue(True)
    
            # We create an empty list and populate it with the lowest node
            # dependencies names (nodes connected to its inputs).
            dependenciesList = []
            for node in nuke.selectedNode().dependencies():
                depName = node.name()
                dependenciesList.append(depName)
        
            # We check the number of the highest input connected and use
            # it to populate an empty list with 1 (if the input in that
            # position is connected) and 0 (if it is not connected).
            # For example, if a Merge has A connected, but not B or mask,
            # the list would be [0,1].
            maxInputConnected = nuke.selectedNode().inputs()
            connectedList = []
            for i in range(maxInputConnected):
                connResult = 1 if nuke.selectedNode().input(i) else 0
                connectedList.append(connResult)
            # We also save the number of dependencies found
            depNumber = len(connectedList)
    
            # Now we have to check what input is connected to the
            # highest node. To do that we will create two different
            # counters: one for the number of dependencies and
            # another one for the number of connections. A node can
            # have two dependencies and three connections, example:
            # a Merge with B and Mask connected, but not A, will
            # have two dependencies (or one if B and Mask are
            # connected to the same node) and three connections (A
            # counts as a connection even if it is not connected).
            depCounter = 0
            connCounter = 0
            while connCounter <= (depNumber-1):
                # Using connectedList we created before, we'll add
                # the string 'Nope' as an element to later match
                # the node name to the correct input number.
                if connectedList[connCounter] == 1:
                    depCounter = depCounter + 1
                    connCounter = connCounter + 1
                elif connectedList[depCounter] == 0:
                    dependenciesList.insert(depCounter, 'Nope')
                    connCounter = connCounter + 1
    
            # Now both dependenciesList and connectedList have the
            # same number of elements, so we just need to find the
            # position of the highest node in dependenciesList to know
            # to what input of the lowest node it's connected to.
            try:
                inputNumber = dependenciesList.index(dotInput)
            except ValueError:
                maxInputsNumber = nuke.toNode(dotOutput).maxInputs()
                if depNumber == maxInputsNumber:
                    try:
                        inputNumber = connectedList.index(0)
                    except ValueError:
                        inputNumber = 0
                else:
                    # Find the first position with a 0 in connectedList, and that
                    # would be the first available input to connect to the dot.
                    try:
                        inputNumber = connectedList.index(0)
                    except ValueError:
                        if maxInputsNumber > depNumber+1:
                            inputNumber = depNumber
                        else:
                            inputNumber = 0
    
            nuke.toNode(dotOutput)['selected'].setValue(False)
    
            # We create our dot on the positions we calculated and
            # select it to connect the input we checked before.
            nuke.nodes.Dot(xpos=topNodeXPos, ypos=sideNodePos, selected=1).setInput(0, nuke.toNode(dotInput)) #for some reason this step takes longer than expected
            nuke.toNode(dotOutput).setInput(inputNumber, nuke.selectedNode())

            # Now we will check if other nodes were connected to the
            # dot input,because those will be connected to the new dot
            # for esthetic purposes. First we look for all the nodes
            # sharing the same center as our new dot.
            sameCenterList = []
            for i in nuke.allNodes():
                # We make sure to remove the new dot and its input from
                # these next steps.
                if not i['selected'].getValue() == True and i['name'].getValue() != dotInput:
                    nodeName = i['name'].getValue()
                    nodeCenter =  i['xpos'].getValue() + nuke.toNode(nodeName).screenWidth() / 2
                    if nodeCenter == topNodeXPos + dotCenter:
                        sameCenterList.append(nodeName)
            # Now we have a list on nodes sharing the same X position.
            
            # Using our new list, we are going to check if those nodes are
            # also connected to the dot input.
            depList = []
            for node in sameCenterList:
                for i in nuke.toNode(node).dependencies():
                    nodeName = i.name()
                    if nodeName == dotInput:
                        depList.append(node)
            # We have removed all the nodes sharing the X position that were
            # not connected to the dot input.

            for i in depList:
                # Following the same method we did before, we fill a list
                # with the names of all the dependencies of the nodes sharing
                # X position with the new dot and also conected to its input.
                dependenciesList = []
                for node in nuke.toNode(i).dependencies():
                    depName = node.name()
                    dependenciesList.append(depName)
                # Another list with 1 (if the input is connected) and 0
                # (if it is not connected). Ex: if a Merge has A connected, 
                # but not B or mask, the list would be [0,1].
                maxInputConnected = nuke.toNode(i).inputs()
                connectedList = []
                for x in range(maxInputConnected):
                    connResult = 1 if nuke.toNode(i).input(x) else 0
                    connectedList.append(connResult)
                # We also save the number of dependencies found
                depNumber = len(connectedList)
                # Now we have to check what input is connected to the
                # dot input. To do that we will create two different
                # counters: one for the number of dependencies and
                # another one for the number of connections
                depCounter = 0
                connCounter = 0
                while connCounter <= (depNumber-1):
                    # Using connectedList we created before, we'll add
                    # the string 'Nope' as an element to later match
                    # the node name to the correct input number.
                    if connectedList[connCounter] == 1:
                        depCounter = depCounter + 1
                        connCounter = connCounter + 1
                    elif connectedList[depCounter] == 0:
                        dependenciesList.insert(depCounter, 'Nope')
                        connCounter = connCounter + 1

                # Now both dependenciesList and connectedList have the
                # same number of elements, so we just need to find the
                # position of the highest node in dependenciesList to know
                # to what input of the lowest node it's connected to.
                try:
                    inputNumber = dependenciesList.index(dotInput)
                except ValueError:
                    maxInputsNumber = nuke.toNode(i).maxInputs()
                    if depNumber == maxInputsNumber:
                        inputNumber = connectedList.index(0)
                    elif depNumber == maxInputsNumber-1:
                        inputNumber = depNumber
                    else:
                        # Find the first position with a 0 in connectedList, and that
                        # would be the first available input to connect to the dot.
                        try:
                            inputNumber = connectedList.index(0)
                        except ValueError:
                            if maxInputsNumber > depNumber+1:
                                inputNumber = depNumber
                            else:
                                inputNumber = 0                
                nuke.toNode(i).setInput(inputNumber, nuke.selectedNode())

            for i in nuke.allNodes():
                i['selected'].setValue(False)
    
        # If nodes are not connected, we will find what is the first input
        # of the lowest node that is not connected.
        else:
            maxInputConnected = nuke.toNode(dotOutput).inputs()
            connectedList = []
            for i in range(maxInputConnected):
                connResult = 1 if nuke.toNode(dotOutput).input(i) else 0
                connectedList.append(connResult)
            # We also save the number of dependencies found to check if it
            # is the max allowed.
            depNumber = len(connectedList)
            maxInputsNumber = nuke.toNode(dotOutput).maxInputs()
    
            nuke.toNode(str(dotInput))['selected'].setValue(True)
        
            # We create our dot on the positions we calculated and
            # select it to connect the input we checked before.
            nuke.nodes.Dot(xpos=topNodeXPos, ypos=sideNodePos, selected=1).setInput(0, nuke.toNode(dotInput)) #for some reason this step takes longer than expected
    
            if depNumber == maxInputsNumber:
                try:
                    firstFreeInput = connectedList.index(0)
                    nuke.toNode(dotOutput).setInput(firstFreeInput, nuke.selectedNode())
                except ValueError:
                    nuke.toNode(dotOutput).setInput(0, nuke.selectedNode())
            elif depNumber == maxInputsNumber-1:
                try:
                    firstFreeInput = connectedList.index(0)
                    nuke.toNode(dotOutput).setInput(firstFreeInput, nuke.selectedNode())
                except ValueError:
                    nuke.toNode(dotOutput).setInput(depNumber, nuke.selectedNode())
            else:
                # Find the first position with a 0 in connectedList, and that
                # would be the first available input to connect to the dot.
                try:
                    firstFreeInput = connectedList.index(0)
                    nuke.toNode(dotOutput).setInput(firstFreeInput, nuke.selectedNode())
                except ValueError:
                    if maxInputsNumber > depNumber+1:
                        nuke.toNode(dotOutput).setInput(depNumber, nuke.selectedNode())
                    else:
                        nuke.toNode(dotOutput).setInput(0, nuke.selectedNode())

            for i in nuke.allNodes():
                i['selected'].setValue(False)
    
    selNodesList = []
    for i in nuke.selectedNodes():
        selNodesNames = i['name'].getValue()
        selNodesList.append(selNodesNames)
    if len(selNodesList) != 2:
        nuke.message('Please, select two nodes to run this action.')
    else:
        XYCheck()


def highDot():
    def XYCheck():
        topNode = None
        sideNode = None
        # Check if Y and X positions are the same
        for i in nuke.selectedNodes():
            if topNode is None:
                topNodeName = i['name'].getValue()
                topNode = i['ypos'].getValue() + (i.screenHeight()/2)
            elif i['ypos'].getValue() + (i.screenHeight()/2) < topNode:
                topNodeName = i['name'].getValue()
                topNode = i['ypos'].getValue() + (i.screenHeight()/2)
            elif i['ypos'].getValue() + (i.screenHeight()/2) == topNode:
                nuke.message('Both nodes have the same Y position. No dot created.')
                return
    
            if sideNode is None:
                sideNode = i['xpos'].getValue() + (i.screenWidth()/2)
            elif i['xpos'].getValue() + (i.screenWidth()/2) < sideNode:
                sideNode = i['xpos'].getValue() + (i.screenWidth()/2)
            elif i['xpos'].getValue() + (i.screenWidth()/2) == sideNode:
                nuke.message('Both nodes have the same X position. No dot created.')
                return

        for i in nuke.selectedNodes():
            if i.maxInputs() == 0 and i['name'].getValue() != topNodeName:
                nuke.message('Lowest selected node does not have an input to connect. No dot created.')
                return 
        createHighDot()
    
    def createHighDot():
        topNode = None
        # Check highest Y position
        for i in nuke.selectedNodes():
            if topNode is None:
                topNode = i['ypos'].getValue()
            elif i['ypos'].getValue() < topNode:
                topNode = i['ypos'].getValue()
    
        sel = nuke.selectedNodes()
    
        for i in sel:
            # If it is the lowest in Y
            if not i['ypos'].getValue() == topNode:
                # We will connect the dot here, so we save its
                # name and X position for later.
                dotOutput = i['name'].getValue()
                sideNodePos = i['xpos'].getValue()
    
            i['selected'].setValue(False)
            # If the node is the highest in Y
            if i['ypos'].getValue() == topNode:
                # Check if it is connected to the lowest one
                existingConnections = []
                topNodeYPos = i['ypos'].getValue()
                i['selected'].setValue(True)
                # Save the name of the node for later
                dotInput = i['name'].getValue()
                for conn in nuke.selectedNode().dependent():
                    connName = conn['name'].getValue()
                    existingConnections.append(connName)
                i['selected'].setValue(False)
    
        # We store some sizes and positions that we will use later to
        # move the dot to an approximate position.
        dotSize = nuke.toNode('preferences').knob('dot_node_scale').value()
        dotCenter = (12*dotSize)/2 # 12 is width and height by default
        dotOutWidthCenter = nuke.toNode(str(dotOutput)).screenWidth() / 2
        sideNodePos = sideNodePos + (dotOutWidthCenter - dotCenter)
        dotOutHeightCenter = nuke.toNode(str(dotOutput)).screenHeight() / 2
        dotInWidthCenter = nuke.toNode(str(dotInput)).screenWidth() / 2
        dotInHeightCenter = nuke.toNode(str(dotInput)).screenHeight() / 2
        if not nuke.toNode(str(dotOutput)).Class() == 'Dot':
            topNodeYPos = topNodeYPos + (dotInHeightCenter - dotCenter)
        else:
            sideNodePos = sideNodePos - (dotOutWidthCenter - dotCenter)
            topNodeYPos = topNodeYPos + (dotInHeightCenter - dotCenter)
        if nuke.toNode(str(dotInput)).Class() == 'Dot':
            sideNodePos = sideNodePos - (dotInHeightCenter - dotCenter)
    
        # If we found both high and low nodes are connected
        if existingConnections != []:
            nuke.toNode(dotOutput)['selected'].setValue(True)
    
            # We create an empty list and populate it with the lowest node
            # dependencies names (nodes connected to its inputs).
            dependenciesList = []
            for node in nuke.selectedNode().dependencies():
                depName = node.name()
                dependenciesList.append(depName)
        
            # We check the number of the highest input connected and use
            # it to populate an empty list with 1 (if the input in that
            # position is connected) and 0 (if it is not connected).
            # For example, if a Merge has A connected, but not B or mask,
            # the list would be [0,1].
            maxInputConnected = nuke.selectedNode().inputs()
            connectedList = []
            for i in range(maxInputConnected):
                connResult = 1 if nuke.selectedNode().input(i) else 0
                connectedList.append(connResult)
            # We also save the number of dependencies found
            depNumber = len(connectedList)
    
            # Now we have to check what input is connected to the
            # highest node. To do that we will create two different
            # counters: one for the number of dependencies and
            # another one for the number of connections. A node can
            # have two dependencies and three connections, example:
            # a Merge with B and Mask connected, but not A, will
            # have two dependencies (or one if B and Mask are
            # connected to the same node) and three connections (A
            # counts as a connection even if it is not connected).
            depCounter = 0
            connCounter = 0
            while connCounter <= (depNumber-1):
                # Using connectedList we created before, we'll add
                # the string 'Nope' as an element to later match
                # the node name to the correct input number.
                if connectedList[connCounter] == 1:
                    depCounter = depCounter + 1
                    connCounter = connCounter + 1
                elif connectedList[depCounter] == 0:
                    dependenciesList.insert(depCounter, 'Nope')
                    connCounter = connCounter + 1
    
            # Now both dependenciesList and connectedList have the
            # same number of elements, so we just need to find the
            # position of the highest node in dependenciesList to know
            # to what input of the lowest node it's connected to.
            try:
                inputNumber = dependenciesList.index(dotInput)
            except ValueError:
                maxInputsNumber = nuke.toNode(dotOutput).maxInputs()
                if depNumber == maxInputsNumber:
                    try:
                        inputNumber = connectedList.index(0)
                    except ValueError:
                        inputNumber = 0
                elif depNumber == maxInputsNumber-1:
                    inputNumber = depNumber
                else:
                    # Find the first position with a 0 in connectedList, and that
                    # would be the first available input to connect to the dot.
                    try:
                        inputNumber = connectedList.index(0)
                    except ValueError:
                        if maxInputsNumber > depNumber+1:
                            inputNumber = depNumber
                        else:
                            inputNumber = 0
    
            nuke.toNode(dotOutput)['selected'].setValue(False)
    
            # We create our dot on the positions we calculated and
            # select it to connect the input we checked before.

            nuke.nodes.Dot(xpos=sideNodePos, ypos=topNodeYPos, selected=1).setInput(0, nuke.toNode(dotInput)) #for some reason this step takes longer than expected
            nuke.toNode(dotOutput).setInput(inputNumber, nuke.selectedNode())

            # Now we will check if other nodes were connected to the
            # dot input,because those will be connected to the new dot
            # for esthetic purposes. First we look for all the nodes
            # sharing the same center as our new dot.
            sameCenterList = []
            for i in nuke.allNodes():
                # We make sure to remove the new dot and its input from
                # these next steps.
                if not i['selected'].getValue() == True and i['name'].getValue() != dotInput:
                    nodeName = i['name'].getValue()
                    nodeCenter =  i['ypos'].getValue() + nuke.toNode(nodeName).screenHeight() / 2
                    if nodeCenter == topNodeYPos + dotCenter:
                        sameCenterList.append(nodeName)
            # Now we have a list on nodes sharing the same X position.
            
            # Using our new list, we are going to check if those nodes are
            # also connected to the dot input.
            depList = []
            for node in sameCenterList:
                for i in nuke.toNode(node).dependencies():
                    nodeName = i.name()
                    if nodeName == dotInput:
                        depList.append(node)
            # We have removed all the nodes sharing the X position that were
            # not connected to the dot input.

            for i in depList:
                # Following the same method we did before, we fill a list
                # with the names of all the dependencies of the nodes sharing
                # X position with the new dot and also conected to its input.
                dependenciesList = []
                for node in nuke.toNode(i).dependencies():
                    depName = node.name()
                    dependenciesList.append(depName)
                # Another list with 1 (if the input is connected) and 0
                # (if it is not connected). Ex: if a Merge has A connected, 
                # but not B or mask, the list would be [0,1].
                maxInputConnected = nuke.toNode(i).inputs()
                connectedList = []
                for x in range(maxInputConnected):
                    connResult = 1 if nuke.toNode(i).input(x) else 0
                    connectedList.append(connResult)
                # We also save the number of dependencies found
                depNumber = len(connectedList)
                # Now we have to check what input is connected to the
                # dot input. To do that we will create two different
                # counters: one for the number of dependencies and
                # another one for the number of connections
                depCounter = 0
                connCounter = 0
                while connCounter <= (depNumber-1):
                    # Using connectedList we created before, we'll add
                    # the string 'Nope' as an element to later match
                    # the node name to the correct input number.
                    if connectedList[connCounter] == 1:
                        depCounter = depCounter + 1
                        connCounter = connCounter + 1
                    elif connectedList[depCounter] == 0:
                        dependenciesList.insert(depCounter, 'Nope')
                        connCounter = connCounter + 1

                # Now both dependenciesList and connectedList have the
                # same number of elements, so we just need to find the
                # position of the highest node in dependenciesList to know
                # to what input of the lowest node it's connected to.
                try:
                    inputNumber = dependenciesList.index(dotInput)
                except ValueError:
                    maxInputsNumber = nuke.toNode(i).maxInputs()
                    if depNumber == maxInputsNumber:
                        inputNumber = connectedList.index(0)
                    elif depNumber == maxInputsNumber-1:
                        inputNumber = depNumber
                    else:
                        # Find the first position with a 0 in connectedList, and that
                        # would be the first available input to connect to the dot.
                        try:
                            inputNumber = connectedList.index(0)
                        except ValueError:
                            if maxInputsNumber > depNumber+1:
                                inputNumber = depNumber
                            else:
                                inputNumber = 0                
                nuke.toNode(i).setInput(inputNumber, nuke.selectedNode())
    
            for i in nuke.allNodes():
                i['selected'].setValue(False)
    
        # If nodes are not connected, we will find what is the first input
        # of the lowest node that is not connected.
        else:
            maxInputConnected = nuke.toNode(dotOutput).inputs()
            connectedList = []
            for i in range(maxInputConnected):
                connResult = 1 if nuke.toNode(dotOutput).input(i) else 0
                connectedList.append(connResult)
            # We also save the number of dependencies found to check if it
            # is the max allowed.
            depNumber = len(connectedList)
            maxInputsNumber = nuke.toNode(dotOutput).maxInputs()
    
            nuke.toNode(str(dotInput))['selected'].setValue(True)
        
            # We create our dot on the positions we calculated and
            # select it to connect the input we checked before.
            nuke.nodes.Dot(xpos=sideNodePos, ypos=topNodeYPos, selected=1).setInput(0, nuke.toNode(dotInput)) #for some reason this step takes longer than expected
    
            if depNumber == maxInputsNumber:
                try:
                    print 'here'
                    firstFreeInput = connectedList.index(0)
                    nuke.toNode(dotOutput).setInput(firstFreeInput, nuke.selectedNode())
                except ValueError:
                    nuke.toNode(dotOutput).setInput(0, nuke.selectedNode())
            elif depNumber == maxInputsNumber-1:
                try:
                    firstFreeInput = connectedList.index(0)
                    nuke.toNode(dotOutput).setInput(firstFreeInput, nuke.selectedNode())
                except ValueError:
                    nuke.toNode(dotOutput).setInput(depNumber, nuke.selectedNode())
            else:
                # Find the first position with a 0 in connectedList, and that
                # would be the first available input to connect to the dot.
                try:
                    firstFreeInput = connectedList.index(0)
                    nuke.toNode(dotOutput).setInput(firstFreeInput, nuke.selectedNode())
                except ValueError:
                    if maxInputsNumber > depNumber+1:
                        nuke.toNode(dotOutput).setInput(depNumber, nuke.selectedNode())
                    else:
                        nuke.toNode(dotOutput).setInput(0, nuke.selectedNode())
    
            for i in nuke.allNodes():
                i['selected'].setValue(False)
    
    selNodesList = []
    for i in nuke.selectedNodes():
        selNodesNames = i['name'].getValue()
        selNodesList.append(selNodesNames)
    if len(selNodesList) != 2:
        nuke.message('Please, select two nodes to run this action.')
    else:
        XYCheck()

Javier Nieto Moncó © 2025

  • linkedin
  • vimeo
  • generic-social-link
bottom of page