How do I grab values from datafile to make legend? - loops

I want to use system call(s) to grab values from first data line in file file and print into legend of plot.
The command returns a syntax error. I admit come confusion about a- the use of system calls and syntax, despite reading few advanced questions here.
This is what I have:
gnuplot> plot for [i=20:30:1] '4He-processed' index i u 8:($22>0.2&&$22<2?$9:1/0):10 w yerr t system("head -2 4He-processed | tail -1 | awk '{printf "%s %8.3f %8.3f %s" , "'", $3, $4,"'"}'")
with the response: ')' expected with the pointer at the "f" in printf.
I want to have the values in $3 and $4 written to the legend.
This alternate command
gnuplot> plot for [i=20:30:1] '4He-processed' index i u 8:($22>0.2&&$22<2?$9:1/0):10 w yerr t system("head -2 4He-processed | tail -1 ")
puts the entire first line, of each index loop, to the legend
It likely has to do with syntax?
I want the values from $3 and $4, not the column headings:
Here is the some lines (but not all the columns) from the file
nz na e0 theta nu xsect ert y fy fye
2 4 0.150 60.000 0.025 0.330E+02 0.752E+00 -0.0459 0.956E+00 0.218E-01
2 4 0.150 60.000 0.030 0.497E+02 0.784E+00 -0.0001 0.146E+01 0.230E-01
2 4 0.150 60.000 0.035 0.483E+02 0.766E+00 0.0315 0.144E+01 0.229E-01
2 4 0.150 60.000 0.040 0.408E+02 0.728E+00 0.0573 0.125E+01 0.224E-01
This continues for many blocks. Here, if I were to start my loop with the first block, the values (at $3 and $4) would be 0.150 and 60.000 which correspond to the energy and angle of the projectile and they would hopefully appear in the legend. The plotted quantities ($8,$22 and $23) not pasted here (too many columns).

The problem is that the double-quoted string in your command starts with head" and runs to printf". That is clearly not what you intended.
Also I am uncertain what you mean by values in $3 and $4. Can you show an example of the first line (2 lines?) of your file and state, in words, what you are trying to extract from it?
Amended answer after seeing the data and a fuller explanation of the requirements
The answer from #theozh should work, but for completeness here is a different approach that works in either gnuplot 5.2 or 5.4.
It uses two passes through the data file; one pass to construct the titles, and a second pass for the actual plot.
$Data <<EOD
nz na e0 theta nu xsect ert y fy fye
1 11 0.150 60.000 5 6 7 8 9 10
2 12 0.150 60.000 5 6 7 8 9 10
3 13 0.150 60.000 5 6 7 8 9 10
4 14 0.150 60.000 5 6 7 8 9 10
nz na e0 theta nu xsect ert y fy fye
1 21 0.250 65.000 5 6 7 8 9 10
2 22 0.250 65.000 5 6 7 8 9 10
3 23 0.250 65.000 5 6 7 8 9 10
4 24 0.250 65.000 5 6 7 8 9 10
nz na e0 theta nu xsect ert y fy fye
1 31 0.350 70.000 5 6 7 8 9 10
2 32 0.350 70.000 5 6 7 8 9 10
3 33 0.350 70.000 5 6 7 8 9 10
4 34 0.350 70.000 5 6 7 8 9 10
EOD
set key out
set key title "e0 theta" left
#set datafile columnheader # omit this line for gnuplot version < 5.4
# columheaders are not actually used anyhow
#
# First pass is just to accummulate an array of titles
#
nblocks = 30 # maximum number of data blocks
array Title[nblocks] # one title for each data blockA
set term push # remember current terminal
set term dumb # could be anything
set out '/dev/null' # throw away the output
plot for [i=0:2:1] $Data index i using 1:2:($0 == 1 ? Title[i+1]=sprintf("%g %g",$3,$4) : "") with labels
#
# Second pass is the actual plot
#
set term pop # restore original terminal
plot for [i=0:2:1] $Data index i using 1:2 with lp title Title[i+1]

I guess you can't use columnheader() (check help columnheader), because by this you will sacrifice the first data line of each block and I assume you do want to keep all data.
The following should work for gnuplot>=5.4.0 and under the assumption that column 3 and 4 do not change within each block. However, this will not work for gnuplot<=5.4.0, because (as I understand) the title for the legend will be evaluated before each plotting iteration and in gnuplot>=5.4.0 after each plotting iteration. For gnuplot<5.4.0 you have to think about other workarounds.
I hope you get the idea and can adapt the script to your case, i.e. filtering, etc.
Script: (works for gnuplot>=5.4.0)
### extract title without using columnheader()
reset session
$Data <<EOD
nz na e0 theta nu xsect ert y fy fye
1 11 0.150 60.000 5 6 7 8 9 10
2 12 0.150 60.000 5 6 7 8 9 10
3 13 0.150 60.000 5 6 7 8 9 10
4 14 0.150 60.000 5 6 7 8 9 10
nz na e0 theta nu xsect ert y fy fye
1 21 0.250 65.000 5 6 7 8 9 10
2 22 0.250 65.000 5 6 7 8 9 10
3 23 0.250 65.000 5 6 7 8 9 10
4 24 0.250 65.000 5 6 7 8 9 10
nz na e0 theta nu xsect ert y fy fye
1 31 0.350 70.000 5 6 7 8 9 10
2 32 0.350 70.000 5 6 7 8 9 10
3 33 0.350 70.000 5 6 7 8 9 10
4 34 0.350 70.000 5 6 7 8 9 10
EOD
set key out
plot for [i=0:2:1] $Data u 1:2:(myTitle=sprintf("%g, %g",$3,$4)) index i \
w p pt 7 ps 2 lc i title myTitle
### end of script
Result:
Addition: (script for gnuplot>=4.6.0, March 2012)
What Ethan did in his answer with an array (available only from 5.2.0 on) you can do with strings and word() for older versions (check help word).
The following works for 4.6.0 and 4.6.5 and >=5.0.0, however, not for 4.6.7 (it complains that ... '+' u (NaN):(NaN) ... "Skipping data file with no valid points").
For gnuplot 4.x you cannot add spaces in your myTitles, but for gnuplot>=5.0.0 you could use double quotes and include spaces, e.g. myTitles=myTitles.sprintf(' "%g, %g"',$3,$4).
You might have to adapt the color numbers in the second plot command depending on which subblocks (index) you are plotting in the first plot command.
Data: SO74320605.dat
nz na e0 theta nu xsect ert y fy fye
1 11 0.150 60.000 5 6 7 8 9 10
2 12 0.150 60.000 5 6 7 8 9 10
3 13 0.150 60.000 5 6 7 8 9 10
4 14 0.150 60.000 5 6 7 8 9 10
nz na e0 theta nu xsect ert y fy fye
1 21 0.250 65.000 5 6 7 8 9 10
2 22 0.250 65.000 5 6 7 8 9 10
3 23 0.250 65.000 5 6 7 8 9 10
4 24 0.250 65.000 5 6 7 8 9 10
nz na e0 theta nu xsect ert y fy fye
1 31 0.350 70.000 5 6 7 8 9 10
2 32 0.350 70.000 5 6 7 8 9 10
3 33 0.350 70.000 5 6 7 8 9 10
4 34 0.350 70.000 5 6 7 8 9 10
Script: (works for gnuplot 4.6.0, 4.6.5, >=5.0.0, but not for 4.6.7)
### extract title from lines without using columnheader()
reset
FILE = "SO74320605.dat"
set key out noautotitle
myTitles = ''
plot for [i=0:2:1] FILE u 1:2:($0==1?myTitles=myTitles.sprintf(' %g,%g',$3,$4):0) \
index i w lp pt 7 ps 2 lc i+1, \
for [i=1:words(myTitles)] '+' u (NaN):(NaN) every ::::0 \
w lp pt 7 ps 2 lc i ti word(myTitles,i)
### end of script
Result: (created with gnuplot 4.6.0)

Related

Stat2Data package doesn't allow me to use the objects in it

Stat2Data package contains a lot of exemplary datasets. I get no errors when installing it or using the library function to call it. However, it doesn't allow me to work with the objects.
Anyone familiar with this package and know what I can do about it? Here's the code that I used:
install.packages("Stat2Data")
library(Stat2Data)
# Attempt 1
MedGPA_ds <- ggplot(MedGPA, aes(x = GPA, y = Acceptance))
# Attempt 2
MedGPA_ds <- ggplot(Stat2Data::MedGPA, aes(x = GPA, y = Acceptance))
You have missed just one step, the use of the data() function to call the specific dataset (MedGPA) contained within the Stat2Data package.
Try the following:
library(Stat2Data)
data(MedGPA)
head(MedGPA)
Accept Acceptance Sex BCPM GPA VR PS WS BS MCAT Apps
1 D 0 F 3.59 3.62 11 9 9 9 38 5
2 A 1 M 3.75 3.84 12 13 8 12 45 3
3 A 1 F 3.24 3.23 9 10 5 9 33 19
4 A 1 F 3.74 3.69 12 11 7 10 40 5
5 A 1 F 3.53 3.38 9 11 4 11 35 11
6 A 1 M 3.59 3.72 10 9 7 10 36 5
Happy coding!

SAS: Stuck in a loop even with changes made? Any pointers?

This is the code that I am using, I have tried changing a few things around but I think I am getting stuck in an endless loop.
DATA songs;
INFILE datalines;
INPUT City $ 1-15 Age domk wj hwow simbh kt aomm libm tr filp ttr;
ARRAY song (10) domk wj hwow simbh kt aomm libm tr filp ttr;
DO i = 1 TO 10;
IF song(i) = 9 THEN song(i) = .;
END;
datalines;
Albany 54 4 3 5 9 9 2 1 4 4 9
Richmond 33 5 2 4 3 9 2 9 3 3 3
Oakland 27 1 3 2 9 9 9 3 4 2 3
Richmond 41 4 3 5 5 5 2 9 4 5 5
Berkeley 18 3 4 9 1 4 9 3 9 3 2
;
PROC PRINT DATA = songs;
TITLE 'WBRK Song Survey';
RUN;
Can you point out what is wrong here? I have already tried changing the DO loop by adding an incremental i.
DO i = 1 TO 10;
IF song(i) = 9 THEN song(i) = .;
i+1;
END;
but the result is the same. I am new to SAS although not new to programming. I am wondering if I am making a syntax error here. Either way, any help is appreciated.
As I suspected, there was an issue with your import statement, at least for me. The following code worked for me:
DATA songs;
INFILE datalines;
informat city $20.;
INPUT City $ Age domk wj hwow simbh kt aomm libm tr filp ttr;
ARRAY song (10) domk wj hwow simbh kt aomm libm tr filp ttr;
DO i = 1 TO 10;
IF song(i) = 9 THEN song(i) = .;
END;
datalines;
Albany 54 4 3 5 9 9 2 1 4 4 9
Richmond 33 5 2 4 3 9 2 9 3 3 3
Oakland 27 1 3 2 9 9 9 3 4 2 3
Richmond 41 4 3 5 5 5 2 9 4 5 5
Berkeley 18 3 4 9 1 4 9 3 9 3 2
;
PROC PRINT DATA = songs;
TITLE 'WBRK Song Survey';
RUN;

Rearranging an array using for loop in Matlab

I have a 1 x 15 array of values:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
I need to rearrange them into a 3 x 5 matrix using a for loop:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
How would I do that?
I'm going to show you three methods. One where you need to have a for loop, and two others when you don't:
Method #1 - for loop
First, create a matrix that is 3 x 5, then keep track of an index that will go through your array. After, create a double for loop that will help you populate the array.
index = 1;
array = 1 : 15; %// Array we wish to access
matrix = zeros(3,5); %// Initialize
for m = 1 : 3
for n = 1 : 5
matrix(m,n) = array(index);
index = index + 1;
end
end
matrix =
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
Method #2 - Without a for loop
Simply put, use reshape:
matrix = reshape(1:15, 5, 3).';
matrix =
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
reshape will take a vector and restructure it into a matrix so that you populate the matrix by columns first. As such, we want to put 1 to 5 in the first column, 6 to 10 in the second and 11 to 15 in the third column. Therefore, our output matrix is in fact 5 x 3. When you see this, this is actually the transposed version of the matrix we want, which is why you do .' to transpose the matrix back.
Method #3 - Another method without a for loop (tip of the hat goes to Luis Mendo)
You can use vec2mat, and specify that you need to have 5 columns worth for your matrix:
matrix = vec2mat(1:15, 5);
matrix =
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
vec2mat takes a vector and reshapes it into a matrix of as many columns as you specify in the second parameter. In this case, we need 5 columns.
For the sake of (bsx)fun, here is another option...
bsxfun(#plus,1:5,[0:5:10]')
ans =
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
less readable, maybe faster, but who cares if it is such a small of an array...
A = [ 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ] ;
A = reshape( A' , 3 , 5 ) ;
A' = 1 2 3 4 5
6 7 8 9 10
11 12 13 14 15

matlab get neighbours on matrix

I have a simple matrix:
1 2 3 4
5 6 7 8
8 9 10 11
12 13 14 15
I need to loop through each element and build a new matrix with 3 of its surrounding elements (the one to the right, bottom right and bottom). So I will end up with an array like so:
1 2 6 5
2 3 7 6
3 4 8 7
I managed to do this but when I need to jump to the row below I can't seem to figure out how to do it. for the next row it should be:
5 6 9 8
6 7 10 9
...
Any ideas?
[m n] = size(A);
[jj ii] = ndgrid(1:m-1, 1:n-1); %// rows and columns except last ones
kk = sub2ind([m n], ii(:),jj(:)); %// to linear index
B = [ A(kk) A(kk+m) A(kk+m+1) A(kk+1) ] %// pick desired values with linear index
In your example:
B =
1 2 6 5
2 3 7 6
3 4 8 7
5 6 9 8
6 7 10 9
7 8 11 10
8 9 13 12
9 10 14 13
10 11 15 14
My favourite bsxfun being put to work here -
[M,N] = size(A); %// A is Input
ind = bsxfun(#plus,[1:M-1],[(0:N-2).*M]') %//'
out = A(bsxfun(#plus,ind(:),[0 M M+1 1])) %// Desired output
Output using the sample input from question -
out =
1 2 6 5
2 3 7 6
3 4 8 7
5 6 9 8
6 7 10 9
7 8 11 10
8 9 13 12
9 10 14 13
10 11 15 14

How can I create a 3D array by stenciling the columns of a 2D array in MATLAB?

Suppose I have a 2D array called A. I want to create a 3D array called B, whose "pages" are select columns of a stencil moving across A, column-by-column. For example, the first page of B might be the 1st, 3rd, and 5th columns of A. Then the second page would be the 2nd, 4th, and 6th columns of A, etc.
Anyone have an efficient way of doing this is MATLAB?
Thanks!
I am guessing you are looking for this -
%%// Given 2D array
A = randi(10,4,12)
t1 = reshape(A,size(A,1)*2,[]);
t2 = reshape(t1',size(A,2)/2,[],2); %%//'
B = permute(t2,[2 1 3]) %%// Output 3D array
Output -
A =
5 10 3 5 6 8 4 3 8 10 8 7
10 8 3 7 6 10 9 2 7 8 8 5
10 4 7 8 6 4 5 4 1 1 3 7
7 7 6 6 1 10 5 8 9 4 3 3
B(:,:,1) =
5 3 6 4 8 8
10 3 6 9 7 8
10 7 6 5 1 3
7 6 1 5 9 3
B(:,:,2) =
10 5 8 3 10 7
8 7 10 2 8 5
4 8 4 4 1 7
7 6 10 8 4 3
Of course, there is an alternative straight-forward approach for this special case -
B(:,:,1)=A(:,1:2:end);
B(:,:,2)=A(:,2:2:end);

Resources