I have a data file file.dat with three columns (radio, angle, Temperature) for points in the plane, and I want to plot this data as a histogram using polar coordenates and color maps, like in the figure below but using gnuplot. I can create a histogram.dat file with the values of the bins that I want but I don't know how to plot it in gnuplot
To my knowledge there is no right-away "polar heatmap" plotting style in gnuplot (but I could be wrong, at least, I haven't seen an example on the demo page). Hence, you have to implement it yourself.
Basically, for each datapoint you have to plot a filled segment. Therefore, for each datapoint you have to create points on the circumference of this single segment. Then you can plot this segment with filledcurves and a specific color.
Assumptions:
data is in a regular grid/steps in angle (astep) and radius (rstep).
data is in a datablock (how to get it from a file into a datablock, see gnuplot: load datafile 1:1 into datablock)
separators are whitespaces
no header lines
Further optimization potential:
automatic extraction of astep and rstep.
I hope you can adapt the code to your needs.
Code:
### workaround for polar heatmap
reset session
set size square
set angle degrees
unset border
unset tics
set cbtics
set polar
set border polar
unset raxis
# create some test data
f(a,r) = r*cos(a) * r*sin(a) + rand(0)*100
set print $Data
do for [a=0:350:10] {
do for [r=1:20] {
print sprintf("%g %g %g",a,r,f(a,r))
}
}
set print
astep = 10
rstep = 1
# create the segments for each datapoint
set print $PolarHeatmap
do for [i=1:|$Data|] {
a = real(word($Data[i],1))
r = real(word($Data[i],2))
c = real(word($Data[i],3))
do for [j=-5:5] {
print sprintf("%g %g %g",a+j*astep/10., r-0.5*rstep, c)
}
do for [j=5:-5:-1] {
print sprintf("%g %g %g",a+j*astep/10., r+0.5*rstep, c)
}
print ""
print ""
}
set print
set style fill noborder
set palette defined (0 "blue", 1 "grey", 2 "green")
plot $PolarHeatmap u 1:2:3 w filledcurves palette notitle
### end of code
Result:
Related
I have used the stats command to store the x-postion of absolute maxima in my plot of seven datasets in seven variables, grN_pos_max_y with N that goes from 1 to 7. Can I place the tics in the x-axis at the positions specified by these variables?
I tried using
$maxima << EOD
gr1_pos_max_y
gr2_pos_max_y
gr3_pos_max_y
gr4_pos_max_y
gr5_pos_max_y
gr6_pos_max_y
gr7_pos_max_y
EOD
and then
plot ..., \
$maxima u 1:(NaN):xticlabel(1) notitle
but I don't know how to read variables into a data block (if I replace the variable names by their values, however, it works).
Edit: This is what I want (I plotted it using Ethan's answer)
I'm not entirely sure I understand what you want, but this may get you partway there:
set xtics add (gr1_pos_max_y, gr2_pos_max_y, gr3_pos_max_y, gr4_pos_max_y, gr5_pos_max_y, gr6_pos_max_y, gr7_pos_max_y)
plot 'whatever'
That will get you plain (unlabeled) tic marks in addition to whatever tic marks and labels are being generated automatically.
If you want only these marks and no auto-generated marks, remove the keyword add.
If you want to place labels to go with these new tics, change it to:
set xtics add ( "Max 1" gr1_pos_maxy, "Max 2" gr2_pos_maxy, ...
This is all assuming you want these tics to label a plot that contains something other than the tics themselves. If you want only a plot of these y values, perhaps as impulses?, please re-phrase the question or show a sketch of what you want it to look like.
There is no need for awk, you can do it all in gnuplot.
put stats into a loop and write the STATS values into a datablock $Maxima
plot your data and $Maxima as Ethan suggested with impulses
you can also plot the maxima y-value as labels in the graph
The script needs to be adapted depending on your file naming scheme.
Script:
### extract maxima from several files
reset session
N = 7
myFile(n) = sprintf("SO72750257_%d.dat",n)
# create some "random" test data
do for [n=1:N] {
set table myFile(n)
f(x) = -a*(x-x0)**2 +y0
x0 = (n-1)*10./N + rand(0)*10./N
a = rand(0)*50+10
y0 = rand(0)*80+20
plot [0:10] '+' u 1:(f(x))
unset table
}
# extract maxima
set print $Maxima
do for [n=1:N] {
stats myFile(n) u 1:2 nooutput
print sprintf("%.1f %.1f", STATS_pos_max_y, STATS_max_y)
}
set print
set yrange[0:]
set offsets graph 0.05, graph 0.05, graph 0.1, 0
set xtics () # remove all xtics
set key out noautotitle
plot for [i=1:N] myFile(i) u 1:2 w l ti sprintf("Set %d",i), \
$Maxima u 1:2:($0+1):xtic(1) w impulses lc var dt 2, \
$Maxima u 1:2:2 w labels offset 0, char 1
### end of script
Result:
I would like to make a density plot from a distribution like the second subfigure in the following:
Here is what I tried:
unset key
set yrange [0:]
set ytics 5
set print $data
do for [i = 1:100] { print rand(0)*10 }
unset print
binwidth = 1
set boxwidth 0.8*binwidth
# set fill style of bins
set style fill solid 0.5
# define macro for plotting the histogram
hist = 'u (binwidth*(floor(($1)/binwidth)+0.5)):(1.0) smooth freq w boxes'
density = 'u (binwidth*(floor(($1)/binwidth)+0.5)):(1.0) smooth freq with filledcurves y=0'
plot $data #density
It is mainly based on a histogram by adding with filledcurves, but a clear difference is that the resulting figure is not smooth at all.
So, how can I generate smooth density plots from a distribution? Is there any interpolation function that can be used in gnuplot?
I found kernel density estimate in gnuplot can be helpful here.
plot $data u 1:(1/100.) s kdens bandwidth 1 with filledcurves y=0
I'm trying to plot hs-diagram from csv files.
To plot lines I use
plot 'it175.csv' using 7:6 with lines lc rgb 'green' title '175K' at begin, \
'ib50.csv' using 7:6 with lines lc rgb 'red' title '50MPa' at end
It gives nice isotherm titles,
but worse isobaric
How can I rotate line titles and set offset to the end of the line using 'title "title" at end' without using labels, because there are over 430 lines, and it is very difficult to adjust label coordinates for each line by hand
Let me summarize: you want to print the key/legend/title at the end of the curve rotated by a suitable angle.
If you check help plot title and although it is linked to help key for further parameters, I couldn't find any statement about rotated keys (gnuplot 5.4.1).
So, it looks like you have to rotate them yourself, at least, with some effort you can do it automatically.
there is the plotting style with labels which has variable rotation (check help labels)
the rotation angle of the text should be equal to the angle of the last segment of the curve
you need to determine the angle of the last segment of each curve, however, you cannot simply take the coordinates of your plot, but you need to take the "pixel coordinates" of the screen to get the proper "visual" angle.
What the following script does:
generates input files for illustration, like your files which contain the value of the labels already in the filename
get a list of all files obeying a certain pattern, e.g. it*.dat
create a "preliminary" plot in order to get the relationships between plot coordinates and pixel coordinates via the gnuplot variables GPVAL_... which you only get after plotting.
plot your data again with lines and labels and at the same time extract the "visual" angle of the last segment of each curve and rotate the label (key/title) accordingly.
I hope you can follow the script below and adapt it to your data. If you need more explanations, let me know. Maybe there is a simpler solution which I am currently not aware of.
Script:
### rotate title at end of curve
reset session
# create some test data files
do for [t=0:5] {
set print sprintf("it%d.dat",t*5+370)
do for [x=0:100:5] {
print sprintf("%g %g",x,(t/3.+0.2)*x**2+t*2000)
}
set print
}
do for [t=0:6] {
set print sprintf("ib%d.dat",t*5+20)
do for [x=0:100:5] {
print sprintf("%g %g",x*(t+1)/10.,x**3/35.)
}
set print
}
# get a file list
GetFileList(path,expr) = GPVAL_SYSNAME[1:7] eq "Windows" ? \
sprintf('dir /b "%s%s"', path, expr) : \
sprintf('ls "%s%s"', path, expr) # Linux/MacOS
FILES_it = system(GetFileList('','it*.dat'))
FILES_ib = system(GetFileList('','ib*.dat'))
set key noautotitle
set offset 0, graph 0.05, graph 0.05, 0
# plot to get the GPVAL_ ... values
plot for [FILE in FILES_it] FILE u 1:2 w l lc "red", \
for [FILE in FILES_ib] FILE u 1:2 w l lc "green"
# store GPVAL parameters after plot in variables
txmin = GPVAL_TERM_XMIN; txmax = GPVAL_TERM_XMAX; tymin = GPVAL_TERM_YMIN; tymax = GPVAL_TERM_YMAX
xmin = GPVAL_X_MIN; xmax = GPVAL_X_MAX; ymin = GPVAL_Y_MIN; ymax = GPVAL_Y_MAX
# x,y to pix and pix to x,y coordinate conversion
XtoPix(x) = txmin + real(x-xmin) *(txmax-txmin)/( xmax- xmin)
YtoPix(y) = tymin + real(y-ymin) *(tymax-tymin)/( ymax- ymin)
# angle from -180° to +180°
set angle degrees
Angle(x0,y0,x1,y1) = (_dx=x1-x0, _dy=y1-y0, _L=sqrt(_dx**2 + _dy**2), _L==0 ? NaN : \
(_dy>=0 ? acos(_dx/_L) : -acos(_dx/_L) ))
# angle for screen coordinates
AngleScr(x0,y0,x1,y1) = Angle(XtoPix(x0),YtoPix(y0),XtoPix(x1),YtoPix(y1))
myLabel(fname,unit) = sprintf(" %s %s",fname[3:strstrt(fname,'.')-1],unit) # extract number from filename
plot for [FILE in FILES_it] FILE u (last=$0,$1):2 w l lc "red", \
for [FILE in FILES_it] x1=y1=NaN FILE u (x0=x1,x1=$1,$0==1?x1:NaN):(y0=y1,y1=$2,$0==1?y1:NaN):\
(myLabel(FILE,"K")):(AngleScr(x0,y0,x1,y1)) every ::last-1::last w labels rotate var left font ",11", \
for [FILE in FILES_ib] FILE u (last=$0,$1):2 w l lc "green", \
for [FILE in FILES_ib] x1=y1=NaN FILE u (x0=x1,x1=$1,$0==1?x1:NaN):(y0=y1,y1=$2,$0==1?y1:NaN):\
(myLabel(FILE,"MPa")):(AngleScr(x0,y0,x1,y1)) every ::last-1::last w labels rotate var left font ",11"
### end of script
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: