# Saving and Restoring New Node/Edge Positions

**URL:** <https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525>\
**Category:** Help\
**Created:** [March 19, 2023, 7:45pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525 "2023-03-19T19:45:32Z")\
**Posts on this page:** 15\
**Page:** 1

<div class="post-metadata">

**Author:** ![bbx999](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@bbx999](https://forum.graphviz.org/u/bbx999)\
**Post date:** [March 19, 2023, 7:45pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/1 "2023-03-19T19:45:32Z")

</div>

Hi everyone,

I’ve been reading through other posts to try and make sure I’m not asking a duplicate question, but I didn’t find anything quite on point.

I’m trying to support a use case where users will be able to decide to take control of layout on a given diagram and manually reposition nodes and edges. I want to be able to save those new node and edge positions and restore the custom-laid out graph as needed. I also want to be able to add nodes to the graph in a way that does not place those nodes on previously manually positioned nodes.

I thought it might be clever to generate a diagram using dot and then when a user moves a node, to capture the new position, and then regenerate the graph using neato, which supports node positions via pos. However, the translation does not seem to be perfect and I’m wondering why. As a simple test, if I take a dot graph and output to dot (which includes pos for each node / edge) and then use that as input for neato, it does not come out looking the same.

Here’s the input dot:

```auto
digraph {
bgcolor="transparent"
nodesep="0.5"
ranksep="0.75"
fontname="Helvetica"
node [fontsize="10" fontname="Helvetica" fillcolor="#111827" color="#111827" penwidth="0.75"]
edge [fontsize="10" fontname="Helvetica" color="#111827" penwidth="0.75"]
"1679216963259" [id="1679216963259" shape="oval" fontcolor="#111827" color="#111827" margin="0,0.05" width="3" height="1" fixedsize=true color="#111827" fillcolor="#FFFFFF" style="filled" label=<<table border="0" cellborder="0" cellspacing="0" cellpadding="0"><tr><td><font point-size="13"><b>Bob</b></font></td></tr></table>>]
"1679216654435" [id="1679216654435" shape="rectangle" fontcolor="#111827" color="#111827" margin="0.12,0.11" width="3" height="1" fixedsize=true color="#111827" fillcolor="#FFFFFF" style="filled" label=<<table border="0" cellborder="0" cellspacing="0" cellpadding="0"><tr><td><font point-size="13"><b>ABC Inc.</b></font></td></tr><tr><td></td></tr><tr><td></td></tr></table>>]
"1679216963259"->"1679216654435" [arrowsize=0 label=<100%>]
}

```

Here’s the output dot to input into neato:

```auto
digraph {
	graph [bb="0,0,216,210",
		bgcolor=transparent,
		fontname=Helvetica,
		nodesep=0.5,
		ranksep=0.75
	];
	node [color="#111827",
		fillcolor="#111827",
		fontname=Helvetica,
		fontsize=10,
		label="\N",
		penwidth=0.75
	];
	edge [color="#111827",
		fontname=Helvetica,
		fontsize=10,
		penwidth=0.75
	];
	1679216963259	[fillcolor="#FFFFFF",
		fixedsize=true,
		fontcolor="#111827",
		height=1,
		id=1679216963259,
		label=<<table border="0" cellborder="0" cellspacing="0" cellpadding="0"><tr><td><font point-size="13"><b>Bob</b></font></td></tr></table>>,
		margin="0,0.05",
		pos="108,174",
		shape=oval,
		style=filled,
		width=3];
	1679216654435	[fillcolor="#FFFFFF",
		fixedsize=true,
		fontcolor="#111827",
		height=1,
		id=1679216654435,
		label=<<table border="0" cellborder="0" cellspacing="0" cellpadding="0"><tr><td><font point-size="13"><b>ABC Inc.</b></font></td></tr><tr><td></td></tr><tr><td></td></tr></table>>,
		margin="0.12,0.11",
		pos="108,36",
		shape=rectangle,
		style=filled,
		width=3];
	1679216963259 -> 1679216654435	[arrowsize=0,
		label=<100%>,
		lp="120.79,105",
		pos="e,108,71.607 108,138.33 108,118.03 108,92.461 108,72.087"];
}

```

Why doesn’t this work as I expected? I tried playing with inputscale but that didn’t seem to do much. Also, if anyone has any better suggestions on how to achieve this, it would be much appreciated.

Thanks for your time,

Brett

---

<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:** [March 19, 2023, 8:43pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/2 "2023-03-19T20:43:19Z")

</div>

I believe the only thing “missing” is the **-n** option on the **neato** command line. Like so: `neato -n -Tpng myfile.gv>myfile.png` (see [FAQ | Graphviz](https://graphviz.org/faq/#FaqDotWithNodeCoords))  
**neato** will use the (new) node positions & generate appropriate (pretty much) edges.  
Explicitly generating new edges is more of a challenge (see [Fun with edges!](https://forum.graphviz.org/t/fun-with-edges/888))  
Also note that **neato** is OK with (oblivious to) overlapping nodes, and the results can be fun (or not). (see [Stupid Dot tricks](https://forum.graphviz.org/t/stupid-dot-tricks/31))

---

<div class="post-metadata">

**Author:** ![bbx999](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@bbx999](https://forum.graphviz.org/u/bbx999)\
**Post date:** [March 20, 2023, 7:31am UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/3 "2023-03-20T07:31:14Z")

</div>

Thanks for the quick reply! That addresses the issue I raised, and apparently I should have read the FAQ a bit closer.

It seems that having fixed positions is an all or nothing thing? I.e. it is not possible to have fixed positions for nodes X and Y but not for Z and expect neato to put Z somewhere reasonable?

---

<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:** [March 20, 2023, 2:51pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/4 "2023-03-20T14:51:30Z")

</div>

It all depends. The **neato** and **fdp** layout engines will let you use the **pin** attribute ([pin | Graphviz](https://graphviz.org/docs/attrs/pin/)) to fix the location of nodes (not edges). Note the comment in the **pos** documentation about units are points, not inches.  
But **neato** will not do a “good” job of adding nodes to a graph that originated from one of the other layout engines (e.g. **dot** ).

Out of curiosity, why might your users want to add nodes and not re-layout?

---

<div class="post-metadata">

**Author:** ![bbx999](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@bbx999](https://forum.graphviz.org/u/bbx999)\
**Post date:** [March 20, 2023, 3:23pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/5 "2023-03-20T15:23:17Z")

</div>

Thanks for the additional explanation and the pin suggestion.

The app I’m working on calculates new states based on changes in underlying data. But the data is sequentially dependent, kind of like in Excel how if you have cell A1 + cell A2 with the total in A3, if A1 changes, A3 will recalculate. In my app, the user can change A1, at which point the recalculation might add nodes to A3, at which point the user will likely want to re-layout themselves if not relying on the auto-layout. I would just want the new nodes to appear somewhere reasonable for the user to then re-layout (and perhaps not on top of other nodes).

Regarding the units being points, that was a bit of a gotcha for me this morning. I started playing with perhaps using another library to handle the movement of nodes (something that would provide more interactivity features out-of-the-box). The first surprise was that it seems like the positions of pos are relative to the bottom right corner, is that correct? I inferred that because the lower node in the example above has a ‘y’ pos of 36, while the node above it has a ‘y’ pos of 174. When I rendered those coordinates in another diagramming library which uses pixels (so after multiplying by 96/72), the lower node was on top. So I ended up using the bounding box size to calculate when the ‘y’ position would be if using the top left corner as the reference point.

The pos also being the center of the node required calculating the top left corner, which seemed doable since I just had the width and height. I also had to multiple the font size by 96/72.

So far I was able to reproduce a simple chart using the graphviz coordinates, just two nodes with one edge between them.

Any other tips are much appreciated, thanks!

---

<div class="post-metadata">

**Author:** ![Vithanco](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/vithanco/32/292_2.png) [@Vithanco](https://forum.graphviz.org/u/Vithanco)\
**Post date:** [March 26, 2023, 3:42pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/6 "2023-03-26T15:42:14Z")

</div>

bbx999 I am in need of a similar approach. I consider a button to do a full re-layout, and otherwise let the user do gradual changes, based on the previous locations. neato allows to draw all the edges and the locations are kept. New nodes will then be needed to be placed manually.

Problem for me is a “location memory” in a shared session. People keep locations of information in their heads and it’s difficult to keep track. The standard graphviz algorithm is moving things around a lot and this is confusing for others that are not in charge of the session’s network graph.

---

<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:** [March 26, 2023, 4:15pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/7 "2023-03-26T16:15:22Z")

</div>

It can be quite confusing & annoying when a “small” change is made to a a network definition (one “tiny” node or edge is added or deleted) but he resulting layout is unrecognizably different.  
Possibly the **layers** feature ([FAQ | Graphviz](https://graphviz.org/faq/#FaqOverlays)) can help.  
**Layers** can definitely help preserve consistency in alternative networks (“what if”) and can also help when presenting changes going “backward” in time.  
Here links to **layers** usage:

- [Getting layers to work with SVG - #3 by steveroush](https://forum.graphviz.org/t/getting-layers-to-work-with-svg/107/3)
- [Stupid Dot Tricks #2 - Making a video](https://forum.graphviz.org/t/stupid-dot-tricks-2-making-a-video/109)
- [How to pin centrain nodes? How to preserve edges between graphs?](https://forum.graphviz.org/t/how-to-pin-centrain-nodes-how-to-preserve-edges-between-graphs/1250)

---

<div class="post-metadata">

**Author:** ![bbx999](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@bbx999](https://forum.graphviz.org/u/bbx999)\
**Post date:** [March 26, 2023, 5:39pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/8 "2023-03-26T17:39:33Z")

</div>

@steveroush Do layers just achieve the ability to more easily hide / show groups of nodes and edges by associating them with a specific layer (and without triggering a new layout calculation)? Or does putting nodes and edges into different layers somehow also impact the layer calculation?

---

<div class="post-metadata">

**Author:** ![bbx999](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@bbx999](https://forum.graphviz.org/u/bbx999)\
**Post date:** [March 26, 2023, 5:40pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/9 "2023-03-26T17:40:23Z")

</div>

What do you mean by shared session here? What’s your use case?

---

<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:** [March 26, 2023, 6:12pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/10 "2023-03-26T18:12:55Z")

</div>

**Layer** layout is performed once, based on the (super)set of all nodes, edges, and clusters that appear in any of the individual layers. All nodes, edges, and clusters have their positions calculated. Each node, edge, cluster can “appear” in any number of layers (1, 2, n, all).  
Then, each layer can be drawn based on the (sub)set of nodes, edges, and clusters that it includes.  
If you add a new layer, there is a good chance that the entire graph (all the layers) will change, but each of the newly positioned layers will be consistent.  
A set of pictures is worth 10,000 words in this case. I suggest playing with the example in the **FAQ** - then add some new (or delete existing) nodes and/or edges.  
Note that there are some problems with the implementation. My comments about **layerselect** should help.  
Maybe **layers** will work for you and maybe not.

---

<div class="post-metadata">

**Author:** ![Vithanco](https://sea2.discourse-cdn.com/graphviz/user_avatar/forum.graphviz.org/vithanco/32/292_2.png) [@Vithanco](https://forum.graphviz.org/u/Vithanco)\
**Post date:** [March 26, 2023, 6:25pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/11 "2023-03-26T18:25:23Z")

</div>

Several people in front of one screen.

---

<div class="post-metadata">

**Author:** ![bbx999](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@bbx999](https://forum.graphviz.org/u/bbx999)\
**Post date:** [April 18, 2023, 3:15pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/12 "2023-04-18T15:15:17Z")

</div>

Thanks for the clarification.

---

<div class="post-metadata">

**Author:** ![bbx999](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@bbx999](https://forum.graphviz.org/u/bbx999)\
**Post date:** [April 18, 2023, 3:18pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/13 "2023-04-18T15:18:12Z")

</div>

Understood @Vithanco. I’ve definitely experienced people having trouble following when presenting and making changes to a graph where things get reshuffled. Perhaps an initial automatic layout followed by, as you said, manual node positions would work better.

If you give neato the positions of nodes, can/will it route the edges nicely between them?

---

<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:** [April 18, 2023, 3:39pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/14 "2023-04-18T15:39:53Z")

</div>

`neato -n`  
will take explicitly positioned nodes (and clusters) and then position your edges ([FAQ | Graphviz](https://graphviz.org/faq/#FaqDotWithNodeCoords)). The edge positioning is not always identical to **dot** ’s, but very similar to it.  
If you want splined edges, you must explicitly set **splines=true** because **neato** defaults to **splines=false**

---

<div class="post-metadata">

**Author:** ![bbx999](https://avatars.discourse-cdn.com/v4/letter/b/ad7895/32.png) [@bbx999](https://forum.graphviz.org/u/bbx999)\
**Post date:** [April 18, 2023, 7:39pm UTC](https://forum.graphviz.org/t/saving-and-restoring-new-node-edge-positions/1525/15 "2023-04-18T19:39:12Z")

</div>

Thanks!
