Gnuplot: logarithmic axes and dgrid3d not working together - gnuplot

I have a sparse grid of data that I would like to plot with a log scale in the x and y axes, with colours and contours defining the z axis.
Using logscale xy results in a very different looking plot to when I plot a linear plot of the log of each axis.
I want the nice logarithmic axes and positioning of the contour legend of the first plot, with the nice central portion and colour scale of the second plot.
My current script is
set dgrid3d 50,50 splines
set pm3d
set pm3d map
set cntrparam levels auto
set contour surface
#set logscale xy
#splot "test_data.dat" using 1:2:3 with l nosurf lw 3
splot "test_data.dat" using (log10($1)):(log10($2)):3 with lines nosurf lw 3
where I change the comments to change which plots I make.
What am I doing wrong?
All suggestions will be gladly accepted.
edit: Through some more research, I think that the data is being gridded by dgrid3d in linear space, and then plotted in log space by logscale xy. I want the data to be gridded and plotted in log space.
Is there a gnuplot-only solution?

Two-fold solution. 1) the difference in the look of the plots was due to a bug in 5.2.2. Upgrade to 5.2.3 fixed it.
2) Solved the gridding issue by plotting the log of the data on linear axes and then bodging the axes to look logarithmic.
The plot needs to be improved by making the minor tics smaller than the major.
set pm3d
set pm3d map
set cntrparam levels auto
set contour surface
#set xrange [2:6] #setting this makes the image finish at the y2 tics, without changing the xtics
set xtics 2,1,6
unset xtics
# "major" tics
set xtics ("100" 2, "1000" 3, "10000" 4, "100000" 5, "1e6" 6)
# "minor" ticks
set for [i=2:6:1] xtics add ("" log10(2*10**i),"" log10(3*10**i),"" log10(4*10**i),"" log10(5*10**i), "" log10(6*10**i),"" log10(7*10**i),"" log10(8*10**i),"" log10(9*10**i))
set ytics -2,1,-1
unset ytics
set ytics ("0.01" -2, "0.1" -1)
set for [i=-3:0:1] ytics add ("" log10(2*10**i),"" log10(3*10**i),"" log10(4*10**i),"" log10(5*10**i), "" log10(6*10**i),"" log10(7*10**i),"" log10(8*10**i),"" log10(9*10**i))
splot "test_data.dat" using (log10($1)):(log10($2)):3

Related

How to avoid pm3d surface from occluding other objects which are infront of it?

I am trying to plot a simple linear surface of the equation x + y + 2z = 0. This is my file:
set xrange [-4:4]
set yrange [-4:4]
set zrange [-4:4]
set xlabel 'x'
set ylabel 'y'
set zlabel 'z'
set xyplane at -4.0
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)
set label 1 "{/:Italic x} + {/:Italic y} + 2{/:Italic z} = 0" at 4,4.2,-2 font 'Times New Roman, 11'
set arrow 1 from 0,0,-4 to 0,0,4 filled
set arrow 2 from 0,-4,0 to 0,4,0 filled
set arrow 3 from -4,0,0 to 4,0,0 filled
set arrow 4 from 3.9,4.1,-2.1 to 3.6,3.6,-2.5
unset key
set pm3d lighting primary 0.5 specular 0.6
set style fill transparent solid 1 noborder
set palette defined (0 "cyan", 1 "green")
unset colorbox
set pm3d depthorder
splot -x/2-y/2 with pm3d
The result
I'm using arrows to show the axis, since they seem to be stuck to the xy plane, and moving it causes further issues with the tics and border. But now the problem is that they are completely occluded by the surface. Is there a setting which allows to appear in front when they "pierce" the surface? I'd like to make the surface semitransparent, but the problem is clearer with these settings.
I guess your original idea, i.e. "piercing" a 3D surface with an arrow or line does not work right away in gnuplot, because gnuplot will not calculate the piercing points automatically. Please correct me if I am wrong and let me know in case there might be a simple solution to this.
As you did in your simple case, you can just split the arrow at the origin, because you already know the piercing point. However, what do you do if the surface is irregular or has several piercing points?
Solution: take the effort to create a segmented 3D arrow and let gnuplot automatically show and hide the surfaces as needed. This is probably getting close to what you had in mind. However, this solution will show surprises when you want to change the color of the arrows. So, there is still room for improvement.
Code: (simple version with arrows just along x,y,z axes)
### arrows "piercing" a 3D surface
reset session
set view equal xyz
set xyplane relative 0.0
set xrange [-4:4]
set yrange [-4:4]
set zrange [-4:4]
# create 3D arrow
r = 0.01 # radius of arrow
rHead = 0.1 # radius of arrrowhead
n = 6 # corners of arrow
set print $myArrow
do for [h=-100:90] {
do for [a=360/n:360:360/n] {
print sprintf("%g %g %g",r*cos(a),r*sin(a), h/100.)
}
print ""
}
do for [h=90:100] {
do for [a=360/n:360:360/n] {
print sprintf("%g %g %g",rHead*(100-h)/10.*cos(a), \
rHead*(100-h)/10.*sin(a), h/100.)
}
print ""
}
set print
unset key
unset colorbox
set pm3d depthorder
set samples 100
set isosamples 100
set view 65,46,1.3
# function to demonstrate "piercing"
f(x,y) = (sin(x*3)/x + sin(y*3)/y - 3)/2
splot \
f(x,y) w pm3d, \
$myArrow u 1:2:($3*4):(0) w pm3d lc rgb var, \
$myArrow u 2:($3*4):1:(0) w pm3d lc rgb var, \
$myArrow u ($3*4):1:2:(0) w pm3d lc rgb var
### end of code
Result:
gnuplot> help layer
A gnuplot plot is built up by drawing its various components in a fixed order.
This order can be modified by assigning some components to a specific layer
using the keywords `behind`, `back`, or `front`. For example, to replace the
background color of the plot area you could define a colored rectangle with the
attribute `behind`.
set object 1 rectangle from graph 0,0 to graph 1,1 fc rgb "gray" behind
The order of drawing is
behind
back
the plot itself
the plot legend (`key`)
front
Within each layer elements are drawn in the order
grid, axis, and border elements
pixmaps in numerical order
So basically you need to add the "front" attribute to the objects you want to appear in front of the plot.

Heatmap of points in a volume

I have (x,y,z) points with coordinates like the following figure,
I would like to color the points based on their concentration.
The idea is to make a heatmap of points but in a 3D figure.
I would appreciate very much any help possible.
Regards.
Use data values in a 4th column to index a smooth color palette
splot DATA using 1:2:3:4 with points lc palette
The gnuplot development version now supports calculation of a point density function that can in turn be used to color individual points. This depends on a new set of commands that operate on a 3D grid of voxels. Sample script and output:
set title "Gaussian 3D cloud of 3000 random samples\ncolored by local point density"
rlow = -4.0; rhigh = 4.0
set xrange [rlow:rhigh]; set yrange [rlow:rhigh]; set zrange [rlow:rhigh]
set xtics axis nomirror; set ytics axis nomirror; set ztics axis nomirror;
set xyplane at 0
set xzeroaxis lt -1; set yzeroaxis lt -1; set zzeroaxis lt -1;
set log cb; set cblabel "point density"
# define 100 x 100 x 100 voxel grid
set vgrid $vdensity size 100
vclear $vdensity
# datablock $random has previously been loaded with 3000 points
# in a spherical Gaussian distribution about the origin
# The vfill command adds 1 to each voxel in a spherical region with radius 0.33
# around each point in $random
vfill $random using 1:2:3:(0.33):(1.0)
# plot the same points colored by local point density
splot $random using 1:2:3:(voxel($1,$2,$3)) with points pt 7 ps 0.5 lc palette
Full demo here: voxel demo in gnuplot online collection

GNUPlot - Plotting a data set in polar form (r, θ, T(r,θ)) to a contour/heat map

I hope I don't get firebombed here, this is the first time I'm posting. Lol
So after a grueling simulation, I have this large data set of the form r, θ, and T(r,θ). I needed to plot a contour map for this data set. θ is in degrees.
So I ran to GNUPlot and I hoped that this will save me from my problems. I studied a bit about how it works, but I still cannot plot my 2D contour data.
I then researched about my problem then I saw this thread here in SE:
gnuplot 2D polar plot with heatmap from 3D dataset - possible?
I used both codes (that I assume to be working) in that post and NONE is working with my dataset. I hope someone can help me with my problem.
This is what I changed the code into:
reset
set terminal pngcairo size 800,800
set output '3d-polar.png'
set lmargin at screen 0.05
set rmargin at screen 0.85
set bmargin at screen 0.1
set tmargin at screen 0.9
set pm3d map
unset key
set multiplot
# plot the heatmap
set parametric
set isosamples 500
unset border
unset xtics
unset ytics
set angles degree
r = 0.05 # CHANGED THIS
set urange[0:r] # radius
set vrange[0:360] # angle
set xrange[-r:r]
set yrange[-r:r]
set colorbox user origin 0.9,0.1 size 0.03,0.8
splot 'data.dat' using 1:2:3 # CHANGED THIS
# now plot the polar grid only
set style line 11 lc rgb 'white' lw 2
set grid polar ls 11
set polar
set rrange[0:r]
unset raxis
set rtics format '' scale 0
unset parametric
set for [i=0:330:30] label at first (r+0.35)*cos(i), first (r+0.35)*sin(i)\
center sprintf('%d', i)
plot NaN w l
unset multiplot
So I had this little 'eureka' moment. Apparently I had to put dgrid3d and had to convert the coordinates from polar to cartesian.
Upon converting (and putting set dgrid3d) this ugly plot appeared:
reset
set terminal pngcairo size 800,800
set output '3d-polar.png'
set lmargin at screen 0.05
set rmargin at screen 0.85
set bmargin at screen 0.1
set tmargin at screen 0.9
set pm3d map
unset key
set multiplot
# plot the heatmap
set parametric
set isosamples 500
unset border
unset xtics
unset ytics
set angles degree
r = 0.05 # CHANGED THIS
set urange[0:r] # radius
set vrange[0:360] # angle
set xrange[-r:r]
set yrange[-r:r]
set colorbox user origin 0.9,0.1 size 0.03,0.8
set dgrid3d # ADDED THIS
splot 'data.dat' using 1:2:3 # CHANGED THIS
# now plot the polar grid only
set style line 11 lc rgb 'white' lw 2
set grid polar ls 11
set polar
set rrange[0:r]
unset raxis
set rtics format '' scale 0
unset parametric
set for [i=0:330:30] label at first (r+0.35)*cos(i), first (r+0.35)*sin(i)\
center sprintf('%d', i)
plot NaN w l
unset multiplot
The plot.
I'm at my limit here now. Three questions.
1. Am I correct to assume that I can use the mathematics in gnuplot to convert the coordinates from polar to cartesian? Or is there a way for me to use the polar coordinate data immediately?
2. How do I limit the 'colors' to the round polar plot?
3. What happened to the degree and radius readings? Where did they go?
Thanks!

Position of tic marks in Gnuplot

I am looking for a way to position tic marks in gnuplot between the axis, but so far I only found solution to put them in or out:
set tics in
puts all tic marks inside of the canvas
set tics out
puts all tic marks outide of the canvas
All I want is to place tic marks on both sides of the axis, somethink like
--l--l--
Thanks for a hint!
As said in the comments, it seems not possible to place the tics on both sides of the axis. A workaround would be to plot the axis twice, or to draw the tics by hand with the set arrow.
Drawing tics by hand:
Consider the following settings:
Xmin = -4.0 # range in x
Xmax = 4.0
Ymin = -1.2 # range in y
Ymax = 1.2
NXtics = 8 # number of Xtics
NYtics = 4 # number of Ytics
epsX = 0.05 # length of Xtics
epsY = 0.03 # length of Ytics
dX = (Xmax-Xmin)/NXtics # distance between Xtics
dY = (Ymax-Ymin)/NYtics # distance between Ytics
Next, we draw the bottom, top, left, and right tics:
# xtics and x2tics
do for [i=0:NXtics] {
posX = Xmin+i*dX
set arrow from posX,Ymin-epsY to posX,Ymin+epsY nohead front # bottom
set arrow from posX,Ymax-epsY to posX,Ymax+epsY nohead front # top
}
# ytics and y2tics
do for [i=0:NYtics] {
posY = Ymin+i*dY
set arrow from Xmin-epsX,posY to Xmin+epsX,posY nohead front # left
set arrow from Xmax-epsX,posY to Xmax+epsX,posY nohead front # right
}
Since you are drawing the tics by hand, you will need to configure the axis numbers and ranges:
set xtics Xmin,dX,Xmax scale 0 offset 0,-epsY
set ytics Ymin,dY,Ymax scale 0 offset -epsX,0
set xrange [XMIN:XMAX]
set yrange [YMIN:YMAX]
Finally, your highly complicated plot:
plot sin(x)
Result:
This method also allows you to break the axis
Drawing axis twice:
This method is easier; but you need to set set margins of the canvas, and to use the multiplot mode:
set tmargin at screen 0.9 # top margin
set bmargin at screen 0.2 # bottom
set lmargin at screen 0.2 # left
set rmargin at screen 0.9 # right
set yrange [-1.2:1.2]
set multiplot
set tics scale 0.5 # scale size of the tics
plot 2 notitle # a plot outside the canvas, just to draw the axis
set tics out # tics outside
set format xy '' # delete the numbers
unset border # delete the border
plot sin(x) # your awesome plot
unset multiplot
The result is similar :)
Quick & dirty approach:
set multi
set tics scale 0.5
plot sin(x)/x
set tics out
replot
unset multi
Beware this overprints your graph with a second one. Should be OK for bitmap output, but don't do it if you have vector output (pdf, eps), especially if your graph is complicated or contains a lot of datapoints. It blows up the resulting file to twice its size.
Gnuplot at the moment (v 5.0pl1) has no option to place the tics centered on the axis. You'll have to use one of the workarounds shown here.

Gnuplot: how to add y2 axis scale for different units

I'm plotting data from a file. The data points are in metric units. I want to show a second scale on the right (y2) that's in standard units.
The file represents rocket motor thrust over time. The data are in Newtons. I want to show newtons on the left (this happens by itself, naturally) and pounds force on the right. The conversion is a simple factor (multiply N by 0.2248 to obtain lbf).
I can set y2tics and if I set y2range manually, they appear on the right. What I don't know how to do is set y2range automatically to y1range * a factor.
My eventual solution is to plot twice, once in Newtons on y1 and once in pounds on y2, and make the y2 plot almost invisible:
plot '-' using 1:($2*0.2248) with dots axes x1y2 lc rgb 'white' notitle, \
'' using 1:2 with lines lc rgb '<color>' title '<title>'
The solution above often generates slightly different y scales: with autoragne, gnuplot rounds up the range so the top tick on each axis is a round number, and of course the rounding is different for different units.
Ultimately I end up with Python code that finds the highest thrust value in each graph, then I explicitly set yrange to that number and y2range to that number * 0.2248:
f.write("set yrange [0:%s]; set y2range[0:%s]\n" % (peak_thrust, peak_thrust*NEWTON_LBF));
Here's the end result: http://www.lib.aero/hosted/motors/cesaroni_12-15-12.html (sample graph below)
It seems to me that the easiest way to do this is to simply scale the data:
set y2tics
plot sin(x) w lines, 5*sin(x) w lines axes x1y2
Of course, you're plotting data from a file, so it would look something more like:
set y2tics
FACTOR=0.2248 #conversion factor from newtons to lbf
plot 'datafile' u 1:2 w lines, '' u 1:(FACTOR*$2) w lines
If you're setting the yrange explicitly (which you may need to do):
set yrange [ymin:ymax]
set y2range [ymin*FACTOR:ymax*FACTOR]
Finally, if you really want to rely on autoscaling, you're going to need to do some "gymnastics".
First, set a dummy terminal so we can plot without making a plot:
set term unknown
plot 'datafile' u 1:2 #collect information on our data
Now that we've collected information on the data, we can set our real y2range
FACTOR=0.2248
set y2range [FACTOR*GPVAL_Y_MIN : FACTOR*GPVAL_Y_MAX]
set y2tics nomirror
set ytics nomirror
Now set the terminal and plot the data:
set term ...
set output ...
plot 'datafile' u 1:2 w lines
Version 5.0 added support for this kind of relations between the y and y2 (or also x and x2) axis:
set xrange[0:370]
set ytics nomirror
set y2tics
set link y2 via 0.2248*y inverse y/0.2248
plot x
I know it's an old question and the answer has already been accepted, but I think it's worth sharing my approach.
I simply use modified labels for the x2axis. In your case, this would be
set y2tics ("10" 10/0.2248, "20" 20/0.2248 etc etc...
that can be looped this way
do for [i=0:1000:10] { set y2tics add (sprintf("%i",i) i/0.2248) }
where the for range should be adjusted according to your data (you could use stats and the variable GPVAL_DATA_Y_MAX for complete peace of mind).
Don't forget to
set ytics nomirror
This will give exactly what are you looking for, in (almost) a one liner:
If you want to use a grid and have the converted factors on the x2axis, so that for example to the label y=50 N would correspond y2=11.2 (it keeps things tidy if you use a grid) you can do
do for [i=0:1000:50] { set y2tics add (sprintf("%5.1f",i*0.2248) }
This is the result:

Resources