Clip vectors on circle in gnuplot - 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:

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?

Plotting multiple pm3d surfaces each having its own palettes in gnuplot

What I basically want to do is basically the same as the solution to this question
Gnuplot 5.2 splot: Multiple pm3d palette in one plot call
, but which works with pm3d. If you read the comment to that answer, the answerer said that the solution does not work if he used pm3d. Also, would it be possible to define the palette in a simpler manner, such as set palette defined ()?
The development branch of gnuplot supports multiple named palettes. The method shown here, however, works on earlier versions of gnuplot also. It uses the fill style to provide a color (rather than the pm3d palette), and shows how to define the fill colors so that they mimic set palette defined(). This demo constructs only one mapping, but you could define several mappings each with its own array of colors and mapping function to use them.
This demo is extracted from the full demo for named palettes in the development branch. If you are interested you can find the full demo here:
Version 5.5 named palette demo
#
# Demonstrate construction and use of a separate palette
# Ethan A Merritt - May 2020
#
# Method 1:
# The first method works also in 5.2 but requires "lc rgb variable"
# rather than the more natural "fillcolor rgb variable".
# "set pm3d interpolate" breaks the color mapping of this method
#
# This creates a palette equivalent to
# set palette defined (0 "dark-blue", 1 "white")
#
array blues[256]
do for [i=1:256] {
blues[i] = int( (0x7f + (i-1)/(255.) * 0xffff80) );
}
#
# This is the equivalent of
# set cbrange [-1:1]
blues_min = -1
blues_max = 1
#
# This function maps z onto a palette color
#
blues(z) = (z <= blues_min) ? blues[1] \
: (z >= blues_max) ? blues[256] \
: blues[ floor(255. * (z-blues_min)/(blues_max-blues_min)) + 1]
foo(x,y) = sin(x*y)
set samples 41
set isosamples 41
unset colorbox
set cbrange [-1:1]
set xrange [0:5]; set urange [0:5]
set yrange [0:5]; set vrange [0:5]
set title "Use hand-constructed 'blues' palette via rgb variable"
splot '++' using 1:2:(foo($1,$2)):(blues(foo($1,$2))) with pm3d fillcolor rgb variable \
title "pm3d using 1:2:3:4 with pm3d fillcolor rgb variable"
Maybe you could define the palette differently with set palette defined but then you probably would have to combine your 3 palettes into 1 palette and you would lose "color resolution", as far as I know a palette has 256 color steps. To be honest, I haven't thought about this in detail.
I checked again the code you referenced... apparently an additional line will do the "trick". Then you can plot with pm3d.
set pm3d depthorder
Code: (slightly modified code from here: https://stackoverflow.com/a/57501649/7295599)
### multiple "palettes" within one splot command
reset session
set samples 101,101
set isosamples 101,101
f(x,y) = sin(1.3*x)*cos(0.9*y)+cos(.8*x)*sin(1.9*y)+cos(y*.2*x)
set table $Data01
splot f(x,y)
unset table
g(x,y) = y
set table $Data02
splot g(x,y)
unset table
h(x,y) = 0.5*x
set table $Data03
splot h(x,y)
unset table
Zmin = -3
Zmax= 3
set xrange[-5:5]
set yrange[-5:5]
set zrange[Zmin:Zmax]
set hidden3d
set angle degree
Frac(z) = (z-Zmin)/(Zmax-Zmin)
# MyPalette01
Red01(z) = 65536 * ( Frac(z) > 0.75 ? 255 : int(255*abs(2*Frac(z)-0.5)))
Green01(z) = int(255*sin(180*Frac(z)))*256
Blue01(z) = int(255*cos(90*Frac(z)))
MyPalette01(z) = Red01(z) + Green01(z) + Blue01(z)
# MyPalette02
Red02(z) = 65536 * int(255*Frac(z))
Green02(z) = 256 * (Frac(z) > 0.333 ? 255 : int(255*Frac(z)*3))
Blue02(z) = (Frac(z) > 0.5 ? 255 : int(255*Frac(z)*2))
MyPalette02(z) = Red02(z) + Green02(z) + Blue02(z)
# MyPalette03
Red03(z) = 65536 * (Frac(z) > 0.5 ? 255 : int(255*Frac(z)*2))
Green03(z) = 256 * (Frac(z) > 0.333 ? 255 : int(255*Frac(z)*3))
Blue03(z) = int(255*Frac(z))
MyPalette03(z) = Red03(z) + Green03(z) + Blue03(z)
set pm3d depthorder
unset colorbox
set view 44,316
splot $Data01 u 1:2:3:(MyPalette01($3)) w pm3d lc rgb var notitle, \
$Data02 u 1:2:3:(MyPalette02($3)) w pm3d lc rgb var notitle, \
$Data03 u 1:2:3:(MyPalette03($3)) w pm3d lc rgb var notitle
### end of code
Result:

Gnuplot 5: color gradient shading between curves

This was created with Matplotlib. Is it possible to make the same type of shading in Gnuplot 5?
I'm not aware that gnuplot has a gradient fill option, but I could be wrong.
The following is a bit of an "ugly" workaround. You basically create 3 plots on top of each other. You might want to adjust the palette to get the desired colors and a smooth transition.
a dummy plot to get the palette as background (i.e. the colorbox as large as the graph)
cover the part above y>f(x) and y>0 to x2-axis as well as below y<f(x) and y<0 to x1-axis.
plot again f(x) to see f(x) and the axes tics again
Edit:
The earlier version of the code used multiplot. It's not necessary, just use set colorbox back. But then set xzeroaxis ls -1 is not visible anymore, add plot 0 w l ls -1 instead.
Code:
### filled curve with gradient
reset session
f(x) = sin(x)/(1+x)
fabove(x) = f(x)<0 ? 0 : f(x)
fbelow(x) = f(x)>0 ? 0 : f(x)
set samples 200
set palette defined (0 "white", 1 "red", 2 "black")
set colorbox back user origin graph 0, graph 0 size graph 1, graph 1
unset cbtics
set xrange[0:15]
set xzeroaxis ls -1
set yrange[-0.2:0.5]
plot fabove(x) w filledcurves x2 fc rgb "white" not, \
fbelow(x) w filledcurves x1 fc rgb "white" not, \
f(x) w l lw 2 lc rgb "black", \
NaN palette, \
0 w l ls -1
### end of code
Result:

Gnuplot 5.2 splot: Multiple pm3d palette in one plot call

I wonder, can I used two different pm3d palettes in splot? I use Gnuplot 5.2 and
want to show two 3D surfaces, like ocean and land with different color palettes. Can I define this in some way like:
splot "file" u 1:2:3 with pm3d palette 1, "file" 1:2:4 with pm3d palette 2
The data in column 1 and 2 are integers that extend from 0 to 100, they define a grid. The boundaries may be different for different maps. The z axis values are real numbers representing relative changes on logarithmic scale and extend from -10 to 10.
The following might be solution for you. I do not see how to change the palette within a splot command. So, the basic idea of the workaround is to set the linecolor via formulae which can be set differently for each splot-(sub)command. I hope you can adapt the example below to your needs.
Also check help rgbformulae and type show palette rgbformulae which will show you the formulae behind the palettes.
Code:
### multiple "palettes" within one splot command
reset session
set samples 101,101
set isosamples 101,101
f(x,y) = sin(1.3*x)*cos(0.9*y)+cos(.8*x)*sin(1.9*y)+cos(y*.2*x)
set table $Data01
splot f(x,y)
unset table
g(x,y) = y
set table $Data02
splot g(x,y)
unset table
h(x,y) = 0.5*x
set table $Data03
splot h(x,y)
unset table
Zmin = -3
Zmax= 3
set xrange[-5:5]
set yrange[-5:5]
set zrange[Zmin:Zmax]
set hidden3d
set angle degree
Frac(z) = (z-Zmin)/(Zmax-Zmin)
# MyPalette01
Red01(z) = 65536 * ( Frac(z) > 0.75 ? 255 : int(255*abs(2*Frac(z)-0.5)))
Green01(z) = int(255*sin(180*Frac(z)))*256
Blue01(z) = int(255*cos(90*Frac(z)))
MyPalette01(z) = Red01(z) + Green01(z) + Blue01(z)
# MyPalette02
Red02(z) = 65536 * int(255*Frac(z))
Green02(z) = 256 * (Frac(z) > 0.333 ? 255 : int(255*Frac(z)*3))
Blue02(z) = (Frac(z) > 0.5 ? 255 : int(255*Frac(z)*2))
MyPalette02(z) = Red02(z) + Green02(z) + Blue02(z)
# MyPalette03
Red03(z) = 65536 * (Frac(z) > 0.5 ? 255 : int(255*Frac(z)*2))
Green03(z) = 256 * (Frac(z) > 0.333 ? 255 : int(255*Frac(z)*3))
Blue03(z) = int(255*Frac(z))
MyPalette03(z) = Red03(z) + Green03(z) + Blue03(z)
set view 44,316
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
### end of code
Result:

Drawing a plane on a cartesian plane using 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:

Resources