Optimizing graphs is a large and interesting field. And as @eush77 mentioned, Graphviz is a dedicated tool for this type of task.
Although, you could do something with gnuplot. There is a relatively simple algorithm which is based on attracting and repelling forces between vertices. Details can be found e.g. here and here.
First, the script places the vertices at random coordinates and then iterates to a final state (however, which is not always optimal).
You need to play with the constants c1,c2,c3,c4
.
The example below used the gif terminal to visualize the iterations. If you are only interested in the final result, use another terminal and move the replot
after the loop.
The script below is a starting point and can certainly be improved. Suggestions and comments are welcome.
Script: (works with gnuplot>=5.2.0, because of the use of arrays)
### plotting optimized graph
reset session
$Data <<EOD
# ID PointColor
1 0xffaaaa
2 0xaaffaa
3 0xaaaaff
4 0xffaaff
5 0xffffaa
6 0xaaffff
73 0xcccccc
A 0xcccccc
XY 0xcccccc
0 0xffffff
G 0xffffff
# ID1 ID2 LineColor
1 4 0x0000ff
2 4 0x000000
3 4 0x00ff00
5 4 0x000000
6 5 0xff0000
73 3 0xcccccc
73 4 0xcccccc
73 5 0xcccccc
A 2 0xcccccc
A 3 0xcccccc
2 1 0xcccccc
XY 4 0xcccccc
XY 6 0xcccccc
0 2 0xcccccc
0 XY 0xcccccc
G 0 0xcccccc
G A 0xcccccc
EOD
stats $Data u (column(-2)==0?Nv=int($0+1):Ne=int($0+1)) nooutput # get number of vertices and edges
array Vx[Nv]
array Vy[Nv]
array Vt[Nv]
array Vc[Nv]
stats $Data index 0 u (i=int($0)+1, Vt[i]=strcol(1), Vx[i]=rand(0)*10, Vy[i]=rand(0)*10, \
Vc[i]=int($2)) nooutput # random placement of vertices
Vidx(s) = sum[_i=1:|Vx|] ( Vt[_i] eq s ? _i : 0) # get index via lookup of vertex "name"
array E0[Ne]
array E1[Ne]
array Ec[Ne]
stats $Data index 1 u (i=int($0)+1, E0[i]=Vidx(strcol(1)), E1[i]=Vidx(strcol(2)), \
Ec[i]=int($3) ) nooutput # get edge point indices
set size ratio 1
set key noautotitle
set offsets 0.25,0.25,0.25,0.25
unset border
unset tics
set term gif animate delay 20
set output "SO43843240.gif"
plot E0 u (i=int($0+1), x0=Vx[E0[i]]):(y0=Vy[E0[i]]):(Vx[E1[i]]-x0):(Vy[E1[i]]-y0): \
(Ec[i]) w vec lw 2 lc rgb var nohead, \
Vx u (i=int($0+1),Vx[i]):(Vy[i]):(Vc[i]) w p pt 7 ps 6 lc rgb var, \
'' u (i=int($0+1),Vx[i]):(Vy[i]) w p pt 6 ps 6 lc rgb "black", \
'' u (i=int($0+1),Vx[i]):(Vy[i]):(Vt[i]) w labels
# parameters for force
c1 = 2
c2 = 1
c3 = 1
c4 = 0.2
fs(d) = c1*log(d/c2) # force spring attracting/repelling
fr(d) = c3/d # force repelling
dV(i,j) = sqrt((Vx[j]-Vx[i])**2 + (Vy[j]-Vy[i])**2)
set angle degrees
a(i,j) = atan2(Vy[j]-Vy[i], Vx[j]-Vx[i])
array Fx[Nv] # force in x
array Fy[Nv] # force in y
do for [n=1:500] {
set label 1 at screen 1.0,0.97 sprintf("Iteration: % 4d",n) right
# repelling forces
do for [i=1:Nv] {
Fx[i] = Fy[i] = 0 # initialize
do for [j=1:Nv] {
if (i!=j) {
f0 = fr(dV(i,j))
a0 = a(i,j)
Fx[i] = Fx[i] - f0*cos(a0)
Fy[i] = Fy[i] - f0*sin(a0)
}
}
}
# spring forces
do for [n=1:Ne] {
i = E0[n]
j = E1[n]
f0 = fs(dV(i,j))
a0 = a(i,j)
Fx[i]=Fx[i]+f0*cos(a0)
Fy[i]=Fy[i]+f0*sin(a0)
Fx[j]=Fx[j]-f0*cos(a0)
Fy[j]=Fy[j]-f0*sin(a0)
}
# add displacement
do for [i=1:Nv] {
Vx[i] = Vx[i] + c4*Fx[i]
Vy[i] = Vy[i] + c4*Fy[i]
}
stats Fy u 2 nooutput # get maximum change y
if (abs(c4*STATS_max)<0.005) { break } # exit loop when max. y-displacement below threshold
replot
}
set output
### end of script
Result: (animation from gif terminal)
