drawing a perpendicular bisector of two points in gnuplot - graph

Say, I have two points (x1,y1) and (x2,y2) on the same line . The midpoint of joining this two points is (x,y). Is it possible to draw a perpendicular bisector through (x,y) in gnuplot? How will I draw it?

It's simple math:
your line slope: slope = (y2 - y1) / (x2 - x1)
your line equation: line(x) = slope * (x - x1) + y1
the middle point (calling it xm,ym because x,y are reserved):
xm=(x1+x2)/2.0
ym=(y1+y2)/2.0
the perpendicular line equation: line_perp(x) = -(x-xm)/slope + ym
plot both: plot line(x), line_perp(x)
In case y2==y1 or x2==x1 i.e the two points are in horizontal/vertical line you can fix the script using an arrow:
if (y2==y1 || x2==x1) {
set arrow from xm, graph 0 to xm, graph 1 nohead
plot ym
} else {
plot line(x), line_perp(x)
}

Instead of going via y = a*x + b as in #bibi's and #user4489658's answers, where a could be infinite, I would go via the angle (check help atan2).
This covers vertical lines without extra treatment.
Make sure to use set size ratio -1 (check help size) that the perpendicular bisector really looks perpendicular in the graph.
Script:
### drawing perpendicular bisectors
reset session
$Data <<EOD
# x1 y1 x2 y2
10 20 15 20
10 10 20 20
20 10 20 15
12 10 18 12
10 12 12 18
EOD
set key out
set offset 1,1,1,1
set angle degrees
set size ratio -1
colX1 = 1
colY1 = 2
colX2 = 3
colY2 = 4
dx(n) = column(colX2)-column(colX1)
dy(n) = column(colY2)-column(colY1)
a0(n) = atan2(dy(n),dx(n)) + 90
xm(n) = (column(colX1)+column(colX2))*0.5
ym(n) = (column(colY1)+column(colY2))*0.5
Scaling = 0.2
L0(n) = Scaling*sqrt(dx(n)**2 + dy(n)**2)
getParams(n) = (dx0=L0(0)*cos(a0(0)), dy0=L0(0)*sin(a0(0)), x0=xm(0)-dx0, y0=ym(0)-dy0)
plot $Data u colX1:colY1 w p pt 7 lc "blue" ti "Start", \
'' u colX2:colY2 w p pt 7 lc "red" ti "End", \
'' u colX1:colY1:(dx(0)):(dy(0)) w vec lc "web-green" filled ti "Vector", \
'' u (getParams(0),x0):(y0):(2*dx0):(2*dy0) w vec lc "black" dt 3 nohead ti "\nperpendicular\nbisector"
### end of script
Result:

Equation of your line is
y=ax+b
a=(y2-y1)/(x2-x1)
b=(x2*y1-y2*x1)/(x2-x1)
Midpoint:
x3=(x1+x2)/2.;y3=(y1+y2)/2.
Equation of perpendicular line:
y-y3=-1./a*(x-x3)
y=-1./a*x+x3/a+y3
a2=-1./a
b2=x3/a+y3
gnuplot script:
x1=1.;y1=3.;x2=10.;y2=15.
a=(y2-y1)/(x2-x1)
b=(x2*y1-y2*x1)/(x2-x1)
x3=(x2+x1)/2.;y3=(y2+y1)/2.
a2=-1./a
b2=x3/a+y3
set arrow 1 from x1,y1 to x2,y2 nohead
plot [0:15][0:22] a2*x+b2

Related

Positioning objects parallel with a mesh

I'm trying to align multiple line objects along a human body circumference depending on the orientation of the triangles from the mesh. I would like to put the lines parallel to the mesh. I correctly assign the position for the lines along the circumference, but I also need to add the rotation of the lines such that to be parallel with the body.
The body is a mesh formed by multiple triangles and every line is "linked" with a triangle.
All I have is:
3 points for the closest triangle from the mesh for every line
The normal of the triangle
The positions for the instantiated lines (2 points, start and end)
I need to calculate the angle for every X, Y, Z axes for the line such that the normal of the triangle is perpendicular with the line mesh. I don't know how to get the desired angle. I really appreciate if someone would like to help me.
input:
FVector TrianglePoints[3];
FVector Triangle_Normal; //Calculated as (B-A)^(C-A), where A,B,C are the points of the triangle
FVector linePosition; //I also have the start line and the endLine position if that helps
ouput:
//FRotator rotation(x,y,z), such that the triangle normal and the line object to be perpendicular.
An overview of the circumference line construction. Now the rotation is calculated using the Start position and End position for each line. When we cross some irregular parts of the mesh we want to rotate the lines correctly. Now the rotation is fixed, depending just on the line start and end position.
If I have understood correctly your goal, here is some related vector geometry:
A,B,C are the vertices of the triangle:
A = [xA, yA, zA],
B = [xB, yB, zB]
C = [xC, yC, zC]
K,L are the endpoints of the line-segment:
K = [xK, yK, zK]
L = [xL, yL, zL]
vectors are interpreted as row-vectors
by . I denote matrix multiplication
by x I denote cross product of 3D vectors
by t() I denote the transpose of a matrix
by | | I denote the norm (magnitude) of a vector
Goal: find the rotation matrix and rotation transformation of segment KL
around its midpoint, so that after rotation KL is parallel to the plane ABC
also, the rotation is the "minimal" angle rotation by witch we need to
rotate KL in order to make it parallel to ABC
AB = B - A
AC = C - A
KL = L - K
n = AB x AC
n = n / |n|
u = KL x n
u = u / |u|
v = n x u
cos = ( KL . t(v) ) / |KL|
sin = ( KL . t(n) ) / |KL|
U = [[ u[0], u[1], u[2] ],
[ v[0], v[1], v[2] ],
[ n[0], n[1], n[2] ],
R = [[1, 0, 0],
[0, cos, sin],
[0, -sin, cos]]
ROT = t(U).R.U
then, one can rotate the segment KL around its midpoint
M = (K + L)/2
Y = M + ROT (X - M)
Here is a python script version
A = np.array([0,0,0])
B = np.array([3,0,0])
C = np.array([2,3,0])
K = np.array([ -1,0,1])
L = np.array([ 2,2,2])
KL = L-K
U = np.empty((3,3), dtype=float)
U[2,:] = np.cross(B-A, C-A)
U[2,:] = U[2,:] / np.linalg.norm(U[2,:])
U[0,:] = np.cross(KL, U[2,:])
U[0,:] = U[0,:] / np.linalg.norm(U[0,:])
U[1,:] = np.cross(U[2,:], U[0,:])
norm_KL = np.linalg.norm(KL)
cos_ = KL.dot(U[1,:]) / norm_KL
sin_ = KL.dot(U[2,:]) / norm_KL
R = np.array([[1, 0, 0],
[0, cos_, sin_],
[0,-sin_, cos_]])
ROT = (U.T).dot(R.dot(U))
M = (K+L) / 2
K_rot = M + ROT.dot( K - M )
L_rot = M + ROT.dot( L - M )
print(L_rot)
print(K_rot)
print(L_rot-K_rot)
print((L_rot-K_rot).dot(U[2,:]))
A more inspired solution was to use a procedural mesh, generated at runtime, that have all the requirements that I need:
Continuously along multiple vertices
Easy to apply a UV map for texture tiling
Can be updated at runtime
Isn't hard to compute/work with it

How to plot a graph in gnuplot without specifying the coordinates of vertices?

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.
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)

gnuplot change color of the connecting lines

I am using gnuplot for the following. I have n equations which I want to plot based on the xaxis value. Here is a sample
set xrange[0:25]
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
plot (x>0)&&(x<10)?f1(x):(x<20)?f2(x):f3(x)
I know that we can set the color of the line easily by using the below. But it changes the whole color
set style line 1 lt 1 lw 3 pt 3 lc rgb "blue"
But what I want is to make the connecting lines a different color. ie if you plot the above graph you will 5 lines. 3 original lines (from the function) and 2 lines (the almost vertical lines) connecting them. I want to change the color of the connecting lines.
Note 1: These functions are automatically generated by a program, and the number of functions could be large. Even the exact plot command is automatically generated
Note 2: I want a way to differentiate my original lines with the interpolated lines which joins my original lines.
Any help is appreciated
What you actually have is one line defined piecewise, and there isn't an easy way to define colors for line segments within a piecewise line in gnuplot.
Easy way (plot a data file)
I would recommend making a data file looking like this:
# x y color
0 0 0
10 10 0
10 10 1
10 30 1
10 30 0
20 60 0
20 60 1
20 200 1
20 200 0
25 250 0
Notice the double points at x=10 and x=20. This is so the line segments meet at the transitions.
Now plot it with linecolor variable:
#!/usr/bin/env gnuplot
reset
set terminal pdfcairo enhanced color dashed rounded lw 5 size 3,2 font 'Arial,14'
set output 'output2.pdf'
set style data lines
set key top left
set tics scale 0.5 out nomirror
plot 'data.dat' u 1:2:3 lc variable
It looks like this:
You can change the palette (set palette) to determine the colors, and you can have more than 2 color values in the data file if you want.
Harder way (only OK for few segments)
You could define 2n-1 separate lines and connect them:
#!/usr/bin/env gnuplot
reset
set terminal pdfcairo enhanced color dashed rounded lw 5 size 3,2 font 'Arial,14'
set output 'output.pdf'
set style data lines
set key top left
set tics scale 0.5 out nomirror
# points every 0.001 units in the range 0:25
set samples 25001
# main lines
f1(x) = (x <= 9.999) ? x : 1/0
f3(x) = (x >= 10.001) && (x <= 19.999) ? 3*x : 1/0
f5(x) = (x >= 20.001) ? 10*x : 1/0
# define slopes and y-offsets of connecting lines
m2 = (f3(10.001)-f1(9.999))/0.002
b2 = (30.0-10.0)/2.0 + 10.0
m4 = (f5(20.001)-f3(19.999))/0.002
b4 = (200.0-60.0)/2.0 + 60.0
# connecting functions
f2(x) = (x >= 9.999) && (x <= 10.001) ? m2*(x-10) + b2 : 1/0
f4(x) = (x >= 19.999) && (x <= 20.001) ? m4*(x-20) + b4 : 1/0
plot [0:25] f1(x), f2(x), f3(x), f4(x), f5(x)
Which looks like this:
You can define a secondary function to define the breakpoints of your function, which is automatically coloring the right linepiece. The below code is easy to extend to different functions and breakpoints (i.e., you can just change x1 or x2). Adding multiple points is also straightforward.
xmin=0.
xmax=25.
x0=0.
x1=10.
x2=20.
nsample=200.
dx=(xmax-xmin)/nsample
print dx
set xrange[xmin:xmax]
set sample nsample
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
f4(x) = (x>x0)&&(x<x1)?f1(x):(x<x2)?f2(x):f3(x)
f5(x) = x
f5(x) = ( (x>x1&&x<=x1+dx) || (x>x2&&x<=x2+dx) )?1:0
set cbrange [0:1]
unset key
plot '+' using 1:(f4($1)):(f5($1)) lc variable with lines
Not that I have use the special filename '+', which just constructs a data file with equally space datapoints (following nsample).
If it is ok to skip the connecting lines, then you can use a simplified version of #andyras second variant. Just define all functions to be 1/0 when outside a specified range:
set style data lines
unset key
f1(x) = (x > 0) && (x < 10) ? x : 1/0
f2(x) = (x > 10) && (x < 20) ? 3*x : 1/0
f3(x) = (x > 20) ? 10*x : 1/0
plot [0:25] f1(x), f2(x), f3(x)
Following yet another possibility. This assumes, that you can select a sampling high enough, so that the "jumps" which connect the functions are always greater than inside a function:
set style data lines
unset key
set xrange[0:25]
f1(x) = x
f2(x) = 3*x
f3(x) = 10*x
f(x) = ( (x>0)&&(x<10)?f1(x):(x<20)?f2(x):f3(x) )
set samples 1000
curr = 0
prev = 0
lim = 1
plot '+' using (prev = curr, curr=f($1), $1):(f($1)):(abs(curr-prev) < lim ? 0 : 1) lc var

Finding the coordinates of a point contained by a trapezoid programmatically

If I have a trapezoid defined by four points (x1, y1), (x2, y2), (x3, y3), (x4, y4) (chosen as (255, 0), (255, 235), (200, 35), and (200, 235) for the sake of the example), and I divide it arbitrarily in n by m sections like so (pardon the crude drawing):
How could I find the coordinates of (x, y)?
I've tried fooling around with the slopes of the lines, but my math skills are too rusty to figure it out. Any ideas?
For the specific case as per your example it's quite straight forward.
First, the x location is easy. Since the verticals will always be parallel to the y axis, x is simply x width divided by the number of sections:
x = x1+((x2-x1)/a*xa)
where:
x = result coordinate
x1,x2 = edges of the trapezoid
a = number of sections
xa = x coordinate in term of sections
note: I chose a to avoid confusion with the symbol for slope: m.
For y it's a bit more complicated. We first need to find the coordinate that sits on the top and bottom lines of the trapezoid. We use the standard line equation for this:
y = mx+c
Finding m is simple. It's just Dy/Dx:
m = (y2-y1)/(x2-x1)
To get c we just substitute x, y and m into the formula:
c = y-mx
Once we get that, substitute the value of x found earlier into the formula to get the y coordinate. Do this twice to get the points on the top and bottom lines:
1 A 2
x------------x--------------x
| | |
| xC |
| | |
x------------x--------------x
3 B 4
All together (pseudocode):
coordinateFromSection (x1 y1 x2 y2 x3 y3 x4 y4 gridX gridY sectionX sectionY) {
xC = x1+((x2-x1)/gridX*sectionX)
// top line:
m = (y2-y1)/(x2-x1)
c = y1-(m*x1)
yA = m*xC + c
// bottom line:
m = (y4-y3)/(x4-x3)
c = y3-(m*x3)
yB = m*xC + c
// Find yC by dividing line AB by gridY
yC = yA+((yB-yA)/gridY*sectionY)
return (xC yC)
}
All the calculations above assume that (0,0) is the top left of the screen.

How to Create a Spider Plot in Gnuplot?

I would like to produce a spider (aka radar/star) plot using Gnuplot where different axes have independent scales. I am able to produce such a plot using OriginPro (commercial), but with Gnuplot I am only able to set a radar plot with uniform scale.
The (csv file) dataset looks like the following (first row is column labels):
# FEATURE, Product_A, Product_B, Product_C, Product_D
attribute_1, 2, 10, 7, 3.5
attribute_2, 1, 0.5, 3,4
attribute_3, 37, 58, 49, 72
attribute_4, 1985, 1992, 2006, 2010
attribute_5, 0.1, 0.5, 0.3, 0.8
and the plot I am looking for is this one: https://www.dropbox.com/s/uvqubzqvm6puhb8/spider.pdf -
As you can see each axis stands for a different attribute, and has its own scale.
I guess the Gnuplot starting code is:
set polar
set grid polar
set angles degrees
set size square
set style data filledcurves
But I don't know how to proceed. Any suggestions?
here's a hack attempt..
set nokey
set polar
set grid polar
set angles degrees
set size square
set style data lines
a1=0
a2=30
a3=100
a4=200
a5=300
set arrow nohead from 0,0 to first 10*cos(a1) , 10*sin(a1)
set arrow nohead from 0,0 to first 10*cos(a2) , 10*sin(a2)
set arrow nohead from 0,0 to first 10*cos(a3) , 10*sin(a3)
set arrow nohead from 0,0 to first 10*cos(a4) , 10*sin(a4)
set arrow nohead from 0,0 to first 10*cos(a5) , 10*sin(a5)
set xrange [-10:10]
set yrange [-10:10]
plot '-' using ($1==1?a1:($1==2?a2:($1==3?a3:($1==4?a4:($1==5?a5:$1))))):2 lt 2
1 4
2 8
3 6
4 9
5 5
1 4
Here is a suggestion for a "spider-plot" taken from my collection.
Since it uses data from a datablock instead from a file (because it's easier to address certain lines, e.g. via $Data[1]), therefore, it requires gnuplot >=5.2.0.
The actual data is in $Data and some settings for ranges and custom offset adjustments are in $Settings.
The number of axes is automatically adjusted if you add some more rows in $Data and $Settings. Data needs to be separated by whitespace, because the gnuplot function word(string,number) is used to extract some values.
I hope it is more or less self-explaining. Comments, report of bugs or improvements are welcome.
Code:
### spider plot/chart with gnuplot
# also known as: radar chart, web chart, star chart, cobweb chart,
# radar plot, web plot, star plot, cobweb plot, etc. ...
reset session
set size square
unset tics
set angles degree
set key top left
# Data
$Data <<EOD
SpiderData "Product A" "Product B" "Product C" "Product D"
Colors red green blue violet
"attribute 1" 2 10 7 3.5
"attribute 2" 1 0.5 3 4
"attribute 3" 37 58 49 72
"attribute 4" 1985 1992 2006 2010
"attribute 5" 0.1 0.5 0.3 0.8
EOD
HeaderLines = 2
# Settings for scale and offset adjustments
# axis min max tics axisLabelXoff axisLabelYoff ticLabelXoff ticLabelYoff
$Settings <<EOD
1 0 12 6 0.00 -0.02 -0.05 0.00
2 0 6 6 0.00 0.05 0.00 0.05
3 30 90 6 0.00 0.00 0.05 0.03
4 1980 2016 6 0.00 0.00 0.09 -0.02
5 0 1.2 6 0.00 0.05 0.00 -0.05
EOD
# General settings
DataColCount = words($Data[1])-1
AxesCount = |$Data|-HeaderLines
AngleOffset = 90
Max = 1
d=0.1*Max
Direction = -1 # counterclockwise=1, clockwise = -1
# Tic settings
TicCount = 6
TicValue(axis,i) = real(i)*(word($Settings[axis],3)-word($Settings[axis],2)) \
/ word($Settings[axis],4)+word($Settings[axis],2)
TicLabelPosX(axis,i) = PosX(axis,i/TicCount) + word($Settings[axis],7)
TicLabelPosY(axis,i) = PosY(axis,i/TicCount) + word($Settings[axis],8)
TicLen = 0.03
TicdX(axis,i) = 0.5*TicLen*cos(alpha(axis)-90)
TicdY(axis,i) = 0.5*TicLen*sin(alpha(axis)-90)
# Functions
alpha(axis) = (axis-1)*Direction*360.0/AxesCount+AngleOffset
PosX(axis,R) = R*cos(alpha(axis))
PosY(axis,R) = R*sin(alpha(axis))
Scale(axis,value) = real(value-word($Settings[axis],2))/(word($Settings[axis],3)-word($Settings[axis],2))
# Spider settings
set style arrow 1 dt 1 lw 1.0 lc -1 head # style for axes
set style arrow 2 dt 2 lw 0.5 lc -1 nohead # style for weblines
set style arrow 3 dt 1 lw 1 lc -1 nohead # style for axis tics
set samples AxesCount
set isosamples TicCount
set urange[1:AxesCount]
set vrange[1:TicCount]
do for [i=1:DataColCount] { # set linetypes/colors
set linetype i lc rgb word($Data[2],i+1)
}
set style fill transparent solid 0.2
set xrange[-Max-4*d:Max+4*d]
set yrange[-Max-4*d:Max+4*d]
plot \
'+' u (0):(0):(PosX($0,Max+d)):(PosY($0,Max+d)) w vec as 1 not, \
$Data u (PosX($0+1,Max+2*d)+word($Settings[$0+1],5)): \
(PosY($0+1,Max+2*d)+word($Settings[$0+1],6)):1 every ::HeaderLines w labels center enhanced not, \
'++' u (PosX($1,$2/TicCount)):(PosY($1,$2/TicCount)): \
(PosX($1+1,$2/TicCount)-PosX($1,$2/TicCount)): \
(PosY($1+1,$2/TicCount)-PosY($1,$2/TicCount)) w vec as 2 not, \
'++' u (PosX($1,$2/TicCount)-TicdX($1,$2/TicCount)): \
(PosY($1,$2/TicCount)-TicdY($1,$2/TicCount)): \
(2*TicdX($1,$2/TicCount)):(2*TicdY($1,$2/TicCount)) \
w vec as 3 not, \
for [i=1:DataColCount] $Data u (PosX($0+1,Scale($0+1,column(i+1)))): \
(PosY($0+1,Scale($0+1,column(i+1)))) every ::HeaderLines w filledcurves lt i title word($Data[1],i+1), \
'++' u (TicLabelPosX($1,$2)):(TicLabelPosY($1,$2)): \
(sprintf("%g",TicValue($1,$2))) w labels font ",8" not
### end of code
Result:
The answer by #george helped me figure out how to rearrange the dataset, in order to pick from it the corresponding attribute data.
Because I was also looking for different range scales for the different spider axes, in addition to #george's suggestion, I thought that an axis-specific normalisation to the common [0:1] range, would have the problem solved. The main modification is then related to the using field of the plot command.
The code is fairly lengthy, I'm sure it could be optimised. It could also be merged into a script or a simple C code, in order to let the user decide the number of axes (number of attributes), and the different ranges (min, max) for each specific axis.
The following example is for 5 attributes comparing 2 products. Here is shown the plot result image:
set nokey
set polar
set angles degrees
npoints = 5
a1 = 360/npoints*1
a2= 360/npoints*2
a3= 360/npoints*3
a4= 360/npoints*4
a5= 360/npoints*5
set grid polar 360.
set size square
set style data lines
unset border
set arrow nohead from 0,0 to first 1*cos(a1) , 1*sin(a1)
set arrow nohead from 0,0 to first 1*cos(a2) , 1*sin(a2)
set arrow nohead from 0,0 to first 1*cos(a3) , 1*sin(a3)
set arrow nohead from 0,0 to first 1*cos(a4) , 1*sin(a4)
set arrow nohead from 0,0 to first 1*cos(a5) , 1*sin(a5)
a1_max = 10
a2_max = 5
a3_max = 100
a4_max = 2020
a5_max = 1
a1_min = 0
a2_min = 0
a3_min = 50
a4_min = 1980
a5_min = 0
set label "(0:10)" at cos(a1),sin(a1) center offset char 1,1
set label "(0:5)" at cos(a2),sin(a2) center offset char -1,1
set label "(50:100)" at cos(a3),sin(a3) center offset char -1,-1
set label "(1980:2020)" at cos(a4),sin(a4) center offset char 0,-1
set label "(0:1)" at cos(a5),sin(a5) center offset char 3,0
set xrange [-1:1]
set yrange [-1:1]
unset xtics
unset ytics
set rrange [0:1]
set rtics (""0,""0.25,""0.5,""0.75,""1)
plot '-' using ($1==1?a1:($1==2?a2:($1==3?a3:($1==4?a4:($1==5?a5:$1))))):($1==1?(($2-a1_min)/(a1_max-a1_min)):($1==2?(($2-a2_min)/(a2_max-a2_min)):($1==3?(($2-a3_min)/(a3_max-a3_min)):($1==4?(($2-a4_min)/(a4_max-a4_min)):($1==5?(($2-a5_min)/(a5_max-a5_min)):$1))))) w l
1 8
2 3
3 67
4 2000
5 0.2
1 8
plot '-' using ($1==1?a1:($1==2?a2:($1==3?a3:($1==4?a4:($1==5?a5:$1))))):($1==1?(($2-a1_min)/(a1_max-a1_min)):($1==2?(($2-a2_min)/(a2_max-a2_min)):($1==3?(($2-a3_min)/(a3_max-a3_min)):($1==4?(($2-a4_min)/(a4_max-a4_min)):($1==5?(($2-a5_min)/(a5_max-a5_min)):$1))))) w l
1 6
2 1.5
3 85
4 2010
5 0.5
1 6
The following repo shows a spider chart with homogeneous scales. https://github.com/orey/gnuplot-radarchart
For your particular case, I would:
-Create functions that would normalize all data to fit in the diagram scale,
-Hide tge standard scale,
-Use arrows for the axis,
-Add points with labels for your particular scales and place them with your data functions.
I think inspiration can be found in the repo.

Resources