Different line styles for vectors from the same data file - gnuplot

Here is my data file:
25 10 8
0 50 11
34 25 0
14 0 22
200 25 56
And I plot 3D vectors with splot:
splot "data" using (0):(0):(0):1:2:3 with vectors
But I would like different colors for my vectors, using something like ls nth_vector with splot (so ls 1 for the first line of the file, then ls 2, etc.). Is it possible?
Thanks!

If you double space your data file you can achieve this using index. You can use awk within gnuplot to do the spacing on the fly:
splot for [i=0:system("wc -l < data")] '<awk -v s="\n" "{print s}1" data' using (0):(0):(0):1:2:3 index i notitle with vectors
The system command counts the number of lines in the file. awk prints two newlines for every line in the data file, so each line has a separate index. I have used a variable containing the \n character as this avoids difficulties in escaping strings.
edit
There's no need for any of that awk. You can use stats to get the number of lines in your file and every to plot each line separately:
stats 'data' nooutput
splot for [i=0:STATS_records] "data" using (0):(0):(0):1:2:3 every ::i::i with vectors notitle

You can use the row number (zeroth column) as linetype index for the linecolor variable option:
splot 'data' using (0):(0):(0):1:2:3:0 with vectors lc var
For the vectors plotting style you could even use arrowstyle variable to change the whole arrow settings.

Related

Subtract smoothed data from original

I wonder whether there is a way to subtract smoothed data from original ones when doing things of the kind:
plot ["17.12.2020 08:00:00":"18.12.2020 20:00:00"] 'data3-17-28.csv1' using 4:5 title 'Sensor 3' with lines, \
'' using 4:5 smooth acsplines
Alternatively I would need to do it externally, of course.
As #Suntory already suggested you can plot smoothed data into a table.
However, keep in mind, the number of datapoints will be determined by set samples, default setting is 100 and the smoothed datapoints will be equidistant. So, if you set samples to the number of your datapoints and your data is equidistant as well, then all should be fine.
Concatenating data line by line is not straightforward in gnuplot, since gnuplot is not intended to do such operations.
The following gnuplot-only solution assumes that you have your data in a datablock $Data without headers and empty lines. If not, you could either plot it with table from file into a table named $Data or use the following approach in the accepted answer of this question: gnuplot: load datafile 1:1 into datablock
If you don't have equidistant data, you need to interpolate data, which is also not straightforward in gnuplot, see: Resampling data with gnuplot
It's up to you: either you use external tools (which might not be platform-independent) or you apply a somewhat cumbersome platform independent gnuplot-only solution.
Code:
### plot difference of data to smoothed data
reset session
$Data <<EOD
1 0
2 13
3 16
4 17
5 11
6 8
7 0
EOD
stats $Data u 0 nooutput # get number of rows or datapoints
set samples STATS_records
set table $Smoothed
plot $Data u 1:2 smooth acsplines
unset table
# put both datablock into one
set print $Difference
do for [i=1:|$Data|] {
print sprintf('%s %s',$Data[i],$Smoothed[i+4])
}
set print
plot $Data u 1:2 w lp pt 7, \
$Smoothed u 1:2 w lp pt 6, \
$Difference u 1:($2-$4) w lp pt 4 lc "red"
### end of code
Result:
If I well understand you would like this :
First write your smooth's data in out.csv file
set table "out.csv" separator comma
plot 'file' u 4:5 smooth acsplines
unset table
Then this line will paste 'out.csv' to file as an appended column.You will maybe need to delete first lines using sed command (sed '1,4d' out.csv)
stats 'file' matrix
Thanks to stats we automatically get the number of column in your original data (STATS_size_x).
plot "< paste -d' ' file out.csv" u 4:($5-$(STATS_size_x+2)) w l
Could you please try this small code on your data.

Multiple datasets in the same data file in gnuplot

I have a following kind of file:
<string1> <x1> <y1>
<string2> <x2> <y2>
...
I want to draw a scatter plot from the (x,y) values, having the different strings in the first column in different data sets, which will be drawn with different colors (I have many different x,y values but only a few different strings). I tried this:
plot "DATAFILE" using 2:3 title column(1)
Unfortunately, this one picks the first column for the first row and uses that as a title for all entries.
You could use awk to pick only rows where the first column matches your strings:
plot "<awk '$1~/string1/' DATAFILE" using 2:3 title column(1),\
"<awk '$1~/string2/' DATAFILE" using 2:3 title column(1)
and so on. For a built-in gnuplot solution, you can do:
plot "DATAFILE" u 2:(stringcolumn(1) eq "string1" ? $3:1/0),\
"DATAFILE" u 2:(stringcolumn(1) eq "string2" ? $3:1/0)
if you want to do something more automatic that would generate plots for every unique entry in column 1, this solution worked for me:
input file (test.dat - separated, otherwise need to change cut statement below):
one 1 3
two 2 4
ten 3 5
ten 4 3
two 5 4
one 6 5
one 7 3
ten 8 4
two 9 5
ten 10 3
two 11 4
one 12 5
the following line creates a plotting statement for gnuplot, and saves in a file:
cut -f1 test.dat | sort -u | awk '
BEGIN {print "plot\\"}
{print "\"test.dat\" u 2:(stringcolumn(1) eq \""$1"\" ?\$3:1/0),\\"}' > plot.gp
and the contents are:
plot\
"test.dat" u 2:(stringcolumn(1) eq "one" ?$3:1/0),\
"test.dat" u 2:(stringcolumn(1) eq "ten" ?$3:1/0),\
"test.dat" u 2:(stringcolumn(1) eq "two" ?$3:1/0),\
then you'd do:
gnuplot plot.gp
or add the line load "plot.gp" to your script.
I am pretty sure there must be a "gnuplot-only" solution, but that goes beyond my knowledge. Hope this helps.
You have just one plot, so just one title.
If you want to plot separately all datasets (separated by two consecutive blank lines), you (just) need to say so:
N_datasets=3
plot for [i=0:N_datasets-1] "file.dat" using 2:3 index i with title columnhead(1)
But the formatting of your datafile is not what gnuplot expects, and using title columnhead will also skip first line (assumed to contain headers only). The standard gnuplot format for this would be:
string1
x1_1 y1_1
x1_2 y1_2
...
string2
x2_1 y2_1
x2_2 y2_2
...

Whether is it possible to plot normal probability distribution in gnuplot

My data file is as-
2 3 4 1 5 2 0 3 4 5 3 2 0 3 4 0 5 4 3 2 3 4 4 0 5 3 2 3 4 5 1 3 4
My requirement is to plot normal PDF in gnuplot.
I could do it by calculating f(x)
f(x) = \frac{1}{\sqrt{2\pi\sigma^2} } e^{ -\frac{(x-\mu)^2}{2\sigma^2} }
for each x using shell script.
Then I plot it in gnuplot using the command-
plot 'ifile.txt' using 1:2 with lines
But whether is it possible to plot directly in gnuplot?
gnuplot provides a number of processing options under the smooth keyword (try typing help smooth for more info). For your specific case, I would recommend a fit though.
First, note that your data points are in a row, you need to convert it to columns for gnuplot to use it. You can do it with awk:
awk '{for (i=1;i<=NF;i++) print $i}' datafile
which can be invoked from within gnuplot:
plot "< awk '{for (i=1;i<=NF;i++) print $i}' datafile" ...
Now assume that datafile has the right format for simplicity.
You can use the smooth frequency option to see how many occurrences of each value you have:
plot "datafile" u 1:(1.) smooth frequency w lp pt 7
To get the normalized distribution, you divide by the number of values. This can be done automatically within gnuplot with stats:
stats "datafile"
This will store the number of values in variable STATS_records, which in you case has value 33:
gnuplot> print STATS_records
33.0
So the normalized distribution (the probability of getting a value at x) is:
plot "datafile" u 1:(1./STATS_records) smooth frequency w lp pt 7
As you can see, your distribution doesn't really look like a normal distribution, but anyway, let's go on. Create a Gaussian for fitting and fit to your data, and plot it. You need to fit to the probability, rather than to the data itself. To do so, we plot to a table to extract the data generated by smooth frequency:
# Non-normalized Gaussian
f(x)= A * exp(-(x-x0)**2/2./sigma**2)
# Save probability data to table
set table "probability"
plot "datafile" u 1:(1./STATS_records) smooth frequency not
unset table
# Fit the Gaussian to the data, exclude points from table with grep
fit f(x) "< grep -v 'u' probability" via x0, sigma, A
# Normalize the gaussian
g(x) = 1./sqrt(2.*pi*sigma**2) * f(x) / A
# Plot
plot "datafile" u 1:(1./STATS_records) smooth frequency w lp pt 7, g(x)
set table generates some points which you should exclude, that's why I used grep to filter the file. Also, the Gaussian needs to be normalized after the fitting is done with a variable amplitude. If you want to retrieve the fitting parameters:
gnuplot> print x0, sigma
3.40584703189268 1.76237558717934
Finally note that if the spacing between data points is not homogeneous, e.g. instead of x = 0, 1, 2, 3 ... you have values at x = 0, 0.1, 0.5, 3, 3.2 ... then you'll need to use a different way to do this, for example defining bins of regular size to group data points.

Plotting from two data sets delimited two different ways

I need to plot data from a .csv file and from a white space separated file. Both sets of data need to appear on the same plot.
data1.dat
#t y
1 1
2 1
3 1
and
data2.csv
#t,y
1,2
2,2
3,2
normally I would do the following if both were .csv sets:
set datafile separator ','
plot 'data1.csv' using 1:2,'data2.csv' using 1:2
Is there some way to include the setting of the separation character in the plot statement?
plot 'data1.dat' using 1:2,'data2.csv' using datafile separator ',' using 1:2
The above does not work and I tried many different variations of the above code....I had no luck.
You can give more than one character to set datafile separator, in your case ", ". All these are then individually treated as separators. (A tab caracter can be given as "\t", you need to put double quotes around the string then!)
$dat << EOD
1 2,4
2 2,5
3 1,6
4 4,4
EOD
set xr [0.5:4.5]
set dataf sep ", "
plot $dat us 1:2:3 w yerrorbars
Note that the explicit separator characters each count as exactly one separator. "4, 4" with set dataf sep ", " evaluates to "three columns, second is a missing value. If you have incompatible formats in one plot, you can import the data for each subplot with its own separators set using set table $<name>. (check "help datablocks")
If your data files have a very difficult format:
gnuplots using specifier accepts a libC scanf() format string
plot "-" us 1:2 "%lf,%lf"
1,2
2,3
3,4
e
You can give a different format string for every file on your plot command. Note that gnuplot only accepts "double" fp numbers for input, so you have to use the %le or %lf specifier.
Check help using examples, and here is a full description of the format.
AFAIK, there isn't a way to specify the separator. However, if you're in a POSIX compliant environment (and your gnuplot supports pipes -- which most do), you can farm the work out to awk pretty easily:
plot 'data1.dat' using 1:2,\
"<awk -F, '{print $1,$2}' data2.csv" using 1:2
Not just for "retro"-fun, but also for current gnuplot versions, I guess this is the only(?) gnuplot-only solution which works with all versions even with versions before the time of OP's question.
The "trick" is: if you set datafile separator "," and read the first (and only) stringcolumn (of a whitespace separated file), i.e. strcol(1) will contain the full line. Now, you can simply split the string with word() and convert it into a floating point number with real().
If your original data has at least one space after the comma,
1, -0.2
2, -0.1
3, 0.0
the data would be plotted correctly with keeping the separator as whitespace, since the comma after the first column's data will be ignored during number interpretation.
Although, for newer gnuplot versions (>=4.6.7, Apr 2015) you have the possibility to define several separators, however, which will not work as you might think, because
set datafile separator ", "
will interpret each space as column separator. So, if you have an undefined and variable number of spaces your plot command would fail.
Anyway, here is the "always" working solution:
Data:
SO14262760_1.dat (with variable number of spaces)
1 -0.1
2 0.0
3 +0.1
SO14262760_2.dat (with no or some space after ,)
1,-0.2
2,-0.1
3, 0.0
Script: (works with gnuplot>=4.4.0, March 2010)
### different column separators in two files with one plot command
reset
FILE1 = "SO14262760_1.dat"
FILE2 = "SO14262760_2.dat"
set datafile separator ","
myCol(n) = real(word(strcol(1),n))
plot FILE1 u (myCol(1)):(myCol(2)) w lp pt 7 lc rgb "red", \
FILE2 u 1:2 w lp pt 7 lc rgb "blue"
### end of script
Result:

How to add a gap in gnuplot line?

I have a gnuplot line plot. I'd like to add a gap (break) in the line to signify lack of data. How can I do that?
For example, let's say I have data between x=10->100, and also 200->500. So I want a line (the same line, so the legend matches) between 10 and 100, then a gap between 100 and 200, and again the line between 200 and 500.
I have tried adding empty datapoints (i.e. - y values), but gnuplot happily interpolates those points.
There's a very subtle difference between:
plot 'data' u 1:2 w lines
and
plot 'data' u 1:($2) 2 lines
In your case, I think it should work to do:
set datafile missing '-'
plot 'data' u 1:($2) w lines
(Note: this results in a subtlely different plot than the blank line method I'll describe next).
Another way to do it is to just plot a blank line in the datafile where you want to have a gap.
e.g.:
#data
10 15
20 30
100 17
200 25
300 12
500 16
and then plot with either plot 'data' u 1:2 w lines or plot 'data' u 1:($2) w lines. Both should produce an identical plot.
for more information, see help missing in gnuplot.

Resources