Take array input from a file - matlab

I have a file in the first line is of the form:
6, [6; 2], 1000, 0.5, 0.01, [6 2], 0, 3.1416, [1 1 1]
Any of the cells can a vector/array, but only one dimensional
I tried taking input using textscan:
C = (fid, '%f%f%f%f%f%f%f%f%f',1,'delimiter',',');
but this doesn't give me the right output.
How can I take this input such that I get all the arrays?
Thanks in advance!

textscan with that format specifier is always going to fail because the [, ;, , and ] characters aren't going to be parsed properly.
You could instead split the string at the commas, and then use str2num to convert each piece into a number or array. This assumes that you never use , within an array.
value = cellfun(#str2num, strsplit(str, ','), 'uniform', 0)

Related

Debugging the error "Dimensions of arrays being concatenated are not consistent" in MATLAB

I have a function VanderPol() which is supposed to give a vector output, but it doesn't seem to work. It is just three lines of code but I cannot seem to find the bug.
The function is
function [output] = VanderPol(y, i)
output = [y(2,i); (1-y(1,i)^2)*y(2,i) -y(1,i)];
end
and it is called as
z = [1 2 3;
4 5 6];
VanderPol(z,1)
I recieve an error message stating that VanderPol(z,1) is faulty, but no hint why. The exact error message is shown below. Can anyone spot the bug?
Error using vertcat
Dimensions of arrays being concatenated are not consistent.
This is a bit of an edge case: You can construct arrays in MATLAB by separating elements either by a comma , or a space . Thus, the following ways both work and give the same result:
a = [1, 2, 3]
b = [1 2 3]
When building matrices, this works similarly, and rows are separated by a semicolon or a new line, i.e. we have the following equivalent possibilities:
A = [1, 2, 3; 4, 5, 6]
B = [1 2 3; 4 5 6]
C = [1, 2, 3
4, 5, 6]
D = [1 2 3
4 5 6]
Now to your example: your array is the following:
[y(2,i); (1-y(1,i)^2)*y(2,i) -y(1,i)]
The first row contains one element y(2,i). The second row, however, is interpreted as two elements: (1-y(1,i)^2)*y(2,i) and -y(1,i), due to the space between these parts. I.e. MATLAB thinks you are using a space to separate two parts of an array like in b above. It interprets the input like the following:
[y(2,i); (1-y(1,i)^2)*y(2,i), -y(1,i)]
If you paste the code into MATLAB, you will thus get an error complaining that it is not possible to have an array with 1 element in the first and 2 elements in the second row:
>> [y(2,i); (1-y(1,i)^2)*y(2,i) -y(1,i)]
Error using vertcat
Dimensions of arrays being concatenated are not consistent.
To solve the problem you have to tell MATLAB that there is only one element in the second row, given by the subtraction (1-y(1,i)^2)*y(2,i) -y(1,i). Here are some ways to do that:
output = [y(2,i); (1-y(1,i)^2)*y(2,i) - y(1,i)]; % spaces on both sides of -
output = [y(2,i); (1-y(1,i)^2)*y(2,i)-y(1,i)]; % no spaces around -
output = [y(2,i); ((1-y(1,i)^2)*y(2,i) -y(1,i))]; % parentheses around everything

De-nest elements of cell-matrix into a matrix

EDIT: It turns out this problem is not solved, as it fails to handle empty cells in the source data. i.e. k = {1 2 [] 4 5}; cat( 2, k{:} ) gives 1 2 4 5 not 1 2 NaN 4 5. So the subsequent reshape is now misaligned. Can anyone outline a strategy for handling this?
I have data of the form:
X = { ...
{ '014-03-01' [1.1] [1.2] [1.3] }; ...
{ '014-03-02' [2.1] [2.2] [2.3] }; ... %etc
}
I wish to replace [1.1] with 1.1 etc, and also replace the date with an integer using datenum
So I may as well use a standard 2D matrix to hold the result (as every element can be expressed as a Double).
But how to go out this repacking?
I was hoping to switch the dates in-place using X{:,1} = datenum( X{:,1} ) but this command fails.
I can do:
A = cat( 1, X{:} )
dateNums = datenum( cat( 1, A{:,1} ) )
values = reshape( cat( 1, A{:,2:end} ), size(X,1), [] )
final = [dateNums values]
Well, that works, but I don't feel at all comfortable with it.
>> u = A{:,1}
u =
014-03-01
>> cat(1,u)
ans =
014-03-01
This suggests only one value is output. But:
>> cat(1,A{:,1})
ans =
014-03-01
014-03-02
So A{:,1} must be emitting a sequential stream of values, and cat must be accepting varargs.
So now if I do A{:,2:end}, it is now spitting out that 2D subgrid again as a sequential stream of values...? And the only way to get at that grid is to cat -> reshape it. Is this a correct understanding?
I'm finding MATLAB's console output infuriatingly inconsistent.
The "sequential stream of values" is known as a comma-separated list. Doing A{:,1} in MATLAB in the console is equivalent to the following syntax:
>> A{1,1}, A{2,1}, A{3,1}, ..., A{end,1}
This is why you see a stream of values because it is literally typing out each row of the cell for the first column, separated by commas and showing that in the command prompt. This is probably the source of your infuriation as you're getting a verbose dump of all of the contents in the cell when you are unpacking them into a comma-separated list. In any case, this is why you use cat because doing cat(1, A{:,1}) is equivalent to doing:
cat(1, A{1,1}, A{2,1}, A{3,1}, ... A{end,1})
The end result is that it takes all elements in the 2D cell array of the first column and creates a new result concatenating all of these together. Similarly, doing A{:, 2:end} is equivalent to (note the column-major order):
>> A{1, 2}, A{2, 2}, A{3, 2}, ..., A{end, 2}, A{1, 3}, A{2, 3}, A{3, 3}..., A{end, 3}, ..., A{end, end}
This is why you need to perform a reshape because if you did cat with this by itself, it will only give you a single vector as a result. You probably want a 2D matrix, so the reshape is necessary to convert the vector into matrix form.
Comma-separated lists are very similar to Python's splat operator if you're familiar with Python. The splat operator is used for unpacking input arguments that are placed in a single list or iterator type... so for example, if you had the following in Python:
l = [1, 2, 3, 4]
func(*l)
This is equivalent to doing:
func(1, 2, 3, 4)
The above isn't really necessary to understand comma-separated lists, but I just wanted to show you that they're used in many programming languages, including Python.
There is a problem with empty cells: cat will skip them. Which means that a subsequent reshape will throw a 'dimension mismatch' error.
The following code simply removes rows containing empty cells (which is what I require) as a preprocessing step.
(It would only take a minor alteration to replace empty cells with NaNs).
A = cat( 1, X{:} );
% Remove any row containing empty cells
emptiesInRow = sum( cellfun('isempty',A), 2 );
A( emptiesInRow > 0, : ) = [];
% Date is first col
dateNums = datenum( cat( 1, A{:,1} ) );
% Get other cols
values = reshape( cat( 1, A{:,2:end} ), size(A,1), [] );
% Recombine into (double) array
grid = [dateNums values]; %#ok<NASGU>

How to Convert a Vector to a Number in Matlab?

I have a vector, A=[2 2 4 5]. I want to convert A to a number. Answer should be 2245.
Example 2. B=[5,6,7,8,9]. Answer should be 56789.
Thanks.
PS. Thanks to all. Now I understand to convert the vector to a string and delete the space, and convert back to a number.
You could try this -
>> a = [2 3 10];
>> str2num(strrep(num2str(a), ' ', ''))
ans =
2310
Why does it work? Well, num2str ("number to string") converts the vector into its character representation
>> num2str(a)
ans =
2 3 10
which is almost what you want, except for the spaces between the numbers. So you call strrep ("string replace") to replace all the spaces (' ') with the empty string ('')
>> strrep('hi there', ' ', '')
ans =
hithere
and finally use str2num ("string to number") to convert the resulting string back into a number.
Take each number, convert it to a string and concatenate the results. Take this string and convert it back into a number. You can use num2str on the array, remove any white spaces that result from this conversion using ismember then convert the string back to a number with num2str:
C = [2 3 10];
strC = num2str(C);
strC(ismember(strC, ' ')) = [];
out = str2num(strC)
out =
2310
Alternatively, you can use strrep to replace all spaces with nothing after you run num2str, then convert back to a number:
C = [2 3 10];
strC = num2str(C);
strC = strrep(strC, ' ', '');
out = str2num(strC)
out =
2310
Tipping the hat to Chris Taylor, this can all be done in one line:
out = str2num(strrep(num2str(C), ' ', ''))
out =
2310
One more for academic purposes is to use regular expressions. Specifically, use regexprep on the converted string array that is output from num2str and replace all spaces with nothing:
C = [2 3 10];
strC = num2str(C);
out = str2num(regexprep(strC, '\s*', ''))
out =
2310
The pattern \s* searches for 0 or more white space characters. We find these and set them to nothing.
Thanks to #obchardon for a correction.
This uses only arithmetics (no strings). It works for numbers greater than 0. A can be a row or column vector.
A = [2 0 3 10];
x = cumsum(floor(log10(A.'+(A.'==0)))+1);
x = x(end)-x;
result = A(:).'*10.^x
which gives
result =
20310
If you want to string all of the digits together like they are the digits in a single integer you can convert the vector to a string, remove the spaces to smoosh the digits together, and then convert it back to a single number.
This way will handle an arbitrary number of digits in each vector element (assuming they are all real integers) rather than trying to multiply each element by the respective power of 10 and taking the sum.
Example code:
A = [2 44 12 6];
Astr = num2str(A);
Astr(strfind(Astr, ' ')) = [];
Anum = str2double(Astr);
This uses num2str without having to worry about whitespaces.
Apply num2str to every number using arrayfun, concatenate the resulting strings, convert back to number. Sadly it is quite a bit slower than the whitespace-deleting or numerical approach.
numStrings = arrayfun(#num2str,a,'uni',0);
out = str2num(cat(2,numStrings{:}))
out =
2310

How to find the position of a value in an array in matlab

Think I have an array like
A = { 1,2,3,4,5,6}
I need to get the position of 4 in this array.
I tried,
p = find(A==4)
Please help.
If you really need a cell array (for example because the cells can contain vectors of different sizes):
A = {1, [1 2 3], 4, [1 2], [3 4]}; %// example cell array
sought = [1 2]; %// sought contents
index = find(cellfun(#(x) isequal(x, sought), A));
you created a cell-array instead of a normal vector.
Try:
A = [1,2,3,4,5,6]
find(A==4)
Cell arrays are great to store variables with different types.You could, for example, create a cell array that contains strings as well as digits.
If you have only digits in your array you should defintely use normal arrays.
These are defined by [ ] instead of { }
As you have defined a cell array you need to convert it to a numeric array for find to work, fortunately this is simple to achieve with a couple of well placed brackets.
A = { 1,2,4,3,5,6};
find([A{:}]==4)
ans =
3
So A{:} writes out the numeric values from your array and the [] contains the output for find to work.
p.s. I re-arranged the numbers in A to show that it was working as '4' is now in position 3 to provide a better test.

Matlab - Writing Text and Numeric Data to a File in a Loop

I have googled many times to solve my peculiar situation about writing/output to file without much success.
I have a for loop which generates me 1 cell matrix and 1 regular matrix. For each loop the Cell Matrix can be of variable length. Assuming dimentions of <1x5>, the cell matrix stores the following strings:
Aggregated Day, AggreVal from Curve, Val3_Name, Val4_Name, Val5_Name
The cell matrix can have different content and size for next loop.
The numeric matrix is of same size as cell matrix and represents the values corresponding to names in cell matrix. Hence, for this loop it has size 1x5 and stores values as:
1.3, 1300, 14, 15, 16
I want to write the above cell and numeric matrix to ONE single file (preferrably excel or txt file for future manipulation) as they are being generated. First I want to output the cell matrix and right after that numeric matrix. Followed by cell matrix of second loop and so on.
I remember it being very easy to do so in C++ by opening the file in append mode, but it appears to be tricky here in Matlab. I have tried playing with xlswrite, dlmwrite, xlsappend, etc but nothing has worked so far.
Hence, the output file will look something like:
Loop1
Aggregated Day, AggreVal from Curve, Val3_Name, Val4_Name, Val5_Name
1.3, 1300, 14, 15, 16
Loop2
Aggaed Dy, AgeVal fm Curve, China, Val4_Name, Brazil
1.453, 1300, 1774, 1115, 1613
Thanks
Could you avoid closing the file until after all the loops have finished, i.e.:
fid = fopen('filename.txt','w');
% Loop stuff, adding lines to your file
fclose(fid);
It looks like the kind of output you want is a custom format, rather than an xls file, which assumes a table-like structure. Try using fprintf to print your data:
foo = {'abc','def','ghi'};
foo2 = [1 2 3 4];
fid = fopen('foo.txt','w');
fprintf(fid, '%s ', foo{:});
fprintf(fid, '\n');
fprintf(fid, '%f ', foo2);
fprintf(fid, '\n');
fclose(fid)
I'd do this:
A{1} = {'Aggregated Day', 'AggreVal from Curve', 'Val3_Name', 'Val4_Name', 'Val5_Name'}
A{2} = {1.3, 1300, 14, 15, 16};
B = cat(1,A{:});
xlswrite(filename,B);
%s={'Aggregated Day', 'AggreVal from Curve', 'Val3_Name', ...
'Val4_Name', 'Val5_Name'};
%n=[1.3, 1300, 14, 15, 16];
filename='myfile.xlsx'; % Change it to myfile.txt if needed for text version
% the trick is to retain the row number to append contents
%N = no. of entries.
for k = 1:2:N %Sheet %Row
xlswrite( filename, s , 1, sprintf('A%d',k) )
xlswrite( filename, n , 1, sprintf('A%d',k+1) )
end