goccy / go-graphviz

Go bindings for Graphviz
MIT License
730 stars 70 forks source link

Bad rendering #106

Open pebbe opened 3 weeks ago

pebbe commented 3 weeks ago

Rendering of this graph is all wrong:

strict graph gr {

    ranksep=".4"
    nodesep=.05

    margin=.05;
    outputMode="edgesfirst";
    node [shape=box, height=0, width=0, style=filled, fontsize=12, color="#ffc0c0", fontname="Helvetica"];

    n0 [label="top"];
    n1 [label="smain", style=bold, color="#ff0000"];
    n3 [label="np", style=bold, color="#ff0000"];
    n6 [label="ppart", style=bold, color="#ff0000"];

    node [fontname="Helvetica-Oblique", color="#c0c0ff"];

    n2 [label="werd"];
    n4 [label="groot", style=bold, color="#0000ff"];
    n5 [label="alarm", style=bold, color="#0000ff"];
    n7 [label="Wel"];
    n8 [label="meteen"];
    n10 [label="geslagen"];

    {rank=same; edge[style=invis]; n7 -- n2 -- n8 -- n4 -- n5 -- n10}

    edge [sametail=true, samehead=true, color="#d3d3d3", fontname="Helvetica", fontsize=10];

    n0 -- n1 [label=" --  "];
    n1 -- n2 [label=" hd  "];
    n1 -- n3 [label=" su  ", color="#000000"];
    n1 -- n6 [label=" vc  "];
    n3 -- n4 [label=" mod  ", color="#000000"];
    n3 -- n5 [label=" hd  ", color="#000000"];
    n6 -- n7 [label=" mod  "];
    n6 -- n8 [label=" mod  "];
    n6 -- n3 [label=" svp  ", color="#000000"];
    n6 -- n10 [label=" hd  "];

}

How it should look (rendered with the dot program):

ok

How it looks:

wrong

marcelom97 commented 3 weeks ago

Looks to be working fine in this example in all 4 formats.

package main

import (
    "context"
    "fmt"
    "log"
    "os"

    "github.com/goccy/go-graphviz"
)

func main() {
    ctx := context.Background()
    gv, err := graphviz.ParseBytes([]byte(`
 strict graph gr {

     ranksep=".4"
     nodesep=.05

     margin=.05;
     outputMode="edgesfirst";
     node [shape=box, height=0, width=0, style=filled, fontsize=12, color="#ffc0c0", fontname="Helvetica"];

     n0 [label="top"];
     n1 [label="smain", style=bold, color="#ff0000"];
     n3 [label="np", style=bold, color="#ff0000"];
     n6 [label="ppart", style=bold, color="#ff0000"];

     node [fontname="Helvetica-Oblique", color="#c0c0ff"];

     n2 [label="werd"];
     n4 [label="groot", style=bold, color="#0000ff"];
     n5 [label="alarm", style=bold, color="#0000ff"];
     n7 [label="Wel"];
     n8 [label="meteen"];
     n10 [label="geslagen"];

     {rank=same; edge[style=invis]; n7 -- n2 -- n8 -- n4 -- n5 -- n10}

     edge [sametail=true, samehead=true, color="#d3d3d3", fontname="Helvetica", fontsize=10];

     n0 -- n1 [label=" --  "];
     n1 -- n2 [label=" hd  "];
     n1 -- n3 [label=" su  ", color="#000000"];
     n1 -- n6 [label=" vc  "];
     n3 -- n4 [label=" mod  ", color="#000000"];
     n3 -- n5 [label=" hd  ", color="#000000"];
     n6 -- n7 [label=" mod  "];
     n6 -- n8 [label=" mod  "];
     n6 -- n3 [label=" svp  ", color="#000000"];
     n6 -- n10 [label=" hd  "];
 }`))
    if err != nil {
        log.Fatal("failed to parse graphviz: ", err)
    }

    g, err := graphviz.New(ctx)
    if err != nil {
        log.Fatal("failed to create graphviz: ", err)
    }

    formats := []graphviz.Format{graphviz.PNG, graphviz.SVG, graphviz.JPG, graphviz.XDOT}
    for _, format := range formats {
        f, err := os.Create(fmt.Sprintf("example.%s", format))
        if err != nil {
            log.Fatal("failed to create file: ", err)
        }
        defer f.Close()

        if err := g.Render(ctx, gv, format, f); err != nil {
            // don't exit here, just log the error
            fmt.Printf("failed to render graph to %s: %v\n", format, err)
        }
    }
}
pebbe commented 3 weeks ago

Running this code I get what you see below. Only the svg version (top right) looks identical to the original (top left). Is it something platform dependant? I am using Go version go1.23.2 on linux/amd64.

screen1

pebbe commented 3 weeks ago

Or is it a library version thing? This is my go.mod for this program:

require github.com/goccy/go-graphviz v0.2.9

require (
        github.com/disintegration/imaging v1.6.2 // indirect
        github.com/flopp/go-findfont v0.1.0 // indirect
        github.com/fogleman/gg v1.3.0 // indirect
        github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
        github.com/tetratelabs/wazero v1.8.1 // indirect
        golang.org/x/image v0.21.0 // indirect
        golang.org/x/text v0.19.0 // indirect
)
marcelom97 commented 2 weeks ago

I ran it on go1.23.2 darwin/arm64

Maybe try to run it in docker on a different platform

WolvenSpirit commented 1 week ago

Same bug with rendering edges happens on my platform also (which is actually Github codespace)

$ uname -ai
Linux codespaces-51c77b 6.5.0-1025-azure #26~22.04.1-Ubuntu SMP Thu Jul 11 22:33:04 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux
go version go1.23.1 linux/amd64

From go.mod

require github.com/goccy/go-graphviz v0.2.9

require (
    github.com/disintegration/imaging v1.6.2 // indirect
    github.com/flopp/go-findfont v0.1.0 // indirect
    github.com/fogleman/gg v1.3.0 // indirect
    github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
    github.com/tetratelabs/wazero v1.8.1 // indirect
    golang.org/x/image v0.22.0 // indirect
    golang.org/x/text v0.20.0 // indirect
)

image Reproducing it in codespace would be trivial as it happens out of the box.

goccy commented 1 week ago

It’s likely an issue with the feature you are using. Does the rendering break with a simpler example as well ? If not, please provide a minimal sample.

WolvenSpirit commented 1 week ago

An example, I skipped a lot of things to get a really slim code sample. Note: The codespace dev env is as provided by Github nothing was installed besides this library via go get ....

package main

import (
    "context"

    gv "github.com/goccy/go-graphviz"
)

func main() {
    ctx := context.Background()
    g, _ := gv.New(ctx)
    graph, _ := g.Graph()
    a, _ := graph.CreateNodeByName("a")
    b, _ := graph.CreateNodeByName("b")
    c, _ := graph.CreateNodeByName("c")
    d, _ := graph.CreateNodeByName("d")
    e, _ := graph.CreateNodeByName("e")
    f, _ := graph.CreateNodeByName("f")
    a.Root().CreateEdgeByName("a-b", a, b)
    a.Root().CreateEdgeByName("a-c", a, c)
    b.Root().CreateEdgeByName("b-c", b, c)
    a.Root().CreateEdgeByName("a-d", a, d)
    d.Root().CreateEdgeByName("d-e", d, e)
    e.Root().CreateEdgeByName("e-f", e, f)
    g.RenderFilename(ctx, graph, "png", "sample.png")
}

Output image While the svg code would seem to render properly when doing

// instead of RenderFilename
buff := new(bytes.Buffer)
g.Render(ctx, graph, "svg", buff)
ioutil.WriteFile("sample.svg", buff.Bytes(), fs.ModePerm)

Output image

So probably this is either specific to RenderFilename or rendering png/jpg specifically.