You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How to split into different tables a multi-level cell?
4 views (last 30 days)
Show older comments
My final goal is to have a 428x11 table from an image analysis that I ran which final outcome is 'data'. Object 'data' is a 428x1 cell, and that one column is a 1x11 cell that looks like ['name', v1, v2, v3, v4, v5, 6, v7, v8, V9, v10], and again, 428 times.
I have tried using data_table=regexp(data(:), '\s+', 'split'); but get an error using regexp 'All cells must be char row vectors.', and tried with 'cellstr' but didn't work. I have also tried with loops -although I am not proficient with iterations- but I can't index with multi-level cells, and something like data2=data{2:end,1}{1,1}; or data2=data{:,1}{:,1}; hasn't worked. I have seen similar questions in but MATLAB Answers haven't worked for me so far.
I really appreciate any help!
Accepted Answer
per isakson
on 2 Dec 2017
Edited: per isakson
on 2 Dec 2017
"final goal is to have a 428x11 table"
Study this
data = {
{'name1',1,2,3,4,5,6,7,8,9,0}
{'name2',1,2,3,4,5,6,7,8,9,0}
{'name3',1,2,3,4,5,6,7,8,9,0}
};
cac = cat( 1, data{:} );
mytable = cell2table( cac )
it displays in the command window
mytable =
cac1 cac2 cac3 cac4 cac5 cac6 cac7 cac8 cac9 cac10 cac11
_______ ____ ____ ____ ____ ____ ____ ____ ____ _____ _____
'name1' 1 2 3 4 5 6 7 8 9 0
'name2' 1 2 3 4 5 6 7 8 9 0
'name3' 1 2 3 4 5 6 7 8 9 0
12 Comments
JoanManBar
on 2 Dec 2017
Thank you so much for your answer. It actually worked with YOUR sample matrix but not with my data. However it's getting close since it creates a 242x11 table. So I wonder what I am doing wrong. I am sharing my cell in case you want to take a closer look. Thank you once again!
per isakson
on 3 Dec 2017
Edited: per isakson
on 3 Dec 2017
- "it creates a 242x11 table" thus the two lines of code do what they are supposed to do
- "what I am doing wrong" I cannot see any requirement besides "242x11 table" and that is fulfilled. What do you further require? What do you want to achieve? You don't say.
>> load('matlab.mat')
>> cac = cat( 1, data{:} );
mytable = cell2table( cac )
mytable =
cac1 cac2 cac3 cac4 cac5 cac6 cac7 cac8 cac9 cac10 cac11
_______________ ____ ______ ______ ______ ____ ______ ______ ______ ______ ______
'sample006.tif' 71 172.31 138.36 112.3 2570 130.46 25.35 172.31 138.36 112.3
'sample026.tif' 116 168.1 134.01 106.86 952 68.517 17.91 168.1 134.01 106.86
'sample223.tif' 96 163.64 137.07 115.81 1293 83.787 20.473 163.64 137.07 115.81
'sample231.tif' 107 178.36 150.75 127.69 2283 115.56 25.323 178.36 150.75 127.69
'sample006.tif' 71 172.31 138.36 112.3 2570 130.46 25.35 172.31 138.36 112.3
'sample223.tif' 96 163.64 137.07 115.81 1293 83.787 20.473 163.64 137.07 115.81
'sample006.tif' 71 172.31 138.36 112.3 2570 130.46 25.35 172.31 138.36 112.3
'sample231.tif' 107 178.36 150.75 127.69 2283 115.56 25.323 178.36 150.75 127.69
'sample223.tif' 96 163.64 137.07 115.81 1293 83.787 20.473 163.64 137.07 115.81
'sample026.tif' 116 168.1 134.01 106.86 952 68.517 17.91 168.1 134.01 106.86
...
Speculations: The cell array data isn't what you think it is. There are only four unique row headers, i.e. file names in data
>> col1 = cac(:,1);
>> length(col1)
ans =
242
>> [ col1_unique, ixa, ixc ] = unique( col1 );
>> col1_unique
col1_unique =
'sample006.tif'
'sample026.tif'
'sample223.tif'
'sample231.tif'
>>
Actually, there are only four unique rows
>> [ cac_unique_rows, ixa, ixc ] = unique_rows( cac, [1:size(cac,2)] );
>> cac_unique_rows
cac_unique_rows =
'sample006.tif' [ 71] [172.3078] [138.3623] [112.3047] [2570] [130.4569] [25.3503] [172.3078] [138.3623] [112.3047]
'sample026.tif' [116] [168.1040] [134.0053] [106.8592] [ 952] [ 68.5168] [17.9097] [168.1040] [134.0053] [106.8592]
'sample223.tif' [ 96] [163.6419] [137.0719] [115.8105] [1293] [ 83.7872] [20.4729] [163.6419] [137.0719] [115.8105]
'sample231.tif' [107] [178.3574] [150.7464] [127.6881] [2283] [115.5610] [25.3232] [178.3574] [150.7464] [127.6881]
JoanManBar
on 3 Dec 2017
Edited: per isakson
on 5 Dec 2017
More than just an answer, this was a meaningful lesson! You are right, my data cell was completely wrong, and although I still don't accomplish my objective (sheet with RGB and size of my seeds), you answered wisely the question I asked. I am still struggling really bad to learn the basics of Matlab.
I know I have already asked a lot, but if you would still like to help me, all that I want is my files' names in each corresponding row, i.e. 'sample..' instead of numbers from 1 to number of files -I know that's a different question.
I am attaching my code and files anyways.
.
.
Two copies removed
.
close all; clear all; clc;
imagefiles = dir('*.tif');
filenames = {imagefiles.name};
nfiles = length(imagefiles);
for i=1:nfiles
currentfilename = imagefiles(i).name;
currentimage = imread(currentfilename);
images = currentimage;
images = imcrop(images, [0 0 1557 1844]);
Red_ch = images(:,:,1);
Green_ch = images(:,:,2);
Blue_ch = images(:,:,3);
binary = Red_ch > 90;
binary = bwareafilt(binary, [100, inf]);
se = strel('disk',7,0);
binary = imerode(binary, se);
[labeledI, numSeeds] = bwlabel(binary);
props = regionprops(labeledI, 'Area', 'MajorAxisLength',
'MinorAxisLength');
for k = 1:numSeeds
Areas(k) = props(k).Area;
Length(k) = props(k).MajorAxisLength;
Width(k) = props(k).MinorAxisLength;
end
propsR = regionprops(labeledI, Red_ch, 'MeanIntensity',
'PixelValues');
propsG = regionprops(labeledI, Green_ch, 'MeanIntensity',
'PixelValues');
propsB = regionprops(labeledI, Blue_ch, 'MeanIntensity',
'PixelValues');
MeansR = [propsR.MeanIntensity];
MeansG = [propsG.MeanIntensity];
MeansB = [propsB.MeanIntensity];
for j = 1:numSeeds
PixMeansR(j) = mean(propsR(j).PixelValues);
PixMeansR = PixMeansR';
PixMeansG(j) = mean(propsG(j).PixelValues);
PixMeansG = PixMeansG';
PixMeansB(j) = mean(propsB(j).PixelValues);
PixMeansB = PixMeansB';
end
if exist('data','var')~=1
data = [repmat(i,1,numSeeds)', (1:numSeeds)', MeansR', MeansG',
MeansB', Areas', Length', Width', filenames];
else
data = vertcat(data,[repmat(i,1,numSeeds)', (1:numSeeds)',
MeansR', MeansG', MeansB', Areas', Length', Width']);
end
end
THANK YOU SO MUCH!
per isakson
on 4 Dec 2017
Edited: per isakson
on 4 Dec 2017
I assume your question is about
if exist('data','var')~=1
data = [repmat(i,1,numSeeds)', (1:numSeeds)', MeansR', MeansG', ...
MeansB', Areas', Length', Width', filenames];
else
data = vertcat(data,[repmat(i,1,numSeeds)', (1:numSeeds)', ...
MeansR', MeansG', MeansB', Areas', Length', Width']);
end
In the second iteration of the loop, when the else-clause is executed for the first time, I get the error
Error using vertcat
Dimensions of matrices being concatenated are not consistent.
Error in cssm (line 57)
data = vertcat(data,[repmat(i,1,numSeeds)', (1:numSeeds)', ...
which shouldn't surprise.
Comments on this if-else-end construct
- it attempts to create a cell array, data, which differs from data that you uploaded in the mat-file. E.g. MeanR ... in the uploaded data are scalars, here they are vectors with one element per seed.
- In the uploaded data the format of the first row didn't differ from the rest. It might be a good idea to show column headers in the first row, e.g. ...,'MeansR','MeansG','MeansB','Areas','Length','Width',...
- this construct is inefficient and hard to read. The numbers of files is known, thus pre-allocating the cell array, data = cell( nfiles, 12 );, and use assignments to fill it with data.
I'm lost. Show with an example what data shall look like.
JoanManBar
on 4 Dec 2017
I am so sorry, I feel like I'm wasting your time and that's because I haven't been clear at all. The previous code was a little different that the second one since I realized -thank to you- that the array was not what I thought it was. Additionally, the second I uploaded was had mistakes as well. I honestly don't know what to do!
Dear Per Isakson, I want to have a spread sheet that shows these columns and their corresponding values:
Image_Name, Seed, Mean_Red, Mean_Green, Mean_Blue, Area, Length, Width
Where:
Image_Name: Name of each photo
Seed: Number of seeds per photo
Mean_Red: Mean red value of each seed
Mean_Green: Mean green value of each seed
Mean_Blue: Mean blue value of each seed
Area: Area of each seed
Length: Length of each seed
Width: Width of each seed
I'd like to have other variables, but that would be more than enough. How can I do that?
Thank you once again, I really appreciate all the time and help you have provided.
per isakson
on 4 Dec 2017
Edited: per isakson
on 4 Dec 2017
There is a serious problem with this loop and a couple of minor.
for k = 1:numSeeds
Areas(k) = props(k).Area;
Length(k) = props(k).MajorAxisLength;
Width(k) = props(k).MinorAxisLength;
end
- When the outer loop encounters a picture with fewer seeds than the previous the values at the end of Areas etc. will not be overwritten. The length of Areas etc. will increase down the table. Pictures with few seeds will give entries in the table with data on seeds of previous pictures.
- pre-allocation of memory is a good habit.
- The generic names, e.g. Length, make me nervous. There is a risk, they are in conflict with names used by Matlab.
per isakson
on 4 Dec 2017
Edited: per isakson
on 4 Dec 2017
First I downloaded the picture and made an extra copy of sample006.tif, which I called sample.306.tif. (I was surprised that three pictures contained exactly 112 seeds. Ok, it's copies of the same picture.)
Then I modified your code.
Now the question is whether the result is what you expected.
>> data = cssm()
data =
'Image_Name' 'Seed' 'Mean_Red' 'Mean_Green' 'Mean_Blue' 'Area' 'Length' 'Width'
'sample006.tif' [ 69] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double]
'sample026.tif' [ 112] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double]
'sample223.tif' [ 112] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double]
'sample231.tif' [ 112] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double]
'sample306.tif' [ 69] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double]
where
function data = cssm()
%#ok<*AGROW>
%#ok<*NASGU>
%#ok<*ASGLU>
imagefiles = dir('sample*.tif');
filenames = {imagefiles.name};
nfiles = length(imagefiles);
%
data = cell( nfiles+1, 8 );
data(1,:) = { 'Image_Name','Seed','Mean_Red','Mean_Green' ...
, 'Mean_Blue' ,'Area','Length' ,'Width' };
%
for i=1:nfiles
currentimage = imread( imagefiles(i).name );
%
Red_ch = currentimage(:,:,1);
Green_ch = currentimage(:,:,2);
Blue_ch = currentimage(:,:,3);
%
binary = Red_ch > 90;
binary = bwareafilt(binary, [100, inf]);
se = strel('disk',7,0);
binary = imerode(binary, se);
%
[labeledI, numSeeds] = bwlabel(binary);
%
props = regionprops(labeledI,'Area','MajorAxisLength','MinorAxisLength');
%
Areas = reshape([props.Area] , [], 1 );
Length = reshape([props.MajorAxisLength], [], 1 );
Width = reshape([props.MinorAxisLength], [], 1 );
%
propsR = regionprops(labeledI, Red_ch, 'MeanIntensity', 'PixelValues');
propsG = regionprops(labeledI, Green_ch, 'MeanIntensity', 'PixelValues');
propsB = regionprops(labeledI, Blue_ch, 'MeanIntensity', 'PixelValues');
%
MeansR = reshape([propsR.MeanIntensity], [], 1 );
MeansG = reshape([propsG.MeanIntensity], [], 1 );
MeansB = reshape([propsB.MeanIntensity], [], 1 );
%
data(i+1,:) = { imagefiles(i).name, numSeeds ...
, MeansR, MeansG, MeansB ...
, Length, Areas, Width };
end
end
Comments:
- I have problems with the blip as a shortcut for transpose. I prefer reshape, because the name is good and reshape outputs the desired shape regardless of whether the input is row or column.
- I removed some help-variables, which I didn't think added any value.
- I vectorized the loops over numSeeds.
- I removed the crop-command to simplify testing.
per isakson
on 4 Dec 2017
And finally
>> mytable = cell2table( data(2:end,:), 'VariableNames', data(1,:) )
mytable =
Image_Name Seed Mean_Red Mean_Green Mean_Blue Area Length Width
_______________ ____ ______________ ______________ ______________ ______________ ______________ ______________
'sample006.tif' 69 [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double]
'sample026.tif' 112 [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double]
'sample223.tif' 112 [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double]
'sample231.tif' 112 [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double] [112x1 double]
'sample306.tif' 69 [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double] [ 69x1 double]
JoanManBar
on 4 Dec 2017
Today is one of the best days of my life thanks to you! I can't believe it finally works! And I can't tell with words how grateful I feel with you!
I realized that I uploaded the wrong images and that's why three of them have the same results. I apologize!
Would you mind doing one last thing for me? Could you please tell me how the first column (Image_Name) can have the sample name repeated in rows as many times as there is seeds?
If there is anything I can do for you, please let me know!
THANKS A LOT!
per isakson
on 5 Dec 2017
Here is a function, which takes the cell array data from above and returns the table you want (I think). In this table there is one row per seed. There are no row names.
I find it most rewarding to learn that I really helped you.
My functions lack both comments and error checking. I encourage you to try to understand the code and add some.
>> out_tbl = cssm2( data )
out_tbl =
Image_Name Seed Mean_Red Mean_Green Mean_Blue Area Length Width
_______________ ____ ________ __________ _________ ______ ______ ______
'sample006.tif' 1 171.83 137.49 111.47 122.38 2117 22.299
'sample006.tif' 2 170.82 134.89 109.36 117.08 1800 20.107
'sample006.tif' 3 178.06 145.43 115.19 129.65 5976 82.874
'sample006.tif' 4 153.78 118.21 89.604 128.57 3121 31.13
'sample006.tif' 5 171.72 141.22 116.84 124.48 1920 20.122
...
...
>> whos out_tbl data
Name Size Bytes Class Attributes
data 6x8 28410 cell
out_tbl 474x8 95114 table
where
function out_tbl = cssm2( data )
%
colhead = data( 1, : );
out_tbl = one_batch_of_seeds_to_table( data(2,:), colhead );
%
for jj = 3 : size( data, 1 )
tbl = one_batch_of_seeds_to_table( data(jj,:), colhead );
out_tbl = vertcat( out_tbl, tbl ); %#ok<AGROW>
end
end
and where
function tbl = one_batch_of_seeds_to_table( body, colhead )
%
len = length( body{3} );
pic = repmat( body(1), len, 1 );
sno = reshape( (1:len), [], 1 );
tbl = table( pic, sno, body{3:end}, 'VariableNames', colhead );
end
JoanManBar
on 6 Dec 2017
Once again, thank you very much! I'm having some trouble with that last part since 'body' is not defined but I think it's time for me to stop bothering you and do the work myself.
I have learned more from your answers than from my experience reading the MATLAB documentation and I really appreciate that.
More Answers (0)
See Also
Categories
Find more on Matrix Indexing in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom(English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)