Can I plot 1D heatmap with gnuplot? - gnuplot

I'm trying to plot a 1D heatmap using two columns of data (x value and y value) in gnuplot. The linegraph plotted using my data is like this:
Linegraph:
However after some trying I can only achieve this:
What I've got:
And what I want to get is something like this. (Only example)
What I want:
The gnuplot script that I use is as follows:
set view map
set size ratio 0.2
unset ytics
unset key
splot 'test.dat' u 1:(1):2 palette
Could anyone help please?

So you want to use the y axis as a fake dimension in order to increase the width of your second line plot?
Sure, this is e.g. possible with boxxyerror with explicit ymin and ymax errors that fill the yrange.
set xr [-10:10]
set yr [0:1]
xspacing = 0.1
plot '+' u 1:(0.5):($1-xspacing):($1+xspacing):(0):(1):(sin($1)) w boxxyerror lc palette
In your case replace the sin(x) with the respective column of your data. With the special file '+' the x-width has no effect, but in your case you might need to play around with a proper xspacing in order to avoid white gaps between the points.

I would do it like this:
unset key
set xrange noextend
set offset 0,0,graph .05,graph .05
set palette cubehelix negative
plot 'foo.dat' using 0:3 with lines lc "black", \
'foo.dat' using 0:(70):3 with lines lc palette lw 10

Related

4D contour plots in gnuplot

I have 4D data X,Y,Z plus a field. I would like to do a 4d plot of the field restricted to a sphere. I already use splot w pm3d to have the color bar on the sphere indexed by my field, but I think it would be more readable if I could add 3d contour lines.
I would like something like last example of "function plot" (protein orientation) at http://www.originlab.com/index.aspx?go=Products/Origin/Graphing
Is it even possible in gnuplot ? If so, how to do it ?
Gnuplot cannot generate 4d contour plots.
But if I understand correctly, you have a special case, you do not really have 4d data. The z coordinate depends on x and y such that the point is on a sphere. Maybe this can be used to get the contours.
I assume the datafile contains datapoints for the complete sphere, arranged circle by circle from bottom to top of the sphere, each circle in a separate block.
I have tried this:
Separate the points on the upper half from points of the lower half of the sphere, we need this separation for the sign of z.
Plot the contours of the two halfs in two datafiles contour_l.dat and contour_u.dat. This will only plot the x and y coordinates.
Merge the original datafile and the two contour datafiles into one plot. Pythagoras could help reconstructing the z coordinates for the contour datafiles.
This is the script:
set pm3d depthorder interpolate 5,5
set hidden3d front
unset surface
set contour surface
set zrange [0:1.1]
set table "contour_u.dat"
splot "sh.dat" using 1:2:4 w l
unset table
set zrange [-1.1:0]
set table "contour_l.dat"
splot "sh.dat" using 1:2:4 w l
unset table
set surface
unset contour
set xrange [-1.1:1.1]
set yrange [-1.1:1.1]
set zrange [-1.1:1.1]
set xyplane relative 0.0
set terminal pngcairo size 640,640
set output "c.png"
unset key
splot "sh.dat" using 1:2:3:4 w pm3d, \
"contour_u.dat" using 1:2:( sqrt(1.0-($1*$1+$2*$2))):3 w l lc rgb "black",\
"contour_l.dat" using 1:2:(-sqrt(1.0-($1*$1+$2*$2))):3 w l lc rgb "black"
You did not post data, so I have taken one of the spherical harmonics. With Gnuplot 4.6, I get the following result:
As you can see, it is still not perfect. The contour at x=0 should be investigated, and if I remove the "sh.dat" w pm3d line, the image gets very strange.
But at least this approach might be a starting point, one could try to manually play with the contour line datafiles.

How to plot multiple y-axes?

I saw this graph and only for the curiosity sake was wondering whether it was possible to plot figure with multiple y-axis as in the figure
Many thanks!
As andyras wrote, you can use the second y-axis if you only have two datasets. In this case, you also need to to
set ytics nomirror # remove the tickmarks of the left ayis on the right side
set y2tics # make the right y-axis 'visible'
If you want to plot more than one dataset, I would suggest to use multiplot. You can overlay several independent plots and put a unique offset to the y-axis for each of them.
However, you need to take care that the number of y-tics and y-tick positions is the same.
Plot:
(I did not care about the key here, this still needs adjustment)
Code:
set multiplot
set xrange[0:10]
# We need place to the left, so make the left margin 30% of screen
set lmargin screen 0.3
##### first plot
set ytics 0.4
set yrange[-1.2:1.2]
set ylabel "Voltage" textcolor rgb "red"
plot sin(x)
##### Second plot
set ytics 1
set yrange[-3:3]
set ytics offset -8, 0
set ylabel "Current" offset -8, 0 textcolor rgb "green"
plot 3*cos(x) linecolor 2
##### Third plot
set ytics 0.5
set yrange[-1.5:1.5]
set ytics offset -16, 0
set ylabel "Power" offset -16, 0 textcolor rgb "blue"
plot 3*sin(x)*cos(x) linecolor 3
unset multiplot
Yes, you can have two y axes for free, e.g.
plot x, x**2 axes x1y2
The axes specification lets you put things on x1y1, x2y1, etc. If you want more than two things plotted on the same y axes you have to normalize things yourself:
plot 'data1.dat' using 1:($2/MAX_1), \
'data2.dat' using 1:($2/MAX_2), \
'data3.dat' using 1:($s/MAX_3)
The variables MAX_X can be precalculated by using the stats command in gnuplot 4.6+, or you can put them in manually.

Gnuplot interchanging Axes

I would like to reproduce this plot with gnuplot:
My data has this format:
Data
1: time
2: price
3: volume
I tried this:
plot file using 1:2 with lines, '' using 1:3 axes x1y2 with impulses
Which gives a normal time series chart with y1 as price and y2 as volume.
Next, I tried:
plot file using 2:1 with lines, '' using 2:3 axes x1y2 with impulses
Which gives prices series with y1 as time and y2 as volume.
However, I need the price to remain at y1 and volume at x2.
Maybe something like:
plot file using 1:2 with lines,' ' using 2:3 axes y1x2 with impulses
However, that does not give what I want.
Gnuplot has no official way to draw this kind of horizontal boxplots. However, you can use the boxxyerrorbars (shorthand boxxy) to achieve this.
As I don't have any test data of your actual example, I generated a data file from a Gaussian random-walk. To generate the data run the following python script:
from numpy import zeros, savetxt, random
N = 500
g = zeros(N)
for i in range(1, N):
g[i] = g[i-1] + random.normal()
savetxt('randomwalk.dat', g, delimiter='\t', fmt='%.3f')
As next thing, I do binning of the 'position data' (which in your case would be the volume data). For this one can use smooth frequency. This computes the sum of the y values for the same x-values. So first I use a proper binning function, which returns the same value for a certain range (x +- binwidth/2). The output data is saved in a file, because for the plotting we must exchange x and y value:
binwidth = 2
hist(x) = floor(x+0.5)/binwidth
set output "| head -n -2 > randomwalk.hist"
set table
plot 'randomwalk.dat' using (hist($1)):(1) smooth frequency
unset table
unset output
Normally one should be able to use set table "randomwalk.hist", but due to a bug, one needs this workaround to filter out the last entry of the table output, see my answer to Why does the 'set table' option in Gnuplot re-write the first entry in the last line?.
Now the actual plotting part is:
unset key
set x2tics
set xtics nomirror
set xlabel 'time step'
set ylabel 'position value'
set x2label 'frequency'
set style fill solid 1.0 border lt -1
set terminal pngcairo
set output 'randwomwalk.png'
plot 'randomwalk.hist' using ($2/2.0):($1*binwidth):($2/2.0):(binwidth/2.0) with boxxy lc rgb '#00cc00' axes x2y1,\
'randomwalk.dat' with lines lc rgb 'black'
which gives the result (with 4.6.3, depends of course on your random data):
So, for your data structure, the following script should work:
reset
binwidth = 2
hist(x) = floor(x+0.5)/binwidth
file = 'data.txt'
histfile = 'pricevolume.hist'
set table histfile
plot file using (hist($2)):($3) smooth unique
unset table
# get the number of records to skip the last one
stats histfile using 1 nooutput
unset key
set x2tics
set xtics nomirror
set xlabel 'time'
set ylabel 'price'
set x2label 'volume'
set style fill solid 1.0 border lt -1
plot histfile using ($2/2.0):($1*binwidth):($2/2.0):(binwidth/2.0) every ::::(STATS_records-2) with boxxy lc rgb '#00cc00' axes x2y1,\
file with lines using 1:2 lc rgb 'black'
Note, that this time the skipping of the last table entry is done by counting all entries with the stats command, and skipping the last one with every (yes, STATS_records-2 is correct, because the point numbering starts at 0). This variant doesn't need any external tool.
I also use smooth unique, which computes the average value of the , instead of the sum (which is done with smooth frequency).

gnuplot: max and min values in a range

I'm plotting some data with a different X range and I would like to change yrange according to the maximum and minimum value of the data in the current X range. When I use GPVAL_Y_MAX and GPVAL_Y_MIN, these values correspond to the maximum and minimum of the whole data, not just the data in the range.
For example, I have the following data:
1 3
2 5
3 8
4 20
5 30
I use the following script:
plot 'data.txt' u 1:2;
set xrange [1:3];
replot
set xrange [1:5];
replot
In the first plot I would like to set yrange in [3:8], but in the second plot the yrange sholud be [3:30]. If I use something like
set yrange [GPVAL_Y_MIN:GPVAL_Y_MAX]
GPVAL_Y_MIN and GPVAL_Y_MAX have the same value independently of the xrange.
Any solution?
The variables you want are GPVAL_DATA_Y_MIN and GPVAL_DATA_Y_MAX, which are the y-min/max of the data plotted in a certain range. GPVAL_Y_MIN and GPVAL_Y_MAX are a little less useful generally because they tell you where the edges of the plot border are (in general these values extend a little beyond the GPVAL_DATA... variables because gnuplot leaves a little space between the data and the edge of the plot).
To take advantage of these variables you have to use the range specifiers to the plot command:
plot [1:3] 'data.txt'
set yr [GPVAL_DATA_Y_MIN:GPVAL_DATA_Y_MAX]
replot
...
By the way, the u 1:2 specification is redundant unless you want to remind yourself of which columns you are plotting, since plotting the first two columns as x and y is the gnuplot default. If you don't want to replot to the same output terminal (which is not helpful in some terminals like eps where replotting makes a second page with the same plot), use this command sequence:
set terminal unknown
plot [1:3] 'data.txt'
set terminal <actual output terminal here>
set output 'output.trm'
plot [1:3][GPVAL_DATA_Y_MIN:GPVAL_DATA_Y_MAX] 'data.txt'
Note the use of the range specifier again, this time with a y range specified. This is a little more compact than specifying with set yrange, but makes for a longer line of code.
If you have gnuplot 4.6.0 or higher, you can take advantage of the stats command to avoid replotting. The stats command creates a bunch of handy variables
stats [1:3] 'data.txt'
plot [1:3][stats_min_y:stats_max_y] 'data.txt'
A slightly different command,
stats [1:3] 'data.txt'
plot [stats_min_x:stats_max_x][stats_min_y:stats_max_y] 'data.txt'
Would fill the plot in the x direction based on where the actual data lie. For instance if you had data points at {(1.1, 3), (2, 4), (2.9,5)}, the x range would be set to [1.1:2.9].
Setting the yrange to GPVAL_DATA_Y_MIN:GPVAL_DATA_Y_MAX has the disadvantage of not using gnuplots autoscaling functionality which extends the ranges to the next tic.
In automatic plotting I therefore prefer the following
f(x)=sin(x)>0.5? 1:-1 #example function
set ytics 0.2
plot 1.01*f(x) # dummy plot to set GPVAL_*
set yrange [GPVAL_Y_MIN:GPVAL_Y_MAX]
plot f(x) # actual plot
This also works for data plots of course:
plot 'data.csv' u 1:(1.01*$2)
set yrange [GPVAL_Y_MIN:GPVAL_Y_MAX]
plot 'data.csv' u 1:2
I use it like this to define an x range for a funcion
plot [0:5] sin(10*x) + cos(3*x)
Also, you can set the range before ploting
set xrange [0:5]
plot sin(10*x) + cos(3*x)

Reduce distance between points in splot

I have this gnuplot script
reset
set palette model RGB defined (0 "gray", 0.1 "white", 0.33 "yellow", 0.66 "orange", 1 "red")
set xlabel "x"
set ylabel "y"
set view map
set border 0
unset xtics
unset ytics
splot file_name u 1:2:5:xtic(3):ytic(4) w points ps 5 pt 5 palette
And this is the result:
How can I remove the distance between the points so that I end up with a set of adjacent squares? I want to plot a heatmap with a square for each point in my grid file.
EDIT
The correct way to plot a "grid" heatmap as per #andyras answer is:
set pm3d map
plot file_name u 1:2:5:xtic(3):ytic(4) with image
Which gives this image:
gnuplot offers a third way to plot a heatmap based on connecting points of a 3d surface, rather than grid cells. That is, the x,y coordinates at columns 1,2 are used as corners, or connecting points, of a surface mesh and the colors used in each region are the average of the RGB/HSV values for the 4 defining corners:
set pm3d map
splot file_name u 1:2:5:xtic(3):ytic(4)
I usually go with the options
set pm3d map
plot file_name u 1:2:5:xtic(3):ytic(4) with image
for gridded data (it makes a smaller file if you use vector formats). I suspect your problem may be to do with the fact that you specify a point style and size for your splot. So, you could try setting the pm3d map option and using splot without the point specification, or plot ... with image.

Resources