# Aligning elements within a subgraph/cluster

**URL:** <https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407>\
**Category:** Help\
**Created:** [August 20, 2024, 6:06am UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407 "2024-08-20T06:06:26Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![jayaprabhakar](https://avatars.discourse-cdn.com/v4/letter/j/90ced4/32.png) [@jayaprabhakar](https://forum.graphviz.org/u/jayaprabhakar)\
**Post date:** [August 20, 2024, 6:06am UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/1 "2024-08-20T06:06:26Z")

</div>

I’m trying to render a graph that looks like a state of an algorithm. For example: I want to render an array, and have another node that has an arrow pointing to an element index.

```auto
digraph {
      rankdir=TB;
// 1. Array of primitive types (horizontal)
    subgraph cluster_array1 {
        style=dashed;
        label="int_array";
        labelfontcolor=lightgray;

        array1_before [label="" shape="inviz" width=0 style=invisible margin="0"];
        array1 [shape=record label="{ {<0>5|<1>4|<2>1|<3>3|<4>2} }"];
        array1_after [label="" shape="inviz" width=0 style=invisible margin="0"];
    }
    # array1_j [label="j=-1"];

    array1_i [label="i=1"];
    array1_i -> array1:1

    array1_j [label="j=-1"]; # The order of the node arra1_j determines the position of array1_before.
    array1_j -> array1_before;
  

    subgraph cluster_array2 {
        style=dashed;
        label="str_array";
        labelfontcolor=lightgray;

        array2_before [label="" shape="inviz" width=0 style=invisible margin="0"];
        array2 [shape=record label="{ <0>abc|<1>def|<2>ghi|<3>jkl|<4>mno }"];
        array2_after [label="" shape="inviz" width=0 style=invisible margin="0"];

    }
    array2_p [label="p=-1"];

    array2_q [label="q=1"];
    array2_q -> array2:1

    array2_p -> array2_before;  
}

```

[Code in viz-js](https://viz-js.com/?dot=ZGlncmFwaCB7CiAgICAgIHJhbmtkaXI9VEI7Ci8vIDEuIEFycmF5IG9mIHByaW1pdGl2ZSB0eXBlcyAoaG9yaXpvbnRhbCkKICAgIHN1YmdyYXBoIGNsdXN0ZXJfYXJyYXkxIHsKICAgICAgICBzdHlsZT1kYXNoZWQ7CiAgICAgICAgbGFiZWw9ImludF9hcnJheSI7CiAgICAgICAgbGFiZWxmb250Y29sb3I9bGlnaHRncmF5OwoKICAgICAgICBhcnJheTFfYmVmb3JlIFtsYWJlbD0iIiBzaGFwZT0iaW52aXoiIHdpZHRoPTAgc3R5bGU9aW52aXNpYmxlIG1hcmdpbj0iMCIgXTsKICAgICAgICBhcnJheTEgW3NoYXBlPXJlY29yZCBsYWJlbD0ieyB7PDA-NXw8MT40fDwyPjF8PDM-M3w8ND4yfSB9IiBdOwogICAgICAgIGFycmF5MV9hZnRlciBbbGFiZWw9IiIgc2hhcGU9Imludml6IiB3aWR0aD0wIHN0eWxlPWludmlzaWJsZSBtYXJnaW49IjAiXTsKICAgIH0KICAgICMgYXJyYXkxX2ogW2xhYmVsPSJqPS0xIl07CgogICAgYXJyYXkxX2kgW2xhYmVsPSJpPTEiXTsKICAgIGFycmF5MV9pIC0-IGFycmF5MToxCgogICAgYXJyYXkxX2ogW2xhYmVsPSJqPS0xIl07ICMgVGhlIG9yZGVyIG9mIHRoZSBub2RlIGFycmExX2ogZGV0ZXJtaW5lcyB0aGUgcG9zaXRpb24gb2YgYXJyYXkxX2JlZm9yZS4KICAgIGFycmF5MV9qIC0-IGFycmF5MV9iZWZvcmU7CiAgCgoKICAgIHN1YmdyYXBoIGNsdXN0ZXJfYXJyYXkyIHsKICAgICAgICBzdHlsZT1kYXNoZWQ7CiAgICAgICAgbGFiZWw9InN0cl9hcnJheSI7CiAgICAgICAgbGFiZWxmb250Y29sb3I9bGlnaHRncmF5OwoKICAgICAgICBhcnJheTJfYmVmb3JlIFtsYWJlbD0iIiBzaGFwZT0iaW52aXoiIHdpZHRoPTAgc3R5bGU9aW52aXNpYmxlIG1hcmdpbj0iMCIgXTsKICAgICAgICBhcnJheTIgW3NoYXBlPXJlY29yZCBsYWJlbD0ieyA8MD5hYmN8PDE-ZGVmfDwyPmdoaXw8Mz5qa2x8PDQ-bW5vIH0iIF07CiAgICAgICAgYXJyYXkyX2FmdGVyIFtsYWJlbD0iIiBzaGFwZT0iaW52aXoiIHdpZHRoPTAgc3R5bGU9aW52aXNpYmxlIG1hcmdpbj0iMCJdOwoKICAgIH0KICAgIGFycmF5Ml9wIFtsYWJlbD0icD0tMSJdOwoKICAgIGFycmF5Ml9xIFtsYWJlbD0icT0xIl07CiAgICBhcnJheTJfcSAtPiBhcnJheTI6MQoKICAgIGFycmF5Ml9wIC0-IGFycmF5Ml9iZWZvcmU7ICAKfQo~)

I need a way to render this correctly. I will be programmatically generating states, so I would want to avoid having to manually edit the text by visually inspecting it.

1. I want a way to represent an array (horizontal and vertical) and tables, along with the variable name. So, the only reliable option I found was to define a subgraph cluster for each variable, have the label of the cluster as variable name. Then set node shape=“record”. I can easily make them look vertical or horizontal or have 2-D table, and I would be able to add direct link from an external node to each cell. This part works without an issue.
2. I need a way to have an invisible node to which an external node can have a link to, to represent when the variable reaches outside the bounds of the array. (Like i=-1 or i=n where n is the length of they 0-indexed array). Here I am having issues.

- For the record node shape, there seems to be no way to keep a zero width (or height for vertical) cells or invisible cells For example: `array1 [shape=record label="{ {<.>|<0>5|<1>4|<2>1|<3>3|<4>2} }"];` creates an empty non-zero width cell.
- On horizontal 1-D array, I couldn’t find a way to keep the before or after node reliably. For example, to point to the case where the index is -1, I want the pointer arrow to point to element left of 0th element, but depending on when the source node of the edge is added, the before shows up after the array.
- On vertical 1-D array, represented as record type with n rows of 1 column, here again, there seems to be no easy way to ensure the before/after nodes appear top or bottom of the array.  
rankdir=LR doesn’t work, because rankdir is the property of graph not subgraph.  
Adding a link from before to 0th element of the array and from nth elelemtn to the after node also doesn’t work because the arrow size is significantly higher making it visually horrible.

Please help me get this to work as expected.

---

<div class="post-metadata">

**Author:** ![steveroush](https://avatars.discourse-cdn.com/v4/letter/s/a9adbd/32.png) [@steveroush](https://forum.graphviz.org/u/steveroush)\
**Post date:** [August 20, 2024, 2:13pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/2 "2024-08-20T14:13:41Z")

</div>

This uses HTML-like labels instead of records. That allows cells with no boundaries ( **sides** ) and no wrestling with **dot** about where invisible nodes should be placed.  
Use of **bgcolor** is optional, of course. Just trying to better define the _out-of-bounds_ nature.

```auto
// changed to HTML-like labels,
// used sides to define out-of-bounds, colors to help location, and compass ports
digraph {
      rankdir=TB;

    subgraph cluster_array1 {
        style=dashed;
        label="int_array";
        labelfontcolor=lightgray;

        array1 [shape=plain label=<
	<table border="0" cellborder="1" cellspacing="0" cellpadding="6"><tr>
	  <td port="before" sides="r" bgcolor="lightpink"> </td>
	  <td port="0">5</td>
	  <td port="1">4</td>
	  <td port="2">1</td>
	  <td port="3">3</td>
	  <td port="4">2</td>
	  <td port="after" sides="l" bgcolor="lightpink"> </td>
	  </tr></table>> ];
    }
 
    array1_i [label="i=1"];
    array1_i -> array1:1
    array1_j [label="j=-1"]; 
    array1_j -> array1:before;

    subgraph cluster_array2 {
        style=dashed;
        label="str_array";
        labelfontcolor=lightgray;

         array2 [shape=plain label=<
 	 <table border="0" cellborder="1" cellspacing="0" cellpadding="6">
	  <tr><td port="before" sides="b" bgcolor="lightpink"> </td></tr>
	  <tr><td port="0">abc</td></tr>
	  <tr><td port="1">def</td></tr>
	  <tr><td port="2">ghi</td></tr>
	  <tr><td port="3">jhl</td></tr>
	  <tr><td port="4">mno</td></tr>
	  <tr><td port="after" sides="t" bgcolor="lightpink"> </td></tr>
	  </table>> ];

    }
    array2_p [label="p=-1"];
    array2_q [label="q=1"];
    ## added compass ports
    array2_q -> array2:1:e
    array2_p -> array2:before:e 
}

```

Giving:  
 ![useSides1](https://global.discourse-cdn.com/graphviz/original/2X/f/fe1e01c98c56d2515f3f6d4253ac950d8a66bf24.png)

---

<div class="post-metadata">

**Author:** ![jayaprabhakar](https://avatars.discourse-cdn.com/v4/letter/j/90ced4/32.png) [@jayaprabhakar](https://forum.graphviz.org/u/jayaprabhakar)\
**Post date:** [August 20, 2024, 4:15pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/3 "2024-08-20T16:15:25Z")

</div>

Thanks. This works great. It looks like I could now avoid the unnecessary subgraph and have a row will colspan for the name, that gives better customization of the appearance.

One issue, I am not sure if this should be a separate question.

The variables i,j,p,q are all placed at much higher at the top than closer to the nodes. Similarly, for this example, it would have been better if p and q are placed left/right of str\_array and have the arrows horizontally.

Although I might be able to manually tune with setting the ranks and rankdir, is there a better way to make the nodes be placed automatically and rankdir chosen for each edge independently to minimize the total length of the edges?

---

<div class="post-metadata">

**Author:** ![steveroush](https://avatars.discourse-cdn.com/v4/letter/s/a9adbd/32.png) [@steveroush](https://forum.graphviz.org/u/steveroush)\
**Post date:** [August 20, 2024, 10:15pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/4 "2024-08-20T22:15:50Z")

</div>

Sorry, one **rankdir** per graph.  
Suggestions - from simplest to hardest:

- Do not mix “horizontal” and “vertical” nodes in one graph. You could create multiple graphs and then use **gvpack** ([https://www.graphviz.org/pdf/gvpack.1.pdf](https://www.graphviz.org/pdf/gvpack.1.pdf)) to glue them together.
- Do not mix “horizontal” and “vertical” nodes on the same rank
- Alter node placement to “top-of-rank” or “bottom-of-rank” (see [reposition nodes within a rank (dot / Graphviz) · GitHub](https://gist.github.com/steveroush/c2c6b6bba00759de8888af2b21961824))
- Try **osage** ([osage | Graphviz](https://www.graphviz.org/docs/layouts/osage/) and [Top Rank Node is not center aligned over some subgraphs - #4 by steveroush](https://forum.graphviz.org/t/top-rank-node-is-not-center-aligned-over-some-subgraphs/2338/4))
- DIY node placement from scratch. Doable, but why in this case?

Here are two graphs in one file ( **dot -O …** ) that created two output files that were then glued together with **gvpack**

```auto
// changed to HTML-like labels,
// used sides to define out-of-bounds, colors to help location, and compass ports
// stopped using cluster for array1
//
// write postscript or use dot ... -O

// horizontal graphs
digraph H {
  rankdir=BT; // note! BT
  array1 [shape=plain label=<
          <table border="0" cellborder="1" cellspacing="0" cellpadding="6">
          <tr><td colspan="6" sides="b" >int_array</td></tr>
          <tr>
          <td port="before" sides="r" bgcolor="lightpink"> </td>
          <td port="0">5</td>
          <td port="1">4</td>
          <td port="2">1</td>
          <td port="3">3</td>
          <td port="4">2</td>
          <td port="after" sides="l" bgcolor="lightpink"> </td>
          </tr></table>> ];
 
    array1_i [label="i=1"];
    array1_j [label="j=-1"];
  
  array1_i -> array1:1
  array1_j -> array1:before;
}

// vertical graphs 
digraph V {
  rankdir=LR;

  array2 [shape=plain label=<
          <table border="0" cellborder="1" cellspacing="0" cellpadding="6">
          <tr><td colspan="1" sides="b" >str_array</td></tr>
          <tr><td port="before" sides="b" bgcolor="lightpink"> </td></tr>
          <tr><td port="0">abc</td></tr>
          <tr><td port="1">def</td></tr>
          <tr><td port="2">ghi</td></tr>
          <tr><td port="3">jhl</td></tr>
          <tr><td port="4">mno</td></tr>
          <tr><td port="after" sides="t" bgcolor="lightpink"> </td></tr>
          </table>> ];

  array2_p [label="p=-1"];
  array2_q [label="q=1"];
  
## added compass ports
  array2:1:e -> array2_q [dir=back] 
  array2_p -> array2:before:w
}

```

Giving:  
 ![o](https://global.discourse-cdn.com/graphviz/original/2X/4/4d0f9d3ddbc0b5ea6c6af7ff4e72fb95674f718f.png)

---

<div class="post-metadata">

**Author:** ![jayaprabhakar](https://avatars.discourse-cdn.com/v4/letter/j/90ced4/32.png) [@jayaprabhakar](https://forum.graphviz.org/u/jayaprabhakar)\
**Post date:** [August 21, 2024, 11:51am UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/5 "2024-08-21T11:51:45Z")

</div>

Thanks.  
I’m not sure about gvpack. But with gvpack would it be possible to add edges between that two graphs?  
For example, if I want to add a link from the int\_array[0] to the str\_array[2]  
Is there a JavaScript/browser implementation for gvpack?

Just some curious question: is this a design choice to not support rankdir at subgraph level or is it some implementation limitation that just was not addressed due to the lack of resources?

---

<div class="post-metadata">

**Author:** ![scnorth](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/scnorth/32/89_2.png) [@scnorth](https://forum.graphviz.org/u/scnorth)\
**Post date:** [August 21, 2024, 1:56pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/6 "2024-08-21T13:56:16Z")

</div>

Yes, mostly a lack of programming resources and know-how at the time. The brittleness of the code doesn’t help.

---

<div class="post-metadata">

**Author:** ![jayaprabhakar](https://avatars.discourse-cdn.com/v4/letter/j/90ced4/32.png) [@jayaprabhakar](https://forum.graphviz.org/u/jayaprabhakar)\
**Post date:** [August 21, 2024, 5:12pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/7 "2024-08-21T17:12:13Z")

</div>

I understand, and thanks for developing/maintaining this wonderful tool. Considering the initial release was 33 years old, I won’t be surprised the complexity.

Also, using C/C++ also doesn’t help either ☹ (not complaining, that was the best option in the early 90s.).

Do you think it would be possible to support a way to build layout plugins in Rust/Go/JavaScript?  
That would increase participation as well.

---

<div class="post-metadata">

**Author:** ![steveroush](https://avatars.discourse-cdn.com/v4/letter/s/a9adbd/32.png) [@steveroush](https://forum.graphviz.org/u/steveroush)\
**Post date:** [August 21, 2024, 10:52pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/8 "2024-08-21T22:52:48Z")

</div>

> [@jayaprabhakar](#):
>
> But with gvpack would it be possible to add edges between that two graphs?  
> For example, if I want to add a link from the int\_array[0] to the str\_array[2]

I am not sure if **gvpack** could handle edges between packed components, but here are two versions of the requested edges added to the _output_ of **gvpack** and then piped to **neato**.  
 ![tweakmet](https://global.discourse-cdn.com/graphviz/original/2X/6/683444892bd3c438c86d6c29a40bf33c992082b9.png)  
 ![tweakmeb](https://global.discourse-cdn.com/graphviz/original/2X/9/9b3087bb0b829bb8ba91d32d7b7531c64bb62abd.png)

> [@jayaprabhakar](#):
>
> Is there a JavaScript/browser implementation for gvpack?

Not that I am aware of.

My guess: Maybe you would get “best result” and “least heartburn” by explicitly assigning **pos** values to all the nodes and then just using **neato** ( **viz-js** ) to layout the edges & create the resultant image.  
If there are only going to be a few nodes (say \< 6-ish), a simple placement algorithm should not be too difficult. Determining the node sizes would be fiddley, but probably manageable (don’t allow infinite font selection).  
Easy for me to say.

Or, if **viz-js** permits, run **viz-js** twice, behind the scenes. Once to size all the nodes, then your code would _only_ have to determine node placement, and then **neato** to produce a finished graph.

---

<div class="post-metadata">

**Author:** ![smattr](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/smattr/32/85_2.png) [@smattr](https://forum.graphviz.org/u/smattr)\
**Post date:** [August 23, 2024, 12:47am UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/9 "2024-08-23T00:47:37Z")

</div>

> [@jayaprabhakar](#):
>
> Do you think it would be possible to support a way to build layout plugins in Rust/Go/JavaScript?

That’s already supported today for languages/wrappers that expose a C ABI. If you can figure out how to build your plugin into a Shared Object and put it in the Graphviz plugin dir, and comprehend `gvplugin_library_load` in the Graphviz source, you should be able to wire it up.

---

<div class="post-metadata">

**Author:** ![steveroush](https://avatars.discourse-cdn.com/v4/letter/s/a9adbd/32.png) [@steveroush](https://forum.graphviz.org/u/steveroush)\
**Post date:** [August 23, 2024, 1:12am UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/10 "2024-08-23T01:12:29Z")

</div>

Here is a list of known “bindings”, including Go & Rust. [External Resources | Graphviz](https://www.graphviz.org/resources/#language-bindings).

Also know that you probably would not have to sweat the edge layout algorithms. Every Graphviz layout engine, except for **dot** , uses the **neato** edge routines.

---

<div class="post-metadata">

**Author:** ![jayaprabhakar](https://avatars.discourse-cdn.com/v4/letter/j/90ced4/32.png) [@jayaprabhakar](https://forum.graphviz.org/u/jayaprabhakar)\
**Post date:** [August 30, 2024, 11:01pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/11 "2024-08-30T23:01:29Z")

</div>

@smattr @steveroush I definitely want to try that. Last I used C/C++ were 25 years ago, when first learning to code before learning Java and others that I never looked back.

Would it be possible for any of you to help me with a tiny tutorial on how to create a layout plugin in any other language like Go, Javascript, Python or any newer languages. In Go, I know how to create a shared object (at least I can find a tutorial) but I don’t know how to get it to work with graphviz.

---

<div class="post-metadata">

**Author:** ![smattr](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/smattr/32/85_2.png) [@smattr](https://forum.graphviz.org/u/smattr)\
**Post date:** [August 31, 2024, 2:27pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/12 "2024-08-31T14:27:35Z")

</div>

I am not sure if it is possible to create a plugin in Java or Python. The problem is that these are “managed” languages in the sense that they have a runtime.

Creating a plugin in Go should work, but I don’t know enough about Go to know how to do this. You could look at one of the newer simpler plugins in the tree like plugin/kitty/gvplugin\_kitty.c to see what symbols you need to expose.

I would suggest first experimenting with how you call into Go from C. Start with a C file like:

```c
extern int doStuff(const char *message);

int main(void) {
  return doStuff("hello world");
}

```

Then figure out how to implement `doStuff` in Go, compile it into a shared library, and then compile the C and have this use your shared library at runtime:

```bash
$ cc -std=c99 main.c -lmy_go_lib
$ env LD_LIBRARY_PATH=$(pwd) ./a.out

```

---

<div class="post-metadata">

**Author:** ![jayaprabhakar](https://avatars.discourse-cdn.com/v4/letter/j/90ced4/32.png) [@jayaprabhakar](https://forum.graphviz.org/u/jayaprabhakar)\
**Post date:** [September 1, 2024, 9:11pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/13 "2024-09-01T21:11:09Z")

</div>

cat mylib.go

```auto
package main

import "C"
import "fmt"

//export doStuff
func doStuff(message *C.char) C.int {
    goMessage := C.GoString(message)
    fmt.Println("Go function received message:", goMessage)
    return 0 
}

```

Compiled using:  
`go build -o libmylib.so -buildmode=c-shared mylib.go `

This created the .h and .so files

```auto
ls -l
total 2880
-rw-r--r-- 1 jp staff 1681 Sep 1 14:06 libmylib.h
-rw-r--r-- 1 jp staff 1458274 Sep 1 14:06 libmylib.so
-rw-r--r-- 1 jp staff 133 Sep 1 14:01 main.c
-rw-r--r-- 1 jp staff 223 Sep 1 14:06 mylib.go

```

`cat main.c`

```auto
#include <stdio.h>
#include "libmylib.h" // Include the generated Go header file

int main(void) {
    return doStuff("hello world");
}

```

Compiled using `cc -std=c99 main.c -L. -lmylib`  
./a.out  
Go function received message: hello world

---

<div class="post-metadata">

**Author:** ![jayaprabhakar](https://avatars.discourse-cdn.com/v4/letter/j/90ced4/32.png) [@jayaprabhakar](https://forum.graphviz.org/u/jayaprabhakar)\
**Post date:** [September 1, 2024, 9:28pm UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/14 "2024-09-01T21:28:17Z")

</div>

Should this be moved into a separate thread, but still keep it public so act as a tutorial?

---

<div class="post-metadata">

**Author:** ![smattr](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/smattr/32/85_2.png) [@smattr](https://forum.graphviz.org/u/smattr)\
**Post date:** [September 3, 2024, 12:19am UTC](https://forum.graphviz.org/t/aligning-elements-within-a-subgraph-cluster/2407/15 "2024-09-03T00:19:23Z")

</div>

I’m fine to continue here, as we don’t know what side quests this exploration might go on.
