plotting single (datum,column) from each block with lines in gnuplot - gnuplot

I have a data file containing constant-size blocks of data. In order to plot element (n,m) from each block I do
pl file u m ev ::n-1::n-1
This works fine, but the graph is displayed in point style since this is default for data. When I add "with lines" to the command above, this produces an empty graph.

Maybe there are shorter solutions, but the first solution which comes to my mind is to plot the data into a datablock and then plot this datablock. This will remove empty lines and hence datapoints will be connected when plotting with lines or with linespoints.
Code:
### plot individual datapoints from each block with lines
reset session
$Data <<EOD
1 11
2 12
3 13
4 14
5 15
6 16
7 17
8 18
9 19
EOD
m = 2
n = 1
set table $DataSelected
plot $Data u m every ::n-1::n-1 w table
unset table
plot $DataSelected u 1 w linespoints pt 7
### end of code
Result:

Related

gnuplot: how to draw a set of triangles from a file?

In gnuplot, we can set object polygon to draw a polygon, including triangles, given its coordinates.
But how to do draw a set of triangles whose coordinates are stored in a file where each line is in the format <x1> <y1> <x2> <y2> <x3> <y3>?
As for rectrangles/circles, this task can be done using plot and with boxxy/with circles options, but there is no with triangles option in gnuplot.
A possible solution is to use with vectors by drawing each edge, but it is a bit complicated and this method does not support color filling.
I cannot think of a way to do this in one step; the data format does not match any of gnuplot's plotting styles.
One approach is to transform the data via a temporary file. Here is an example that works in version 5.2 and newer. If you are using a newer gnuplot then you could substitute with polygons for with filledcurves closed.
$DATA << EOD
1 1 2 2 3 1
11 11 14 14 17 11
21 21 22 22 23 21
15 5 16 6 17 5
6 6 7 7 8 6
EOD
set table "temp.dat"
plot $DATA using (sprintf("%g %g\n %g %g\n %g %g\n \n",$1,$2,$3,$4,$5,$6)) with table
unset table
unset key
set style fill solid noborder
plot "temp.dat" using 1:2 with filledcurves closed fillcolor "forest-green"
Note: I was originally going to show use of a temporary datablock rather than an intermediate temporary file, but it this doesn't work because the formatted output from with table does not translate the newline characters \n into empty datablock lines.
Edit (show variable color)
The extra data field containing a RGB color must be present in every input line of the reformatted data, but only the value from the first vertex of each polygon is used. The sprintf format in this example has been modified to reproduce the color (NB: hexadecimal integer value) from the original data file accordingly, with zeros for the dummy values in the remaining polygon vertices.
$DATA << EOD
1 1 2 2 3 1 0x00ffff
11 11 14 14 17 11 0x191970
21 21 22 22 23 21 0x2e8b57
15 5 16 6 17 5 0xffc020
6 6 7 7 8 6 0x8b000
EOD
set table "temp.dat"
plot $DATA using (sprintf("%g %g 0x%x\n %g %g 0\n %g %g 0\n \n",$1,$2,int($7),$3,$4,$5,$6)) with table
unset table
unset key
set style fill solid noborder
plot "temp.dat" using 1:2:3 with filledcurves closed fillcolor rgb variable
My suggestion would have been the same as #Ethan's. Therefore, here is an alternative approach using set object polygon.
It also requires gnuplot>=5.2 since it uses indexing of datablock lines. Hence, the data should already be in a datablock without empty or commented lines. But how to get a file into a datablock?
Either something like:
set table $Data
plot FILE u 1:2:3:4:5:6:7 w table
unset table
or alternatively see here: gnuplot: load datafile 1:1 into datablock
Script:
### draw some colored triangles from a datablock
reset session
$Data <<EOD
0 0 2 1 1 2 0xff0000
5 1 3 2 4 4 0x00ff00
3 3 2 5 1 4 0x0000ff
EOD
vx(n,t) = word($Data[n],t*2-1) # vertex x-coordinate
vy(n,t) = word($Data[n],t*2) # vertex y-coordinate
color(n) = word($Data[n],7) # triangle color
set linetype 1 lc rgb "black"
do for [n=1:|$Data|] {
set obj n polygon from vx(n,1),vy(n,1) to vx(n,2),vy(n,2) to vx(n,3),vy(n,3) to vx(n,1),vy(n,1)
set obj n fc rgb color(n) fs solid 0.5 border lt 1 lw 3
}
set size square
set xrange[0:5]
set yrange[0:5]
plot NaN notitle # or plot something else
### end of script
Result:
Addition:
Alternatively, similar to Ethan's solution, plotting triangles instead of drawing triangles, but without using a temporary file on disk (but a datablock). The result is identical to the graph above. I haven't tested whether drawing or plotting is faster and/or more efficient if you want to draw/plot thousands of triangles.
Script:
### plot some colored triangles from a datablock
reset session
$Data <<EOD
0 0 2 1 1 2 0xff0000
5 1 3 2 4 4 0x00ff00
3 3 2 5 1 4 0x0000ff
EOD
vx(n,t) = word($Data[n],t*2-1) # vertex x-coordinate
vy(n,t) = word($Data[n],t*2) # vertex y-coordinate
color(n) = word($Data[n],7) # triangle color
set print $Triangles
do for [n=1:|$Data|] {
print sprintf("%s %s %s\n%s %s 0\n%s %s 0\n%s %s 0\n\n", \
vx(n,1),vy(n,1),color(n), vx(n,2),vy(n,2), vx(n,3),vy(n,3), vx(n,1),vy(n,1))
}
set print
set size square
set xrange[0:5]
set yrange[0:5]
set linetype 1 lc rgb "black" lw 3
set style fill solid 0.5
plot $Triangles u 1:2:3 w filledcurves lc rgb var notitle
### end of script

plot 10 line sof 1000 values on gnuplot

I have a data file with 10 lines with 1000 values each line and I'm trying to plot this values with this script
#!/usr/bin/gnuplot -persist
plot "data.dat" using [1:1000] title "" with lines
but I get this error
plot "data.dat" using [1:1000] title "" with lines
^
"./plot.sh", line 3: invalid expression
How can I indiate a interval form the first value to the 1000 value?I't posible to set a diferent random clor to every line?
As #vaettchen pointed out, gnuplot wants data in columns and plotting rows is not straightforward. So, best would be if your data was transposed. Unfortunately, gnuplot has no function to transpose data. So, you have to use external tools to transpose your data.
Although, if your data is 10 lines with 1000 values each, i.e. a strict 10x1000 matrix, you could do something with gnuplot only (see below).
However, if your data is not a strict matrix, e.g. one line has more or less values or one value missing the method below won't work.
The following example (just 5 lines with 7 values each) illustrates plotting columns and plotting rows.
### plotting columns and rows
reset session
set colorsequence classic
$Data <<EOD
11 12 13 14 15 16 17
21 22 23 24 25 26 27
31 32 33 34 35 36 37
41 42 43 44 45 46 47
51 52 53 54 55 56 57
EOD
# get the number of rows
stats $Data u 0 nooutput
RowCount = STATS_records
# do the plot
set multiplot layout 1,2
set title "Plotting columns"
set xlabel "Row no."
set xtics 1
# plot all columns from 1 to *(=autodetection)
plot for [i=1:*] $Data u ($0+1):i w lp pt 7 not
set title "Plotting rows"
set xlabel "Column no."
# plot all rows
plot for [i=0:RowCount-1] $Data matrix u ($1+1):0 every :::i::i w lp pt 7 not
unset multiplot
### end of code
Which results in:

Plotting same line number of several blocks data with gnuplot

I have a data file with the following structure
block1: line 1
line 2
line 3
.....
block2: line 1
line 2
line 3
......
block3: .....
To plot only the block2, I use the command
plot 'file' u x1:x2 every :::2::2 w l
How to gather only line 1 of each block on the plot command?
my guess would be, because the datapoints are from different blocks they are separated by an empty line. And datapoints separated by an empty line are not plotted connected using "with lines".
Try the following: write your desired data into a new table, like the example below (gnuplot 5.2.5).
### plot values of different blocks connected with lines
reset session
set colorsequence classic
$Data <<EOD
# block line xvalue yvalue
0 0 1 0
0 1 2 1
0 2 3 2
0 3 4 3
1 0 5 10
1 1 6 11
1 2 7 12
1 3 8 13
2 0 9 20
2 1 10 21
2 2 11 22
2 3 12 23
EOD
set table $Data2
plot $Data u 0:3:4 every ::0::0 with table
unset table
print $Data2
plot $Data u 3:4 w lp,\
$Data2 u 2:3 w lp
### end code
addition: if you want to do this with several files try the following below
(little drawback so far: points from different files are not connected)
### plot every Nth line of all blocks of several systematic files
reset session
FileCount = 2 # number of files
Col1 = 1 # e.g. column of x value
Col2 = 2 # e.g. column of y value
N = 0 # N=0 is first line of each datablock, N=1 second line, etc...
set print $EveryNthLineFromAllBlocksOfAllFiles
do for [i=1:FileCount] {
FILE = sprintf("name_%d.dat",i)
set table $EveryNthLine
plot FILE u Col1:Col2 every ::N::N with table
unset table
print $EveryNthLine
}
set print
print $EveryNthLineFromAllBlocksOfAllFiles
plot $EveryNthLineFromAllBlocksOfAllFiles u 1:2 w lp
### end code

Calculate y from x for a single label

I want to manually add a label in the graph at a certain x position by only entering x and calculate y from the datapoint.
e.g.:
1 set terminal png
2 set output 'test2.png'
3
4 x = 3
5 y = 33
6 set label "test" at x,y
7
8 plot '-' using 1:2 with lines
9 1 11
10 2 22
11 3 33
12 4 22
13 5 33
So, I don't want to hardcode "33" in line 5.
Is that possible?
(I have googled this question and inspected the possible duplicates offered by Stackoverflow after I entered the title. Nada.)
Method 1 (data scan)
For not too-large inputs, one could load the x/y data into two separate arrays and then locate the y-value corresponding to a given x-value:
$DATA <<EOD
1 11
2 22
3 33
4 22
5 33
EOD
stat $DATA nooutput
N = STATS_records
array data_x[N]
array data_y[N]
stat $DATA u (data_x[1+$0]=$1,data_y[1+$0]=$2,$1):2 nooutput
x0 = 3
y0 = NaN
do for [i=1:N] {
if (data_x[i] == x0) {
y0 = data_y[i]
}
}
set label "test" at x0,y0
plot $DATA using 1:2 with lines t ''
The trick here is the second stat command which is used solely in order to populate the arrays data_x, and data_y. The expression (data_x[1+$0]=$1,data_y[1+$0]=$2,$1):2 basically evaluates for each row in the data to 1:2. However, due to the comma operator, it has the side effect of setting the corresponding elements of data_x, and data_y.
Method 2 (fitting)
As an approximate alternative, one might fit a narrow Gaussian centered at x0 = 3 to the input data set. If the characteristic width sigma of this Gaussian is smaller than the characteristic spacing between data points, then the amplitude should match the input y-value:
$DATA <<EOD
1 11
2 22
3 33
4 22
5 33
EOD
x0 = 3
sigma = 0.1
f(x) = a*exp(-(x - x0)**2 / (2*sigma**2))
fit f(x) $DATA using 1:2 via a
print a
y0 = a
set label "test" at x0,y0
plot $DATA using 1:2 with lines t ''
Method 3 (external tool)
As a more robust alternative, one could delegate this task to an external utility invoked in Gnuplot via the system call. The example is using gawk to scan the input data file. If it finds a matching value in the first column, it prints the corresponding y value and exits (so that only the first occurence is reported):
inputFileName = 'data.txt'
x0 = 3
getY(fName, x) = system(sprintf("gawk '$1==%d{print $2;exit}' '%s'", x, fName))
y0 = getY(inputFileName, 3)
set label "test" at x0,y0
plot inputFileName using 1:2 with lines t ''
You say "manually", so maybe interactive placement is an option? A mouse click on the desired location will load variables MOUSE_X and MOUSE_Y, which can then be used to generate a label. There is a demo "mouselabels.dem" in the distribution that automates this and might be informative, but in essence you would do
plot FOO # initial plot with no labels
pause mouse # wait for mouse click
set label 1 "test" at MOUSE_X, MOUSE_Y
replot # same plot with a label at the requested position

How does gnuplot skip irrelevent column in plot?

I have a data file like this
# Time A irrelevent_col B
1 2 3 4
2 3 4 5
3 4 5 6
4 5 6 7
I am trying to plot two lines Time vs A, Time vs B with labels "A" and "B". How can I skip the "irrelevent_col" column?
I did the following, but the code still plots the "irrelevent_col" column. Shouldn't the ? : operator gets ride of that column?
set datafile commentschars "!!!"
plot for [i=2:4] filename using 1:(columnhead(i+1) ne "irrelevent_col" ? column(i) : 1/0) title columnhead(i+1)
Thanks!
If I understood correctly your question:
plot "filename" using 1:2 title "A" with lines,\
"filename" using 1:4 title "B" with lines
Let me repeat what I've understood from your question:
You have a large number of columns and you want to plot them all in a loop, but exclude a single column (or a few) by name.
Of course, you can specify all columns you do want to plot, like in #ViniciusPlacco's answer, however, as I understand that's what you wanted to avoid, since you have many more columns in your real data. You can also always use external tools to pre-process your data, but here I would like to suggest a gnuplot-only and hence platform-independent solution.
Why your solution is not working, I can only speculate: I guess using columnheader twice in a plot iteration creates problems (at least for gnuplot<=5.2). But I could be wrong. But as I will show below, your solution will work for gnuplot>=5.4.0.
Furthermore, you want to specify the columns by header not by column number.
In addition, your header line starts with the comment char '#', but you can easily change that to access the columnheader information.
In the example below you can specify a list of several headers which you don't want to plot. Maybe the script(s) can be further simplified.
Script: (works for gnuplot>=5.4.0, July 2020)
### exclude some columns by header from plotting loop (gnuplot>=5.4.0)
reset session
$Data <<EOD
# Time A B C D E
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
EOD
set datafile commentschars '' # no commentchar
set key top left noenhanced noautotitle
inList(w,list) = int(sum[_i=1:words(list)] w eq word(list,_i))
doNotPlot = 'B C'
color = 1
plot for [col=2:6] $Data u 1:((b=inList(myHeader=columnhead(col+1),doNotPlot)) ? \
NaN : ($0==1?color=color+1:0, column(col))) w lp pt 7 lc color ti (b ? '' : myHeader)
### end of script
Result:
For older gnuplot versions <5.4.0 you need a different approach:
get all headers into a string
specify all your headers of the columns you don't want to plot in a string
for gnuplot>=5.0.0, subtract two lists and keep the column numbers for the header you do want to plot
Script: (works for gnuplot>=5.2.2, Nov. 2017; result same as graph above)
### exclude some columns by header from plotting loop (gnuplot>=5.2.2)
reset session
$Data <<EOD
# Time A B C D E
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
EOD
set datafile commentschars '' # no commentchar
set key top left noenhanced noautotitle
inList(w,list) = int(sum[_i=1:words(list)] w eq word(list,_i))
doNotPlot = 'B C'
myHeaders = ''
color = 1
plot for [col=2:6] $Data u 1:((b=inList(myHeader=columnhead(col+1),doNotPlot)) ? NaN : \
($0==1 ? (color=color+1, myHeaders=myHeaders.' '.myHeader) : 0, column(col))) w lp pt 7 lc color, \
for [i=1:color] NaN w lp pt 7 lc i ti word(myHeaders,i)
### end of script
Script: (works for gnuplot>=5.0.0, Jan. 2015; result same as graph above)
### exclude some columns by header from plotting loop (gnuplot>=5.0.0)
reset session
$Data <<EOD
# Time A B C D E
1 2 3 4 5 6
2 3 4 5 6 7
3 4 5 6 7 8
4 5 6 7 8 9
EOD
set datafile commentschars '' # no commentchar
set datafile separator "\n" # or another character which is not in the header line
stats $Data u (allHeaders = strcol(1)[2:]) ever ::::0 nooutput # get header line into string
set datafile commentschar # reset to default
set datafile separator whitespace # ditto
inList(w,list) = int(sum[_i=1:words(list)] w eq word(list,_i))
subtractLists(list1,list2) = (_s=' ', sum[_j=1:words(list1)] (_s0=word(list1,_j), \
inList(_s0,list2) ? 0 : (_s=_s._s0.' ', \
myColNos=myColNos.' '._j), 0), _s)
doNotPlot = 'B C'
myColNos = ''
myHeaders = subtractLists(allHeaders,doNotPlot)
myColNo(i) = column((word(myColNos,i)))
set key top left noenhanced noautotitle
plot for [i=2:words(myHeaders)] $Data u 1:(myColNo(i)) w lp pt 7 ti word(myHeaders,i)
### end of script

Resources