QNodeEditor.scene.NodeScene#

class QNodeEditor.scene.NodeScene(parent: QWidget = None)#

Bases: QObject

Scene container holding nodes, sockets, layouts, edges, and utility functions.

This class represents a scene containing nodes connected by edges. The scene has a set number of nodes that can be used in the scene, with one being the dedicated output node.

See the available_nodes property for details on how to set the nodes that can be used in the scene, and see output_node for setting the dedicated output node.

Examples

To create a new scene and add some nodes to it:

# Create a scene
scene = NodeScene()

# Set the nodes that can be used in the scene
scene.available_nodes = {
    'Some node': SomeNode,
    'Another node': AnotherNode
}

# Set the node that is used as the output
scene.output_node = SomeNode

# Create two nodes and add them to the scene
node1 = SomeNode()
node2 = AnotherNode()
scene.addNodes([node1, node2])

To display a node scene, use a NodeView instance.

nodes#

List of nodes that are present in the scene

Type:

list[Node]

edges#

List of edges that are present in the scene

Type:

list[Edge]

Properties

available_nodes

Get or set the nodes that can be used in the scene.

errored(PyQt_PyObject)

Signal that emits the error if once occurs during evaluation

evaluated(PyQt_PyObject)

Signal that emits a dictionary with the result of evaluating the scene

output_node

Get or set the type of node that is considered the scene output.

progress(double)

pyqtSignal -> Signal that emits the current progress of the evaluation [0.0, 1.0]

Methods

__init__

Create a new node scene.

add_node

Add a new node to the scene.

add_nodes

Add multiple new nodes to the scene.

available_classes

Get a list of the class definitions of nodes that are available in the scene.

available_codes

Get a list of the unique codes of all nodes that are available in the scene.

clear

Remove all nodes (and thus all edges) from the scene.

digraph

Create a directional graph that represents the node scene.

evaluate

Evaluate the scene by traversing the nodes and their connections.

find_output_node

Find the instance of the output node in the scene (if any)

get_node_class

Get a node class definition by its unique code

get_state

Get the state of this scene as a (JSON-safe) dictionary.

has_cycles

Check if the nodes and edges in the scene form a cycle.

load

Load the scene state from a file

remove_node

Remove a node from the scene.

save

Save the scene state to a file.

set_editing_flag

Set a flag showing that content is being edited in a node.

set_state

Set the state of this scene from a state dictionary.

simplified_digraph

Get a directional graph representing the scene with only nodes connected to the output.

socket_instances

Get a dictionary of all sockets and their IDs in this scene

__init__(parent: QWidget = None)#

Create a new node scene.

Parameters:

parent (QWidget, optional) – Parent object for the node scene (if any)

add_node(node: Node) None#

Add a new node to the scene.

Parameters:

node (Node) – Node to add to the scene

Return type:

None

add_nodes(nodes: Iterable[Node]) None#

Add multiple new nodes to the scene.

Parameters:

nodes (Iterable[Node]) – Iterable of nodes to add to the scene

Return type:

None

available_classes() list[Type[Node]]#

Get a list of the class definitions of nodes that are available in the scene.

Examples

With the following value for the available_nodes property:

scene.available_nodes = {
    'Name 1': SomeNode,
    'Group 1': {
        'Name 2': AnotherNode,
        'Name 3': YetAnotherNode
    },
    'Name 4': FinalNode
}

This function would return:

[SomeNode, AnotherNode, YetAnotherNode, FinalNode]
Returns:

List of node classes for all available nodes

Return type:

list[Type[Node]]

available_codes() list[int]#

Get a list of the unique codes of all nodes that are available in the scene.

Examples

With the following value for the available_nodes property:

scene.available_nodes = {
    'Name 1': SomeNode,           # Unique code: 0
    'Group 1': {
        'Name 2': AnotherNode,    # Unique code: 1
        'Name 3': YetAnotherNode  # Unique code: 2
    },
    'Name 4': FinalNode           # Unique code: 3
}

This function would return:

[0, 1, 2, 3]
Returns:

List of unique codes for all available nodes

Return type:

list[int]

clear() None#

Remove all nodes (and thus all edges) from the scene.

Return type:

None

digraph() DiGraph#

Create a directional graph that represents the node scene.

This graph is used to check for cycles in the graph to prevent infinite recursion when evaluating.

Returns:

Directional graph object representing the nodes and connections in the scene.

Return type:

DiGraph

evaluate() None#

Evaluate the scene by traversing the nodes and their connections.

This starts the asynchronous evaluation of the scene. All nodes leading up to the output node are evaluated, and the final result is emitted through the evaluated signal.

If an error occurs during the evaluation, it is emitted through the errored signal (and nothing through the evaluated signal).

For each node that is evaluated, the progress signal emits the current progress in the evaluation. The signal emits a float that represents the percentage of the current evaluation (0.0 to 1.0).

Return type:

None

find_output_node() Node#

Find the instance of the output node in the scene (if any)

This function raises an error if the output node could not be found. This can be due to one of the following reasons:

  • No output node has been set through the output_node property

  • There is no instance of the specified output node in the scene

  • There is more than one instances of the specified output node in the scene

Returns:

Output node instance

Return type:

Node

Raises:

ValueError – If the node could not be found, or there is more than one output node instance

get_node_class(code: int) Type[Node]#

Get a node class definition by its unique code

This only works for nodes that are set in the available_nodes property.

Parameters:

code (int) – Unique code of node class definition to retrieve

Returns:

Node class definition matching the unique code

Return type:

Type[Node]

Raises:

ValueError – If no node with the specified unique code exists

get_state() dict#

Get the state of this scene as a (JSON-safe) dictionary.

The dictionary contains:

  • 'nodes': list of node states

  • 'edges': list of edge states

Returns:

JSON-safe dictionary representing scene state

Return type:

dict

has_cycles() bool#

Check if the nodes and edges in the scene form a cycle.

Returns:

Whether a cycle is present in the node scene

Return type:

bool

load(filepath: str) None#

Load the scene state from a file

Parameters:

filepath (str) – Path to file to load scene state from

Return type:

None

remove_node(node: Node) None#

Remove a node from the scene.

Does not raise an error if the node does not exist.

Parameters:

node (Node) – Node to remove from the scene

Return type:

None

save(filepath: str) None#

Save the scene state to a file.

Parameters:

filepath (str) – Path to file to save scene state to

Return type:

None

set_editing_flag(editing: bool) None#

Set a flag showing that content is being edited in a node.

When this flag is set to True, nodes will not be deleted when pressing the Delete key.

This flag is automatically set when a ValueBox is edited, as well as for select other widgets (see connect_signal()).

Parameters:

editing (bool) – Whether content is being edited in a node.

Return type:

None

set_state(state: dict, restore_id: bool = True) bool#

Set the state of this scene from a state dictionary.

The dictionary contains:

  • 'nodes': list of node states

  • 'edges': list of edge states

Parameters:
  • state (dict) – Dictionary representation of the desired scene state

  • restore_id (bool) – Whether to restore the internal IDs of the entry sockets (used to reconnect saved edges)

Returns:

Whether setting the scene state succeeded

Return type:

bool

simplified_digraph() DiGraph#

Get a directional graph representing the scene with only nodes connected to the output.

This graph is used to determine how many nodes will have to be calculated during scene evaluation.

Returns:

Directional graph object representing the nodes connected to the output node.

Return type:

DiGraph

socket_instances() dict[str, Socket]#

Get a dictionary of all sockets and their IDs in this scene

The returned dictionaries has the socket ID (string) and socket instance as keys and values respectively.

Returns:

Dictionary of (ID, instance) pairs for all sockets in the scene

Return type:

dict[str, socket.Socket]

property available_nodes: dict[str, Type[Node]]#

Get or set the nodes that can be used in the scene.

Setting the available nodes is done using a (nested) dictionary. The keys are used as names in the node editor context menu, and the corresponding values are types of a node that are placed when a name is selected.

You can only add nodes to the scene that are in the available_nodes property. This is to keep track of the nodes such that they can be saved and loaded.

Nodes may only appear once in the (nested) dictionary.

Examples

A scene with two nodes:

scene.available_nodes = {
    'Name 1': SomeNode,
    'Name 2': AnotherNode
}

The resulting context menu would have the following structure:

Add node
 ├─ Name 1
 └─ Name 2

Choosing either option results in placing a new instance of the corresponding node type.

A more complicated menu can be created like this:

scene.available_nodes = {
    'Name 1': SomeNode,
    'Group 1': {
        'Name 2': AnotherNode,
        'Name 3': YetAnotherNode
    },
    'Name 4': FinalNode
}

The resulting context menu would now have the following structure:

Add node
 ├─ Name 1
 ├─ Group 1
 │   ├─ Name 2
 │   └─ Name 3
 └─ Name 4
errored(PyQt_PyObject): Signal#

Signal that emits the error if once occurs during evaluation

Type:

Signal

evaluated(PyQt_PyObject): Signal#

Signal that emits a dictionary with the result of evaluating the scene

Type:

Signal

property output_node: Type[Node]#

Get or set the type of node that is considered the scene output.

The node that is set will not be evaluated. Instead, all inputs of this node will be collected by traversing through the node scene. This is then collected and emitted as the result of the scene through the evaluated signal.

The output node can be set by either passing the class type, its unique code property, or an instance of that node.

Examples

# Create a scene and set the available nodes and output node
scene = NodeScene()
scene.available_nodes = {'Some node': SomeNode}
scene.output_node = SomeNode

# Create an instance of the output node and add it to the scene
node = SomeNode()  # Node with two inputs, 'Value 1' and 'Value 2'
scene.addNode(node)

# Evaluate the scene (without any connections to the output node)
scene.evaluated.connect(print)  # Give the scene result to the 'print' function
scene.evaluate()                # Start the evaluation

The output of this script looks like this:

$ python test.py

{'Value 1': None, 'Value 2': None}

The values for both items are None since nothing is wired into them.

If the input entries in SomeNode had widgets such as a ValueBox, its value would be used instead.

If the input entries were wired to another node, it would be evaluated and that result would be used instead.

progress(double): Signal#

pyqtSignal -> Signal that emits the current progress of the evaluation [0.0, 1.0]