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.
Related
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)
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:
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:
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:
I have x- and y-data points representing a star cluster. I want to visualize the density using Gnuplot and its scatter function with overlapping points.
I used the following commands:
set style fill transparent solid 0.04 noborder
set style circle radius 0.01
plot "data.dat" u 1:2 with circles lc rgb "red"
The result:
However I want something like that
Is that possible in Gnuplot? Any ideas?
(edit: revised and simplified)
Probably a much better way than my previous answer is the following:
For each data point check how many other data points are within a radius of R. You need to play with the value or R to get some reasonable graph.
Indexing the datalines requires gnuplot>=5.2.0 and the data in a datablock (without empty lines). You can either first plot your file into a datablock (check help table) or see here:
gnuplot: load datafile 1:1 into datablock
The time for creating this graph will increase with number of points O(N^2) because you have to check each point against all others. I'm not sure if there is a smarter and faster method. The example below with 1200 datapoints will take about 4 seconds on my laptop. You basically can apply the same principle for 3D.
Script: works with gnuplot>=5.2.0
### 2D density color plot
reset session
t1 = time(0.0)
# create some random rest data
set table $Data
set samples 700
plot '+' u (invnorm(rand(0))):(invnorm(rand(0))) w table
set samples 500
plot '+' u (invnorm(rand(0))+2):(invnorm(rand(0))+2) w table
unset table
print sprintf("Time data creation: %.3f s",(t0=t1,t1=time(0.0),t1-t0))
# for each datapoint: how many other datapoints are within radius R
R = 0.5 # Radius to check
Dist(x0,y0,x1,y1) = sqrt((x1-x0)**2 + (y1-y0)**2)
set print $Density
do for [i=1:|$Data|] {
x0 = real(word($Data[i],1))
y0 = real(word($Data[i],2))
c = 0
stats $Data u (Dist(x0,y0,$1,$2)<=R ? c=c+1 : 0) nooutput
d = c / (pi * R**2) # density: points per unit area
print sprintf("%g %g %d", x0, y0, d)
}
set print
print sprintf("Time density check: %.3f sec",(t0=t1,t1=time(0.0),t1-t0))
set size ratio -1 # same screen units for x and y
set palette rgb 33,13,10
plot $Density u 1:2:3 w p pt 7 lc palette z notitle
### end of script
Result:
Would it be an option to postprocess the image with imagemagick?
# convert into a gray scale image
convert source.png -colorspace gray -sigmoidal-contrast 10,50% gray.png
# build the gradient, the heights have to sum up to 256
convert -size 10x1 gradient:white-white white.png
convert -size 10x85 gradient:red-yellow \
gradient:yellow-lightgreen \
gradient:lightgreen-blue \
-append gradient.png
convert gradient.png white.png -append full-gradient.png
# finally convert the picture
convert gray.png full-gradient.png -clut target.png
I have not tried but I am quite sure that gnuplot can plot the gray scale image directly.
Here is the (rotated) gradient image:
This is the result:
Although this question is rather "old" and the problem might have been solved differently...
It's probably more for curiosity and fun than for practical purposes.
The following code implements a coloring according to the density of points using gnuplot only. On my older computer it takes a few minutes to plot 1000 points. I would be interested if this code can be improved especially in terms of speed (without using external tools).
It's a pity that gnuplot does not offer basic functionality like sorting, look-up tables, merging, transposing or other basic functions (I know... it's gnuPLOT... and not an analysis tool).
The code:
### density color plot 2D
reset session
# create some dummy datablock with some distribution
N = 1000
set table $Data
set samples N
plot '+' u (invnorm(rand(0))):(invnorm(rand(0))) w table
unset table
# end creating dummy data
stats $Data u 1:2 nooutput
XMin = STATS_min_x
XMax = STATS_max_x
YMin = STATS_min_y
YMax = STATS_max_y
XRange = XMax-XMin
YRange = YMax-YMin
XBinCount = 20
YBinCount = 20
BinNo(x,y) = floor((y-YMin)/YRange*YBinCount)*XBinCount + floor((x-XMin)/XRange*XBinCount)
# do the binning
set table $Bins
plot $Data u (BinNo($1,$2)):(1) smooth freq # with table
unset table
# prepare final data: BinNo, Sum, XPos, YPos
set print $FinalData
do for [i=0:N-1] {
set table $Data3
plot $Data u (BinNumber = BinNo($1,$2),$1):(XPos = $1,$1):(YPos = $2,$2) every ::i::i with table
plot [BinNumber:BinNumber+0.1] $Bins u (BinNumber == $1 ? (PointsInBin = $2,$2) : NaN) with table
print sprintf("%g\t%g\t%g\t%g", XPos, YPos, BinNumber, PointsInBin)
unset table
}
set print
# plot data
set multiplot layout 2,1
set rmargin at screen 0.85
plot $Data u 1:2 w p pt 7 lc rgb "#BBFF0000" t "Data"
set xrange restore # use same xrange as previous plot
set yrange restore
set palette rgbformulae 33,13,10
set colorbox
# draw the bin borders
do for [i=0:XBinCount] {
XBinPos = i/real(XBinCount)*XRange+XMin
set arrow from XBinPos,YMin to XBinPos,YMax nohead lc rgb "grey" dt 1
}
do for [i=0:YBinCount] {
YBinPos = i/real(YBinCount)*YRange+YMin
set arrow from XMin,YBinPos to XMax,YBinPos nohead lc rgb "grey" dt 1
}
plot $FinalData u 1:2:4 w p pt 7 ps 0.5 lc palette z t "Density plot"
unset multiplot
### end of code
The result: