colour-science / colour

Colour Science for Python
https://www.colour-science.org
BSD 3-Clause "New" or "Revised" License
2.14k stars 263 forks source link

PR: Port-Based Node-Graph #1277

Closed KelSolaar closed 4 months ago

KelSolaar commented 4 months ago

Summary

This PR implements support for a port-based node-graph via 6 new classes:

The idea behind it is to be able to construct processing graph, initially with code but possibly using a UI in the future.

The API is as follows:

class NodeAdd(PortNode):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.description = "Perform the addition of the two input port values."

        self.add_input_port("a")
        self.add_input_port("b")
        self.add_output_port("output")

    def process(self):
        a = self.get_input("a")
        b = self.get_input("b")

        if a is None or b is None:
            return

        self._output_ports["output"].value = a + b

        self.dirty = False

class NodeMultiply(PortNode):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.description = (
            "Perform the multiplication of the two input port values."
        )

        self.add_input_port("a")
        self.add_input_port("b")
        self.add_output_port("output")

    def process(self):
        a = self.get_input("a")
        b = self.get_input("b")

        if a is None or b is None:
            return

        self._output_ports["output"].value = a * b

        self.dirty = False

node_add = NodeAdd()
node_add.set_input("a", 1)
node_add.set_input("b", 1)
node_multiply = NodeMultiply()
node_multiply.set_input("b", 2)

graph = PortGraph()

graph.add_node(node_add)
graph.add_node(node_multiply)

graph.connect(node_add, "output", node_multiply, "a")

graph.process()

print(node_multiply.get_output("output"))
graph.to_graphviz().draw("Graph.png", prog="dot")

image

This is obviously a simple and naive example but the immediate use case is for colour-hdri:

image image image image

Preflight

Code Style and Quality

Documentation

KelSolaar commented 4 months ago

I will look at creating some subclasses that have an execution route instead of relying on the ports, that would allow for adding some control flow nodes, e.g., for loop and conditional branching.

KelSolaar commented 4 months ago

I have implemented support for looping, this can be done sequentially, via thread or multiprocessing using the colour.utilities.For, colour.utilities.ParallelForThread and colour.utilities.ParallelForMultiProcess nodes respectively.

coveralls commented 4 months ago

Coverage Status

coverage: 99.835% (-0.1%) from 99.973% when pulling 91b88de9b364bf5c449894fa18da1144545ac9af on feature/graph into e21773141a9726dc5c68777a4d38bdc985382132 on develop.

tjdcs commented 4 months ago

I'll have more time for a review on Sunday time in central US. Looks promising!

KelSolaar commented 4 months ago

I'm going to merge this one! The feature is at a point where it works really well. What might happen in the future though is that we will extract this in its own repository but for now here is good as colour is the lowest common denominator in our projects.