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

Try to replicate a dagre layout #21

Closed
tylerlong opened this issue Apr 18, 2018 · 13 comments
Closed

Try to replicate a dagre layout #21

tylerlong opened this issue Apr 18, 2018 · 13 comments
Labels

Comments

@tylerlong
Copy link

tylerlong commented Apr 18, 2018

I have experience with https://github.com/dagrejs/dagre. And below is a layout produced by it:

image

Let's ignore the shapes and assume all of them are rectangles.

I tried the following:

const elk = new ELK({
  defaultLayoutOptions: {
    'elk.algorithm': 'layered',
    'elk.direction': 'RIGHT',
    'elk.padding': '[top=25,left=25,bottom=25,right=25]',
    'elk.spacing.componentComponent': 25, // unconnected nodes are individual subgraphs, referred to as named components
    'elk.layered.spacing.nodeNodeBetweenLayers': 25, // this has effect, but only if there are edges.
    'elk.edgeLabels.inline': true
  }
})
const graph = {
      id: 'root',
      layoutOptions: { 'elk.direction': 'DOWN' },
      children: [
        {
          id: 'n1',
          width: 100,
          height: 50,
          labels: [{ text: 'Chrismas' }]
        },
        {
          id: 'n2',
          width: 100,
          height: 50,
          labels: [{ text: 'Go shopping' }]
        },
        {
          id: 'n3',
          width: 100,
          height: 50,
          labels: [{ text: 'Let me think' }]
        },
        {
          id: 'n4',
          width: 100,
          height: 50,
          labels: [{ text: 'Laptop' }]
        },
        {
          id: 'n5',
          width: 100,
          height: 50,
          labels: [{ text: 'iPhone' }]
        },
        {
          id: 'n6',
          width: 100,
          height: 50,
          labels: [{ text: 'Car' }]
        }
      ],
      edges: [
        {
          id: 'e1',
          sources: ['n1'],
          targets: ['n2'],
          type: 'DIRECTED',
          labels: [{ width: 80, height: 20, text: 'Get money' }]
        },
        {
          id: 'e2',
          sources: ['n2'],
          targets: ['n3'],
          type: 'DIRECTED'
        },
        {
          id: 'e3',
          sources: ['n3'],
          targets: ['n4'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'One' }]
        },
        {
          id: 'e4',
          sources: ['n3'],
          targets: ['n5'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Two' }]
        },
        {
          id: 'e5',
          sources: ['n3'],
          targets: ['n6'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Three' }]
        }
      ]
    }

What I produced is:

image

It is actually not bad!

But I am wondering is it possible to do the following:

  1. make the layout horizontally symmetric
  2. reserve the order of edge labels One, Two & Three.

With above two points achieved, it will be a perfect dagre layout replication.

I am not saying dagre is better. Actually I think elkjs is more flexible. Here I just investigate and learn something about elkjs.

@uruuru
Copy link
Member

uruuru commented Apr 18, 2018 via email

@tylerlong
Copy link
Author

tylerlong commented Apr 18, 2018

I set 'elk.edgeRouting': 'POLYLINE' and it is now balanced:

image

I think I've found a bug: edge label is not inline. I will create a new issue to track it.

Update: as @uruuru said, the key is favourStraightEdges. different edgeRouting value has different default favourStraightEdges values that's why changing edgeRouting value also has effects.

@uruuru
Copy link
Member

uruuru commented Apr 18, 2018 via email

@tylerlong
Copy link
Author

tylerlong commented Apr 18, 2018

@uruuru I cannot make the crossingMinimization.semiInteractive solution work. I tried the following:

const graph = {
      id: 'root',
      layoutOptions: {
        'elk.direction': 'DOWN',
        'elk.layered.crossingMinimization.semiInteractive': true
      },
      children: [
        {
          id: 'n1',
          width: 100,
          height: 50,
          labels: [{ text: 'Chrismas' }]
        },
        {
          id: 'n2',
          width: 100,
          height: 50,
          labels: [{ text: 'Go shopping' }]
        },
        {
          id: 'n3',
          width: 100,
          height: 50,
          labels: [{ text: 'Let me think' }]
        },
        {
          id: 'n4',
          width: 100,
          height: 50,
          labels: [{ text: 'Laptop' }],
          layoutOptions: { 'elk.position': '[x=0,y=0]' }
        },
        {
          id: 'n5',
          width: 100,
          height: 50,
          labels: [{ text: 'iPhone' }],
          layoutOptions: { 'elk.position': '[x=10,y=0]' }
        },
        {
          id: 'n6',
          width: 100,
          height: 50,
          labels: [{ text: 'Car' }],
          layoutOptions: { 'elk.position': '[x=20,y=0]' }
        }
      ],
      edges: [
        {
          id: 'e1',
          sources: ['n1'],
          targets: ['n2'],
          type: 'DIRECTED',
          labels: [{ width: 80, height: 20, text: 'Get money' }]
        },
        {
          id: 'e2',
          sources: ['n2'],
          targets: ['n3'],
          type: 'DIRECTED'
        },
        {
          id: 'e3',
          sources: ['n3'],
          targets: ['n4'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'One' }]
        },
        {
          id: 'e4',
          sources: ['n3'],
          targets: ['n5'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Two' }]
        },
        {
          id: 'e5',
          sources: ['n3'],
          targets: ['n6'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Three' }]
        }
      ]
    }

But it has no effect. Could you please kindly advise?

@tylerlong
Copy link
Author

I've got it:

const elk = new ELK({
  defaultLayoutOptions: {
    'elk.algorithm': 'layered',
    'elk.direction': 'RIGHT',
    'elk.padding': '[top=25,left=25,bottom=25,right=25]',
    'elk.spacing.componentComponent': 25,
    'elk.layered.spacing.nodeNodeBetweenLayers': 25,
    'elk.edgeLabels.inline': true,
    'elk.edgeRouting': 'SPLINES'
  }
})
const graph = {
      id: 'root',
      layoutOptions: {
        'elk.direction': 'DOWN',
        'elk.layered.crossingMinimization.semiInteractive': true,
        'elk.layered.crossingMinimization.strategy': 'INTERACTIVE'
      },
      children: [
        {
          id: 'n1',
          width: 100,
          height: 50,
          labels: [{ text: 'Chrismas' }]
        },
        {
          id: 'n2',
          width: 100,
          height: 50,
          labels: [{ text: 'Go shopping' }]
        },
        {
          id: 'n3',
          width: 100,
          height: 50,
          labels: [{ text: 'Let me think' }]
        },
        {
          id: 'n4',
          width: 100,
          height: 50,
          labels: [{ text: 'Laptop' }],
          layoutOptions: { 'elk.position': '[x=0,y=0]' }
        },
        {
          id: 'n5',
          width: 100,
          height: 50,
          labels: [{ text: 'iPhone' }],
          layoutOptions: { 'elk.position': '[x=10,y=0]' }
        },
        {
          id: 'n6',
          width: 100,
          height: 50,
          labels: [{ text: 'Car' }],
          layoutOptions: { 'elk.position': '[x=20,y=0]' }
        }
      ],
      edges: [
        {
          id: 'e1',
          sources: ['n1'],
          targets: ['n2'],
          type: 'DIRECTED',
          labels: [{ width: 80, height: 20, text: 'Get money' }]
        },
        {
          id: 'e2',
          sources: ['n2'],
          targets: ['n3'],
          type: 'DIRECTED'
        },
        {
          id: 'e3',
          sources: ['n3'],
          targets: ['n4'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'One' }]
        },
        {
          id: 'e4',
          sources: ['n3'],
          targets: ['n5'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Two' }]
        },
        {
          id: 'e5',
          sources: ['n3'],
          targets: ['n6'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Three' }]
        }
      ]
    }

image

@uruuru
Copy link
Member

uruuru commented Apr 18, 2018

Setting 'elk.layered.crossingMinimization.strategy': 'INTERACTIVE' has more effects than you may want. Still, solely setting the semiInteractive doesn't work for me either. I'll double check it later.

@tylerlong tylerlong reopened this Apr 18, 2018
@tylerlong
Copy link
Author

Ok, let's not close it until you post the update.

@uruuru
Copy link
Member

uruuru commented Apr 18, 2018

Can you try setting the positions like so: '(10,20)'. I guess we need to improve the documentation on how to specify these kind of options.

@tylerlong
Copy link
Author

I confirm the following works:

const graph = {
      id: 'root',
      layoutOptions: {
        'elk.direction': 'DOWN',
        'elk.layered.crossingMinimization.semiInteractive': true
      },
      children: [
        {
          id: 'n1',
          width: 100,
          height: 50,
          labels: [{ text: 'Chrismas' }]
        },
        {
          id: 'n2',
          width: 100,
          height: 50,
          labels: [{ text: 'Go shopping' }]
        },
        {
          id: 'n3',
          width: 100,
          height: 50,
          labels: [{ text: 'Let me think' }]
        },
        {
          id: 'n4',
          width: 100,
          height: 50,
          labels: [{ text: 'Laptop' }],
          layoutOptions: { 'elk.position': '(1,0)' }
        },
        {
          id: 'n5',
          width: 100,
          height: 50,
          labels: [{ text: 'iPhone' }],
          layoutOptions: { 'elk.position': '(2,0)' }
        },
        {
          id: 'n6',
          width: 100,
          height: 50,
          labels: [{ text: 'Car' }],
          layoutOptions: { 'elk.position': '(3,0)' }
        }
      ],
      edges: [
        {
          id: 'e1',
          sources: ['n1'],
          targets: ['n2'],
          type: 'DIRECTED',
          labels: [{ width: 80, height: 20, text: 'Get money' }]
        },
        {
          id: 'e2',
          sources: ['n2'],
          targets: ['n3'],
          type: 'DIRECTED'
        },
        {
          id: 'e3',
          sources: ['n3'],
          targets: ['n4'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'One' }]
        },
        {
          id: 'e4',
          sources: ['n3'],
          targets: ['n5'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Two' }]
        },
        {
          id: 'e5',
          sources: ['n3'],
          targets: ['n6'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Three' }]
        }
      ]
    }

So the correct way to specify position is (1,2) instead of [x=1,y=2].

@tylerlong
Copy link
Author

tylerlong commented Apr 19, 2018

And if I specify 'elk.layered.crossingMinimization.strategy': 'INTERACTIVE', I don't need to specify anything else (semiInteractive and node positions) and it just works.

Sample:

    const graph = {
      id: 'root',
      layoutOptions: {
        'elk.direction': 'DOWN',
        // 'elk.layered.crossingMinimization.semiInteractive': true,
        'elk.layered.crossingMinimization.strategy': 'INTERACTIVE'
      },
      children: [
        {
          id: 'n1',
          width: 100,
          height: 50,
          labels: [{ text: 'Chrismas' }]
        },
        {
          id: 'n2',
          width: 100,
          height: 50,
          labels: [{ text: 'Go shopping' }]
        },
        {
          id: 'n3',
          width: 100,
          height: 50,
          labels: [{ text: 'Let me think' }]
        },
        {
          id: 'n4',
          width: 100,
          height: 50,
          labels: [{ text: 'Laptop' }]
          // layoutOptions: { 'elk.position': '(1,0)' }
        },
        {
          id: 'n5',
          width: 100,
          height: 50,
          labels: [{ text: 'iPhone' }]
          // layoutOptions: { 'elk.position': '(2,0)' }
        },
        {
          id: 'n6',
          width: 100,
          height: 50,
          labels: [{ text: 'Car' }]
          // layoutOptions: { 'elk.position': '(3,0)' }
        }
      ],
      edges: [
        {
          id: 'e1',
          sources: ['n1'],
          targets: ['n2'],
          type: 'DIRECTED',
          labels: [{ width: 80, height: 20, text: 'Get money' }]
        },
        {
          id: 'e2',
          sources: ['n2'],
          targets: ['n3'],
          type: 'DIRECTED'
        },
        {
          id: 'e3',
          sources: ['n3'],
          targets: ['n4'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'One' }]
        },
        {
          id: 'e4',
          sources: ['n3'],
          targets: ['n5'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Two' }]
        },
        {
          id: 'e5',
          sources: ['n3'],
          targets: ['n6'],
          type: 'DIRECTED',
          labels: [{ width: 60, height: 20, text: 'Three' }]
        }
      ]
    }

@tylerlong tylerlong reopened this Apr 19, 2018
@tylerlong
Copy link
Author

@uruuru Do you have any idea why 'elk.layered.crossingMinimization.strategy': 'INTERACTIVE' works without me specifying position for nodes?

@uruuru
Copy link
Member

uruuru commented Apr 19, 2018

I'd assume that it's by chance.

@tylerlong
Copy link
Author

Many thanks!

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

No branches or pull requests

2 participants