A quick question about a gnuplot.
I have two graphs, ploted from file, like this:
plot "t2" using 1:75 with linespoints title "crop 20",\
"t2" using 1:11 with linespoints title "crop 30"
Now I want to identify points on both graphs if they have identical height e.g Y coordinate.
It could be a different colour, or a perfect solution would be to draw a line between them.
Any ideas?
Thanks a lot.
EDIT
Thanks for the reply Sunhwan Jo, method suggested works fine, as long as similar values appear in the same order. See the image
Two graphs share several more points in the same height, but its not picked up due to length difference.
You may use external program to filter out data points that have same data in two different column (here I've examined if 75th and 11th column has same entry).
plot "t2" using 1:75 with linespoints title "crop 20",\
"t2" using 1:11 with linespoints title "crop 30",\
"< awk '{if ($75==$11) print $0}' t2" us 1:11 with lines points title "crop 20/30"
EDIT:
Okay, above will not work if you would like to show the data points that have same data in different rows. AWK script will be more elaborated. I have tried as below, hope this helps.
Here's test data.
0 0.0 0.0
1 0.3 0.6
2 1.6 1.6
3 0.3 1.5
4 0.6 3.6
5 0.3 4.3
6 0.3 0.7
7 5.5 5.5
8 6.6 6.6
9 5.2 5.2
10 8.3 8.3
11 2.7 5.0
12 2.8 8.3
13 3.3 2.8
14 7.9 3.9
15 9.9 7.9
16 15.3 15.3
17 14.7 14.7
18 3.8 18.1
19 18.1 12.1
And the gnuplot command (note some obvious difference in column designation):
plot 'test.dat' us 1:2 w lp title "1", \
'test.dat" us 1:3 w lp title "2", \
"< awk '{ind[NR]=$1; arr1[NR]=$2; arr2[NR]=$3} END{for (i=1; i<=NR; i++) {for (j=1; j<=NR; j++) {if (arr1[i]==arr2[j]) print ind[i], arr1[i]}}}' test.dat' test.dat" us 1:2 w lp title '1==2'
Resulting plot:
The previous answer using a awk script to preprocess the data is a good method. Here I give a method using only gnuplot. There is a ternary operator--"?:". Uisng this operator you can pick the points with same value out. For example, "plot 'data.dat' u 1:($11==$75?$11:1/0) w p lc rgb'blue'" will plot only the points with $11==$75. I have written the details in my blog. If any question, visit http://gnuplot-surprising.blogspot.com/2011/09/manipulate-data-using-ternary-operator.html.
Related
I'm trying to plot the following data file
#x y s err
1 1 0.1 0.2
2 2 0.2 0.2
3 3 0.3 0.2
4 4 0.4 0.2
5 5 0.5 0.2
6 6 0.6 0.2
7 7 0.7 0.2
8 8 0.8 0.2
9 9 0.9 0.2
10 10 1.0 0.2
where the points have a variable size given by column 3 and the errors are given in column 4. I can get
plot "test" u 1:2:3 pt 7 ps variable
plot "test" u 1:2:4 w yerrorbars pt 7
to work independently, giving me this:
But when I try to combine them
plot "test" u 1:2:4:3 w yerrorbars pt 7 ps variable
I get something very strange:
yerrorbars seems to be using column 4 as the y column and column 3 as the yerror column. Even stranger, I get the same output if I try u 1:2:3:4. Is there something wrong with how I'm doing this? I can manually draw the errorbars as vectors, but I'd prefer to use the built-in errorbars style if possible.
gnuplot> help yerrorbars
The `yerrorbars` (or `errorbars`) style is only relevant to 2D data plots.
`yerrorbars` is like `points`, except that a vertical error bar is also drawn.
At each point (x,y), a line is drawn from (x,y-ydelta) to (x,y+ydelta) or
from (x,ylow) to (x,yhigh), depending on how many data columns are provided.
The appearance of the tic mark at the ends of the bar is controlled by
`set errorbars`.
2 columns: [implicit x] y ydelta
3 columns: x y ydelta
4 columns: x y ylow yhigh
An additional input column (4th or 5th) may be used to provide information
such as variable point color.
So in order to provide more than 3 columns and still use a single value for the ydelta, you should be able to do
plot "test" u 1:2:($2-$4):($2+$4):3 w yerrorbars pt 7 ps variable
However, as you point out this doesn't actually work as documented.
Work-around
An alternative is to make two passes; first plot the errorbar lines and suppress the points, second plot the point with the desired properties :
unset key
plot "test" u 1:2:3 with yerrorbars pt 0, \
"" u 1:2:4 with points pt 7 ps variable
I want to plot points with individual labels and colors in Gnuplot.
I have a data file a.dat:
###label x y z
1 244.8 18 6.1
2 248.0 10.4 7
3 294.4 6.3 13.7
4 248.0 7.5 8.92
5 240.0 3.69 6.61
6 240.48 3.69 8.92
7 256 5.7 15.8
8 256 7 10.6
9 256 4.1 8.2
10 256 5.1 12.3
The following commands work.
splot 'a.dat' using 2:3:4:1 with labels
set palette model RGB defined (0 'black',1 'blue', 2 'green', 3 'red')
splot 'a.dat' using 2:3:4:($1==3?1:$1==6?2:$1==9?3:0) with points palette
But how can I mix them?
Assuming I understood your question correctly, do you really need a palette if you just want to set only a few specific colors to a few specific points?
You are using two plotting styles with points and with labels you can combine them in one plot command.
Code:
### variable color points
reset session
$Data <<EOD
###label x y z
1 244.8 18 6.1
2 248.0 10.4 7
3 294.4 6.3 13.7
4 248.0 7.5 8.92
5 240.0 3.69 6.61
6 240.48 3.69 8.92
7 256 5.7 15.8
8 256 7 10.6
9 256 4.1 8.2
10 256 5.1 12.3
EOD
myColor(col) = column(col)==3 ? 0x0000ff : \
column(col)==6 ? 0x00ff00 : \
column(col)==9 ? 0xff0000 : 0
set key noautotitle
splot $Data u 2:3:4:(myColor(1)) w p pt 7 lc rgb var, \
'' u 2:3:4:1 w labels offset 0.0,0.7,0.7
### end of code
Result:
Addition: (colored labels)
If you want to have colored labels then change the plot command as follows:
splot $Data u 2:3:4:1:(myColor(1)) w labels tc rgb var
Well, you have to decide:
using only labels it might be difficult to locate the exact position of your data point
using a point and a label without offset it might be diffcult to read the number
Result: (colored label without point)
I am making a gnuplot animation of a satellite going around a planet. My task is to display it's XY trajectory and associated values of velocity and energy versus time. I know how to plot the path, but I've been having problems displaying velocity etc.
the code below does the following:
satellite track and time steps -- column 3:4;
satellite position -- column 3:4;
planet position -- column 6:7.
do for [n=0:int(STATS_records)] {
plot "sat.dat" u 3:4 every ::0::n w lp ls 2 t sprintf("steps=%i", n), \
"sat.dat" u 3:4 every ::n::n w lp ls 4 notitle, \
"sat.dat" u 6:7 every ::0::n w lp ls 3 notitle , \
}
How do I display the associated velocity values for each sprintf ? The velocity values are in column 5. Thank you everyone in advance.
It seems that you want to put everything in the "key" (legend), but another option is to use labels, which can be easily placed arbitrarily. There are labels you can place one at a time (with set label) and with labels for plotting with actual labels. Don't get them confused.
Your main issue seems to be how to pull out the velocity value from column 5. My first instinct (which is quite hacky) is to use some external program, like awk:
v = system(sprintf("awk 'NR==%d{print $5}' '%s'", n+1, infile))
set label 1 sprintf("v=%.3f", v+0) at screen 0.2,0.9
This is also an example of a label (named 1). The screen keyword means screen-relative rather than graph-relative. Putting this inside your for loop will reassign label 1 every iteration, so it overwrites the label from the previous iteration. Not using this 1 will just plop another label on top of the last one, so it would get messy.
Using an external command line like this isn't very portable. (I don't think it would work on Windows.) I saw this question that shows how to pull a value from a specific row and column of a file. The problem I had with using this is that stats implicitly filters according to whatever xrange is set. When making animations like this, I've noticed that the camera can jump around too much from autoranging, so it's nice to have tight control over the plotting range. Defining an xrange at the top of the file interfered with a subsequent stats command to read a velocity value.
You can, however, specify a range for stats (before the file name, such as stats [*:*] infile). But I had issues using this in combination with a predefined xrange based for position. I found that it did work if I specify the desired plotting range on the plot line instead of a set xrange. Here is another (full script) version using only gnuplot:
set terminal pngcairo
infile = 'anim.dat'
stats infile using 3:4 name 'data' nooutput
set key font 'Courier'
do for [n=0:data_records-1] {
set output sprintf('frame-%03d.png', n)
stats [*:*] infile every ::n::n using 5 name 'velocity' nooutput
plot [data_min_x:1.1*data_max_x][data_min_y:1.1*data_max_y] \
infile u 3:4 every ::0::n w linespoints ls 2 t \
sprintf("steps =%6d\nvelocity =%6.3f", n, velocity_min), \
'' u 3:4 every ::n::n w points pt 7 ps 3 notitle
}
Notice that you could easily change this to a set label if you want. Another option is to plot
'' u (x):(y):5 every ::n::n w labels
to place a label at graph position (x,y).
I don't have your data, but I made my own file with what I hope is a similar format to yours:
anim.dat
0 0.0 0.0 0.0 1.11803398875 0.625
1 0.05 0.05 0.02375 1.09658560997 0.625
2 0.1 0.1 0.045 1.07703296143 0.625
3 0.15 0.15 0.06375 1.05948100502 0.625
4 0.2 0.2 0.08 1.04403065089 0.625
5 0.25 0.25 0.09375 1.0307764064 0.625
6 0.3 0.3 0.105 1.01980390272 0.625
7 0.35 0.35 0.11375 1.01118742081 0.625
8 0.4 0.4 0.12 1.00498756211 0.625
9 0.45 0.45 0.12375 1.00124921973 0.625
10 0.5 0.5 0.125 1.0 0.625
11 0.55 0.55 0.12375 1.00124921973 0.625
12 0.6 0.6 0.12 1.00498756211 0.625
13 0.65 0.65 0.11375 1.01118742081 0.625
14 0.7 0.7 0.105 1.01980390272 0.625
15 0.75 0.75 0.09375 1.0307764064 0.625
16 0.8 0.8 0.08 1.04403065089 0.625
17 0.85 0.85 0.06375 1.05948100502 0.625
18 0.9 0.9 0.045 1.07703296143 0.625
19 0.95 0.95 0.02375 1.09658560997 0.625
I have this iris data ...
5.1 3.5 1.4 0.2 Iris-setosa
4.9 3 1.4 0.2 Iris-setosa
7 3.2 4.7 1.4 Iris-versicolor
6.4 3.2 4.5 1.5 Iris-versicolor
7.1 3 5.9 2.1 Iris-virginica
6.3 2.9 5.6 1.8 Iris-virginica
.
.
.
and I got graph using gnuplot (plot 'c:\iris.data')
But I want points with color group by 5th column (iris-setosa, iris-versicolor, iris-virginica)
For example . . .
iris-setosa = color red, iris-versicolor= color green, iris-virginica = color blue
How can I get color graph?
Please answer . . . .
Replace your colours with numerical indices, e.g., like this:
5.1 3.5 1.4 0.2 0
4.9 3 1.4 0.2 0
7 3.2 4.7 1.4 1
6.4 3.2 4.5 1.5 1
7.1 3 5.9 2.1 2
6.3 2.9 5.6 1.8 2
A simple search-and-replace script should be able to do this for you.
Then you can use Gnuplot’s linecolor palette, e.g. as follows:
plot "iris.data" u 1:2:5 w p lc palette
To adjust the colours used like this:
set palette defined (0 "red", 1 "green", 2 "blue")
Note that while I chose to use the exact indices here, the palette definition is relative and I might as well have used:
set palette defined (-11 "red", -2 "green", 7 "blue")
If you want to keep the string values in your data file, you can construct some kind of lookup-table with gnuplot, using the few string functions which gnuplot provides (see also Different coloured bars in gnuplot bar chart? for a similar use case):
IrisColors = 'Iris-setosa Iris-versicolor Iris-virginica'
index(s) = words(substr(IrisColors, 0, strstrt(IrisColors, s)-1)) + 1
set style fill solid noborder
set linetype 1 lc rgb 'red'
set linetype 2 lc rgb 'green'
set linetype 3 lc rgb 'blue'
plot 'iris.data' using 1:2:(index(strcol(5))) linecolor variable
Note, that the string comparison is case-sensitive, and that you cannot use strings with white spaces as single keys.
In case you don't want to modify your original data (as required in Wrzlprmft's answer) or if you are using the palette already for some other purpose in the graph or if you need more than 255 colors (rarely), you can use the following.
Here, Christoph's lookup function is slightly modified because it would return index 4 if a colorname from the file is not in the list and it would give wrong results in the specially constructed case e.g. index("Test1") with the list "Test100 Test10 Test1".
You are basically looking for a mapping function for your own color names.
This reminds me also to this question.
You could also use the sum function to construct your lookup-table. And from gnuplot>=5.2.0 you could additionally use arrays.
In case you want a legend entry for each color you need to plot it in a loop and filter the data for each color accordingly.
Script:
### color according to colorname from file
reset session
$Data <<EOD
5.1 3.5 1.4 0.2 Iris-setosa
4.9 3 1.4 0.2 Iris-setosa
7 3.2 4.7 1.4 Iris-versicolor
6.4 3.2 4.5 1.5 Iris-versicolor
7.1 3 5.9 2.1 Iris-virginica
6.3 2.9 5.6 1.8 Iris-virginica
EOD
myColors = 'Iris-setosa Iris-versicolor Iris-virginica'
myColorsRGB = '0xff0000 0x00ff00 0x0000ff'
index(s) = words(substr(myColors, 0, strstrt(myColors.' ', s.' ')))
myColor(col) = (_i=index(strcol(col)), _i ? int(word(myColorsRGB,_i)) : 0xcccccc)
set key out Left reverse noautotitle
set multiplot layout 2,1
plot $Data u 1:2:(myColor(5)) w p pt 7 ps 2 lc rgb var
myFilter(colD,colF,i) = strcol(colF) eq word(myColors,i) ? column(colD) : NaN
plot for [i=1:words(myColors)] $Data u 1:(myFilter(2,5,i)):(myColor(5)) \
w p pt 7 ps 2 lc rgb var ti word(myColors,i)
unset multiplot
### end of script
Result:
Let's say I have data I'd like to be plotted in a file "animals.txt":
cat 5.2 1.0
cat 5.4 1.3
cat 5.2 1.2
dog 3.8 1.1
dog 3.5 1.5
dog 3.6 1.3
giraffe 1.3 9.7
giraffe 1.5 9.0
giraffe 1.4 9.9
I can generate a scatter plot with labels using:
plot "animals.txt" u 2:3:1 w labels
I can also vary the style of each point using something like:
plot "animals.txt" u 2:3 w points pointtype 3
Instead of using labels (which might overlap), is it possible to have the points use different point types or colors for each category? (For instance, "cat" would be in red using pointtype 3, "dog" would be in blue using pointtype 4, etc.)
I could use "lc variable" and replace the labels column with colors, but the file I'm working with has too many different labels for me to do that easily.
I don't think there is a way to do this directly.
However, an easy fix is to use gnuplot's interface to awk. You can then plot 3 separate graphs, one for each animal.
plot "<awk '{ if($1 == \"cat\") print $2,$3 }' animals.dat" u 1:2 w points title "cat", \
"<awk '{ if($1 == \"dog\") print $2,$3 }' animals.dat" u 1:2 w points title "dog", \
"<awk '{ if($1 == \"giraffe\") print $2,$3 }' animals.dat" u 1:2 w points title "giraffe"
Since the only difference between each line is the name of the animal, you could probably script this in a better way, but you get the idea,
Tom