Filled area in 3d in gnuplot - gnuplot

I am plotting a 3D heat map in gnuplot. I would like to plot a filled area on top of it.
The datafile looks the following
118.01363 0.31794
139.62999 0.31216
173.51509 0.30177
210.90555 0.28675
244.79065 0.26942
268.15969 0.25209
293.86563 0.23764
318.40312 0.21974
341.77215 0.20414
303.21324 0.28270
292.69718 0.29194
279.25998 0.30350
254.13827 0.31794
234.27459 0.31967
173.51509 0.31563
153.65141 0.31274
139.62999 0.31216
I know how to get the result in 2d using plot 'data' w filledcurve, which gives the following result:
However, I cannot figure out how to plot it equivalently on a 3d map. I tried, e.g., splot 'data' u 1:2:(1) w filledcurve in order to obtain filledarea at constant value of z=1 but it does not do the job and it basically shows lines in z-axis direction:
Howe can I fill the area from the example at a constant value of z-axis on top of a pm3d map plot?

The plot style with polygons works in both 2D and 3D plots. You can provide a constant z value of zero or some other value to make sure the polygon sits in front of or behind whatever else is in the plot.
$Data << EOD
118.01363 0.31794
139.62999 0.31216
173.51509 0.30177
210.90555 0.28675
244.79065 0.26942
268.15969 0.25209
293.86563 0.23764
318.40312 0.21974
341.77215 0.20414
303.21324 0.28270
292.69718 0.29194
279.25998 0.30350
254.13827 0.31794
234.27459 0.31967
173.51509 0.31563
153.65141 0.31274
139.62999 0.31216
EOD
splot $Data using 1:2:(0) with polygon, '' using 1:2:(0) with lp lw 4

If I understood your question correctly, this sounds like a simple task, however, I am not aware that you can easily draw filledcurves in 3D.
gnuplot help filledcurves explicitly mentions that this is only a 2D plotting style. Although, there is zerrorfill (check help zerrorfill) which allows to draw fence plots, but there seems to be no xyerrorfill.
So, it seems you have to create a point grid out of your data for being able to plot a surface with pm3d.
If your path or area is not too special you could create a grid by adding points ranging from the mean x,y coordinate to your curve (i.e. like a spider web).
However, the result together with another surface is not satisfying at all. The surface is not nicely hidden behind the other curve. Maybe increasing N or interpolating along the path might help but will take much longer.
I hope very much that there are better solutions.
Script:
### attempt of filledcurved in 3D
reset session
$Data <<EOD
118.01363 0.31794
139.62999 0.31216
173.51509 0.30177
210.90555 0.28675
244.79065 0.26942
268.15969 0.25209
293.86563 0.23764
318.40312 0.21974
341.77215 0.20414
303.21324 0.28270
292.69718 0.29194
279.25998 0.30350
254.13827 0.31794
234.27459 0.31967
173.51509 0.31563
153.65141 0.31274
139.62999 0.31216
EOD
set table $myGrid
stats $Data u 1:2 nooutput
N = 20
do for [i=0:N] {
x0(x) = (x-STATS_mean_x)*i/N + STATS_mean_x
y0(y) = (y-STATS_mean_y)*i/N + STATS_mean_y
plot $Data u (x0($1)):(y0($2)) w table
plot '+' u ("") every ::0::0 w table # insert empty line
}
unset table
f(x,y)=sin(0.1*x)+cos(50*y)
set pm3d hidden noborder depthorder
set samples 100,100
set isosamples 100,100
set key noautotitle
set cbrange [-2:2]
set view 35,30
set multiplot layout 2,1
splot $myGrid u 1:2:(0):(0xff0000) w l lc rgb var
splot f(x,y) w pm3d, \
$myGrid u 1:2:(0):(0xff00ff) w pm3d lc rgb var
unset multiplot
### end of code
Result: (first plot with lines "spider web", second plot with pm3d and another surface)

Related

In gnuplot show only the maxmimum point of the graph and highlight it

In Gnuplot I write below code:
set xlabel "Time in Seconds"
set ylabel "Resistance in Ohms"
while(1){
set multiplot layout 2, 1 title " " font ",12"
set tmargin 1.5
set title "MQ7 Gas Sensor Data"
unset key
plot 'putty2.log' using 0:1 with lines ,'' using 0:2:2 with labels center boxed bs 1 notitle column
set title "MQ9 Gas Sensor Data"
unset key
plot 'putty2.log' using 0:3 with lines
pause 1;
reread;
}
This code is described by drawing the multiplot of the data file 'putty.log' in Gnuplot. After doing this I got this:
but I want to show only the maximum point in the 1st multigraph.
Any help will be appreciated.
As starting point, the following script is a simple way to identify maxima in noisy curves. Actually, the random test data generation takes almost more lines than the maxima extraction.
On the smoothened curve you simply check if the 3 consecutive y-values y0,y1,y2 fulfil y0<y1 && y1>y2, then you have a maximum at y1.
The smoothing via smooth bezier might not be suitable for all type of data. Maybe some averaging together with smoothing might lead to better results.
For example, in the example below the human eye would also detect maxima at 35 and 42.
Futhermore, if you also want to display the y-values of the maxima, the Bezier smoothing probably will mostly return too low values compared to what averaging would give.
I hope you can optimize the script for your data and special needs.
Script:
### find maxima on smoothened data
reset session
# create some random test data
set table $Backbone
set samples 30
plot [0:100] '+' u 1:(rand(0)*10+10) w table
set table $CSpline
set samples 1000
plot $Backbone u 1:2 smooth cspline
set table $Data
noise(h) = (rand(0)*2-1)*h
spike(p,h) = rand(0) < p ? (rand(0)*2-1)*h : 0
plot $CSpline u 1:($2 + noise(1) + spike(0.2,3)) w table
unset table
# smooth the data to facilitate identification of maxima
set table $Smooth
set samples 200
plot $Data u 1:2 smooth bezier
unset table
# simple maxima extraction
set table $Maxima
plot x2=x1=y2=y1=NaN $Smooth u (x0=x1,x1=x2,x2=$1,y0=y1,y1=y2,y2=$2, y0<y1 && y1>y2 ? x1 : NaN):(y1) w table
unset table
set yrange[0:]
set key noautotitle
plot $Data u 1:2 w l lc "red", \
$Smooth u 1:2 w l lc "blue", \
$Maxima u 1:2 w impulses lc "black", \
'' u 1:(0):(sprintf("%.2f",$1)) w labels left offset 1,0.5 rotate by 90 tc "blue"
### end of script
Result:

Scaling image in gnuplot to match with data size

I am trying to plot a data (x, y, z) in gnuplot of range x=(0, 50k+) , y=(0,50k+).
However, the data need to be super imposed on a map which is of size (2000, 2000).
The issue I am having is, the x and y axis range is 50k+ and the data is plotting nicely,
however, the image is rendered in a corner mapping the (0, 2000) range in axis.
I need to render the map independent of the data axis comprising the whole plot area,
over the ata range. Following is what I am trying that doesn't scale the image,
reset
set dgrid3d 200,200 qnorm 2
set xrange [0:57599]
set yrange [0:57599]
set table $Data
splot "data.dat" using 1:2:4
unset table
# create contour lines
set contour base
set cntrparam level incremental 0, 5, 100
unset surface
set table $Contour
splot "data.dat" using 1:2:4
unset table
unset key
set palette defined ( 0 "#ff0000", 40 "#0000ff", 60 "#00ff00", 100 "#e0e0e0" )
set size square
set style fill transparent solid 0.4 noborder
plot "Map.png" binary filetype=png w rgbimage, \
$Data u 1:2:(6):(6):3 with boxxyerror palette,\
$Contour u 1:2:3 w l lt rgb "grey"
This is what I am getting,
this is what I am trying to do,
There are auxilliary keywords that can modify binary filetype=png w rgbimage. The ones you want are dx and dy (see "help binary keywords"). In your case the image is 2000x2000 pixels and each pixel represents an area
57599/2000 = 28.8, so the plot command becomes
plot "Map.png" binary filetype=png dx=28.8 dy=28.8 with rgbimage, \
$Data u 1:2:(6):(6):3 with boxxyerror palette,\
$Contour u 1:2:3 w l lt rgb "grey"
If necessary, you can adjust the image placement relative to the origin of the plot using the keyword origin=(x0,y0)
Alternative answer if you are using the current version (5.4) of gnuplot
Instead of drawing your map as part of the plot command with rgbimage, you can place it as a pixmap filling the plot area and then draw your plot on top of it. The syntax for that would be:
set pixmap 1 "Map.png" at graph 0,0 size graph 1,1 back
plot $Data u 1:2:(6):(6):3 with boxxyerror palette,\
$Contour u 1:2:3 w l lt rgb "grey"
However this loses any connection between the coordinates of the map and the plot, so it is entirely up to you to make sure they match. For example if you zoom the above plot, the zoomed plot will contain a subset of the original data and contours but the entire map image will still be used to fill the plot area. In the solution using with rgbimage, the map and the contours would all zoom together.

Gnuplot: oscilloscope-like line style?

Is it possible in Gnuplot to emulate the drawing style of an analogue oscilloscope, meaning thinner+dimmisher lines on larger amplitudes, like this:?
The effect you see in the oscilloscope trace is not due to amplitude, it is due to the rate of change as the trace is drawn. If you know that rate of change and can feed it to gnuplot as a third column of values, then you could use it to modulate the line color as it is drawn:
plot 'data' using 1:2:3 with lines linecolor palette z
I don't know what color palette would work best for your purpose, but here is an approximation using a function with an obvious, known, derivative.
set palette gray
set samples 1000
plot '+' using ($1):(sin($1)):(abs(cos($1))) with lines linecolor palette
For thickness variations, you could shift the curve slightly up and down, and fill the area between them.
f(x) = sin(2*x) * sin(30*x)
dy = 0.02
plot '+' u 1:(f(x)+dy):(f(x)-dy) w filledcurves ls 1 notitle
This does not allow variable colour, but the visual effect is similar.
Another approach:
As #Ethan already stated, the intensity is somehow proportional to the speed of movement, i.e. the derivative. If you have sin(x) as waveform, the derivative is cos(x). But what if you have given data? Then you have to calculate the derivative numerically.
Furthermore, depending on the background the line should fade from white (minimal derivative) to fully transparent (maximum derivative), i.e. you should change the transparency with the derivative.
Code:
### oscilloscope "imitation"
reset session
set term wxt size 500,400 butt # option butt, otherwise you will get overlap points
set size ratio 4./5
set samples 1000
set xrange[-5:5]
# create some test data
f(x) = 1.5*sin(15*x)*(cos(1.4*x)+1.5)
set table $Data
plot '+' u 1:(f($1)) w table
unset table
set xtics axis 1 format ""
set mxtics 5
set grid xtics ls -1
set yrange[-4:4]
set ytics axis 1 format ""
set mytics 5
set grid ytics ls -1
ColorScreen = 0x28a7e0
set obj 1 rect from screen 0,0 to screen 1,1 behind
set obj 1 fill solid 1.0 fc rgb ColorScreen
x0=y0=NaN
Derivative(x,y) = (dx=x-x0,x0=x,x-dx/2,dy=y-y0,y0=y,dy/dx) # approx. derivative
# get min/max derivative
set table $Dummy
plot n=0 $Data u (d=abs(Derivative($1,$2)),n=n+1,n<=2? (dmin=dmax=d) : \
(dmin>d ? dmin=d:dmin), (dmax<d?dmax=d:dmax)) w table
unset table
myColor(x,y) = (int((abs(Derivative(column(x),column(y)))-dmin)/(dmax-dmin)*0xff)<<24) +0xffffff
plot $Data u 1:2:(myColor(1,2)) w l lw 1.5 lc rgb var not
### end of code
Result:

How do I draw a circle at every point in a gnuplot splot?

I'm trying to plot a set of 3d points stored in a file, as in the standard
set style data lines
splot 'data.dat'
Except I want to draw a circle in the x-y plane along with every point drawn, so that what will be rendered in the end will be a curving tube with the central line on the inside.
I've been able to draw individual circles using parameters, but I'm not sure how you'd do what I've described here.
Is this possible?
If you really want circles, the following might be a solution which comes to my mind. But maybe you actually want a surface plotted? For this there might be other solutions.
Code:
### circles along datapoints
reset session
# create some 3D test data
set samples 50
set table $Data
plot [0:1.5] '+' u (cos(2*pi*$1)):(sin(2*pi*$1)):($1*10) w table
unset table
# define the circle
Radius = 0.1
set samples 24
set table $Circle
plot [0:1] '+' u (cos(2*pi*$1)):(sin(2*pi*$1)) w table
unset table
Offset(i,axis) = real(word($Data[i],axis))
set view 65,124
splot $Data u 1:2:3 w lp pt 7 lw 2 lc rgb "red", \
for [i=1:|$Data|] $Circle u ($1+Offset(i,1)):($2+Offset(i,2)):(Offset(i,3)) w l notitle
### end of code
Result:
Addition:
Here is a slightly modified version (maybe there is a simpler way to achieve it) where you create a datablock $Tube which can be plotted with surfaces. The circles are still parallel to the xy-plane. Although, my suspicion is that you actually might wanted to have the circles orthogonal to the direction of the input data path.
Code:
### circle surface along datapoints
reset session
# create some test data
set samples 50
set table $Data
plot [0:1.5] '+' u (cos(2*pi*$1)):(sin(2*pi*$1)):($1*10) w table
unset table
# define the circle
Radius = 0.1
set samples 24
set table $Circle
plot [0:1] '+' u (cos(2*pi*$1)):(sin(2*pi*$1)) w table
unset table
D(i,axis) = real(word($Data[i],axis))
C(i,axis) = real(word($Circle[i],axis))
# generate "tube" datapoints
set print $Tube
do for [i=1:|$Circle|] {
do for [j=1:|$Data|] {
print sprintf("%.3f %.3f %.3f", C(i,1)+D(j,1), C(i,2)+D(j,2), D(j,3))
}
print "" # empty line
}
set print
set pm3d depthorder noborder
set pm3d lighting specular 0.5
set view 65,124
splot $Data u 1:2:3 w lp pt 7 lw 2 lc rgb "red", \
$Tube u 1:2:3 w pm3d notitle
### end of code
Result:

How can I fix zero to be at the same place when using separate y axes in gnuplot?

I have a data file, with column 1 as the independent variable and columns 2 and 3 as dependent variables. I want to plot variables 2 and 3 on different y axes using something like this:
plot "file.out" u 1:2 axes x1y1, "file.out" u 1:3 axes x1y2
When I do this, the "0" for both axes are offset from one another. How can I fix the zero of one y-axis to the zero of the other y-axis, without explicitly setting yrange to be symmetric for both quantities?
It is possible form version 5 to use set link. However it does not autofit the ratios, so you're left with calculating them yourself
stat "file.out" u 1:2
MAX1=abs(STATS_max_y)
MIN1=-abs(STATS_min_y)
stat "file.out" u 1:3
MAX2=abs(STATS_max_y)
MIN2=-abs(STATS_min_y)
min(a,b)=(a<b)?a:b
set link y2 via min(MAX1/MAX2,MIN1/MIN2)*y inverse y/min(MAX1/MAX2,MIN1/MIN2)
plot "file.out" u 1:2 axes x1y1, "file.out" u 1:3 axes x1y2
Here is a solution which works without linking axes, hence it also works even with gnuplot 4.4 (the version from 2010).
Although, it doesn't need stats but as a disadvantage it requires to replot the data to get the proper scaling of the y2-axis.
Code:
### aligning zero on y1- and y2-axes
reset
set ytics nomirror
set y2tics nomirror
set xzeroaxis
set key top left
plot \
sin(x) axes x1y1 w l, \
cos(x)-0.5 axes x1y2 w l
R0 = -GPVAL_Y_MIN/(GPVAL_Y_MAX-GPVAL_Y_MIN)
y2_min_new = abs(GPVAL_Y2_MIN)>abs(GPVAL_Y2_MAX) ? GPVAL_Y2_MIN : R0*GPVAL_Y2_MAX/(R0-1)
y2_max_new = abs(GPVAL_Y2_MAX)>abs(GPVAL_Y2_MIN) ? GPVAL_Y2_MAX : (R0-1)*GPVAL_Y2_MIN/R0
set y2range[y2_min_new:y2_max_new]
replot
### end of code
Result:
Unfortunately, you can't (at least not in general). If the yrange has the same percent above and below 0, it should probably work, e.g.:
set yrange [-5:10]
set y2range [-10:20]
But if you don't want to do that, then I don't know that there's a better solution...

Resources