Implementing a node-based graphical interface?
Asked Answered
T

7

23

I would like to implement a nodal-interface, basically a DAG where each node performs an operation on it's input connections, and outputs something (which you can connect to another node)

Some example applications:


As a first goal, I would like to have an graphical application with only 2 nodes. A "number" which simply outputs a fixed number, and an "Add" node, which takes two inputs and outputs the sum of the two.

As people have answered so-far, I have a rough idea of how to represent the data in code, for example in Python'y looking pseudo-code:

class Number:
    def __init__(self, value):
        self.value = value

    def eval(self):
        return self.value

class Add:
    def __init__(self, input1, input2):
        self.input1 = input1
        self.input2 = input2

    def eval(self):
        return self.input1.eval() + self.input2.eval()


a = Number(20)
b = Number(72)

adder = Add(a, b)
print adder.eval()

How would I got about wrapping a custom GUI around this? Something like the following, but slightly less hand-drawn!

nodal UI mockup

Where would I begin? I currently plan to write it in Objective-C/Cocoa, although I'm more than open to suggestions for other languages.

Theocracy answered 14/3, 2009 at 4:16 Comment(0)
A
3

I would start by modelling some basic interfaces (in the OOP sense, not the GUI sense). Seems to me you'll have a Node which will accept a collection of inputs and a single output. You didn't give any indication of how broad the data types are, but you'll want some suitable method of representing your inputs/outputs. For your first goal, this could be an integer.

In some generic C style OOP language (hope it makes sense):

class Node<T> {
    Node<T>[] inputs;
    T eval();
}

class AdderNode extends Node<int> {
    int eval() {
        int accum = 0;
        for (inputs : i)
            accum += i.eval();
        return i;
    }
}

class ConstNode<int I> extends Node<int> {
    int eval() { return I; }
}

AdderNode a;
a.inputs.add(ConstNode<2>());
a.inputs.add(ConstNode<3>());
a.eval();

You could expand on this by replacing int with some abstract class, generic, or interface. Actual implementation will vary based on the actual language, of course.

Arethaarethusa answered 14/3, 2009 at 5:38 Comment(0)
D
2

I would start with modeling the interesting operations. Ultimately you will connect them to a UI, but that is the steering wheel and gas pedal, not the engine.

What you are attempting to build has a lot in common with programming languages: variables, values, types, expressions, evaluation, etc. Many of the metaphors are applicable and might provide some guidance.

If you are using .NET 3.5, you have the option of Expression Trees, which allow you to represent and compile code expressions at runtime.

For example, to model your first goal:

using System.Linq.Expressions;

ConstantExpression theNumber2 = Expression.Constant(2);
ConstantExpression theNumber3 = Expression.Constant(3);

BinaryExpression add2And3 = Expression.Add(theNumber2, theNumber3);

To invoke the expression, we need to wrap add2And3 with a method. This is done with a lambda expression:

Expression<Func<int>> add2And3Lambda = Expression.Lambda<Func<int>>(add2And3);

Func<int> represents a method which takes no parameters and returns an int. In C#, the code represented by add2And3Lambda would be:

() => 2 + 3

So what we have is an expression tree whose root is a method. Because a method is callable, we can compile the tree into an instance of the underlying delegate type:

Func<int> add2And3Func = add2And3Lambda.Compile();

Now we can invoke the code we built:

int theNumber5 = add2And3Func();

Every expression available to .NET languages is supported.

Imagine every node in your graph has an Expression associated with it. That might give you an idea of the power of expression trees and how they could help you with this task.

Doable answered 14/3, 2009 at 6:32 Comment(0)
A
1

All that node systems have in common that they describe a functional programming language. A function takes multiple parameters and returns a single result, no matter for what purpose it was designed. Some examples:

  • Graphics: Blur(Image, Kernel, Radius) -> Image

  • Math: Add(Number, Number) -> Number

  • Relational: Filter(Table, Predicate) -> Table

Basically that comes down to a function signature like Func<object[], object> (C#).

You will face the question of how to make your node system persistent. Do you want to make the result of a node usable as parameter by only one other node (tree) or by multiple nodes (graph)?

Example of a tree, directly have the parameters a child nodes:

Add(
  Multiply(
    Constant(5),
    Constant(4)
  ),
  Multiply(
    Constant(5),
    Constant(3)
  )
)

Example of a graph, store all nodes in a list and only use references:

A := Constant(5)
B := Constant(4)
C := Constant(3)

D := Func(Multiply, A, B)
E := Func(Multiply, A, C)

F := Func(Add, D, E)
Advisory answered 14/3, 2009 at 9:45 Comment(0)
T
1

I found some useful information on implementing such an interface in Cocoa:

Theocracy answered 23/5, 2009 at 18:37 Comment(0)
U
1

I stumbled upon this thread while researching for a similar solution. Recently I found a nice project on github https://github.com/nodebox/nodebox which seems to be exactly what you are looking for. At least one could extract and adopt the editor components from the project.

Regards, Stephan

Universality answered 29/10, 2017 at 12:52 Comment(1)
Welcome to StackOverflow, thanks for wanting to contribute but answers with links only are discouraged. Please review the answering guidelines. A good rule of thumb is to look at your answer without the link and if it provides little to no value, consider expanding.Forgat
E
0

Maybe bwise has something of interest?

On the bottom half of this page shows an example of using bwise to create a multiplication block that takes two numbers as an input.

Earthshaker answered 13/5, 2009 at 21:15 Comment(0)
L
0

I implemented a Execution Graph like you describe in this project: GRSFramework

The source code can be found here.

Currently I am working on releasing a better, cleaned version of this system in the project ExecutionGraph.
It might be of interest for you as well.

Then there is also the TensorFlow library from Google which has a similar system implemented TensorFlow

Lx answered 12/3, 2017 at 21:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.