The title might be a little bit confusing , but I can't think of anything better.
I have a file that contains values, for example:
1 2 15
1 2 15
1 2 15
...and so on, and so on N times, where N is the number of lines in the file.
The problem is, then the values across the file are all the same (nothing changes), as in the aforementioned example, I get an error:
Warning: empty x range [0:0], adjusting to [-1:1]
and the plot consists of only dots in the middle of the picture. What I'd like to see in such a case is a series of lines, in this case on y = 1, 2, and 15.
So, how can I set gnuplot to use line num as x value?
The row number can be accessed as column 0:
set style data line
unse key
plot 'file.txt' using 0:1, '' using 0:2, '' using 0:3
This gives you three lines at y=1, y=2 and y=15
You can also iterate over the columns:
plot for [i=1:3] 'file.txt' using 0:i
Related
I have a file where my data are separated into several indexes. I would like to plot some or all of the indexes as stacked filledcurves by adding the values of selected previous indexes to the values of the current index. I could not find a way to use the sum function as in the case of data arranged as columns in a single index (as in this question), even using the pseudocolumn(-2) as the index number.
Important note: every index as strictly identical sets of x values, only the y values differ.
Is there a way to do something like
p 'data.dat' index (sum(ind=1,3,4,5) ind) u 1:2 w filledcurve x1 t 'Sum(1,3,4,5)', '' index (sum(ind=1,2,5) ind) u 1:2 w filledcurve x1 t 'Sum(1,2,5)'
within gnuplot or do I have to resort to a script (maybe a variation of the one in this answer)?
You can do this with some help outside gnuplot (invoked within gnuplot). Imagine you have the following data file with 4 indices (0 to 3):
1 2
2 3
1 5
2 5
1 0
2 3
1 4
2 3
Now say that we want to sum 1 and 2 and 0 and 3. The first sum should return:
1 5
2 8
while the second sum should return
1 6
2 6
We can select the blocks we want using set table:
set table "sum1"
plot for [i in "1 2"] "data3" index 0+i pt 7 not
set table "sum2"
plot for [i in "0 3"] "data3" index 0+i pt 7 not
unset table
Now use sed piping to remove the empty lines and smooth freq to sum for equal x values:
plot "< sed '/^\s*$/d' sum1" smooth freq t "sum1", \
"< sed '/^\s*$/d' sum2" smooth freq t "sum2"
Although you may be able to do it using functions and variables of gnuplot 4.4+, this won't be very efficient as you want to perform an operation on several distant lines in your file, which is in fact an operation on arrays. Gnuplot is not meant for this, the datafiles should have a structure reasonably close to what you want to plot. I advise that you try to produce a file with such a structure, e.g. have the values you want to sum on the same line in different columns.
The starting point is that I have a graph with 4 lines on it. They are the results of my simulation, plotted over an x-axis of iteration, at 4 different locations. I also have experimental values at each of those locations. I want to plot those 4 experimental values as horizontal lines on the same graph. I would also like the line colours of the simulation and experiment results at each location to be the same.
With #Tom's help, below, I have got the following script to do this:
unset bars
max = 1e6
set xrange[7000:24000]
set yrange[-0.5:1.5]
plot for [i=2:5] 'sim' using 1:(column(i)) ls i, \
for [i=1:4] 'expt' using (1):1:(max) every ::(i-1)::(i-1) with xerror ls i ps 0
The problem is that I want the values in xrange[x_min:x_max] and yrange[y_min:y_max] to be taken from sim and expt as follows:
x_min = min(sim[:1]) # where min(sim[:1]) means "min value in file 'sim' col 1"
x_max = max(sim[:1])
y_min = min(sim[:2],sim[:3],sim[:4],sim[:5],expt[:1])
y_max = max(sim[:2],sim[:3],sim[:4],sim[:5],expt[:1])
My OS is Scientific Linux: Release 6.3, Kernel Linux 2.6.32-358.2.1.el6.x86_64, GNOME 2.28.2
sim and expt are .txt files
A representative sample of sim is:
7520 0.282511 0.0756715 -0.222863 -0.0898819
7521 0.315944 0.201687 -0.321723 -0.106345
7522 0.230956 0.102217 -0.34196 -0.061009
7523 1.460043 -0.00118292 -0.045077 0.673926
A representative sample of expt is:
1.112
0.123
-0.45
0.862
Thank you for your help.
I think that this is a way to solve your problem:
unset bars
max = 1e6
set xrange[0:8]
plot for [i=1:4] 2*i+sin(x) ls i, \
for [i=1:4] 'expt' using (1):1:(max) every ::(i-1)::(i-1) with xerror ls i ps 0
Based on some information I found on Gnuplot tricks, I have (ab)used error bars to produce horizontal lines based on the points in this data file:
2
4
6
8
The (1):1:(max) specifies that a point should be plotted at the coordinate (1, y), where y is read from the data file. The max is the value of xdelta, which determines the size of the x error bar. This is one way of achieving a horizontal line in your plot, as a suitably large value of max will result in an error bar across the entire xrange of your plot.
Here's what the output looks like:
Considering, that you have a data file with five columns, one with the x-values and four with y-values. Now you have additional file where a number path_to_expt comes from. In order to plot the columns and one horizontal line having the y-value path_to_expt you can use
plot for [i=2:5] path_to_file using 1:(column(i))
This plot col 2 against 1, 3 vs 1, 4 vs 1 and 5 vs 1. To get different styles, just use set linetype to redefine the automatically assigned line types:
set linetype 1 lc rgb 'orange'
# ... other lt definitions
plot for [i=2:5] path_to_file using 1:(column(i))
If you don't want to overwrite exising linetype 1..4, use e.g. 11..14:
set linetype 11 lc rgb 'orange'
# ...
plot for [i=2:5] path_to_file using 1:(column(i)) lt (9 + i)
Finally, in order to plot a horizontal line, using the same x-values as in the data file, use
mynumber = 27
plot path_to_file using 1:(mynumber)
If you don't put a number in parentheses, it is interpreted as column number (like the 1 here), whereas put inside parentheses, it is treated as number.
Another option would be to set arrows:
set arrow from graph 0, first mynumber to graph 1, first mynumber lt 1
plot for [i=2:5] path_to_file using 1:(column(i))
I have an ascii data file with ~30 columns of data. I would like to make a x vs. y plot (columns 1 and 2) and use column 17 for making the filled color contour plot. If I do:
set pm3d map
splot "datafile" u 1:2:17
then I get a message saying: Warning, Single isoline (scan) is not enough for a pm3d plot.
Hint: Missing blank lines in the data file?
My datafile does not contain any linebreaks. So line 1 contains 30 columns for particle 1, line 2 contains 30 columns for particle 2 ....etc. Is there an easy way to get round this if my file does not contain linebreaks?
I am currently analysing two character combinations in texts and I want to visualize the frequencies in a heatmap using gnuplot. My input file is in the format (COUNT stands for the actual number of this combination)
a a COUNT
a b COUNT
...
z y COUNT
z z COUNT
Now I'd like to create a heatmap (like the first one that is shown on this site). On the x axis as well on the y axis I'd like to display the characters from A-Z, i.e.
a
b
...
z
a b ... z
I am pretty new to gnuplot, so I tried plot "input.dat" using 2:1:3 with images, which results in an error message "Can't plot with an empty x range". My naive approach to run set xrange['a':'z'] did not help much.
There are a bunch of related questions on SO, but they either deal with numeric x-values (e.g. Heatmap with Gnuplot on a non-uniform grid) or with different input data formats (e.g. gnuplot: label x and y-axis of matrix (heatmap) with row and column names)
So my question is: What is the easiest way to transform my input file into a nice gnuplot heatmap?
You need to convert the alphabet characters to integers. It might be possible to do this somehow in gnuplot, but it would probably be messy.
My solution would be to use a quick python script to convert the datafile (let's say it is called data.dat):
#!/usr/bin/env python2.7
with open('data.dat', 'r') as i:
with open('data2.dat', 'w') as o:
lines = i.readlines()
for line in lines:
line = line.split()
x = str(ord(line[0].lower()) - ord('a'))
y = str(ord(line[1].lower()) - ord('a'))
o.write("%s %s %s\n" % (x, y, line[2]))
This takes a file like this:
a a 1
a b 2
a c 3
b a 4
b b 5
b c 6
c a 7
c b 8
c c 9
and converts it to:
0 0 1
0 1 2
0 2 3
1 0 4
1 1 5
1 2 6
2 0 7
2 1 8
2 2 9
Then you can plot it in gnuplot:
#!/usr/bin/env gnuplot
set terminal pngcairo
set output 'test.png'
set xtics ("a" 0, "b" 1, "c" 2)
set ytics ("a" 0, "b" 1, "c" 2)
set xlabel 'First Character'
set ylabel 'Second Character'
set title 'Character Combination Counts'
plot 'data2.dat' with image
It's a little clunky to set the tics manually that way, but it works fine.
Edit: Revised code, better sticking to the original question.
Your question basically boils down to: is there an ord() function in gnuplot?
Answer: No, there is not, but you can built it yourself, without the need for calling external scripts. The "ASCII-Trick" is taken from here: how can I find out the ASCII code of a character in gnuplot
The following example works with gnuplot>=4.6.0 (version at the time of OP's question).
Code:
### plotting heatmap from "alphabetical data"
reset
# definition of chr() and ord()
chr(n) = sprintf('%c',n)
ASCII = ''; do for [i=1:255] {ASCII = ASCII.chr(i)}
ord(c) = strstrt(ASCII,c)
FILE = "SO20428010.dat"
# create some random test data
set print FILE
do for [i=1:26] for [j=1:26] {
print sprintf("%s %s %d", chr(i+96), chr(j+96), int(rand(0)*101))
}
set print
set size square
set xrange[0:27]
set yrange[27:0] reverse
set key noautotitle
set palette rgb 33,13,10
ChrToInt(col) = ord(strcol(col))-96
plot FILE u (ChrToInt(1)):(ChrToInt(2)):3:xtic(1):ytic(2) w image
### end of code
Result:
I am currently using a script to generate histogram plots, e.g., by doing:
set style histogram cluster gap 4
plot for [COL=2:10] 'example.dat' u COL:xticlabels(1) title columnheader(COL)
Now I wish to add the y-values (numbers) above the bars in the histogram but adding w labels gives the 'Not enough columns for this style' error.
plot for [COL=2:10] 'example.dat' u COL:xticlabels(1) title columnheader(COL), \
for [COL=2:10] 'example.dat' u COL title '' w labels
Is it possible to add y-labels using the histogram style?
Note: I know that there are examples for plotting with boxes. I wish to make this work with the histogram style if possible.
Here's a test datafile I came up with:
example.dat
hi world foo bar baz qux
1 2 3 4 5 6
4 5 7 3 6 5
Here's the script I used to plot it:
set yrange [0:*]
GAPSIZE=4
set style histogram cluster gap 4
STARTCOL=2 #Start plotting data in this column (2 for your example)
ENDCOL=6 #Last column of data to plot (10 for your example)
NCOL=ENDCOL-STARTCOL+1 #Number of columns we're plotting
BOXWIDTH=1./(GAPSIZE+NCOL) #Width of each box.
plot for [COL=STARTCOL:ENDCOL] 'example.dat' u COL:xtic(1) w histogram title columnheader(COL), \
for [COL=STARTCOL:ENDCOL] 'example.dat' u (column(0)-1+BOXWIDTH*(COL-STARTCOL+GAPSIZE/2+1)-0.5):COL:COL notitle w labels
Each cluster of histograms takes a total width of 1 unit on the x axis. We know how many widths we need (the number of boxes +4 since that is the gapsize). We can calculate the width of each box (1/(N+4)). We then plot the histograms as normal. (Note that I added with histogram to the plot command).
According to the builtin help, labels require 3 columns of data (x y label). In this case, the y position and the label are the same and can be read directly from the column COL. The x position of the first block is centered 0 (and has a total width of 1). So, the first block is going to be located at x=-0.5+2*BOXWIDTH. The 2 here is because the gap is 4 boxwidths -- two on the left and 2 on the right. The next block is going to be located at -0.5+3*BOXWIDTH, etc. In general, (as a function of COL) we can write this as
-0.5+BOXSIZE*(COL-STARTCOL+1+GAPSIZE/2)
We need to shift this to the right by 1 unit for each additional block we read. Since each block corresponds to 1 line in the data file, we can use pseudo-column 0 (i.e. column(0) or $0) for this since it gets incremented for each "record/line" gnuplot reads. The 0th record holds the titles, the first record holds the first block. Since we want a function which returns 0 for the first record, we use column(0)-1. Putting it all together, we find that the x-position is:
(column(0)-1-0.5+BOXSIZE*(COL-STARTCOL+1+GAPSIZE/2))
which is equivalent to what I have above.