cell array to numeric array for plotting - arrays

I have a cell array containing historic gold price data and a cell array with the associated dates. I want to plot dates against prices for simple analysis but I am having difficulty converting the cell array of prices into a doubles.
My code is:
figure
plot(Date,USDAM,'b')
title('{\bf US Gold Daily Market Price, 2010 to 2015}')
datetick
axis tight
When I try to convert the gold prices (USDAM) into a double using cell2mat(USDAM), it throws the following error:
Error using cat
Dimensions of matrices being concatenated are not consistent.
Error in cell2mat (line 83)
m{n} = cat(1,c{:,n});
I use the following code to import the data:
filename = 'goldPriceData.csv';
delimiter = ',';
startRow = 2;
endRow = 759;
formatSpec = '%s%s%*s%*s%*s%*s%*s%[^\n\r]';
fileID = fopen(filename,'r');
dataArray = textscan(fileID, formatSpec, endRow-startRow+1, 'Delimiter', delimiter, 'EmptyValue' ,NaN,'HeaderLines', startRow-1, 'ReturnOnError', false);
fclose(fileID);
Date = dataArray{:, 1};
USDAM = dataArray{:, 2};

For your problem, cell2mat is the wrong function. Consider the cell array of strings:
>> S = {'1.2';'3.14159';'2.718'}
S =
'1.2'
'3.14159'
'2.718'
>> cell2mat(S)
Error using cat
Dimensions of matrices being concatenated are not consistent.
Error in cell2mat (line 83)
m{n} = cat(1,c{:,n});
That's because each row of the output needs to have the same number of columns, the strings are of different length. You can use strvcat(S) to get a rectangular matrix padded with spaces, but that isn't what you want. You want numeric data.
>> str2double(S)
ans =
1.2000
3.1416
2.7180
Just because it puts a number in scientific notation, doesn't mean it's not the same number. That is, 1.199250000000000e+03 is 1199.25. To get the tick labels looking the way you want them, set YTickLabel property of the axis with formatted strings, the ones in USD.
Regarding your dates, you'll need numeric data to plot on each axis so convert the dates with datenum.
>> dateVals = datenum({'2014-12-30', '2014-12-31'})
dateVals =
735963
735964
Then to get the dates displayed on the x axis correctly, set the XTickLabel properties of the axis to get it looking how you want it (using the strings in Dates). Note that for setting the tick labels, you must ensure that you have the correct (same) number of ticks as labels that you indent to have. But that is a different question, I think.

Related

Automatically assign number to each string in array in Matlab

I have a large cell array in Matlab (imported from Excel) containing numbers and strings.
Let's say the string part looks like this, just bigger with many columns and lines:
Table{1,1} = 'string A'
Table{2,1} = 'string B'
Table{3,1} = 'string B'
And the number part looks like this just bigger:
Table{1,2} = 5;
Table{2,2} = 10;
Table{3,2} = 15;
I am aware that there are disadvantages of working with arrays (right?), so I consider converting EVERYTHING to a numeric matrix by replacing the strings with numbers. (Possibly as a data set with headings - if you don't advise against that?)
My problem is that I have A LOT of different string entries, and I want to automatically assign a number to each entry, e.g. 1 for 'string A', 2 for 'string B' etc., such that:
Matrix(1,1) = 1
Matrix(2,1) = 2
Matrix(3,1) = 2
etc.
and for the numbers simply:
Matrix(1,2) = Table{1,2};
Matrix(2,2) = Table{2,2};
Matrix(3,2) = Table{3,2};
For the strings, I cannot assign the numbers by individual code for each string, because there are so many different string entries. Is there a way to "automate" it?
I am aware of this help site, https://ch.mathworks.com/help/matlab/matlab_prog/converting-from-string-to-numeric.html, but haven't found anything else helpful.
How would you do it?
Find the indices of both numbers and character entries in your cell array using isnumeric (or ischar) with cellfun. Then use third output argument of unique (or findgroups which requires R2015b) for assigning numbers to character entries of your cell array. Now just put the numbers into your required matrix as shown below:
tmp = cellfun(#isnumeric,Table); %Indices of Numbers
Matrix = zeros(size(Table)); %Initialising the matrix
[~, ~, ic] = unique(Table(~tmp)); %Assigning numbers to characters
Matrix(~tmp) = ic; %Putting numbers for characters
%Above two lines can be replaced with Matrix(~tmp) = findgroups(Table(~tmp)); in R2015b
Matrix(tmp) = [Table{tmp}]; %Putting numbers as they are

Updating a struct with new values in a for loop

My image array: C_filled = 256x256x3270
What I would like to do is calculate the centroids of each image, and store each centroid corresponding to each 'slice'/image into an array. However, when I try to update the array, like a regular array, I get this error:
"Undefined operator '+' for input arguments of type 'struct'."
I have the following code:
for i=1:3270;
cen(i) = regionprops(C_filled(:,:,i),'centroid');
centroids = cat(1, cen.Centroid);% convert the cen struct into a regular array.
cen(i+1) = cen(i) + 1; <- this is the problem line
end
How can I update the array to store each new centroid?
Thanks in advance.
That's because the output of regionprops (i.e. cen(i)) is a structure, to which you try to add the value 1. But since you try to add the value to the structure and not one of its field, it fails.
Assuming that each image can contain multiple objects (and therefore centroids), it would be best (I think) to store their coordinates into a cell array in which each cell can be of a different size, contrary to a numeric array. If you have the exact same number of objects in each image, then you could use a numeric array.
If we look at the "cell array" option with code:
%// Initialize cell array to store centroid coordinates (1st row) and their number (2nd row)
centroids_cell = cell(2,3270);
for i=1:3270;
%// No need to index cen...saves memory
cen = regionprops(C_filled(:,:,i),'centroid');
centroids_cell{1,i} = cat(1,cen.Centroid);
centroids_cell{2,i} = numel(cen.Centroid);
end
and that's it. You can access the centroid coordinates of any image using this notation:centroids_cell{some index}.

Split matrix into several depending on value in Matlab

I have a cell array that I need to split into several matrices so that I can take the sum of subsets of the data. This is a sample of what I have:
A = {'M00.300', '1644.07';...
'M00.300', '9745.42'; ...
'M00.300', '2232.88'; ...
'M00.600', '13180.82'; ...
'M00.600', '2755.19'; ...
'M00.600', '15800.38'; ...
'M00.900', '18088.11'; ...
'M00.900', '1666.61'};
I want the sum of the second columns for each of 'M00.300', 'M00.600', and 'M00.900'. For example, to correspond to 'M00.300' I would want 1644.07 + 9745.42 + 2232.88.
I don't want to just hard code it because each data set is different, so I need the code to work for different size cell arrays.
I'm not sure of the best way to do this, I was going to begin by looping through A and comparing the strings in the first column and creating matrices within that loop, but that sounded messy and not efficient.
Is there a simpler way to do this?
Classic use of accumarray. You would use the first column as an index and the second column as the values associated with each index. accumarray works where you group values that belong to the same index together and you apply a function to those values. In your case, you'd use the default behaviour and sum things together.
However, you'll need to convert the first column into numeric labels. The third output of unique will help you do this. You'll also need to convert the second column into a numeric array and so str2double is a perfect way to do this.
Without further ado:
[val,~,id] = unique(A(:,1)); %// Get unique values and indices
out = accumarray(id, str2double(A(:,2))); %// Aggregate the groups and sum
format long g; %// For better display of precision
T = table(val, out) %// Display on a nice table
I get this:
>> T = table(val, out)
T =
val out
_________ ________
'M00.300' 13622.37
'M00.600' 31736.39
'M00.900' 19754.72
The above uses the table class that is available from R2013b and onwards. If you don't have this, you can perhaps use a for loop and print out each cell and value separately:
for idx = 1 : numel(out)
fprintf('%s: %f\n', val{idx}, out(idx));
end
We get:
M00.300: 13622.370000
M00.600: 31736.390000
M00.900: 19754.720000

Array intersection issue (Matlab)

I am trying to carry out the intersection of two arrays in Matlab but I cannot find the way.
The arrays that I want to intersect are:
and
I have tried:[dur, itimes, inewtimes ] = intersect(array2,char(array1));
but no luck.
However, if I try to intersect array1 with array3 (see array3 below), [dur, itimes, inewtimes ] = intersect(array3,char(array1));the intersection is performed without any error.
Why I cannot intersect array1 with array2?, how could I do it?. Thank you.
Just for ease of reading, your formats for Arrays are different, and you want to make them the same. There are many options for you, like #Visser suggested, you could convert the date/time into a long int which allows faster computation, or you can keep them as strings, or even convert them into characters (like what you have done with char(Array2)).
This is my example:
A = {'00:00:00';'00:01:01'} %//Type is Cell String
Z = ['00:00:00';'00:01:01'] %//Type is Cell Char
Q = {{'00:00:00'};{'00:01:01'}} %//Type is a Cell of Cells
A = cellstr(A) %//Convert CellStr to CellStr is essentially doing nothing
Z = cellstr(Z) %//Convert CellChar to CellStr
Q = vertcat(Q{:,:}) %// Convert Cell of Cells to Cell of Strings
I = intersect (A,Z)
>>'00:00:00'
'00:01:01'
II = intersect (A,Q)
>>'00:00:00'
'00:01:01'
This keeps your dates in the format of Strings in case you want to export them back into a txt/csv file.
Your first array would look something like this:
array1 = linspace(0,1,86400); % creates 86400 seconds in 1 day
Your second array should be converted using datenum, then use cell2mat to make it a matrix. Lastly, use ismember to find the intersection:
InterSect = ismember(array2,array1);

Matlab Cell Array Data

I have a cell array it is 100x1, variable name is CellA. As you will see from the png file attached, the cell array contains various size matrices in each of the 100 different cells.
I want to extract that data. Actually, I am trying to find the number of unique elements in each cell and their frequency. Below is my code which gets dimensional errors:
for i=1:length(CellA)
if isempty(CellA{i})
continue;% do nothing
else
unqmz(i,:) = unique(CellA{i})';
countmz(i,:) = histc(CellA{i}, unqmz(i))';
end
Eventually, I want to plot count versus unique number for each different cell array where the total number of counts for that cell exceeds a pre-determined value. e.g.) 4
You can also do it this way:
unqmz = cellfun(#unique, CellA, 'uni', 0);
countmz = arrayfun(#(n) histc(CellA{n},unqmz{n}), 1:numel(CellA), 'uni', 0).';
See if this works out for you -
%// Get result data into unqmz and countmz
unqmz = cell(numel(CellA),1);
countmz = cell(numel(CellA),1);
for ii=1:numel(CellA)
if isempty(CellA{ii})
continue;% do nothing
else
unqmz(ii) = {unique(CellA{ii})'} %//'
countmz(ii) = {histc(CellA{ii}, cell2mat(unqmz(ii)))'} %//'
end
end
%// Count of number of unique numbers in each cell
count_uniqs = cellfun(#numel,unqmz);
%// Plot (assuming you want to plot everything in one figure window)
figure,
for k = 1:size(countmz,1)
if count_uniqs(k)>4
plot(cell2mat(unqmz(k)),cell2mat(countmz(k)),'x')
hold on
end
end

Resources