creating a legend within for loop for Matlab plot - arrays

I want to plot several curves, each having a different length. So, I've placed each curve as an array in a cell index, Y (this allows me to index through arrays of different sizes inside a FOR loop). I use "hold all" below to enable each iteration of the FOR loop to plot each new array in the cell array Y inside the same plot.
hold all;
for i = 1:1:length(maxusers)
time = increment*(0:1:length(Y{i})-1);
plot(time,Y{i,1,:});
end
While the use of a cell array here does simplify plotting the various curves inside Y, the problem I'm having is creating legend. Currently I'm using a really long/ugly switch statement to cover every possible scenario, but I think there should be a more elegant solution.
If I have an array (where maxusers=4, for example) that is:
filesize = [10 100 200 300];
I know the legend Matlab command that works is:
legend(num2str(filesize(1)),num2str(filesize(2)),num2str(filesize(3)),num2str(filesize(4)));
but I get stuck trying to create a legend command when the number of curves is a variable given by maxusers. Any ideas? Thanks in advance.

Try this:
>> filesize = [10 100 200 300];
>> str = strtrim(cellstr(int2str(filesize.'))) %'# Create a cell array of
%# strings
str =
'10'
'100'
'200'
'300'
>> legend(str{:}); %# Pass the cell array contents to legend
%# as a comma-separated list

Related

Declaring two arrays in gnuplot and plotting them one with respect to another

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

Matlab transpose values in a structure within a cell array

I successfully created a moving window of n=85 for my data and put the windows in a cell array:
n = 37886;
cell_array=cell(n,1);
a = 1:n;
for T=1:n-84
M=a(T:T+84);
tmpstruct=struct('M',M);
cell_array{T}=tmpstruct;
end
However, I need to transpose M, which is the data of window values located within the structure within the cell array. That is, instead of the vector of window values being 1x85, I want them to be 85x1.
I've attempted transposing with this:
cell_array = cellfun(#transpose,cell_array,'UniformOutput',false);
But this code doesn't work for me.
Any feedback on how to transpose my windows will be greatly appreciated. I need to transpose 252 cell arrays, so doing this manually is out of the question.
If I clearly understood, what about:
n = 37886;
cell_array=cell(n,1);
a = 1:n;
for T=1:n-84
M=a(T:T+84);
tmpstruct=struct('M',M'); % Modified line to transpose windows!
cell_array{T}=tmpstruct;
end
If you prefer named functions:
n = 37886;
cell_array=cell(n,1);
a = 1:n;
for T=1:n-84
M=a(T:T+84);
tmpstruct=struct('M',transpose(M)); % Modified line to transpose windows!
cell_array{T}=tmpstruct;
end

Split array into smaller unequal-sized arrays dependend on array-column values

I'm quite new to MatLab and this problem really drives me insane:
I have a huge array of 2 column and about 31,000 rows. One of the two columns depicts a spatial coordinate on a grid the other one a dependent parameter. What I want to do is the following:
I. I need to split the array into smaller parts defined by the spatial column; let's say the spatial coordinate are ranging from 0 to 500 - I now want arrays that give me the two column values for spatial coordinate 0-10, then 10-20 and so on. This would result in 50 arrays of unequal size that cover a spatial range from 0 to 500.
II. Secondly, I would need to calculate the average values of the resulting columns of every single array so that I obtain per array one 2-dimensional point.
III. Thirdly, I could plot these points and I would be super happy.
Sadly, I'm super confused since I miserably fail at step I. - Maybe there is even an easier way than to split the giant array in so many small arrays - who knows..
I would be really really happy for any suggestion.
Thank you,
Arne
First of all, since you wish a data structure of array of different size you will need to place them in a cell array so you could try something like this:
res = arrayfun(#(x)arr(arr(:,1)==x,:), unique(arr(:,1)), 'UniformOutput', 0);
The previous code return a cell array with the array splitted according its first column with #(x)arr(arr(:,1)==x,:) you are doing a function on x and arrayfun(function, ..., 'UniformOutput', 0) applies function to each element in the following arguments (taken a single value of each argument to evaluate the function) but you must notice that arr must be numeric so if not you should map your values to numeric values or use another way to select this values.
In the same way you could do
uo = 'UniformOutput';
res = arrayfun(#(x){arr(arr(:,1)==x,:), mean(arr(arr(:,1)==x,2))), unique(arr(:,1)), uo, 0);
You will probably want to flat the returning value, check the function cat, you could do:
res = cat(1,res{:})
Plot your data depends on their format, so I can't help if i don't know how the data are, but you could try to plot inside a loop over your 'res' variable or something similar.
Step I indeed comes with some difficulties. Once these are solved, I guess steps II and III can easily be solved. Let me make some suggestions for step I:
You first define the maximum value (maxValue = 500;) and the step size (stepSize = 10;). Now it is possible to iterate through all steps and create your new vectors.
for k=1:maxValue/stepSize
...
end
As every resulting array will have different dimensions, I suggest you save the vectors in a cell array:
Y = cell(maxValue/stepSize,1);
Use the find function to find the rows of the entries for each matrix. At each step k, the range of values of interest will be (k-1)*stepSize to k*stepSize.
row = find( (k-1)*stepSize <= X(:,1) & X(:,1) < k*stepSize );
You can now create the matrix for a stepk by
Y{k,1} = X(row,:);
Putting everything together you should be able to create the cell array Y containing your matrices and continue with the other tasks. You could also save the average of each value range in a second column of the cell array Y:
Y{k,2} = mean( Y{k,1}(:,2) );
I hope this helps you with your task. Note that these are only suggestions and there may be different (maybe more appropriate) ways to handle this.

Creating sub-arrays from large single array based on marker values

I need to create a 1-D array of 2-D arrays, so that a program can read each 2-D array separately.
I have a large array with 5 columns, with the second column storing 'marker' data. Depending on the marker value, I need to take the corresponding data from the remaining 4 columns and put them into a new array on its own.
I was thinking of having two for loops running, one to take the target data and write it to a cell in the 1-D array, and one to read the initial array line-by-line, looking for the markers.
I feel like this is a fairly simple issue, I'm just having trouble figuring out how to essentially cut and paste certain parts of an array and write them to a new one.
Thanks in advance.
No for loops needed, use your marker with logical indexing. For example, if your large array is A :
B=A(A(:,2)==marker,[1 3:5])
will select all rows where the marker was present, without the 2nd col. Then you can use reshape or the (:) operator to make it 1D, for example
B=B(:)
or, if you want a one-liner:
B=reshape(A(A(:,2)==marker,[1 3:5]),1,[]);
I am just answering my own question to show any potential future users the solution I came up with eventually.
%=======SPECIFY CSV INPUT FILE HERE========
MARKER_DATA=csvread('ESphnB2.csv'); % load data from csv file
%===================================
A=MARKER_DATA(:,2); % create 1D array for markers
A=A'; % make column into row
for i=1:length(A) % for every marker
if A(i) ~= 231 % if it is not 231 then
A(i)=0; % set value to zero
end
end
edgeArray = diff([0; (A(:) ~= 0); 0]); % set non-zero values to 1
ind = [find(edgeArray > 0) find(edgeArray < 0)-1]; % find indices of 1 and save to array with beginning and end
t=1; % initialize counter for trials
for j=1:size(ind,1) % for every marked index
B{t}=MARKER_DATA(ind(j,1):ind(j,2),[3:6]); % create an array with the rows from the data according to indicies
t=t+1; % create a new trial
end
gazeVectors=B'; % reorient and rename array of trials for saccade analysis
%======SPECIFY MAT OUTPUT FILE HERE===
save('Trial_Data_2.mat','gazeVectors'); % save array to mat file
%=====================================

How to set the fields simultaneously in a large structure array in Matlab?

I have a large structure array.
I would like to perform a sensitivity analysis on a function that processes this array.
So, say my structure array has name 's', 10,000 elements, and field names 'x' and 'y'.
I'd like to do the following:
xs = [s(:).x];
xs = xs + 5*randn(size(xs));
s(:).x = xs;
Sadly, the last step is not valid matlab. Any thoughts? Was hoping to avoid a loop.
From this answer and after playing around with deal. I think I have what you are looking for but it requires converting xs into a cell array using num2cell:
xs_cell = num2cell(xs); % convert matrix to cell array.
[S(:).X]=xs_cell{:}; % update the values in the field X

Resources