Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to define default attributes for node, edge, or graph #68

Open
DreamerKMP opened this issue Oct 13, 2020 · 3 comments
Open

How to define default attributes for node, edge, or graph #68

DreamerKMP opened this issue Oct 13, 2020 · 3 comments

Comments

@DreamerKMP
Copy link

Hi, all.

I am trying to use the node, edge, and graph statement from the Lexical and Semantic Notes.
However, since this library always sorts and prints nodes, the order is changed.
How can I always define it first?

Output:

digraph G {
	rank=LR;
	Hello->World[ headlabel="head", taillabel="tail" ];
	Hello->World:f0;
	Hello->World:f1;
	Hello->World:f2;
	Hello [ label="Hi\nStart", shape=Mrecord ];
	World [ label="<f0>one|<f1>two|<f2>three", shape=Mrecord ];
	node [ shape=Mrecord ];
}

You can see that the node line is defined last.

Expected:

digraph G {
	node [ shape=Mrecord ];  <-------------- This line
	rank=LR;
	Hello->World[ headlabel="head", taillabel="tail" ];
	Hello->World:f0;
	Hello->World:f1;
	Hello->World:f2;
	Hello [ label="Hi\nStart", shape=Mrecord ];
	World [ label="<f0>one|<f1>two|<f2>three", shape=Mrecord ];
}

Only when defined like this, the output I want is completed.

Looking at the source code, there seem to be no solutions.
For now, is the only way to add properties to each node?

...
go 1.14

require github.com/awalterschulze/gographviz v2.0.1+incompatible
...
@awalterschulze
Copy link
Owner

awalterschulze commented Oct 22, 2020

I tried to create this test in analysewrite_test.go

func TestOrder(t *testing.T) {
	input := `digraph G {
		node [ shape=Mrecord ];
		rank=LR;
		Hello->World[ headlabel="head", taillabel="tail" ];
		Hello->World:f0;
		Hello->World:f1;
		Hello->World:f2;
		Hello [ label="Hi\nStart" ];
		World [ label="<f0>one|<f1>two|<f2>three" ];
	}`
	g, err := parser.ParseString(input)
	if err != nil {
		t.Fatal(err)
	}
	t.Logf("Parsed: %v\n", g)
}

It prints out node is the right position, but if I move the node to the bottom it stays at the bottom too.

If you add

        ag := NewGraph()
	if err := Analyse(g, ag); err != nil {
		t.Fatal(err)
	}
	t.Logf("Analysed: %v\n", ag)
	agstr := ag.String()
	t.Logf("Written: %v\n", agstr)

Then the node's properties are applied to all the appropriate nodes

        Hello [ label="Hi\nStart", shape=Mrecord ];
	World [ label="<f0>one|<f1>two|<f2>three", shape=Mrecord ];

So I don't think I understand the problem.
Is it possible rephrase it as a test?

@DreamerKMP
Copy link
Author

Here is my code

package main

import (
	"fmt"

	"github.com/awalterschulze/gographviz"
)

func main() {
	g := gographviz.NewGraph()
	g.SetName("G")
	g.SetDir(true)
	g.AddAttr("G", "rank", "LR")
	// This node is ignored.
	g.AddNode("G", "node", map[string]string{
		"shape": "record",
	})
	g.AddNode("G", "Hello", map[string]string{
		"label": fmt.Sprintf("%q", "Hi\nStart"),
		"shape": "Mrecord",
	})
	g.AddNode("G", "node", map[string]string{
		"shape": "Mrecord",
	})
	g.AddNode("G", "World", map[string]string{
		"label": fmt.Sprintf("%q", "<f0>one|<f1>two|<f2>three"),
		"shape": "Mrecord",
	})
	g.AddPortEdge("Hello", "", "World", "", true, map[string]string{
		"headlabel": fmt.Sprintf("%q", "head"),
		"taillabel": fmt.Sprintf("%q", "tail"),
	})
	g.AddPortEdge("Hello", "", "World", "f0", true, nil)
	g.AddPortEdge("Hello", "", "World", "f1", true, nil)
	g.AddPortEdge("Hello", "", "World", "f2", true, nil)

	fmt.Println(g.String())
}

Result:

digraph G {
	rank=LR;
	Hello->World[ headlabel="head", taillabel="tail" ];
	Hello->World:f0;
	Hello->World:f1;
	Hello->World:f2;
	Hello [ label="Hi\nStart", shape=Mrecord ];
	World [ label="<f0>one|<f1>two|<f2>three", shape=Mrecord ];
	node [ shape=Mrecord ];

}

I am using this library in my network management program.
Therefore, several default nodes can be added to the graph in the program logic.

@awalterschulze
Copy link
Owner

In an effort to keep the API smaller, the default node, edge and graph attrs are hidden away and get applied to the nodes, edges and graphs for you, during analyses of the parsed graph, see here: https://github.com/awalterschulze/gographviz/blob/master/analyse.go#L118

So this call will treat "node" as a normal node, named node, instead of a keyword.

g.AddNode("G", "node", map[string]string{
		"shape": "record",
	})

To keep track of default node attrs, I would save them in a map as they come in and apply them to each each node.

Another option is to create your own graph API, that can write to straight to the ast package.

I am sorry that I can't be of more help here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants