gnuplot: 3d scatter plot with circles - gnuplot

I am trying to do a 3d plot, where I want each point to be with my choice of color/shape/shade. The fact is that I want to use the colour palettes from here.
Lets say my data is like this --
0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1
and my gnuplot command looks like this --
set style fill transparent solid 0.75 noborder
set style circle radius screen 0.01
splot "data.out" with circles linecolor rgb "blue"
and I am getting this plot --
as you can see, there is no circle, every point is +.
How do I draw with circles ?

To draw with circles you need
splot "data.out" linecolor "blue" pointtype 6
To get circle try type 6 or 7. Size of circle can be changed by adding option pointsize 2 (number is value of size)

Related

Drawing polygons with holes using Gnuplot

Is there a way using Gnuplot 5.0 to plot a polygon with a hole with filledcurves?
Here are my test data:
# Outer ring
0 -2
-2 0
0 2
2 0
0 -2
# Inner ring
-0.5 0.5
-0.5 -0.5
0.5 -0.5
0.5 0.5
-0.5 0.5
And here is the result:
I know I could re-order the vertices in order to hide the connecting line (in fact the polygon frontier) between the outer and inner ring. But I will deal with machine-generated data, and I would prefer minimize the amount of data preprocessing.
In some other drawing programs, we can draw holes inside polygons by changing the winding-rule to even-odd. But I didn't find such option in gnuplot.
Finally, I cannot just draw the "hole" in white, since in my application I have several shapes to draw, And I want to see other shapes behind the "hole".
Why not just plot the hole in white on top of the shape?
Separate your date into
# shape.txt
0 -2
-2 0
0 2
2 0
0 -2
and
# hole.txt
-0.5 0.5
-0.5 -0.5
0.5 -0.5
0.5 0.5
-0.5 0.5
and then use
plot "shape.txt" u 1:2 w filledcurves, 'hole.txt' u 1:2 w filledcurves lc 'white'
The following solution does what you already mentioned in your question: It reorders the points of the inner polygon in such a way, that the endpoint of the outer polygon and the starting point of the inner polygon have minimal distance (hence no line across the inner polygon). It does is automatically with gnuplot only, so this still might be an acceptable solution for you.
Assumptions:
the outer curve is closed (start point = end point)
the outer curve does not have duplicated points
Procedure:
go through the data and when the first x and y values are found again, the outer structure is finished and the inner structure starts (row index stored in idx0)
when the inner structure starts, it looks for the minimum distance to the start/end point of the outer structure (x0,y0) (row index stored in idx1)
the data is plotted into a datablock $Hollow: first the outer as is and then the inner starting from idx1 to end, and then the inner starting from (idx0+2) to idx1.
In the example below red lines are drawn first to illustrate the empty polygon in the center. Tested with gnuplot 5.0.0.
For multiple holes in a filled curve you might want to check gnuplot: How to draw a filled area with hole? with a rather general but pretty lengthy solution.
Code:
### draw hollow polygon
reset session
$Data <<EOD
# Outer ring
0 -2
-2 0
0 2
2 0
0 -2
# Inner ring
-0.5 0.5
-0.5 -0.5
0.5 -0.5
0.5 0.5
-0.5 0.5
EOD
Distance(x0,y0,x1,y1) = sqrt((x1-x0)**2 + (y1-y0)**2)
GetIdxs(colX,colY) = LastOuter==1 ? ( d1=Distance(x0,y0,column(colX),column(colY)), \
d0==d0 ? (d1<dmin ? (idx1=column(0), dmin=d1) : 0) : \
(idx1=column(0),dmin=d1), d0=d1, LastOuter) : \
column(0)==0 ? (d0=d1=dmin=NaN,x0=column(colX),y0=column(colY)) : \
column(colX)==x0 && column(colY)==y0 && LastOuter==0 ? \
(idx0=column(0),x0=column(colX),y0=column(colY),LastOuter=1 ) \
: LastOuter
set table $Dummy
plot LastOuter=0 $Data u 1:2:(GetIdxs(1,2)):(d1) w table
set table $Hollow
plot $Data u 1:2 every ::::idx0 w table
plot $Data u 1:2 every ::idx1 w table
plot $Data u 1:2 every ::idx0+2::idx1 w table
unset table
plot for [i=-5:5] -x+i/5.lw 2 lc "red" notitle, \
$Hollow u 1:2 w filledcurves lc 1
### end of code
Result:
Just for better understanding the content of $Dummy and $Hollow.
$Dummy
0 -2 -2 nan
-2 0 0 nan
0 2 0 nan
2 0 0 nan
0 -2 1 nan
-0.5 0.5 1 2.54951
-0.5 -0.5 1 1.58114
0.5 -0.5 1 1.58114
0.5 0.5 1 2.54951
-0.5 0.5 1 2.54951
$Hollow
0 -2
-2 0
0 2
2 0
0 -2
-0.5 -0.5
0.5 -0.5
0.5 0.5
-0.5 0.5
-0.5 -0.5
My other solution is based on reordering the inner curve in order to avoid the connection line from outer to inner curve crossing the open area. However, this was rather cumbersome with dummy and extra tables and with a lengthy, confusing expression.
Here is a another much simpler solution:
It is based on variable linecolors, i.e. invisible (fully-transparent) lines, when you switch from the outer curve to the inner curve. This should be fine unless you want to create a SVG or DXF and use the graph as pattern for a cutter.
Prerequisites:
outer and inner curves must be closed (first point = last point)
you have to make sure that outer and inner curves have opposite directions (CW=clockwise and CCW=counterclockwise), this was the case in your example. Otherwise the area will not be hollow but filled.
there should be no empty line between inner and outer curves, but two empty lines between the shapes.
You can easily tell gnuplot when the outer curve ends: when the first x,y-coordinates appears again. It doesn't matter where the inner curve starts as long as the direction is reversed to the outer one.
Just for illustration, I plotted sin(x) and made the 1st structure opaque and 2nd and 3rd structure in semitransparent color.
Script: (works for gnuplot>=5.0.3)
### plot areas with holes
reset session
$Data <<EOD
0 -2 0 # outer CW
-2 0 0
0 2 0
2 0 0
0 -2 0
-0.5 0.5 1 # inner CCW
-0.5 -0.5 1
0.5 -0.5 1
0.5 0.5 1
-0.5 0.5 1
-0.5 -1 0 # outer CCW
-0.1 -0.1 0
-1 0.5 0
-1.5 -1 0
-0.5 -1 0
-0.8 0.2 1 # inner CW
-0.2 -0.1 1
-0.6 -0.8 1
-1.2 -0.8 1
-0.8 0.2 1
0 -1 0 # outer CCW
1 -1 0
1.3 0 0
0.3 0 0
0 -1 0
1.1 -0.2 1 # inner CW
0.9 -0.8 1
0.2 -0.8 1
0.4 -0.2 1
1.1 -0.2 1
EOD
myColors = "0x00ff00 0x770000ff 0x77ff0000"
myColor(i) = i+1>words(myColors) ? 0x000000 : int(word(myColors,i+1))
myColorX(i) = (x0=x1, x1=$1, y0=y1, y1=$2, \
$0==0 ? (fx=x1,fy=y1) : x1==fx && y1==fy ? last=1 : 0, \
last ? 0xff123456 : myColor(i))
set key noautotitle
set multiplot layout 1,2
set title "fixed linecolor"
plot 2*sin(2*x) lw 2, \
for [i=0:2] $Data u 1:2:(myColor(i)) index i w filledcurves lc rgb var lw 2
set title "variable line color with fully transparent lines"
plot 2*sin(2*x) lw 2, \
for [i=0:2] x1=y1=(last=0,NaN) $Data u 1:2:(myColorX(i)) index i \
w filledcurves lc rgb var lw 2
unset multiplot
### end of script
Result:

How to set different heights for separate plots using multiplot

How can one set different heights for two or more plots in multiplot-mode using set size <x>,<y> respecting correct arrangement for the x-axes of the plots? Following problem: I've got a heatmap plot and another linespoint plot with the same time axis. The heatmap plot contains way more information and should use e.g. 80% of the canvas height. Using
set multiplot layout 2,1 margins .1,.8,.05,.95 spacing .05
sets the plots in perfect arrangement but without the possibility to change heights; or at least I didn't manage to get it right. Here are two examples using code from the gnuplot demopage:
$map2 << EOD
0 0 5
0 1 4
0 2 3
0 3 1
0 4 0
1 0 2
1 1 2
1 2 0
1 3 0
1 4 1
2 0 0
2 1 0
2 2 0
2 3 1
2 4 0
3 0 0
3 1 0
3 2 0
3 3 2
3 4 3
4 0 0
4 1 1
4 2 2
4 3 4
4 4 3
EOD
set multiplot layout 2,1 margins .1,.8,.05,.95 spacing .05
plot '$map2' using 2:1:3 with image
plot sin(x)*cos(x)**2, tan(x)
unset multiplot
which results:
Setting explicit sizes and origins before the plotting commands doesn't have any effect.
Plotting without the margins/spacing option and instead setting explicit sizes and origins for each plot one could only guess the correct x-width for the second plot. Guessing it between .85 and .9 in the code:
$map2 << EOD
0 0 5
0 1 4
0 2 3
0 3 1
0 4 0
1 0 2
1 1 2
1 2 0
1 3 0
1 4 1
2 0 0
2 1 0
2 2 0
2 3 1
2 4 0
3 0 0
3 1 0
3 2 0
3 3 2
3 4 3
4 0 0
4 1 1
4 2 2
4 3 4
4 4 3
EOD
set multiplot layout 2,1
set size 1,.75
set origin 0.025,.25
plot '$map2' using 2:1:3 with image
set size .85,.25 # <---
set origin 0.025,0
plot sin(x)*cos(x)**2, tan(x)
unset multiplot
lets me plot it like that:
I hope I could explain my question and thanks a lot for your help! It is highly appreciated!
If I have understood your question, you have to only change rmargin and lmargin:
set size 1,1
set origin 0,0
unset bmargin, unset lmargin, unset tmargin, unset rmargin
set multiplot
set size 1,0.8
set origin 0,0.2
set lmargin at screen 0.1
set tmargin at screen 0.95
set rmargin at screen 0.9
plot 'map2.dat' using 2:1:3 with image
set size 1,0.2
set origin 0,0
set tmargin 0
set lmargin at screen 0.1
set bmargin at screen 0.1
set rmargin at screen 0.9
plot[GPVAL_X_MIN:GPVAL_X_MAX] sin(x)*cos(x)**2, tan(x)
unset multiplot

GNUplot surface using a predefined color map

My data file is a 9800x128 matrix of floating point values, and I'm having trouble plotting a surface graph, that should look similar to MATLABs surf() plot.
Using:
splot '/directory/data.txt' every ::1:1 matrix with lines
works fine, but everything is in one color which makes it impossible to see what's going on. The color palette that I've imported is:
set palette defined (0 0 0 0.5, 1 0 0 1, 2 0 0.5 1, 3 0 1 1, 4 0.5 1 0.5, 5 1 1 0, 6 1 0.5 0, 7 1 0 0, 8 0.5 0 0)
Which is similar to the default one used in MATLAB. Drawing just a 2D contour using this palette:
plot '/directory/data.txt' matrix notitle with image
works just fine as well, it's as soon as I try to marry the color map with a surface plots, as follows:
splot '/directory/data.txt' every ::1:1 matrix with image
I get the following warning message and I'm left with an empty plot.
warning: Number of pixels cannot be factored into integers matching grid. N = 1244473 K = 762
If your data is saved as matrix format, i.e. arranged as
z00 z10 z20 z30 ...
z01 z11 z21 z31 ...
z02 z12 z22 z32 ...
z03 z13 z23 z33 ...
...
then you can plot you data with
set palette defined (0 0 0 0.5, 1 0 0 1, 2 0 0.5 1, 3 0 1 1, 4 0.5 1 0.5, 5 1 1 0, 6 1 0.5 0, 7 1 0 0, 8 0.5 0 0)
splot 'data.txt' matrix with pm3d

Heatmap with Gnuplot on a non-uniform grid

I would like to create a heatmap with gnuplot based on a non-uniform grid, meaning that my x axis bins do not have all the same width, and I can't figure out how to do that because when I plot my data with for example "with image" I get uniformly sized boxes which do no correspond to my coordinates at all (because "image" treats the data just as matrix I guess). So I would like to find a method to get non-uniform boxes which are also positioned in the right place on the Cartesian plane.
My data look something like this:
1 1 0.2
1 2 0.8
1 3 0.1
1 4 0.2
2 1 0.7
2 2 0.2
2 3 0.3
2 4 0.1
5 1 0.2
5 2 0.4
5 3 0.1
5 4 0.9
7 1 0.3
7 2 0.2
7 3 0.9
7 4 0.6
If I run this command on Gnuplot
set xrange [1:10]
p 'mydata.dat' with image
I get an image with 16 boxes that have the same width and height (apparently I don't have enough "reputation" on Stackoverflow to post an image, otherwise I would), but ideally I would like the boxes to have different widths and be in the right place on the plane. For example the first box should range from 1 to 2, the second one from 2 to 5, the third one from 5 to 7, and the last one from 7 to 10 (which is why I wrote set xrange [1:10]).
Could anyone help me please? Thank you very much!
The easiest (maybe only viable) way is to add some dummy data points and use splot ... with pm3d. This plotting style handles heatmaps with general quadrangles.
The image plotting style plots one box (one big pixel) for each data point, while pm3d takes each data point as corner of one or more quadrangles. The color of each quadrangles is determined by the values of the corners and is adjustable with set pm3d corners2color.
So, in your case you need to expand the 4x4 matrix to a 5x5 matrix (expand to right and top), but select the lower left corner to determine the color set pm3d corners2color c1.
The changed data file is then:
1 1 0.2
1 2 0.8
1 3 0.1
1 4 0.2
1 5 0.5
2 1 0.7
2 2 0.2
2 3 0.3
2 4 0.1
2 5 0.5
5 1 0.2
5 2 0.4
5 3 0.1
5 4 0.9
5 5 0.5
7 1 0.3
7 2 0.2
7 3 0.9
7 4 0.6
7 5 0.5
10 1 0.5
10 2 0.5
10 3 0.5
10 4 0.5
10 5 0.5
To plot it use
set pm3d map corners2color c1
set autoscale fix
set ytics 1
splot 'mydata.dat' using 1:($2-0.5):3 notitle
The result with 4.6.3 is:
In general, the z-value of the dummy data points doesn't matter, but in the above script it should lay somewhere between minimum and maximum values to allow set autoscale fix to work properly on the color scale.
If you don't want to change the data file manually, you could do it with some script, but that's a different question.
Here is an alternative solution without splot ... pm3d, but with boxxyerror.
If you plot data it should go as automatic as possible and there should be no need to "invent" and manually add data.
The following solution (a little bit more complex) takes care about the widths (+/-dx) and heights (+/-dy) of the boxes according to the following principle:
if it is an "inner" box, take half the distance to the adjacent datapoint on that side
if it is an "outer" box, take half the distance to the adjacent "inner" datapoint
Here, x-distances are irregular and y-distances are regular, but y-distances could also be irregular.
Data: SO19294342.dat
1 1 0.2
1 2 0.8
1 3 0.1
1 4 0.2
2 1 0.7
2 2 0.2
2 3 0.3
2 4 0.1
5 1 0.2
5 2 0.4
5 3 0.1
5 4 0.9
7 1 0.3
7 2 0.2
7 3 0.9
7 4 0.6
Script: (works with gnuplot>=4.6.0, March 2012)
### heatmap with boxxyerror and variable box-sizes
reset
FILE = "SO/SO19294342.dat"
set style fill solid 1.0
set tics out
set size ratio -1
# extract x-positions
Xs = Ys = ''
Nx = Ny = 0
b = -1
stats FILE u (column(-1)!=b ? (Nx=Nx+1, Xs=Xs.sprintf(" %g",$1), b=column(-1)) : 0, \
column(-1)==0 ? (Ny=Ny+1, Ys=Ys.sprintf(" %g",$2)) : 0) nooutput
d(vs,n0,n1) = abs(real(word(vs,n0))-real(word(vs,n1)))/2
dn(vs,n) = (n==1 ? (n0=1,n1=2) : (n0=n,n1=n-1), -d(vs,n0,n1))
dp(vs,n) = (Ns=words(vs), n==Ns ? (n0=Ns-1,n1=Ns) : (n0=n,n1=n+1), d(vs,n0,n1))
plot FILE u 1:2:($1+dn(Xs,column(-1)+1)):($1+dp(Xs,column(-1)+1)):\
($2+dn(Ys,int(column(0))%Ny+1)):($2+dp(Ys,int(column(0))%Ny+1)):3 w boxxy palette notitle
### end of script
For gnuplot>=4.6.5 you could add :xtic(1):xtic(2) to the plot command to only show your x- and y-coordinates as x,y-ticlabels.
plot FILE u 1:2:($1+dn(Xs,column(-1)+1)):($1+dp(Xs,column(-1)+1)):\
($2+dn(Ys,int(column(0))%Ny+1)):($2+dp(Ys,int(column(0))%Ny+1)):3:\
xtic(1):ytic(2) w boxxy palette notitle
And for gnuplot>=5.0.0 you could add noextend to the ranges to avoid white areas on the sides:
set xrange[:] noextend
set yrange[:] noextend
Result: (created with gnuplot 4.6.0)

vary point color based on column value for multiple data blocks gnuplot

My question is very similar to this one, from which I was able to learn a lot. However, I am working with multiple data blocks, like this:
1 2 3
4 5 6
7 8 0
4 3 0
4 5 7
2 3 0
4 5 0
5 6 7
and I am plotting them like this:
plot "file.txt" index 0 u 1:2 w points pt 1,\
"file.txt" index 1 u 1:2 w points pt 2
which creates 2 different sets of points, each a different color. Now, my goal is to modify this script so that if the 3rd data column is 0, the color of the point will become black. I would like for the other points to remain the colors that they currently are though (meaning different from one another). I have done this:
set palette model RGB defined ( 0 'black', 1 'green' )
unset colorbox
plot file index 0 u 1:2:( $3 == 0 ? 0 : 1 ) w points pt 1 palette,\
file index 1 u 1:2:( $3 == 0 ? 0 : 1 ) w points pt 2 palette
This does exactly what I want, except of course both sets are now plotted in green. Is there any way to plot the black ones as desired, but also make each index a different color?
This is what the special "variable" color is for:
plot 'test.dat' i 0 u 1:2:($3 == 0? 0:1) w p pt 1 lc variable,\
'test.dat' i 1 u 1:2:($3 == 0? 0:2) w p pt 2 lc variable
variable in this context says to use the color of whatever "style index" was given in the third column. I set filters on the 3rd column variable which transforms the third column into a constant (1 or 2) if the data in that column isn't 0.
Another, less direct approach (which works since you're using points) is:
plot 'test.dat' i 0 u 1:($3 == 0? 1/0: $2) w p pt 1 lc rgb "red",\
'test.dat' i 0 u 1:($3 == 0? $2:1/0) w p pt 1 lc rgb "black,\
'test.dat' i 1 u 1:($3 == 0? 1/0: $2) w p pt 1 lc rgb "green",\
'test.dat' i 1 u 1:($3 == 0? $2:1/0) w p pt 1 lc rgb "black,\
It should work to define an extra point in the palette:
set palette model RGB defined ( 0 'black', 1 'green', 2 'red')
unset colorbox
plot file index 0 u 1:2:( $3 == 0 ? 0 : 1 ) w points pt 1 palette,\
file index 1 u 1:2:( $3 == 0 ? 0 : 2 ) w points pt 2 palette

Resources