I am using gnuplot 5.2.4.
I am doing a for-loop, to analyse in each cycle a different column (or combination of columns) of a file. The column to be used is written in an array and is passed to the commands as a macro.
The code is written in a .plt file that I load in gnuplot.
It looks like this
(here for example I'm using the 1.dat file in the \gnuplot\demo)
:
set macros
array label[2]
label[1]="First_Cycle"
label[2]="Second_Cycle"
array index[2]
index[1]="(column(2))"
index[2]="(column(2)-column(1))"
fileDat = "1.dat"
do for [k = 1 : 2] {
fileExport = sprintf("%s.gif",label[k])
print fileExport
set term gif size 1920,1280 enhanced
set output fileExport
indexk = index[k]
print k," ",index[k]," ", indexk
stats fileDat u #indexk name "DV" #noout
plot fileDat u #indexk ti label[k]
}
indexk is printed correctly at each cycle, however, I obtain the following warning:
warning: indexk is not a string variable
and the commands stats and plot analise always the column in index[1] at each cycle.
However, if I comment the do for loop and increase the k by hand, the code works correctly, no warning, no problem,
like this:
set macros
array label[2]
label[1]="First_Cycle"
label[2]="Second_Cycle"
array index[2]
index[1]="(column(2))"
index[2]="(column(2)-column(1))"
fileDat = "1.dat"
k=2
#do for [k = 1 : 2] {
fileExport = sprintf("%s.gif",label[k])
print fileExport
set term gif size 1920,1280 enhanced
set output fileExport
indexk = index[k]
print k," ",index[k]," ", indexk
stats fileDat u #indexk name "DV" #noout
plot fileDat u #indexk ti label[k]
#}
You can think of gnuplot macros (# + string variable name) as roughly equivalent to C language preprocessor directives. They describe a substitution that is performed only once, the first time the line of code is encountered. So trying to change one inside a loop will not work.
In some contexts the gnuplot directive "evaluate( )" is equivalent to dynamic macro substitution, but in the case shown you need an expression rather than a statement. So something like:
Col(k) = (k == 1) ? column(2) : column(2) - column(1)
do for [k=1:2] {
...
stats fileDat using Col(k) name "DV"
plot fileDat using Col(k) ti label[k]
}
Related
Gnuplot version 5.2 supports arrays. As given here, one can declare 1D arrays and plot them
array A[100]
do for [i=1:100] { A[i] = sin(2*pi*i/100.) + 0.1*rand(0) }
plot A
This plots the matrix A with the index i.
Is there a way to have two 1D arrays (Eg: x and y) and plot them y vs x.
OR
Declare a 2D array A and plot the 2nd column of A with respect to the first column of A?
Answer #2
If the two arrays A and B are guaranteed to have the same size, a simpler plot command is possible. We start by noting that all of the following plot commands are equivalent.
plot A
plot A using 1:2
plot A using (column(1)):(column(2))
plot A using ($1):($2)
plot A using ($1):(A[$1])
This is because for purposes of plotting an array A is treated as providing two columns of information, the index i (column 1) and the value A[i] (column 2). Following standard gnuplot syntax, each field in the "using" specifier of a plot command may contain either a bare column number or an expression in parentheses. Inside an expression the value of a column can be referred either by prefixing a $ sign or by using the function column(i).
With this in mind, it follows that the command below plots the values of array B against the values of array A.
plot A using (A[$1]):(B[$1])
The trick is to have gnuplot generate a set of samples to plot. Instead of a filename you can provide the string '+' to generate a set of samples along one dimension or '++' to generate a set of samples along two dimensions. Gnuplot calls these "special file names". In your case you want to generate 100 samples (integers from 1 to 100) and use each sample as an index into your arrays.
array A[100]
array B[100]
do for [i=1:100] {
A[i] = something
B[i] = something else
}
plot sample [i=1:100] '+' using (A[i]):(B[i]) with linespoints
The keyword "sample" guarantees that the term in square brackets will not be mis-interpreted as setting the horizontal range ("set xrange") of the plot.
Documentation entries
help +
help special-filenames
help sampling
Answer #3
You ask whether there is an alternative to make A a 2-dimensional array. Not exactly, but remember that in gnuplot floating point numbers are actually complex values. So you could use the real and imaginary components of each A[i] to place it in the x/y plane:
array A[36]
set angle degree
i = {0,1} # i = sqrt(-1) as a complex value
do for [n=1:36] {
A[n] = cos(real(10.*n)) + i * sin(real(10.*n))
}
plot A using (real(A[$1])):(imag(A[$1])) with lp
Is there any special reason why you want to have data in arrays first?
As you are filling your arrays with values of functions, you can also plot two functions (or as you say two columns of a 2D-array) directly against each other without first defining arrays in a do for loop.
Just define some functions and plot them against each other.
Use set samples to define the number of points and use plot sample [] for setting the range. I guess this would be easier than setting the array size, doing the loop and "messing" around with the index i and the range and/or offsets.
### plot one function vs. another function
reset session
f(x) = sin(x) + 0.1*rand(0)
g(x) = cos(x) + 0.1*rand(0)
set samples 100
plot sample [0:2*pi] '+' u (f($1)):(g($1)) w lp pt 7 lc rgb "red"
### end of code
I found the following question/answer that I think does what I would like to do: https://www.stata.com/statalist/archive/2009-09/msg00449.html
However, I am unclear what is going on in all of it, and would like to understand better. The code for the solution is as follows:
unab vars : var1-var30
local nvar : word count `vars'
forval i = 1/`nvar' {
forval j = 1/`=`i'-1' {
local x : word `i' of `vars'
local y : word `j' of `vars'
generate `x'X`y' = `x' * `y'
}
}
I do not understand what is going on in line 4 with the statement: ``=i'-1'.
The i refers to the number in the set {1,...,n}, but I do not understand what the equals or the -1 are doing. My assumption is that the -1 is somehow removing the own observation, but I am unclear. Any explanation would be appreciated.
Suppose you have local macro i that varies over a range and you want its value minus 1. You can always do this
local j = `i' - 1
and then refer to j. You can also do this on the fly:
`= `i' - 1'
Within
`= '
Stata will evaluate the expression, here
`i' - 1
and substitute the result of that expression in a command line.
You can do this with scalars too:
scalar foo = 42
and then refer to
`= foo'
However, watch out. Scalar names and variable names occupy the same namespace.
`= scalar(foo)'
disambiguates and arguably is good style in any case.
I just discover gnuplot 4.6 and the beautiful loop tool.
I want to plot a curve with different x axis, but it doesnt work.
I have a file called file.txt, where there is a list of data like :
E002 = ...
E003 = ...
.
.
.
E021 = ...
The point is to shift the x axis of each plot with the corresponding data, something like this :
load 'file.txt'
plot for [a=2:21] 'my_data_file.dat' u ($1+'E00'.a ):a w l
But this doesn't work, and I have the error : 'Non-numeric string found where a numeric expression was expected'.
I do not know how to bypass this issue.
Second question,
i would like after to sum all the column but shifted like before. Something like :
($1+E002):$2 + ($1+E003):$3 +...
Is there a way to do that ?
For the first question, you need to use the value to get the value of a variable.
I suggest to use a more versatile sprintf command to manipulate strings:
plot for [a=2:21] 'my_data_file.dat' u ($1+value(sprintf('E%03d',a))):a w l
Type help value and help sprintf to get more info about those commands
I don't understand very well the second question, maybe something like this could help?
my_sum=0
plot for [a=2:21] my_val=value(sprintf('E%03d',a)), my_sum=my_sum+my_val, 'my_data_file.dat' u ($1+my_val):a w l
print my_sum
the last line, should print the sum of all you Exxx values.
I am trying to convert a vector which is the following :
A =
[
02376R102 ;
21871B206 ;
81765M106 ;
G3156P103]
into string.
It should give the following result :
['02376R102' ;
'21871B206' ;
'81765M106' ;
'G3156P103']
I can not use functions such as num2str because my vector is composed of both letters and numbers...
The ultimate goal is that I want to use the function mkdir to create directories with names in the vector A.
for i=1:end
mkdir('mypath', A(i))
end
but the mkdir functions need to have strings in A...
Thank you a lot for your help
edit :
Sorry for my mispecification, the array I am working with are CUSIP (firms code created by CRSP database) which I have uploaded with excel. The exact array when I copy paste the array is :
'02376R102'
'21871B206'
'81765M106'
'G3156P103'
Which looks like strings... But when I try the function for directories
i=1:end
mkdir('mypath', A(i))
end
matlab says that argument must contain a string.
The full code is the following :
CUSIP_list = unique(CUSIP)
for i = 1:length(CUSIP_list)
mkdir('C:\Users\Marc-Aurèle\Desktop\MASTER THESIS\DATAS',CUSIP_list(i))
end
You are looking for cells instead of strings, first I wonder how you loaded your data in, because data formats with numbers and string should be loaded in as cells, cell arrays or char arrays:
A = {
'02376R102' ;
'21871B206' ;
'81765M106' ;
'G3156P103'}
This would generate 4 x 1 cells
Alternatively you can use vertcat to concatenate them into 1 cell array
A = vertcat( '02376R102','21871B206')
which would give you 2 x 9 chars
I believe you might want to use the second method, after which you can run your function to create directories.
I have a script to take the output of a simulink model and put this information in an array, such that each loop is written and then can be plotted/analysed etc. However on running the script I get the following:
test1
Outvs =
68.0000
68.0007
68.0430
68.0746
In an assignment A(I) = B, the number of elements in B and I must be the same.
Error in test1 (line 19)
output(sensv0) = Outvs;
My script is the following:
%Vectors/containers to store values%
%input = zeros(4,4);
output = zeros(4,4);
%INITIAL VELOCITY (v0)
%do a sensitivity analysis for different input values
for sensv0 = 85:88
%step 1: define input value to variable
v0 = sensv0;
%step 2: run simulation
sim('sldemo_absbrake');
%step 3: look at graphs at t=0,5,10,15s for Vehicle Speed
Outvs = getdatasamples(vs, [2,6,11,14]);
%Display Outvs (troubleshooting)
Outvs
%input(sensv0) = v0;
output(sensv0) = Outvs;
end
Two ways to handle such things.
If the size of outvs is constant, you can initialize a variable with the appropriate size:
var=zeros([4,4])
for k=85:88
var(k-84, :)=outvs;
end
the size of outvs varies, use a cell array (with curvy braces).
for k=85:88
var{k-84}=outvs;
end