Gnuplot 3D: x + y = const - gnuplot

How do I draw a vertical plane that is represented by:
x + y = 1
^
|
1y | \
| \
| \ <-- this vertical plane
| \
| \
<-----------------------+----------------------->
-1x | -1x
|
|
|
-1y |
|
v
Additionally I need to display multiple complex 3D equations (without parametric) at the same time.

You can use parametric to plot your 3D equations like this:
f(x,y) = sin(x**2 + y**2)/(x**2 + y**2)
set parametric
splot u,v,f(u,v)
Together with the plane, a full script could look as follows:
set parametric
f(x,y) = sin(x**2 + y**2)/(x**2 + y**2)
const = 5
set xrange [-5:5]
set yrange [-5:5]
set ticslevel 0
splot u,const-u,v title 'plane', u,v,f(u,v) title '3D equation'
For you real use case you might need to scale the v used as z-axis of the plane and maybe also the urange and vrange.

Related

gnuplot: arrows between circles

How can I draw arrows between circles where
the arrows point to the centers of the circles,
but have reduced length such that they only touch the circumference,
independent of the terminal size ratio?
Sounds easy, but I haven't found a shorter solution than the example below. You need to to some coordinate transformations between axes coordinates and terminal coordinates.
For this, you need to know the terminal size of the plot and you'll get these values into the GPVAL_... variables only after plotting you have to do a dummy plot first and then replot.
If I overlooked some obvious and simpler procedure, please let me know.
Code:
### arrows touching circles
reset session
# Factor between axes and terminal coordinates
FactorX(n) = real(GPVAL_X_MAX-GPVAL_X_MIN)/(GPVAL_TERM_XMAX-GPVAL_TERM_XMIN)
FactorY(n) = real(GPVAL_Y_MAX-GPVAL_Y_MIN)/(GPVAL_TERM_YMAX-GPVAL_TERM_YMIN)
# Axis coordinates to terminal coordinates
AxisToTermX(x) = (x-GPVAL_X_MIN)/FactorX(0)+GPVAL_TERM_XMIN
AxisToTermY(y) = (y-GPVAL_Y_MIN)/FactorY(0)+GPVAL_TERM_YMIN
xt(x) = AxisToTermX(x)
yt(y) = AxisToTermY(y)
rt(r) = r/FactorX(0)
Lt(x1,y1,x2,y2) = sqrt((xt(x2)-xt(x1))**2 + (yt(y2)-yt(y1))**2)
# terminal coordinates reduced by radii
x1tr(x1,y1,r1,x2,y2,r2) = rt(r1)*(xt(x2)-xt(x1))/Lt(x1,y1,x2,y2)+xt(x1)
y1tr(x1,y1,r1,x2,y2,r2) = rt(r1)*(yt(y2)-yt(y1))/Lt(x1,y1,x2,y2)+yt(y1)
x2tr(x1,y1,r1,x2,y2,r2) = (Lt(x1,y1,x2,y2)-rt(r2))*(xt(x2)-xt(x1))/Lt(x1,y1,x2,y2) + xt(x1)
y2tr(x1,y1,r1,x2,y2,r2) = (Lt(x1,y1,x2,y2)-rt(r2))*(yt(y2)-yt(y1))/Lt(x1,y1,x2,y2) + yt(y1)
# Terminal coordinates to axis coordinates
TermToAxisX(xt) = real(xt-GPVAL_TERM_XMIN)*FactorX(0)+GPVAL_X_MIN
TermToAxisY(yt) = real(yt-GPVAL_TERM_YMIN)*FactorY(0)+GPVAL_Y_MIN
# axis coordinates reduced by radii
x1r(x1,y1,r1,x2,y2,r2) = TermToAxisX(x1tr(x1,y1,r1,x2,y2,r2))
y1r(x1,y1,r1,x2,y2,r2) = TermToAxisY(y1tr(x1,y1,r1,x2,y2,r2))
x2r(x1,y1,r1,x2,y2,r2) = TermToAxisX(x2tr(x1,y1,r1,x2,y2,r2))
y2r(x1,y1,r1,x2,y2,r2) = TermToAxisY(y2tr(x1,y1,r1,x2,y2,r2))
# dummy plot
set xrange [-10:10]
set yrange [-10:10]
plot NaN notitle
$Data <<EOD
0 0 1.0
-6 2 3.0
0 5 0.75
7 -8 2.0
5 8 1.5
EOD
N = |$Data| # length of datablock
# draw N circles
do for [i=0:N-1] {
set obj i+1 circle at word($Data[i+1],1),word($Data[i+1],2) size word($Data[i+1],3) fc "blue"
}
# draw N arrows
do for [i=0:N-1] {
x1 = word($Data[i+1],1)
y1 = word($Data[i+1],2)
r1 = word($Data[i+1],3)
x2 = word($Data[(i+1)%N+1],1)
y2 = word($Data[(i+1)%N+1],2)
r2 = word($Data[(i+1)%N+1],3)
set arrow i+1 from x1r(x1,y1,r1,x2,y2,r2), y1r(x1,y1,r1,x2,y2,r2) \
to x2r(x1,y1,r1,x2,y2,r2), y2r(x1,y1,r1,x2,y2,r2) heads lc "red"
}
replot
### end of code
Result: (wxt size 600,600)
The same code with (wxt size 700,300)

symmetric logarithmic plot (symlog)

How would you make a symlog plot in gnuplot?
matplolib has such a feature:
I'm thinking about some axis + tics manipulation or multiplot where on panel has reversed axis.
Finally, I need this for the z axis (cbrange) the show the residuals as an image.
symlog(x) = (-1 < x && x < 1) ? x/10. \
: (x < 0) ? -log(-x) - 0.1 \
: log(x) + 0.1
invsymlog(x) = (-0.1 < x && x < 0.1) ? x*10. \
: (x < 0) ? -exp(-(x+0.1)) \
: exp(x-0.1)
set xlabel "Symlog axis"
set nonlinear x via symlog(x) inv invsymlog(x)
set xrange [-4*pi : 4*pi]
set sample 500
set xtics -10,1,10 nomirror
set xtics add ("//" 0)
set xtics font ",10"
plot x*cos(x)
The region between -1 and +1 is linear, the rest is log scale.

Break y-axis in three parts in gnuplot

I try to plot some data that has a huge gap in the y axis which I wish to exclude from the graph.
noises:
I found this guide to split the graph into two parts, which works great for me.
reset
unset key
bm = 0.15
lm = 0.12
rm = 0.95
gap = 0.03
size = 0.75
y1 = 9.25e+06; y2 = 9.35e+06; y3 = 1.24e+07; y4 = 1.25e+07
set multiplot
set xlabel 'Number of Iterations'
set border 1+2+8
set xtics nomirror
set ytics nomirror
set lmargin at screen lm
set rmargin at screen rm
set bmargin at screen bm
set tmargin at screen bm + size * (abs(y2-y1) / (abs(y2-y1) + abs(y4-y3) ) )
set yrange [y1:y2]
plot 'upquValues.dat' title 'upper quartile', 'MedianValues.dat' using 1 title 'median value', 'loquValues.dat' title 'lower quartile', 'MeanValues.dat' using 1 title 'mean value';
unset xtics
unset xlabel
set border 2+4+8
set bmargin at screen bm + size * (abs(y2-y1) / (abs(y2-y1) + abs(y4-y3) ) ) + gap
set tmargin at screen bm + size + gap
set yrange [y3:y4]
set label 'Runtime [ns]' at screen 0.03, bm + 0.5 * (size + gap) offset 0,-strlen("PRuntime [ns]")/4.0 rotate by 90
set arrow from screen lm - gap / 4.0, bm + size * (abs(y2-y1) / (abs(y2-y1)+abs(y4-y3) ) ) - gap / 4.0 to screen \
lm + gap / 4.0, bm + size * (abs(y2-y1) / (abs(y2-y1) + abs(y4-y3) ) ) + gap / 4.0 nohead
set arrow from screen lm - gap / 4.0, bm + size * (abs(y2-y1) / (abs(y2-y1)+abs(y4-y3) ) ) - gap / 4.0 + gap to screen \
lm + gap / 4.0, bm + size * (abs(y2-y1) / (abs(y2-y1) + abs(y4-y3) ) ) + gap / 4.0 + gap nohead
set arrow from screen rm - gap / 4.0, bm + size * (abs(y2-y1) / (abs(y2-y1)+abs(y4-y3) ) ) - gap / 4.0 to screen \
rm + gap / 4.0, bm + size * (abs(y2-y1) / (abs(y2-y1) + abs(y4-y3) ) ) + gap / 4.0 nohead
set arrow from screen rm - gap / 4.0, bm + size * (abs(y2-y1) / (abs(y2-y1)+abs(y4-y3) ) ) - gap / 4.0 + gap to screen \
rm + gap / 4.0, bm + size * (abs(y2-y1) / (abs(y2-y1) + abs(y4-y3) ) ) + gap / 4.0 + gap nohead
plot 'upquValues.dat' title 'upper quartile', 'MedianValues.dat' using 1 title 'median value', 'loquValues.dat' title 'lower quartile', 'MeanValues.dat' using 1 title 'mean value';
unset multiplot
noises_break
How Can I split it into three parts now? Also the legend and title of the graph does get lost, which I also would like to fix.
My next problem includes saving the graph as png or postscript.
When I first use set term png; set output 'img.png' I generate an empty img.png file. When I plot first and set the term later and use replot only the upper graph is printed.
A simple way to "mimic" two axis breaks is to use set multiplot layout 3,1 and to fix the y-ranges accordingly and to replot your data.
Code:
### two axes breaks
reset session
set colorsequence classic
set key left
set multiplot layout 3,1
set lmargin 5
unset xtics
set border 14
set ytic 1
set yrange [8:10]
plot x, sin(x)*10, -0.3*x**2+10
unset key
set border 10
set yrange [-2:2]
replot
set border 11
set xtics nomirror
set yrange [-10:-8]
replot
unset multiplot
### end of code
Result:
To your other question:
If I use png or pngcairo or postscript terminal, I do:
set term pngcairo
set output 'img.png'
plot x
set output
If I omit the last set output I will get a file 'img.png' with 0 bytes.

Generation of pie chart using gnuplot

I have a CSV file with data like:
name,age
raju,23
anju,34
manju,56
sanju,56
I'm trying to generate a pie chart using gnuplot.
Here's the command I'm executing:
#!/usr/bin/gnuplot -persist
reset
set terminal wxt
unset key
set datafile separator ","
set xlabel "USERS"
set ylabel "AGE"
plot 'file.csv' using ($0):2:($0):xticlabels(1) with circles lc variable notitle
What am I doing wrong?
Apparently, Gnuplot does not support pie charts yet; but we can draw it by hand.
First, we need to obtain the angles and percentages related to the second column in your datafile:
set datafile separator ','
stats 'file.csv' u 2 noout # get STATS_sum (sum of column 2)
ang(x)=x*360.0/STATS_sum # get angle (grades)
perc(x)=x*100.0/STATS_sum # get percentage
Then configure the canvas:
set size square # square canvas
set xrange [-1:1.5]
set yrange [-1.25:1.25]
set style fill solid 1
unset border
unset tics
unset key
and draw the pie chart:
Ai = 0.0; Bi = 0.0; # init angle
mid = 0.0; # mid angle
i = 0; j = 0; # color
yi = 0.0; yi2 = 0.0; # label position
plot 'file.csv' u (0):(0):(1):(Ai):(Ai=Ai+ang($2)):(i=i+1) with circle linecolor var,\
'file.csv' u (1.5):(yi=yi+0.5/STATS_records):($1) w labels,\
'file.csv' u (1.3):(yi2=yi2+0.5/STATS_records):(j=j+1) w p pt 5 ps 2 linecolor var,\
'file.csv' u (mid=Bi+ang($2)*pi/360.0, Bi=2.0*mid-Bi, 0.5*cos(mid)):(0.5*sin(mid)):(sprintf('%.0f (%.1f\%)', $2, perc($2))) w labels
The first line in the plot command draws the pie chart, where the columns (0):(0):(1):(Ai):(Ai=Ai+ang($2)):(i=i+1) are:
columns 1-2: x and y coordinates of the center of the disk
column 3: radius of the disk
column 4-5: begin and end angles of the region
column 6: color of the region
The second and third lines in the plot command place the labels, and the last line puts the percentages in the middle of each region.
The result:
References: (1) Gnuplot surprising (2) Gnuplot tricks
EDIT:
Based on two related questions (this and this), a new script is proposed:
filename = 'test.csv'
rowi = 1
rowf = 7
# obtain sum(column(2)) from rows `rowi` to `rowf`
set datafile separator ','
stats filename u 2 every ::rowi::rowf noout prefix "A"
# rowf should not be greater than length of file
rowf = (rowf-rowi > A_records - 1 ? A_records + rowi - 1 : rowf)
angle(x)=x*360/A_sum
percentage(x)=x*100/A_sum
# circumference dimensions for pie-chart
centerX=0
centerY=0
radius=1
# label positions
yposmin = 0.0
yposmax = 0.95*radius
xpos = 1.5*radius
ypos(i) = yposmax - i*(yposmax-yposmin)/(1.0*rowf-rowi)
#-------------------------------------------------------------------
# now we can configure the canvas
set style fill solid 1 # filled pie-chart
unset key # no automatic labels
unset tics # remove tics
unset border # remove borders; if some label is missing, comment to see what is happening
set size ratio -1 # equal scale length
set xrange [-radius:2*radius] # [-1:2] leaves space for labels
set yrange [-radius:radius] # [-1:1]
#-------------------------------------------------------------------
pos = 0 # init angle
colour = 0 # init colour
# 1st line: plot pie-chart
# 2nd line: draw colored boxes at (xpos):(ypos)
# 3rd line: place labels at (xpos+offset):(ypos)
plot filename u (centerX):(centerY):(radius):(pos):(pos=pos+angle($2)):(colour=colour+1) every ::rowi::rowf w circle lc var,\
for [i=0:rowf-rowi] '+' u (xpos):(ypos(i)) w p pt 5 ps 4 lc i+1,\
for [i=0:rowf-rowi] filename u (xpos):(ypos(i)):(sprintf('%05.2f%% %s', percentage($2), stringcolumn(1))) every ::i+rowi::i+rowi w labels left offset 3,0
This new code results in:

Smooth Convex Hull

I have started working a convex hull algorithm and was wondering what method I could employ to smooth the polygon edge. The outline of the hull is not smooth. What I would like to do is make the lines through the vertices smoother, so that they are not as angled.
I have tried to implement Beziers (only to realize the shape was nothing like the shape of the hull) and b-splines (again the shape was nothing like, in fact I could not make the b-spline a closed shape).
I am failing and hopes someone can offer guidance.
(Note! that is not the solution)
I tried to find the exact solution as Lagrange polynomial in polar coordinates, but find out, that somtimes "smoothing curve" lies inside the convex polygon. The first derivatives matching condition (in start point) is fundamentaly solvable by adding extra moveable invisible point outside theta in [0:2 * pi] interval. But above problem is not solvable anyways at my mind.
Here is the Lua script with my attemptions (uses qhull, rbox (from qhull toolchain) and gnuplot utilities):
function using()
return error('using: ' .. arg[0] .. ' <number of points>')
end
function points_from_file(infile)
local points = {}
local infile = io.open(infile, 'r')
local d = infile:read('*number')
if d ~= 2 then
error('dimensions is not two')
end
local n = infile:read('*number')
while true do
local x, y = infile:read('*number', '*number')
if not x and not y then
break
end
if not x or not y then
error('wrong format of input file: line does not contain two coordinates')
end
table.insert(points, {x, y})
end
infile:close()
if n ~= #points then
error('second line not contain real count of points')
end
return points
end
if not arg then
error("script should use as standalone")
end
if #arg ~= 1 then
using()
end
local n = tonumber(arg[1])
if not n then
using()
end
local bounding_box = math.sqrt(math.pi) / 2.0
local fnp = os.tmpname()
local fnchp = os.tmpname()
os.execute('rbox ' .. n .. ' B' .. bounding_box .. ' D2 n t | tee ' .. fnp .. ' | qhull p | tee ' .. fnchp .. ' > nul') -- Windows specific part is "> nul"
local sp = points_from_file(fnp) -- source points
os.remove(fnp)
local chp = points_from_file(fnchp) -- convex hull points
os.remove(fnchp)
local m = #chp
if m < 3 then
io.stderr:write('convex hull consist of less than three points')
return
end
local pole = {0.0, 0.0} -- offset of polar origin relative to cartesian origin
for _, point in ipairs(chp) do
pole[1] = pole[1] + point[1]
pole[2] = pole[2] + point[2]
end
pole[1] = pole[1] / m
pole[2] = pole[2] / m
print("pole = ", pole[1], pole[2])
local chcc = {}
for _, point in ipairs(chp) do
table.insert(chcc, {point[1] - pole[1], point[2] - pole[2]})
end
local theta_min = 2.0 * math.pi -- angle between abscissa ort of cartesian and ort of polar coordinates
local rho_mean = 0.0
local rho_max = 0.0
local chpc = {} -- {theta, rho} pairs
for _, point in ipairs(chcc) do
local rho = math.sqrt(point[1] * point[1] + point[2] * point[2])
local theta = math.atan2(point[2], point[1])
if theta < 0.0 then -- [-pi:pi] -> [0:2 * pi]
theta = theta + 2.0 * math.pi
end
table.insert(chpc, {theta, rho})
if theta_min > theta then
theta_min = theta
end
rho_mean = rho_mean + rho
if rho_max < rho then
rho_max = rho
end
end
theta_min = -theta_min
rho_mean = rho_mean / m
rho_max = rho_max / rho_mean
for pos, point in ipairs(chpc) do
local theta = (point[1] + theta_min) / math.pi -- [0:2 * pi] -> [0:2]
local rho = point[2] / rho_mean
table.remove(chpc, pos)
table.insert(chpc, pos, {theta, rho})
end
table.sort(chpc, function (lhs, rhs) return lhs[1] < rhs[1] end)
-- table.insert(chpc, {chpc[#chpc][1] - 2.0 * math.pi, chpc[#chpc][2]})
table.insert(chpc, {2.0, chpc[1][2]})
-- table.sort(chpc, function (lhs, rhs) return lhs[1] < rhs[1] end)
local solution = {}
solution.x = {}
solution.y = {}
for _, point in ipairs(chpc) do
table.insert(solution.x, point[1])
table.insert(solution.y, point[2])
end
solution.c = {}
for i, xi in ipairs(solution.x) do
local c = solution.y[i]
for j, xj in ipairs(solution.x) do
if i ~= j then
c = c / (xi - xj)
end
end
solution.c[i] = c
end
function solution:monomial(i, x)
local y = self.c[i]
for j, xj in ipairs(solution.x) do
if xj == x then
if i == j then
return self.y[i]
else
return 0.0
end
end
if i ~= j then
y = y * (x - xj)
end
end
return y
end
function solution:polynomial(x)
local y = self:monomial(1, x)
for i = 2, #solution.y do
y = y + self:monomial(i, x)
end
return y
end
local gnuplot = io.popen('gnuplot', 'w')
gnuplot:write('reset;\n')
gnuplot:write('set terminal wxt 1;\n')
gnuplot:write(string.format('set xrange [%f:%f];\n', -bounding_box, bounding_box))
gnuplot:write(string.format('set yrange [%f:%f];\n', -bounding_box, bounding_box))
gnuplot:write('set size square;\n')
gnuplot:write(string.format('set xtics %f;\n', 0.1))
gnuplot:write(string.format('set ytics %f;\n', 0.1))
gnuplot:write('set grid xtics ytics;\n')
gnuplot:write('plot "-" using 1:2 notitle with points, "-" using 1:2:3:4 notitle with vectors;\n')
for _, point in ipairs(sp) do
gnuplot:write(string.format('%f %f\n', point[1], point[2]))
end
gnuplot:write('e\n')
for _, point in ipairs(chcc) do
gnuplot:write(string.format('%f %f %f %f\n', pole[1], pole[2], point[1], point[2]))
end
gnuplot:write('e\n')
gnuplot:flush();
gnuplot:write('reset;\n')
gnuplot:write('set terminal wxt 2;\n')
gnuplot:write('set border 0;\n')
gnuplot:write('unset xtics;\n')
gnuplot:write('unset ytics;\n')
gnuplot:write('set polar;\n')
gnuplot:write('set grid polar;\n')
gnuplot:write('set trange [-pi:2 * pi];\n')
gnuplot:write(string.format('set rrange [-0:%f];\n', rho_max))
gnuplot:write('set size square;\n')
gnuplot:write('set view equal xy;\n')
-- gnuplot:write(string.format('set xlabel "%f";\n', rho_mean - 1.0))
gnuplot:write(string.format('set arrow 1 from 0,0 to %f,%f;\n', rho_max * math.cos(theta_min), rho_max * math.sin(theta_min)))
gnuplot:write(string.format('set label 1 " origin" at %f,%f left rotate by %f;\n', rho_max * math.cos(theta_min), rho_max * math.sin(theta_min), math.deg(theta_min)))
gnuplot:write('plot "-" using 1:2:3:4 notitle with vectors, "-" using 1:2 notitle with lines, "-" using 1:2 notitle with lines;\n')
for _, point in ipairs(chpc) do
gnuplot:write(string.format('0 0 %f %f\n', point[1] * math.pi, point[2]))
end
gnuplot:write('e\n')
for _, point in ipairs(chpc) do
gnuplot:write(string.format('%f %f\n', point[1] * math.pi, point[2]))
end
gnuplot:write('e\n')
do
local points_count = 512
local dx = 2.0 / points_count
local x = 0.0
for i = 1, points_count do
gnuplot:write(string.format('%f %f\n', x * math.pi, solution:polynomial(x)))
x = x + dx
end
gnuplot:write('e\n')
end
gnuplot:flush();
gnuplot:write('reset;\n')
gnuplot:write('set terminal wxt 3;\n')
gnuplot:write(string.format('set xrange [-1:2];\n'))
gnuplot:write(string.format('set yrange [0:2];\n'))
gnuplot:write(string.format('set size ratio %f;\n', rho_max / 3.0))
gnuplot:write(string.format('set xtics %f;\n', 0.5))
gnuplot:write(string.format('set ytics %f;\n', 0.5))
gnuplot:write('set grid xtics ytics;\n')
gnuplot:write(string.format('set arrow 1 nohead from 0,%f to 2,%f linetype 3;\n', chpc[1][2], chpc[1][2]))
gnuplot:write(string.format('set label 1 "glue points " at 0,%f right;\n', chpc[1][2]))
gnuplot:write('plot "-" using 1:2 notitle with lines, "-" using 1:2 notitle with lines;\n')
for _, point in ipairs(chpc) do
gnuplot:write(string.format('%f %f\n', point[1], point[2]))
end
gnuplot:write('e\n')
do
local points_count = 512
local dx = 2.0 / points_count
local x = 0.0
for i = 1, points_count do
gnuplot:write(string.format('%f %f\n', x, solution:polynomial(x)))
x = x + dx
end
gnuplot:write('e\n')
end
gnuplot:flush();
os.execute('pause');
gnuplot:write('exit\n');
gnuplot:flush();
gnuplot:close()
The second terminal contains Lagrange polynomial approximation.
I'd approach it like this, using your example:
start with the longest outer segment (in your example, this is the lower-left) - this one we keep straight;
imagine a circle at the bottom end of the long line, facing inwards;
a tangent from this circle can be extended to the next point;
in the next case (bottom-right circle), there is no tangent that joins onto the following point, so use another circle and join circles at the tangents;
continue in this fashion.
So, you are drawing a circular arc then a straight line and repeating that.
Your circle sizes determine the overall smoothness. But of course if they are too big you will need to drop some points.

Resources