Ortho edges and ports - a partial work-around

The ortho edge implementation does not handle ports (see Regarding graphviz's "orthogonal" edge routing - #2 by steveroush, [Dot] orthogonal edges in dot (#352) · Issues · graphviz / graphviz · GitLab, or spline = ortho produces unexpected output with ports (#1415) · Issues · graphviz / graphviz · GitLab)

Here is a link (Graphviz: fixOrtho - a work-around to allow ortho edges to connect to ports · GitHub) to a gvpr program that will often allow ortho edges to connect to ports.
It is easy, but not trivial to use:

  1. run dot -Gsplines=true myFile.gv > myFile.dot (Use any layout engine. This will position all the nodes and ports)
  2. run gvpr -cf fixOrtho.gvpr myFile.dot >myfileFixed.dot (This adds nodes and edges and alters existing edges)
  3. run neato -n -Tpng myFileFixed.dot >myfileFixed.png (Creates viewable image)

Note: the commands above can also be run as a single pipeline.

This is modestly tested software (surprisingly complex). Please try it and comment on the gist page. If/when it settles down, it can become part of the Graphviz package it that is desired, though I consider this a temporary “fix”.

Here are three versions of the ports.gv file that is included in the Graphviz source. (The red edge components are just to show the changes)

4 Likes

Hi @steveroush,

I am currently trying to plot a fairly large graph (100s of nodes) and later a larger graph (1000s of nodes). The graph has been partitioned into a 3x3 grid and merged back together using gvpack and some postprocessing though a Python script.

The merged result for a reduced complexity example with only 27 nodes is as follows:

pack_ext.dot:
[dot verbose=true engine=nop2]

digraph root {
	graph [bb="0,0,994,415",
		rankdir=LR,
		splines=ortho
	];
	node [label="{<left> | \N | <right>}",
		shape=record
	];
	subgraph G {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r0c0 {
			graph [bb="0,282,326,415",
				color=blue,
				label="(R:0, C:0)",
				lheight=0.21,
				lp="163,403.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=0,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r0c0_A	[height=0.55556,
				pos="77,365",
				rects="8.5,345.5,39.5,384.5 39.5,345.5,114.5,384.5 114.5,345.5,145.5,384.5",
				width=1.9028];
			r0c0_C	[height=0.55556,
				pos="250,337",
				rects="181.5,317.5,211.5,356.5 211.5,317.5,287.5,356.5 287.5,317.5,318.5,356.5",
				width=1.9028];
			r0c0_A:right -> r0c0_C:left	[pos="e,180.88,351 145.14,351 145.14,351 170.88,351 170.88,351"];
			r0c0_B	[height=0.55556,
				pos="77,309",
				rects="8.5,289.5,38.5,328.5 38.5,289.5,114.5,328.5 114.5,289.5,145.5,328.5",
				width=1.9028];
			r0c0_B:right -> r0c0_C:left	[pos="e,180.88,323 145.14,323 145.14,323 170.88,323 170.88,323"];
		}
	}
	subgraph G_gv1 {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r0c1 {
			graph [bb="334,282,660,415",
				color=blue,
				label="(R:0, C:1)",
				lheight=0.21,
				lp="497,403.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=1,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r0c1_A	[height=0.55556,
				pos="411,365",
				rects="342.5,345.5,373.5,384.5 373.5,345.5,448.5,384.5 448.5,345.5,479.5,384.5",
				width=1.9028];
			r0c1_C	[height=0.55556,
				pos="584,337",
				rects="515.5,317.5,545.5,356.5 545.5,317.5,621.5,356.5 621.5,317.5,652.5,356.5",
				width=1.9028];
			r0c1_A:right -> r0c1_C:left	[pos="e,514.88,351 479.14,351 479.14,351 504.88,351 504.88,351"];
			r0c1_B	[height=0.55556,
				pos="411,309",
				rects="342.5,289.5,372.5,328.5 372.5,289.5,448.5,328.5 448.5,289.5,479.5,328.5",
				width=1.9028];
			r0c1_B:right -> r0c1_C:left	[pos="e,514.88,323 479.14,323 479.14,323 504.88,323 504.88,323"];
		}
	}
	subgraph G_gv2 {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r0c2 {
			graph [bb="668,282,994,415",
				color=blue,
				label="(R:0, C:2)",
				lheight=0.21,
				lp="831,403.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=2,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r0c2_A	[height=0.55556,
				pos="744,365",
				rects="675.5,345.5,706.5,384.5 706.5,345.5,781.5,384.5 781.5,345.5,812.5,384.5",
				width=1.9028];
			r0c2_C	[height=0.55556,
				pos="918,337",
				rects="849.5,317.5,879.5,356.5 879.5,317.5,955.5,356.5 955.5,317.5,986.5,356.5",
				width=1.9028];
			r0c2_A:right -> r0c2_C:left	[pos="e,848.88,351 813.14,351 813.14,351 838.88,351 838.88,351"];
			r0c2_B	[height=0.55556,
				pos="744,309",
				rects="675.5,289.5,705.5,328.5 705.5,289.5,781.5,328.5 781.5,289.5,812.5,328.5",
				width=1.9028];
			r0c2_B:right -> r0c2_C:left	[pos="e,848.88,323 813.14,323 813.14,323 838.88,323 838.88,323"];
		}
	}
	subgraph G_gv3 {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r1c0 {
			graph [bb="0,141,326,274",
				color=blue,
				label="(R:1, C:0)",
				lheight=0.21,
				lp="163,262.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=3,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r1c0_A	[height=0.55556,
				pos="77,224",
				rects="8.5,204.5,39.5,243.5 39.5,204.5,114.5,243.5 114.5,204.5,145.5,243.5",
				width=1.9028];
			r1c0_C	[height=0.55556,
				pos="250,196",
				rects="181.5,176.5,211.5,215.5 211.5,176.5,287.5,215.5 287.5,176.5,318.5,215.5",
				width=1.9028];
			r1c0_A:right -> r1c0_C:left	[pos="e,180.88,210 145.14,210 145.14,210 170.88,210 170.88,210"];
			r1c0_B	[height=0.55556,
				pos="77,168",
				rects="8.5,148.5,38.5,187.5 38.5,148.5,114.5,187.5 114.5,148.5,145.5,187.5",
				width=1.9028];
			r1c0_B:right -> r1c0_C:left	[pos="e,180.88,182 145.14,182 145.14,182 170.88,182 170.88,182"];
		}
	}
	subgraph G_gv4 {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r1c1 {
			graph [bb="334,141,660,274",
				color=blue,
				label="(R:1, C:1)",
				lheight=0.21,
				lp="497,262.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=4,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r1c1_A	[height=0.55556,
				pos="411,224",
				rects="342.5,204.5,373.5,243.5 373.5,204.5,448.5,243.5 448.5,204.5,479.5,243.5",
				width=1.9028];
			r1c1_C	[height=0.55556,
				pos="584,196",
				rects="515.5,176.5,545.5,215.5 545.5,176.5,621.5,215.5 621.5,176.5,652.5,215.5",
				width=1.9028];
			r1c1_A:right -> r1c1_C:left	[pos="e,514.88,210 479.14,210 479.14,210 504.88,210 504.88,210"];
			r1c1_B	[height=0.55556,
				pos="411,168",
				rects="342.5,148.5,372.5,187.5 372.5,148.5,448.5,187.5 448.5,148.5,479.5,187.5",
				width=1.9028];
			r1c1_B:right -> r1c1_C:left	[pos="e,514.88,182 479.14,182 479.14,182 504.88,182 504.88,182"];
		}
	}
	subgraph G_gv5 {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r1c2 {
			graph [bb="668,141,994,274",
				color=blue,
				label="(R:1, C:2)",
				lheight=0.21,
				lp="831,262.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=5,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r1c2_A	[height=0.55556,
				pos="744,224",
				rects="675.5,204.5,706.5,243.5 706.5,204.5,781.5,243.5 781.5,204.5,812.5,243.5",
				width=1.9028];
			r1c2_C	[height=0.55556,
				pos="918,196",
				rects="849.5,176.5,879.5,215.5 879.5,176.5,955.5,215.5 955.5,176.5,986.5,215.5",
				width=1.9028];
			r1c2_A:right -> r1c2_C:left	[pos="e,848.88,210 813.14,210 813.14,210 838.88,210 838.88,210"];
			r1c2_B	[height=0.55556,
				pos="744,168",
				rects="675.5,148.5,705.5,187.5 705.5,148.5,781.5,187.5 781.5,148.5,812.5,187.5",
				width=1.9028];
			r1c2_B:right -> r1c2_C:left	[pos="e,848.88,182 813.14,182 813.14,182 838.88,182 838.88,182"];
		}
	}
	subgraph G_gv6 {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r2c0 {
			graph [bb="0,0,326,133",
				color=blue,
				label="(R:2, C:0)",
				lheight=0.21,
				lp="163,121.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=6,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r2c0_A	[height=0.55556,
				pos="77,83",
				rects="8.5,63.5,39.5,102.5 39.5,63.5,114.5,102.5 114.5,63.5,145.5,102.5",
				width=1.9028];
			r2c0_C	[height=0.55556,
				pos="250,55",
				rects="181.5,35.5,211.5,74.5 211.5,35.5,287.5,74.5 287.5,35.5,318.5,74.5",
				width=1.9028];
			r2c0_A:right -> r2c0_C:left	[pos="e,180.88,69 145.14,69 145.14,69 170.88,69 170.88,69"];
			r2c0_B	[height=0.55556,
				pos="77,27",
				rects="8.5,7.5,38.5,46.5 38.5,7.5,114.5,46.5 114.5,7.5,145.5,46.5",
				width=1.9028];
			r2c0_B:right -> r2c0_C:left	[pos="e,180.88,41 145.14,41 145.14,41 170.88,41 170.88,41"];
		}
	}
	subgraph G_gv7 {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r2c1 {
			graph [bb="334,0,660,133",
				color=blue,
				label="(R:2, C:1)",
				lheight=0.21,
				lp="497,121.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=7,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r2c1_A	[height=0.55556,
				pos="411,83",
				rects="342.5,63.5,373.5,102.5 373.5,63.5,448.5,102.5 448.5,63.5,479.5,102.5",
				width=1.9028];
			r2c1_C	[height=0.55556,
				pos="584,55",
				rects="515.5,35.5,545.5,74.5 545.5,35.5,621.5,74.5 621.5,35.5,652.5,74.5",
				width=1.9028];
			r2c1_A:right -> r2c1_C:left	[pos="e,514.88,69 479.14,69 479.14,69 504.88,69 504.88,69"];
			r2c1_B	[height=0.55556,
				pos="411,27",
				rects="342.5,7.5,372.5,46.5 372.5,7.5,448.5,46.5 448.5,7.5,479.5,46.5",
				width=1.9028];
			r2c1_B:right -> r2c1_C:left	[pos="e,514.88,41 479.14,41 479.14,41 504.88,41 504.88,41"];
		}
	}
	subgraph G_gv8 {
		graph [bb="",
			color="",
			label="",
			lheight="",
			lp="",
			lwidth="",
			penwidth="",
			rankdir=LR,
			shape="",
			sortv="",
			splines=ortho
		];
		node [height="",
			label="{<left> | \N | <right>}",
			pos="",
			rects="",
			shape=record,
			width=""
		];
		edge [headport="",
			pos="",
			tailport=""
		];
		subgraph cluster_r2c2 {
			graph [bb="668,0,994,133",
				color=blue,
				label="(R:2, C:2)",
				lheight=0.21,
				lp="831,121.5",
				lwidth=0.94,
				penwidth=2.0,
				rankdir=LR,
				shape=rectangle,
				sortv=8,
				splines=ortho
			];
			node [height="",
				label="{<left> | \N | <right>}",
				pos="",
				rects="",
				shape=record,
				width=""
			];
			edge [headport="",
				pos="",
				tailport=""
			];
			r2c2_A	[height=0.55556,
				pos="744,83",
				rects="675.5,63.5,706.5,102.5 706.5,63.5,781.5,102.5 781.5,63.5,812.5,102.5",
				width=1.9028];
			r2c2_C	[height=0.55556,
				pos="918,55",
				rects="849.5,35.5,879.5,74.5 879.5,35.5,955.5,74.5 955.5,35.5,986.5,74.5",
				width=1.9028];
			r2c2_A:right -> r2c2_C:left	[pos="e,848.88,69 813.14,69 813.14,69 838.88,69 838.88,69"];
			r2c2_B	[height=0.55556,
				pos="744,27",
				rects="675.5,7.5,705.5,46.5 705.5,7.5,781.5,46.5 781.5,7.5,812.5,46.5",
				width=1.9028];
			r2c2_B:right -> r2c2_C:left	[pos="e,848.88,41 813.14,41 813.14,41 838.88,41 838.88,41"];
		}
	}
}

[/dot]

(Edit: [dot] tag doesn’t seem to work draw edges between subgraphs so here is an image of the graph)

I am now trying to use your code to get orthogonal edges that connect to the ports.

I adapted your steps as follows:

neato -n2 -Gsplines=true pack_ext.dot > tmp.dot
gvpr -cf fixOrtho.gvpr tmp.dot > tmp2.dot
neato -n -Tsvg tmp2.dot > pack.svg

However, I get the following error on the last step:

Warning: the bounding boxes of some nodes touch - falling back to straight line edges

I would be very grateful for any suggestions on how to address this.

Many thanks,
Tim

I can’t find a way to extract your source. Could you embed it within 3 backticks (`) above & below. Like so

source code here

My guess is that you need a larger margin inside the clusters.
But just a guess until I can test with the source.

It rendered fine after a page reload. I took the liberty to add the option verbose=true so the code became visible.

2 Likes

Thanks Magnus :slightly_smiling_face:

Thanks so much for getting back to me and so quickly :slightly_smiling_face:

After Magnus’s edit the source code should now be visible.

I have tried setting large margins, but it didn’t seem to help.

Now, I did get it to draw after changing the last step to:

neato -n -Goverlap=scale -Tsvg tmp2.dot > pack.svg

However, the problem I am now having is that the bounding boxes don’t scale with the subgraphs:

I can increase the margins of subgraphs, but I don’t know how to set a good value other than by trial-and-error and it gives me a lot of unused white space:

Any ideas on how to fix this?

I can’t work on images (just source files), but:

  • try wrapping this subgraph around all your clusters
{ margin=30     //  units = pt  probably more than needed
        // your subgraphs go here
}
  • add ranksep=“.8” // units = inches probably more than needed
  • setting overlap will probably never work, seems to get neato confused