0

I want to use gnuplot to plot relations rather than the exact coordinates. Something like Igraph in R where I can do A->B without specifying the coordinates in space. I am using a gnuplot script specified on other SO answers inside the system call.

I want to integrate it with my ocaml compiler inside LLVM. If there are any suggestions on that as well, please let me know.

Thank you so much.

theozh
  • 22,244
  • 5
  • 28
  • 72
Hooli
  • 711
  • 2
  • 13
  • 24

1 Answers1

0

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)

enter image description here

theozh
  • 22,244
  • 5
  • 28
  • 72