awalterschulze / gographviz

Parses the Graphviz DOT language in golang

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Default attributes are not inherited by nodes or edges in subgraphs

nkitchen opened this issue · comments

Given an input graph with default node/edge attributes and a subgraph, like this one:

digraph g {
    node [shape=record];
    edge [style=dashed];
    subgraph cluster_key {
        graph [label=KEY];
        key_user [fontcolor=red];
        key_dep  [fontcolor=blue];
        key_user -> key_dep;
    }
    A [fontcolor=red];
    B [fontcolor=blue];
    A -> B;
}

In the rendering from dot, the default attributes are inherited by the objects in the subgraph:

image

but gographviz only applies the attributes to the top-level objects, not the ones in the subgraph:

image

How do you get this output?
Do you parse the input you provided and output is again using the String method?

Yes, as you said. Here is my test program used to produce the results I posted here:

package main

import "fmt"
import "io/ioutil"
import "log"
import "os"

import gv "github.com/awalterschulze/gographviz"

func main() {
    b, err := ioutil.ReadAll(os.Stdin)
    if err != nil {
        log.Fatal(err)
    }

    g, err := gv.Read(b)
    if err != nil {
        log.Fatal(err)
    }

    fmt.Print(g.String())
}

Ok so this will then output

digraph g {
	key_user->key_dep;
	A->B[ style=dashed ];
	subgraph cluster_key {
		label=KEY;
		key_dep [ fontcolor=blue ];
		key_user [ fontcolor=red ];
	};
	A [ fontcolor=red, shape=record ];
	B [ fontcolor=blue, shape=record ];
}

Thanks for reporting. I think this is going to require some thought.

package gographviz

import (
	"testing"
)

// https://github.com/awalterschulze/gographviz/issues/26
func TestIssue26(t *testing.T) {
	input := `digraph g {
    node [shape=record];
    edge [style=dashed];
    subgraph cluster_key {
        graph [label=KEY];
        key_user [fontcolor=red];
        key_dep  [fontcolor=blue];
        key_user -> key_dep;
    }
    A [fontcolor=red];
    B [fontcolor=blue];
    A -> B;
	}`
	g, err := Read([]byte(input))
	if err != nil {
		t.Fatal(err)
	}
	t.Log(g.String())
}

I wrote an expanded version of the test and a partial fix: nkitchen@a9940d.

The test also checks that default attributes are only applied to nodes or edges that appear after them. That's the functionality that my fix does not cover. stmtVisitor.edgeStmt is calling w.g.AddNode unconditionally, which is overwriting the earlier attribute values.

Excellent work :)

With unconditionally you mean whether the node already exists or not, right?

Since the stmtVisitor is going "in order" your fix should work if the node wasn't overwritten later again.

Am I understanding correctly?

Where does it say that the inheritance only works in order?
I think it might be good to reference just for thoroughness.

Yes, that's precisely what I mean by "unconditionally", and yes, I think your understanding of the fix is correct.

From the man page of dot, under "GRAPH FILE LANGUAGE":

Statements may be:

name=val;
node [name=val];
edge [name=val];

Set default graph, node, or edge attribute name to val. Any subgraph, node, or edge appearing after this inherits the new default attributes.

Sorry for the delay I have been and will be really busy this week.

I fixed your test, mostly using your code that you already started

0a96aed

Would you like to add yourself to the contributors or authors as appropriate.

Thank you very much for you great work here :)