Skip to content

Node

Nodes carry the sockets, the title and the content widget of a graph element.

nodeeditor.node_node

A module containing NodeEditor's class for representing Node.

Node

Bases: QObject, Serializable

Class representing Node in the Scene.

title property writable

title

Title shown in the scene

:getter: return current Node title :setter: sets Node title and passes it to Graphics Node class :type: str

pos property

pos

Retrieve Node's position in the Scene

:return: Node position :rtype: QPointF

setNodeLabel

setNodeLabel(text, store_history=True)

Set the floating single-line label above the node.

:param text: label text; empty string hides the label :param store_history: store undo history entry (skip during load/deserialize)

getNodeLabel

getNodeLabel()

Return floating label text ("" when none).

clearNodeLabel

clearNodeLabel(store_history=True)

Remove the floating label.

setNodeLabelVisible

setNodeLabelVisible(visible)

Show or hide the floating label of this Node.

The label stays hidden while it carries no text.

:param visible: True shows the label, False hides it :type visible: bool

isNodeLabelVisible

isNodeLabelVisible()

Is the floating label of this Node currently visible?

:return: True if the label is visible :rtype: bool

setNodeLabelOffset

setNodeLabelOffset(offset)

Set the gap between the top of this Node and the bottom of its floating label.

:param offset: gap in pixels :type offset: float

setPos

setPos(x, y)

Sets position of the Graphics Node

:param x: X Scene position :param y: Y Scene position

initInnerClasses

initInnerClasses()

Sets up graphics Node (PyQt) and Content Widget

getNodeContentClass

getNodeContentClass()

Returns class representing nodeeditor content

getGraphicsNodeClass

getGraphicsNodeClass()

Returns class representing the graphics node

initSettings

initSettings()

Initialize properties and socket information

getSocketShapeName

getSocketShapeName(socket_type, is_input)

Name of the shape used by a socket of socket_type on this node.

The side's own map is consulted first, then its '*' wildcard entry, and the circle is the last resort. Types that are not mapped keep the classic circle.

:param socket_type: the socket's type, as passed to initSockets :param is_input: True for an input socket :return: the registered shape name :rtype: str

Example::

class MyNode(Node):
    def initSettings(self):
        super().initSettings()
        self.input_socket_shapes = {1: 'chevron'}
        self.output_socket_shapes = {'*': 'triangle'}

initSockets

initSockets(
    inputs,
    outputs,
    input_text=[],
    output_text=[],
    reset=True,
)

Create sockets for inputs and outputs

:param inputs: list of Socket Types (int) :type inputs: list :param outputs: list of Socket Types (int) :type outputs: list :param input_text: list of Socket Types (int) :type input_text: list :param output_text: list of Socket Types (int) :type output_text: list :param reset: if True destroys and removes old Sockets :type reset: bool

onEdgeConnectionChanged

onEdgeConnectionChanged(new_edge)

Event handling that any connection (Edge) has changed. Currently not used...

:param new_edge: reference to the changed :class:~nodeeditor.node_edge.Edge :type new_edge: :class:~nodeeditor.node_edge.Edge

onInputChanged

onInputChanged(socket)

Event handling when Node's input Edge has changed. We auto-mark this Node to be Dirty with all it's descendants

:param socket: reference to the changed :class:~nodeeditor.node_socket.Socket :type socket: :class:~nodeeditor.node_socket.Socket

onDeserialized

onDeserialized(data)

Event manually called when this node was deserialized. Currently called when node is deserialized from scene Passing data containing the data which have been deserialized

onDoubleClicked

onDoubleClicked(event)

Event handling double click on Graphics Node in Scene

doSelect

doSelect(new_state=True)

Shortcut method for selecting/deselecting the Node

:param new_state: True if you want to select the Node. False if you want to deselect the Node :type new_state: bool

isSelected

isSelected()

Returns True if current Node is selected

hasConnectedEdge

hasConnectedEdge(edge)

Returns True if edge is connected to any :class:~nodeeditor.node_socket.Socket of this Node

getSocketPosition

getSocketPosition(index, position, num_out_of=1)

Get the relative x, y position of a :class:~nodeeditor.node_socket.Socket. This is used for placing the Graphics Sockets on Graphics Node.

:param index: Order number of the Socket. (0, 1, 2, ...) :type index: int :param position: Socket Position Constant describing where the Socket is located. See :ref:socket-position-constants :type position: int :param num_out_of: Total number of Sockets on this Socket Position :type num_out_of: int :return: Position of described Socket on the Node :rtype: x, y

getSocketScenePosition

getSocketScenePosition(socket)

Get absolute Socket position in the Scene

:param socket: Socket which position we want to know :return: (x, y) Socket's scene position

updateConnectedEdges

updateConnectedEdges()

Recalculate (Refresh) positions of all connected Edges. Used for updating Graphics Edges

remove

remove()

Safely remove this Node (detaches from parent Group first)

isDirty

isDirty()

Is this node marked as Dirty

:return: True if Node is marked as Dirty :rtype: bool

markDirty

markDirty(new_value=True)

Mark this Node as Dirty. See :ref:evaluation for more

:param new_value: True if this Node should be Dirty. False if you want to un-dirty this Node :type new_value: bool

onMarkedDirty

onMarkedDirty()

Called when this Node has been marked as Dirty. This method is supposed to be overridden

markChildrenDirty

markChildrenDirty(new_value=True)

Mark all first level children of this Node to be Dirty. Not this Node it self. Not other descendants

:param new_value: True if children should be Dirty. False if you want to un-dirty children :type new_value: bool

markDescendantsDirty

markDescendantsDirty(new_value=True)

Mark all children and descendants of this Node to be Dirty. Not this Node it self

The traversal is iterative and keeps a visited set, so a graph with a cycle terminates instead of exhausting the interpreter's recursion limit, and a node reachable through several paths is visited once rather than once per path.

:param new_value: True if children and descendants should be Dirty. False if you want to un-dirty children and descendants :type new_value: bool

isInvalid

isInvalid()

Is this node marked as Invalid?

:return: True if Node is marked as Invalid :rtype: bool

markInvalid

markInvalid(new_value=True)

Mark this Node as Invalid. See :ref:evaluation for more

:param new_value: True if this Node should be Invalid. False if you want to make this Node valid :type new_value: bool

onMarkedInvalid

onMarkedInvalid()

Called when this Node has been marked as Invalid. This method is supposed to be overridden

markChildrenInvalid

markChildrenInvalid(new_value=True)

Mark all first level children of this Node to be Invalid. Not this Node it self. Not other descendants

:param new_value: True if children should be Invalid. False if you want to make children valid :type new_value: bool

markDescendantsInvalid

markDescendantsInvalid(new_value=True)

Mark all children and descendants of this Node to be Invalid. Not this Node it self

The traversal is iterative and keeps a visited set, so a graph with a cycle terminates instead of exhausting the interpreter's recursion limit, and a node reachable through several paths is visited once rather than once per path.

:param new_value: True if children and descendants should be Invalid. False if you want to make children and descendants valid :type new_value: bool

eval

eval(index=0)

Evaluate this Node. This is supposed to be overridden. See :ref:evaluation for more

evalChildren

evalChildren()

Evaluate all children of this Node

getChildrenNodes

getChildrenNodes()

Retreive all first-level children connected to this Node Outputs

:return: list of Nodes connected to this Node from all Outputs :rtype: List[:class:~nodeeditor.node_node.Node]

getInput

getInput(index=0)

Get the first Node connected to the Input specified by index

:param index: Order number of the Input Socket :type index: int :return: :class:~nodeeditor.node_node.Node which is connected to the specified Input or None if there is no connection or the index is out of range :rtype: :class:~nodeeditor.node_node.Node or None

getInputWithSocket

getInputWithSocket(index=0)

Get the first Node connected to the Input specified by index and the connection Socket

:param index: Order number of the Input Socket :type index: int :return: Tuple containing :class:~nodeeditor.node_node.Node and :class:~nodeeditor.node_socket.Socket which is connected to the specified Input or None if there is no connection or the index is out of range :rtype: (:class:~nodeeditor.node_node.Node, :class:~nodeeditor.node_socket.Socket)

getInputWithSocketIndex

getInputWithSocketIndex(index=0)

Get the first Node connected to the Input specified by index and the connection Socket

:param index: Order number of the Input Socket :type index: int :return: Tuple containing :class:~nodeeditor.node_node.Node and :class:~nodeeditor.node_socket.Socket which is connected to the specified Input or None if there is no connection or the index is out of range :rtype: (:class:~nodeeditor.node_node.Node, int)

getInputs

getInputs(index=0)

Get all Nodes connected to the Input specified by index

:param index: Order number of the Input Socket :type index: int :return: all :class:~nodeeditor.node_node.Node instances which are connected to the specified Input or [] if there is no connection or the index is out of range :rtype: List[:class:~nodeeditor.node_node.Node]

getOutputs

getOutputs(index=0)

Get all Nodes connected to the Output specified by index

:param index: Order number of the Output Socket :type index: int :return: all :class:~nodeeditor.node_node.Node instances which are connected to the specified Output or [] if there is no connection or the index is out of range :rtype: List[:class:~nodeeditor.node_node.Node]

serialize

serialize()

Serialize this Node into an OrderedDict for storing in memory or on disk.

:return: data serialized in OrderedDict :rtype: OrderedDict

deserialize

deserialize(
    data, hashmap={}, restore_id=True, *args, **kwargs
)

Deserialize this Node from a dict of serialized data.

Sockets missing in the data are created, sockets already present are reused.

:param data: Dictionary containing serialized data :type data: dict :param hashmap: Helper dictionary containing references (by id == key) to existing objects :type hashmap: dict :param restore_id: True if we are creating new Sockets. False is useful when loading existing Sockets of which we want to keep the existing object's id. :type restore_id: bool :return: True if deserialization was successful, otherwise False :rtype: bool

nodeeditor.node_multi_input_node

A module containing the MultiInputNode class: a :class:~nodeeditor.node_node.Node whose input :class:~nodeeditor.node_socket.Socket accepts any number of :class:~nodeeditor.node_edge.Edge (s) and reads them in an explicit, persisted order.

MultiInputNode

Bases: Node

Base class for nodes reading an arbitrary number of inputs in order.

Subclass it, declare the sockets you need and read them with :meth:getOrderedSources / :meth:getOrderedValues::

class Sum(MultiInputNode, CalcNode):
    def evalImplementation(self):
        return [sum(self.getOrderedValues())]

By default every input socket accepts multiple Edges (:attr:multi_input_all_inputs). Set :attr:multi_input_socket and :attr:multi_input_all_inputs = False to make only one socket do so.

The order is, by default, the order the Edges were connected in. It can be changed at any time from code (:meth:setEdgeOrder, :meth:moveEdgeTo, :meth:swapEdges) and is saved to / loaded from the graph file.

This class deliberately does not define __init__, so it can be mixed into an existing node hierarchy without changing its constructor chain.

:Instance Attributes:

- **multi_input_socket** - index of the input `Socket` which accepts
  many `Edges` when :attr:`multi_input_all_inputs` is ``False``
- **multi_input_all_inputs** - ``True`` to let every input `Socket`
  accept multiple `Edges`

initSettings

initSettings()

Initialize properties and socket information

initSockets

initSockets(
    inputs,
    outputs,
    input_text=[],
    output_text=[],
    reset=True,
)

Create sockets for inputs and outputs, keeping only :attr:multi_input_socket multi-edged if :attr:multi_input_all_inputs is False

getMultiSocket

getMultiSocket(index=None)

Get the input :class:~nodeeditor.node_socket.Socket which accepts many Edges.

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: the ordered input Socket or None if the node has no such socket :rtype: :class:~nodeeditor.node_socket.Socket or None

compactEdgeOrder

compactEdgeOrder(index=None)

Renumber the input Edges to a gap free 0..n-1 sequence.

Called automatically on every connection change, so it is only needed after assigning :attr:~nodeeditor.node_edge.Edge.input_index directly.

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: True if anything actually changed :rtype: bool

getOrderedEdges

getOrderedEdges(index=None)

Get the connected Edges of the ordered input Socket in read order.

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: Edges ordered by :attr:~nodeeditor.node_edge.Edge.input_index :rtype: List[:class:~nodeeditor.node_edge.Edge]

getOrderedSources

getOrderedSources(index=None)

Get the (node, socket) pairs feeding the ordered input Socket.

One entry per connected Edge, in read order, so a source connected twice appears twice.

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: source Node and its Socket per read position :rtype: List[Tuple[:class:~nodeeditor.node_node.Node, :class:~nodeeditor.node_socket.Socket]]

getOrderedValues

getOrderedValues(index=None)

Evaluate every source of the ordered input Socket in read order.

The returned list always has one entry per connected Edge; a source which fails to evaluate contributes None instead of raising, so len(getOrderedValues()) always equals the number of connections.

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: evaluated value per read position :rtype: list

getOrderedNodes

getOrderedNodes(index=None)

Get the source :class:~nodeeditor.node_node.Node (s) of the ordered input Socket in read order.

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: source Nodes, one per read position :rtype: List[:class:~nodeeditor.node_node.Node]

describeInputOrder

describeInputOrder(index=None)

Human readable one-line-per-position description of the input order.

Handy for tooltips and for logging what the node currently sees::

0: Input
1: Add

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: description of the current read order :rtype: str

orderLabel staticmethod

orderLabel(position)

Display label for read position position (0-based).

:param position: 0-based read position :type position: int :return: "#1" for position 0, "#2" for position 1, and so on :rtype: str

updateInputOrderLabels

updateInputOrderLabels(index=None)

Write :meth:orderLabel onto every Edge of the ordered input Socket. No-op when :attr:show_input_order_labels is False.

Called automatically after every connection change and reorder, so you only need it when toggling :attr:show_input_order_labels on for a node that already has connections.

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None

setEdgeOrder

setEdgeOrder(edges, index=None)

Set the read order of the connected Edges of the ordered input Socket.

edges may be a partial list; edges missing from it are appended afterwards keeping their relative order.

:param edges: Edges of this node's ordered input Socket, first read position first :type edges: List[:class:~nodeeditor.node_edge.Edge] :param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: True if the order changed :rtype: bool

setEdgeOrderByNodes

setEdgeOrderByNodes(nodes, index=None)

Set the read order from a list of source :class:~nodeeditor.node_node.Node (s).

Each node moves to the first read position that is not already taken by an earlier entry, so listing the same node twice moves it to position 0 and pushes the rest down.

:param nodes: source Nodes, first read position first :type nodes: List[:class:~nodeeditor.node_node.Node] :param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: True if the order changed :rtype: bool

moveEdgeTo

moveEdgeTo(edge, position, index=None)

Move a connected Edge to read position position.

:param edge: :class:~nodeeditor.node_edge.Edge connected to this node :type edge: :class:~nodeeditor.node_edge.Edge :param position: target read position :type position: int :param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: True if the order changed :rtype: bool

moveEdgeBy

moveEdgeBy(edge, offset, index=None)

Shift a connected Edge by offset read positions.

Clamped at both ends, so offset=-1 on the first input is a no-op.

:param edge: :class:~nodeeditor.node_edge.Edge connected to this node :type edge: :class:~nodeeditor.node_edge.Edge :param offset: how many positions to move, negative moves earlier :type offset: int :param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: True if the order changed :rtype: bool

swapEdges

swapEdges(edge_a, edge_b, index=None)

Swap the read positions of two Edges connected to this node.

:param edge_a: first :class:~nodeeditor.node_edge.Edge to swap :type edge_a: :class:~nodeeditor.node_edge.Edge :param edge_b: second :class:~nodeeditor.node_edge.Edge to swap :type edge_b: :class:~nodeeditor.node_edge.Edge :param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: True if the order changed :rtype: bool

reverseEdgeOrder

reverseEdgeOrder(index=None)

Reverse the read order of the connected Edges.

:param index: index of the input Socket or None to use :attr:multi_input_socket :type index: int or None :return: True if the order changed :rtype: bool

onEdgeConnectionChanged

onEdgeConnectionChanged(new_edge)

Keep the read order gap free after any connection change.

This is the single hook every connection path already goes through (EdgeDragging, EdgeRerouting, Edge.remove), so :attr:~nodeeditor.node_edge.Edge.input_index stays a contiguous 0..n-1 sequence and the #N labels (see :attr:show_input_order_labels) stay in sync. An Edge that just detached from our ordered socket gets its managed #N label cleared. onInputChanged is intentionally not overridden so existing subclass chains keep working.