jacomyal / sigma.js

A JavaScript library aimed at visualizing graphs of thousands of nodes and edges
https://www.sigmajs.org
MIT License
11.22k stars 1.59k forks source link

How to generate a json file from dot file understood by sigmajs #1366

Closed vricosti closed 1 year ago

vricosti commented 1 year ago

Hi,

I would like to use the json loading feature and when I look at an example I can see that the json has the following format:

{
  "nodes": [
    {
      "key": "0.0",
      "attributes": {
        "x": 268.72385,
        "y": 91.18155,
        "size": 22.714287,
        "label": "Myriel",
        "color": "#D8482D"
      }
    },
    {
      "key": "1.0",
      "attributes": {
        "x": 296.39902,
        "y": 57.118374,
        "size": 15,
        "label": "Napoleon",
        "color": "#B30000"
      }
    },
    {
      "key": "2.0",
      "attributes": {
        "x": 248.45229,
        "y": 52.22656,
        "size": 16.714285,
        "label": "MlleBaptistine",
        "color": "#BB100A"
      }
    },
    {
      "key": "3.0",
      "attributes": {
        "x": 224.83313,
        "y": 98.01885,
        "size": 16.714285,
        "label": "MmeMagloire",
        "color": "#BB100A"
      }
    },
  ],
  "edges": [
    {
      "key": "0",
      "source": "1.0",
      "target": "0.0",
      "attributes": {
        "size": 1
      }
    },
    {
      "key": "1",
      "source": "2.0",
      "target": "0.0",
      "attributes": {
        "size": 8
      }
    },
    {
      "key": "2",
      "source": "3.0",
      "target": "0.0",
      "attributes": {
        "size": 10
      }
    },
    {
      "key": "3",
      "source": "3.0",
      "target": "2.0",
      "attributes": {
        "size": 6
      }
    }
  ]
}

However I have a dot file looking like that:

digraph {
    graph [bb="0,0,6591,3780",
        splines=false
    ];
    node [label="\N"];
    {
        "A" [height=0.5,
            label="A",
            pos="145.68,3762",
            width=3.2422];
        B   [height=0.5,
            label=B,
            pos="570.68,3690",
            width=2.1843];
        "C" [height=0.5,
            label="C",
            pos="351.68,3618",
            width=2.3332];
        "D" [height=0.5,
            label="D",
            pos="86.684,3618",
            width=2.4079];
    }
    ...

And I have tried all the graphviz output format and I never managed to get a format like that. Do I have to convert it manually ?

sim51 commented 1 year ago

Hi, sorry I don't know if a lib that convert DOT notation to JSON exists. Have you search on npm ?

vricosti commented 1 year ago

some answers suggests to use graphviz since it supportes the following formats: //'canon', 'cmap', 'cmapx', 'cmapx_np', 'dot', 'dot_json', 'eps', 'fig', 'gv', 'imap', 'imap_np',
//'ismap', 'json', 'json0', 'mp', 'pic', 'plain', 'plain-ext', 'pov', 'ps', 'ps2', 'svg', 'tk', 'xdot', //'xdot1.2', 'xdot1.4', 'xdot_json'

I have also found a python script (based on networkx and pydot) but the result does not look like the one I want.

Or does sigmajs implements a layout as good as graphviz because the resulting graph is ugly compared to it.

sim51 commented 1 year ago

I don't know what you want to have, so I can't answer to your question.

Personnaly, I use graphviz to make documentation (ex: to explain a graph structure), but not to display graphs with a huge number of nodes.

In fact it seems that graphviz can produce a json : https://graphviz.org/docs/outputs/json/ Then it's easy to transform this output to the one that graphology needs.

If you need help, the best location is stackoverflow (github's issue are for bugs).

Cheers.

vricosti commented 1 year ago

Finally here is how I did it:

import * as Viz from '@viz-js/viz'
import * as dot from 'graphlib-dot'

// Fix for @viz-js/viz
global.atob = function(str) {
    return Buffer.from(str, 'base64').toString('binary');
}

public async getGraph(flowid: number) {
        return this.getNodesAndBacklinks(flowid)
        .then((rows) => {
            //console.table(rows);
            //... here is I build a dot graph from some database info
            return graphDotFmt;
        })
        .then((dotFmtStr) => {
            return Viz.instance().then(function(viz) {
                // From the simple dot file we ask graphviz to generate an optimized layout in dot format
                let dotLayoutFmtStr = viz.renderString(dotFmtStr, {
                    engine:'dot',
                    format: 'dot',
                }); 
                return dotLayoutFmtStr;
            });
        })
        .then((dotLayoutFmtStr) => {

            let output = {
                nodes: [],
                edges: [],
              };
             // Parse dot file 
            let digraph = dot.read(dotLayoutFmtStr);
            for (const nodeName of digraph.nodes()) {
                //console.log('nodeName: ', nodeName);
                if (nodeName.startsWith('sg')) { continue; }

                const attrs = digraph.node(nodeName);
                let pos = attrs.pos.split(",").map(parseFloat);

                output.nodes.push({
                    key: nodeName,
                    x: pos[0],
                    y: pos[1],
                    size: 7,
                    label: attrs.label,
                    color: "#D8482D"
                });
              }

              // Populate the edges
              for (const edge of digraph.edges()) {
                output.edges.push({
                  source: edge.v,
                  target: edge.w,
                });
              }

              const jsonGraph = JSON.stringify(output, null, 2);
              return jsonGraph;
            // Save the dot layout string to a file
            //return saveToFile('output/jsonGraph.json', jsonGraph)
            //.then(() => jsonGraph);
        })
        .catch(error => {
            console.error('An error occurred:', error);
        });
    }