Drawing a plane on a cartesian plane using gnuplot - gnuplot

I'm trying to reproduce a figure I've found on a linear algebra book using gnuplot. This is the original image
You can see an intersection between two planes described by the two equations:
2u + v + w = 5
4u - 6v = -2.
I suppose that in order to plot the first equation using gnuplot I have to transform it in the form:
splot 5 - 2*x - y
where u -> x; v -> y and w -> z which is the free variable. But the result is very different from what expected. Any clue?

The approach you outline makes sense, however, the results may be far from what you expect.
I propose you draw single lines, using the arrow function in gnuplot.
This example will generate a plot very similar to the one you showed (only one plane, though):
set term gif
set output "demo_plane.gif"
# define your axis limits:
xmax = 6.5
xmin = -1.5
ymax = 8.5
ymin = -1.5
zmax = 5.5
zmin = -0.5
set xrange [xmin:xmax]
set yrange [ymin:ymax]
set zrange [zmin:zmax]
# remove the original axis
unset border
unset xtics
unset ytics
unset ztics
# define you data points:
x1 = 3.0
y1 = -1.0
z1 = 0.0
x2 = -1.0
y2 = 7.0
z2 = 0.0
x3 = -3.0
y3 = 7.0
z3 = 4.0
x4 = 1.0
y4 = -1.0
z4 = 4.0
# define 'arrow' without head:
set arrow 1 from x1,y1,z1 \
to x2,y2,z2 nohead
set arrow 2 from x2,y2,z2 \
to x3,y3,z3 nohead
set arrow 3 from x3,y3,z3 \
to x4,y4,z4 nohead
set arrow 4 from x4,y4,z4 \
to x1,y1,z1 nohead
# draw new axis manually (again, using arrow):
set arrow 5 from 0,0,0 \
to 6,0,0
set arrow 6 from 0,0,0 \
to 0,6,0
set arrow 7 from 0,0,0 \
to 0,0,5
# annotate axis labels:
set label "u" at 6.25,0,0
set label "v" at 0,6.25,0
set label "w" at 0,0,5.25
# plot will not show when empty, include dummy plot command:
set parametric
splot x1, y1, z1 not
With a little rotation you will get a figure like this:

Related

Is there a mismatch between splot and arrow coordinates in gnuplot or am I missing something?

I'm trying to plot the following 3 intersecting planes:
x + 2y + 4z = 7
2x + 3y + 3z = 1
3x + 7y + 2z = -11
To add emphasis, I wanted to include some headless arrows along the intersection of each pair of planes and a small sphere to indicate the intersection point. But for some reason the planes themselves seem to be out of alignment with the axes. From the equations I can easily find the coordinate of the intersection point, find the coordinates of the edges of the lines that run along the intersection of each pair of planes and if needed find the parametric equation of the lines. But so far when I plot the lines as arrows from the edges of my plot or the intersection as a circle, the planes seem to be wrongly positioned within the coordinates. I can see that the circle or the lines are positioned correctly, but the planes themselves seem to have been shifted. What could be causing this? Am I entering the equations wrong? Maybe the shift of the xy plane moves things around? I think it must be something obvious I'm just not seeing. I find it quite puzzling.
reset
samps = 500
set samples samps,samps
set isosamples samps,samps
f(x,y) = 7/4 - x/4 - y/2
set table $Data01
splot f(x,y)
unset table
g(x,y) = 1/3 - 2/3*x - y
set table $Data02
splot g(x,y)
unset table
h(x,y) = -11/2 - 3/2*x - 7/2*y
set table $Data03
splot h(x,y)
unset table
Zmin = 1.0
Zmax = 3.5
set xrange [-1.2:0.5]
set yrange [-4:0]
set zrange [Zmin:Zmax]
set hidden3d
set xlabel 'x'
set ylabel 'y'
set zlabel 'z'
set xyplane at Zmin
unset xzeroaxis
unset yzeroaxis
unset zzeroaxis
set border 1023-128
set xtics out nomirror
set ytics out nomirror
set ztics out
#set xtics add ('' -4)
Frac(z) = (z - Zmin) / (Zmax - Zmin)
#MyPalette01
Red01(z) = 0
Green01(z) = 255*256
Blue01(z) = int(255*Frac(z))
MyPalette01(z) = Red01(z) + Green01(z) + Blue01(z)
#MyPalette02
Red02(z) = 255*256*256
Green02(z) = int(165*Frac(z))*256
Blue02(z) = 0
MyPalette02(z) = Red02(z) + Green02(z) + Blue02(z)
# MyPalette03
Red03(z) = int(-95*Frac(z)+255)*256*256
Green03(z) = int(32*Frac(z))*256
Blue03(z) = int(-15*Frac(z)+255)
MyPalette03(z) = Red03(z) + Green03(z) + Blue03(z)
#Red03(z) = int(255*Frac(z))*256*256
#Green03(z) = int(255*Frac(z))*256
#Blue03(z) = int(255*Frac(z))
set object circle at -1,-2,3 size 0.05 front
unset key
set pm3d
set pm3d lighting primary 0.5 specular 0.6
set pm3d ftriangles
set style fill transparent solid 0.75 noborder
set pm3d depthorder
unset colorbox
set view 68, 126
splot $Data01 u 1:2:3:(MyPalette01($3)) w l lc rgb var notitle, \
$Data02 u 1:2:3:(MyPalette02($3)) w l lc rgb var notitle, \
$Data03 u 1:2:3:(MyPalette03($3)) w l lc rgb var notitle
I found how to set multiple styles for each plane in here:
Gnuplot 5.2 splot: Multiple pm3d palette in one plot call
And this is how it looks:
Any Ideas?

Clip vectors on circle in gnuplot

I try to draw some vector fields in a circular region. Consider the following MWE
unset grid
unset tics
unset colorbox
unset border
set size square
besselj(n, x) = n > 1 ? 2*(n-1)/x*besselj(n-1,x) - besselj(n-2,x) : (n == 1 ? besj1(x) : besj0(x))
dbesselj(n, x) = n/x*besselj(n,x) - besselj(n+1,x)
rho(x,y) = sqrt(x**2+y**2)
phi(x,y) = atan2(y,x)
d = 1.0
l = 1.0
z = l/2
q = 1
set xrange [-d/2*1.1:d/2*1.1]
set yrange [-d/2*1.1:d/2*1.1]
Erho(x,y,n,ynp) = (-1/rho(x,y)) * besselj(n, (ynp*2/d)*rho(x,y)) * (-n*sin(n*phi(x,y))) * sin(q*pi*z/l)
Ephi(x,y,n,ynp) = (ynp*2/d) * dbesselj(n, (ynp*2/d)*rho(x,y)) * (cos(n*phi(x,y))) * sin(q*pi*z/l)
Ex(x,y,n,ynp) = rho(x,y) > d/2 ? NaN : cos(phi(x,y))*Erho(x,y,n,ynp) - sin(phi(x,y))*Ephi(x,y,n,ynp)
Ey(x,y,n,ynp) = rho(x,y) > d/2 ? NaN : sin(phi(x,y))*Erho(x,y,n,ynp) + cos(phi(x,y))*Ephi(x,y,n,ynp)
mag(x,y,n,ynp) = sqrt(Ex(x,y,n,ynp)**2 + Ey(x,y,n,ynp)**2)
set object circle at 0,0 size 0.5 fc black lw 3 front
set multiplot layout 1,2
set title 'TE_{01}'
set table 'tmp.dat'
set samples 16
set isosamples 16
plot '++' u 1:2:(Ex($1,$2,0,3.832)/50):(Ey($1,$2,0,3.832)/50) w vectors
unset table
set samples 250
set isosamples 250
plot '++' u 1:2:(mag($1,$2,0,3.832)) w image notitle, \
'tmp.dat' u 1:2:3:4 w vectors head filled lc black lw 1 notitle
set title 'TE_{11}'
set table 'tmp.dat'
set samples 16
set isosamples 16
plot '++' u 1:2:(Ex($1,$2,1,1.841)/20):(Ey($1,$2,1,1.841)/20) w vectors
unset table
set samples 250
set isosamples 250
plot '++' u 1:2:(mag($1,$2,1,1.841)) w image notitle, \
'tmp.dat' u 1:2:3:4 w vectors head filled lc black lw 1 notitle
unset multiplot
which plots the vector field as well as its magnitude inside the circle with diameter d. The result from this is
which is totally okay for the left image (TE01), but the right image (TE11) looks ugly because there are some vectors which are drawn outside the circle. My actually desired result is this
where I have no vectors outside of the black circle. How can I achieve that?
I know there is the clip function in gnuplot, but this does not allow to specify the shape to be used for clipping.
Here is what you can try. Define your own clip function, e.g. a circle.
First you need to check whether a data point is outside of your circle or not.
Clip(x,y) returns NaN if it is outside and 0 if it is inside.
Now, when you plot simply add the value of the clip function to your value. Your data will be clipped within a circle because something +0 remains unchanged and something +NaN will be NaN and will not be plotted. It is sufficient if you do this just for x (vector start) and x + delta x (vector end).
Code:
### clip function in circle form
reset session
set size square
# create some test data
set samples 25
Scaling = 0.5
set table $Data
plot [-5:5] '++' u 1:2:(Scaling*$1/sqrt($1**2+$2**2)): \
(Scaling*$2/sqrt($1**2+$2**2)) : (sqrt($1**2+$2**2)) with table
unset table
set palette rgb 33,13,10
CenterX = 0
CenterY = 0
Radius = 3.5
Clip(x,y) = sqrt((x-CenterX)**2 + (y-CenterY)**2) > Radius ? NaN : 0
set xrange[-6:6]
set yrange[-6:6]
set multiplot layout 1,3
plot $Data u 1:2:3:4:5 w vec lc pal not
plot $Data u ($1+Clip($1,$2)):2:($3+Clip($1+$3,$2+$4)):4:5 w vec lc pal not
CenterX = 1
CenterY = 1
plot $Data u ($1+Clip($1,$2)):2:($3+Clip($1+$3,$2+$4)):4:5 w vec lc pal not
unset multiplot
### end of code
Result:

Plotting piecewise linear functions with gnuplot inaccurately

I have a problem when plotting a piecewise linear function h(x) = max(0, 1-|x|) (hat function) with gnuplot. My goal is to showcase the interpolation of a polynomial employing these hat functions as basis functions. Thus I need to shift and scale them to different grid points.
My code looks like this:
set key inside bottom right
set xrange [0:1]
set yrange [0:6]
set grid xtics
set style line 1 linecolor rgb '#0060ad' linetype 1 linewidth 2
set ytics 1
set xtics 2**(-3)
set key right top
s(x) = (3.0 * x - 1)
a0 = 2
a1 = -6
a2 = 5
a3 = 5
a4 = -5
a5 = 1
f(x) = a0 + a1*s(x) + a2*(s(x)**2) + a3*(s(x)**3) + a4*(s(x)**4) + a5*(s(x)**5)
max(x, y) = (x > y) ? x:y
h(x) = max(0, 1 - abs(x))
nodal(x, i)=h(2**(3)*x - i) * f(i * 2**(-3))
plot f(x) title "f(x)", nodal(x, 1)
The output however looks like this:
Obviously towards the point where the nodal basis function is not differentiable it fails to nicely plot the function, which looks bad. As I want to include this a thesis I have to submit, it is not something that I could include. Is there any solution for this problem?

Glowing (neon) effect in gnuplot

I want to reproduce this effect in gnuplot:
How can I achive it? If it can't be done, what software can I use to reproduce it?
Using a 2d kernel for every pixel can be done inside gnuplot. That way, more dense accumulations get brighter than single pixels. Check show palette rgbformulae and the respective chapter in the help to change the colours.
set term wxt size 300,300 background rgb 0
set view map
set samp 140
set dgrid3d 180,180, gauss kdensity2d 0.2,0.2
set palette rgbform 4,4,3
splot "+" us 1:(sin($1/3)**2*20):(1) with pm3d notitle
Disclaimer: It can be done with gnuplot as instructed in this answer but you should probably consider a different tool to draw this particular type of plot.
There is at least one way to do it, with preprocessing of the data. The idea is to mimic the glow effect by using a Gaussian kernel to smear the data points. Consider the following data, contained in a file called data:
1 2
1 2.1
1.1 2.2
2 3
3 4
I have purposely placed the first 3 points close to each other to be able to observe the intensified glow of neighboring points. These data look like this:
Now we smear the data points using a 2D Gaussian kernel. I have written the following python code to help with this. The code has a cutoff of 4 standard deviations (sx and sy) around each point. If you want the glow to be a circle, you should choose the standard deviations so that the sx / sy ratio is the same as the ratio of the x/y axes lengths in gnuplot. Otherwise the points will look like ellipses. This is the code:
import numpy as np
import sys
filename = str(sys.argv[1])
sx = float(sys.argv[2])
sy = float(sys.argv[3])
def f(x,y,x0,y0,sx,sy):
return np.exp(-(x-x0)**2/2./sx**2 -(y-y0)**2/2./sy**2)
datafile = open(filename, 'r')
data = []
for datapoint in datafile:
a, b = datapoint.split()
data.append([float(a),float(b)])
xmin = data[0][0]
xmax = data[0][0]
ymin = data[0][1]
ymax = data[0][1]
for i in range(1, len(data)):
if(data[i][0] < xmin):
xmin = data[i][0]
if(data[i][0] > xmax):
xmax = data[i][0]
if(data[i][1] < ymin):
ymin = data[i][1]
if(data[i][1] > ymax):
ymax = data[i][1]
xmin -= 4.*sx
xmax += 4.*sx
ymin -= 4.*sy
ymax += 4.*sy
dx = (xmax - xmin) / 250.
dy = (ymax - ymin) / 250.
for i in np.arange(xmin,xmax+dx, dx):
for j in np.arange(ymin,ymax+dy, dy):
s = 0.
for k in range(0, len(data)):
d2 = (i - data[k][0])**2 + (j - data[k][1])**2
if( d2 < (4.*sx)**2 + (4.*sy)**2):
s += f(i,j,data[k][0],data[k][1],sx,sy)
print i, j, s
It is used as follows:
python script.py data sx sy
where script.py is the name of the file where the code is located, data is the name of the data file, and sx and sy are the standard deviations.
Now, back to gnuplot, we define a palette that mimics a glowing pattern. For isolated points, the summed Gaussians yield 1 at the position of the point; for overlapping points it yields values higher than 1. You must consider that when defining the palette. The following is just an example:
set cbrange [0:3]
unset colorbox
set palette defined (0 "black", 0.5 "blue", 0.75 "cyan", 1 "white", 3 "white")
plot "< python script.py data 0.05 0.05" w image
You can see that the points are actually ellipses, because the ratio of the axes lengths is not the same as that of the standard deviations along the different directions. This can be easily fixed:
plot "< python script.py data 0.05 0.06" w image
Set a black background, and then plot your dataset several time in different colours with decreasing pointsize.
set term wxt backgr rgb "black"
plot sin(x) w p pt 7 ps 2 lc rgb 0x00003f not, \
sin(x) w p pt 7 ps 1.5 lc rgb 0x00007f not, \
sin(x) w p pt 7 ps 1 lc rgb 0x0000af not, \
sin(x) w p pt 7 ps .5 lc rgb 0x0000ff
Alternatively, some combination of splot with pm3d,set dgrid3d gauss kdensity2d, and set view map, combined with a suitable palette, can be used, see my other answer.

Logarithmic y with zero in GnuPlot

My goal is to display 0 values on a logarithmic scale a little bit under 1.
I managed to plot my own simple histogram (with boxes) with logarithmic Y scale. My Y values are non-negative integers up to 25000. I cannot differentiate the 0 and 1 values as the Y scale begins at 1. Which is mathematically correct, but I want to hack a zero just under the one.
If I were to write a program that plots my graph, I would add 1 to all of my data, and remove 1 from the Y labels. Is there any tricks that would do something like that for me?
gnuplot> set xrange [0:2]
gnuplot> set log y
gnuplot> set yrange [0.1:100]
gnuplot> set ytics ("0" 0.1, "1" 1, "10" 10)
gnuplot> plot cosh(x)
gnuplot>
I think the best option would be to plot your histogram using a modified function:
plot 'data' using 1:($2 < 1 ? $2 : log10($2)+1) with boxes
The above command plots the log10()+1 of your data if it is above or equal to 1, otherwise it plots simply your data. Then, you can modify your y axis so that it's linear between 0 and 1 and logarithmic between 1 and the highest value:
ymax = 10000
set yrange [0:log10(ymax)]
unset ytics
set ytics 1 add ("0" 0, "1" 1)
set for [i=2:log10(ymax)] ytics add (sprintf("%g",10**(i-1)) i) # Add major tics
set for [i=1:log10(ymax)] for [j=2:9] ytics add ("" log10(10**i*j) 1) # Add minor tics
set for [j=1:9] ytics add ("" j/10. 1) # Add minor tics between 0 and 1
plot 'data' using 1:($2 < 1 ? $2 : log10($2)+1) with boxes
The 1 after the tic position is to adjust the minor tics' length (thanks to #Christoph). Anyway, this looks like the following figure for a test case x^2, where you can see how the y axis is linear up to 1 and logarithmic beyond:
I hope this can help you. this is not just a "hack", but a real way to have a linear-log y axis on gnuplot:
reset
set terminal wxt 0 enhanced font 'Sans,13'
#%%% SIZE SETTINGS (whole figure)
tm = 0.90; bm = 0.2
lm = 0.12; rm = 0.885
size = 0.8
#%%% RANGE SETTINGS
y1 = 0.; y2 = 1.; #(lin interval)
y3 = 1.; y4 = 1000.; #(log interval)
x1 = -8.0; x2 = 8.0
set xrange [x1:x2];
#%%% SIZE SETTINGS (single plots)
I_1 = abs(y2-y1)
I_2 = abs(log10(y4)-log10(y3))
denom = I_1 + I_2
T_m_1 = lm + size * (I_1/denom)
T_m_2 = lm + size * ((I_1+I_2))/denom)
f(x) = (15.*sin(x)/x)**2
#%%% BEGIN MULTIPLOT
set multiplot
# Left and Right margins
set lmargin at screen lm
set rmargin at screen rm
# X-axis settings:
set xlabel "X [ux]"; set format x "%2.1f";
set xtics 2 nomirror; set mxtics 4
do for [i=(x1+1):(x2-1):2] {
set xtics add ("" i) }
set samples 10000;
# Y-axis label
set label 'Y [uy]' \
at screen 0.03,bm + 0.5*size \
offset 0,-strlen("X [ux]")/4.0 \
rotate by 90
#%% First plot, first interval
set border 1+2+8
set bmargin at screen bm
set tmargin at screen T_m_1
set yrange [y1:y2]
set format y "%1.0f";
set ytics 1; set mytics 5;
plot f(x) lw 2 \
lc rgb "navy" notitle
#%% End first plot
unset xlabel; unset xtics
#%% Second (and last) plot
set border 2+4+8
set bmargin at screen T_m_1
set tmargin at screen T_m_2
# showing mirror xtics via a x2 axis
set link x via x inverse x
set format x2 "";
set x2tics nomirror; set mx2tics 4;
do for [i=(x1+1):(x2-1):2] {
set x2tics add ("" i) }
set logscale y;
set ytics autofreq; set mytics autofreq;
set format y "10^{%L}";
set ytics add ("" 1.0);
set yrange [y3:y4]
plot f(x) lw 2 \
lc rgb "navy" notitle
#%% End second plot
unset multiplot
#%%% END MULTIPLOT
Result:
image
Practical guide to the code:
start by modifying the "RANGE SETTINGS" to adapt them to your plot
then choose the "X-axis settings" and "Y-axis label" you prefer
comment the two lines specifying the ytics and yformat in the "first plot" part (aka let Gnuplot set those for you, for now)
modify "first" plot command to plot (between y1 and y2) your function/datafile
adapt the part under "showing mirror xtics via a x2 axis" to your X axis setting (if you want specular tics)
modify "second" plot command to plot (between y3 and y4) your function/datafile
see the result and fix minor details, like labels, formats, tics, mtics, and so on.

Resources