I am plotting a file with different columns and I am using the for loop of gnuplot. I want to completely control the look of my graph so I use set line style to control the color of my lines. I want to do the same with the pattern fills but it seems that it is not possible with gnuplot.
So far I have come to that solution, which does not work as well, for unknown reasons:
set terminal cairolatex standalone pdf
set style line 2 linecolor rgbcolor "#F9E0B0" linewidth 2 pt 13
# etc ... up to 10
pat="0 2 4 7 2 4 7 2 4 7" ## An attempt to define the pattern style I want
set style fill pattern 1 border ## this control the first pattern, then the next ones are incremented but it cannot control each index
set output "myplot.tex"
plot for [i=2:10] "myfile.dat" index 0 u i:xtic(1) fillstyle pattern int(word(pat, i)) ls i ti columnheader ## The color is controlled according to me via the linestyle, but the fillstyle does not work
## An alternate solution giving a little bit of control but not fully satisfactory since I want to avoid the pattern 3
# plot for [i=2:10] "myfile.dat" index 0 u i:xtic(1) fillstyle pattern i%3+1 ls i ti columnheader
unset output
With this solution I get the following error: unexpected or unrecognized token
Any idea why word fails after fillstyle pattern, or does anyone have an idea on how to specify for each data the pattern?
EDIT: I am using gnuplot 5.0
The parser is expecting the entity immediately following "fillstyle" to be a number, but it doesn't recognize int("foo") as a number. That's a bug. You can work around this by using instead the syntax
fillstyle pattern 0+word(pat,i)
Related
Basically, what I want to do is look at the range information of a unified diff and know exactly which lines of code I should pay attention to.
For instance, this:
## -1827,7 +1827,7 ##
This tells me that in total only 1 line has changed, because the diff shows 3 lines above and below the change (so 7 - 6 = 1), and it also points me to the line 1830 (i.e. 1827 + 3).
To be more pedantic, this particular range information actually tells me that at line 1830, a line was removed (-), and at line 1830 a line was added (+).
Or to make that more obvious consider this range information for another diff:
## -878,15 +878,13 ##
What this is telling me is that at line 881 (878 + 3) 9 lines were deleted (15 - 6), but at line 881 only 7 lines were added (13 - 6).
So the question is, using a regex or some other Ruby string method, how do I pull out the above information easily?
i.e. how do I easily pull out this info:
Both The line numbers (i.e. just the 1827 or 878), which I can then add + 3 to determine the actual inline number I care about. It has to be both because both lines may not always be identical.
The number of lines affected (aka the 7, 15 or 13 right after the , in the above examples)
While I do that, how do I make sure to track the operation (addition or deletion) for each of the operations.
I tried slicing the string and going directly for a character -- e.g. myString[3] which gives me -, but that's the only character it reliably works for because the line numbers can be 1, 10, 100, 1000, 10000, etc. So the only way is to just scan the string and then parse it.
Edit 1
To add some code to show what I have tried.
Assume I have the contents of a diff in a variable called #diff_lines:
#diff_lines.each do |diff_line|
if diff_line.start_with?("##")
del_line_num_start = diff_line.split(/## /).second.split.first.split(/-/).second.split(/,/).first.to_i + 3
num_deleted_lines = diff_line.split(/## /).second.split.first.split(/-/).second.split(/,/).second.to_i - 6
add_line_num_start = diff_line.split(/## /).second.split.second.split(/\+/).second.split(/,/).first.to_i + 3
num_added_lines = diff_line.split(/## /).second.split.second.split(/\+/).second.split(/,/).second.to_i - 6
As you can see, the above works....but it is quite horrendous to look at and is OBVIOUSLY not very DRY.
Ideally I would like to be able to achieve the same thing, but just cleaner.
The general idea is to write a regular expression that has capture groups in it ((...)) to pick apart that string into something useful. For example:
diff_line.match(/\A##\s+\-(\d+),(\d+)\s+\+(\d+),(\d+)\s+##/)
This yields a MatchData object on a successful match. You can then apply this to some variables like:
if (m = diff_line.match(...))
a_start, a_len, b_start, b_len = m[1..4].map(&:to_i)
end
Then you can do whatever computations you need to do with these numbers.
If you're ever having trouble visualizing what a regular expression does, try a tool like Rubular to better illustrate the internals.
I have file with many columns that I'd like to plot as follows:
plot for [i=1:30] 'test' using 1:i w lp
This gives the plot I want, but when I do set key, then the key I see has all lines labeled as 1:i:
How can I make this output more meaningful, by actually displayin the value of i?
If you don't set an explicit title, gnuplot selects an automatic title based on the plain plot command call. If you want a meaningful title, you must give it explicitly, like
plot for [i=1:30] 'test' using 1:i w lp title sprintf("column %d", i)
I'm getting confused with how to use for-loops in gnuplot.
The following code works fine:
plot for [quadIter=0:270:90] \
path using 1:(column(1 + quadIter))
It plots 4 curves on one graph.
I also want to plot 4 horizontal lines on the same graph. I have written the following script to do this:
plot for [quadIter=0:270:90] \
path using 1:(column(1 + quadIter)) , \
path_to_expt[1 + quadIter/3: 19] \
But it only plots one additional line on the graph, so it is not being included in the for-loop. Please can you tell me how to get the additional line included in the loop?
Also, the constant value that is plotted is not the value I was expecting it would plot. Please can you tell me how to print the value of quadIter to the screen, so that I can check it against the value in the file?
Finally, I tried just to plot the 4 horizontal lines with this script:
plot for [quadIter=0:270:90] \
path_to_expt[1 + quadIter/3: 19] \
But I got an error message, "Non-numeric string found where a numeric expression was expected". I find this strange, as I didn't get this error message when I ran the second script but, as the second script isn't working how I would like, hopefully by getting the second and third scripts to work, I will have a better understanding of how for-loops work in gnuplot.
Thank you for your help!
The for iteration applies only the the current plot expression. The line
plot for [i=1:4] i*x, i*x**2
creates five plots, whereas in order to get eight plots you must do
plot for [i=1:4] i*x, for [i=1:4] i*x**2
Concerning your last expression path_to_expt[1 + quadIter/3: 19]: array expressions aren't supported by gnuplot (however path_to_expt looks like one).
My question is pretty basic. I am plotting several functions at once using gnuplot, and I want to print out (in either a file or on the graph itself) the maximum y-values of every function. Any idea how I could do that?
I looked into STATS and GPVAL_DATA_Y_MAX but I can't really figure out how to make them work with several functions at the same time.
Without going into too much details, let's suppose that my file looks like that :
plot 'file1.dat' us 1:2 title "file1" w lines,\
'file2.dat' us 1:2 title "file2" w lines,\
'file3.dat' us 1:2 title "file3" w lines
You can use the name parameter of the stats option to save the maximum of every file in a different set of variables:
stats 'file1.dat' using 2 nooutput name 'file1'
stats 'file2.dat' using 2 nooutput name 'file2'
stats 'file3.dat' using 2 nooutput name 'file3'
Now you can either print the values to an external file
set print 'max.dat'
print file1_max
print file2_max
print file3_max
If you want to place a respective label near the maximum in your graph, you must also know the corresponding x-value where the data has its maximum. This data is not readily available from the first stats command, only its index in the data file. So you need an additional call to stats in order to get the x-value where the maximum y-value was:
stats 'file1.dat' using 1 every ::file1_index_max::file1_index_max name 'file1_x'
...
And then you can use
set label center at first file1_x_max,first file1_max sprintf('y = %.2f', file1_max) offset char 0,1
Unfortunately, most of the commands cannot be iterated properly with changing variable names.
I am plotting the creation times of a large batch of files in gnuplot to see if they are created linearly in time (they are not).
Here is my code:
#!/bin/bash
stat -c %Y img2/*png > timedata
echo "set terminal postscript enhanced colour
set output 'file_creation_time.eps'
plot 'timedata'" | gnuplot
The problem I have is that the y data are the creation time in seconds since unix start time, so the plot just has 1.333...e+09 on the y-axis. I would like to have the creation time of the first file scaled to zero so that the relative creation times are readable.
I encounter this problem in a number of data-plotting contexts, so I would like to be able to do this within gnuplot rather than resorting to awk or some utility to preprocess the data.
I know the first time will be the smallest since the files are named serially, so is there a way to access the first element in a file, something like
`plot 'data' using ($1-$1[firstelement])`
?
I think you can do something like that...(the following is untested, but I think it should work...). Basically, you have to plot the file twice -- the first time through gnuplot picks up statistics about the dataset. The second time through, you use what you found on the first run-through to plot what you actually want.
set terminal unknown
plot 'datafile' using 1:2
set terminal post enh eps color
set output 'myfile.eps'
YMIN=GPVAL_Y_MIN
plot '' u 1:($2-YMIN)
If you have gnuplot 4.6, you can do the same thing with the stats command.
http://www.gnuplot.info/demo/stats.html
EDIT It appears you want the first point to provide the offset (sorry, misread the question)...
If you want the first point to provide the offset, you may be able to do something like (again, untested -- requires gnuplot >= 4.3):
first=0;
offset=0;
func(x)=(offset=(first==0)?x:offset,first=1,x-offset)
plot 'datafile' using (func($1))
Gnuplot accepts unix commands, so you can say something like
gnuplot> plot "< tail -3 test.dat" using 1:2 with lines
in order to plot just the last three lines. You can use something like this for your purpose. Moreover, if you want to plot let's say from line 1000 to 2000
plot "<(sed -n '1000,2000p' filename.txt)" using 1:2 with lines
You can check this website, for more examples.
I found a related stackoverflow question here and exploited the awk script from one of the answers:
#!/bin/bash
stat -c %Y img2/*png > timedata
echo "set terminal postscript enhanced colour
set output 'file_creation_time.eps'
unset key
set xlabel 'file number'
set ylabel 'file creation time (after first)'
plot \"<awk '{if(NR==1) {shift = \$1} print (\$1 - shift)}' timedata\"" | gnuplot
The output looks like this (these are not the data I was talking about in my question, but similar):
So, gnuplot can do what I want but it does depend on the UNIX environment...
I also tried mgilson's method:
plot 'timedata'
YMIN=GPVAL_Y_MIN
plot '' u ($1-YMIN)
but gnuplot (my version is 4.4.2) did not find the minimum correctly. It came close; it looks like it plotted such that the minimum of the y range is 0: