How can I display and access structure array contents in MATLAB? - arrays

Firstly, I have the user input their own text files consisting of states, capitals, and populations and I put all of these values into a structure array using the following code:
clear
clc
%Part A
textfile=input('What is the name of your text file?\n','s');
fid=fopen(textfile);
file=textscan(fid,'%s %s %f','delimiter',',');
State=file{1}
Capital=file{2}
Population=file{3}
regions=struct('State',State,...
'Capital',Capital,...
'Population',Population)
fclose(fid);
My first question: is it possible to display all of the values in the structure? Displaying the structure array just gives me this:
50x1 struct array with fields:
State
Capital
Population
And my second question: is it possible for me to access information in this structure by trying to find, for example, 'California' only?

As you've already discovered, the default display of structure arrays in MATLAB doesn't tell you much, just the array dimensions and field names. If you want to see the contents, you'll have to create formatted output yourself. One way you can do this is to use STRUCT2CELL to collect the structure contents in a cell array, then use FPRINTF to display the cell contents in a particular format. Here's an example:
>> regions = struct('State',{'New York'; 'Ohio'; 'North Carolina'},...
'Capital',{'Albany'; 'Columbus'; 'Raleigh'},...
'Population',{97856; 787033; 403892}); %# Sample structure
>> cellData = struct2cell(regions); %# A 3-by-3 cell array
>> fprintf('%15s (%s): %d\n',cellData{:}); %# Print the data
New York (Albany): 97856
Ohio (Columbus): 787033
North Carolina (Raleigh): 403892
With regard to your second question, you can collect the entries from the 'State' fields in a cell array, compare them to a given name with STRCMP to get a logical index, then get the corresponding structure array element:
>> stateNames = {regions.State}; %# A 1-by-3 cell array of names
>> stateIndex = strcmp(stateNames,'Ohio'); %# Find the index for `Ohio`
>> stateData = regions(stateIndex) %# Get the array element for `Ohio`
stateData =
State: 'Ohio'
Capital: 'Columbus'
Population: 787033
NOTE:
As you mention in a comment, each 'Population' entry in your structure array ends up containing the entire 50-by-1 vector of population data. This is likely due to the fact that file{3} in your sample code contains a vector, while file{1} and file{2} contain cell arrays. In order to properly distribute the contents of the vector in file{3} across the elements of the structure array, you need to break the vector up and place each value in a separate cell of a cell array using NUM2CELL before passing it to STRUCT. Defining Population like this should solve the problem:
Population = num2cell(file{3});

Related

How do you split an array in matlab into bins of different sizes within the same data structure?

Suppose I have the following array defined in MATLAB:
x = 1:100;
I would like to form a single data structure "bin" as shown below:
bin(:,1) = x(1:33); % copy 33 elements into 1st bin
bin(:,2) = x(34:66); % copy another 33 elements into 2nd bin
bin(:,3) = x(67:100);% copy remaining 34 elements into 3rd bin
However, matlab will not allow for the last 34 elements to be added to bin(:,3) since the previous two are of size 33. I would prefer not to use a different variable just to store the last 34 elements. Is there a way in MATLAB to get around this (i.e. how do I use the same data structure "bin" to store all 100 elements in 3 columns of different sizes?)
For problems like this, there exist cells. They work like pointers in other languages: one distinguishes between its address and its content. So you can look over the address (which is next to each other) while accessing its content (which may be of different size or type)
bin = cell(1,3); % allocating the cell. not necessary but good practice
bin{1} = x(1:33); % copy 33 elements into 1st bin
bin{2} = x(34:66); % copy another 33 elements into 2nd bin
bin{3} = x(67:100);% copy remaining 34 elements into 3rd bin
indexing with curly brackets { } will give you the content of the cell, while ( ) gives you the element of the cell (which is obviously a cell). It works like slicing of other variable types.
Note that you fit complete arrays into a single element of a cell bin{1} or bin{1,1} returns a 1x33 numeric array.
A cell array is a structure which can hold any object, for example arrays of different length. mat2cell allows you to split your array into a cell of several arrays.
bin=mat2cell(x,[33,33,34])

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}.

cell array of strings to matlab structure

I need to create a matlab structure as such ds=struct('name',{{'my_name_is'},{'matlab_thining_hair'}}) which stores as a 1x2 struct array with fields: name. A call to ds.name generates the output:
ds.name
ans =
'my_name_is'
ans =
'matlab_thining_hair'
Please note the single quotes in the output. They are important. That said, I need to create the above mentioned structure using the following variable:
X = [1x46 char] [1x47 char] i.e., 1x2 cell, which I believe is actually a cell array of strings. Among other things, I've tried the following:
Y = cell2struct(X, 'name', 1)'
which results in a 1x2 structure array with fields name, however a call to Y generates the output:
Y.name
ans = my_name_is
ans = matlab_thining_hair
Note that the single quotes in the output are missing, and albeit both Y and ds are 1x2 struct arrays with fields name, the field values are not formatted the same and the structures also vary in their bytes size. How to format the field values as character arrays?
In your first case you have created a struct with two fields whose values are cell arrays. The cell arrays are displayed with quotes.
In your second case your struct fields have char arrays which is what you want. Char arrays display without quotes.
You can verify this by typing in your command prompt {'abc'} and then 'abc'.
In your first case you can create non-cell array field values by passing the strings outside cell parenthesis.
ds=struct('name',{'my_name_is','matlab_thining_hair'})
Stick your char strings in another layer of cells before calling cell2struct. Instead of:
X = { 'foo', 'bar' }
Try:
X = { {'foo'}, {'bar'} }
That is, a 1-by-2 cell whose cell contents are themselves cells, not chars. Then cell2struct(X, 'name', 1) should give you a struct array with fields of cell arrays.
If your existing X is a cellstr, I think you can just call num2cell on it to push each cell down into another layer of cell indirection.

MATLAB: Determine total length/size of a structure array with fields as structure arrays

I have a structure array containing fields as structure arrays of varying length. For example:
's' is a structure
'data' is a field in 's', and also a structure array itself
and
length(s(n).data) ~= length(s(m).data)
I want to preallocate an array that takes a time stamp from every field s.data.timestamp.
Is there a way to do this without using a for loop twice? This is what I have so far:
% find the total length
count=0;
for x=1:length(s)
count=count+length(s(x).data);
end
% preallocate timestamp array
timestamp=zeros(1,count);
% populate timestamp array
index=1;
for x=1:length(s)
for y=1:length(s(x).data)
timestamp(index)=s(x).data(y).timestamp;
index=index+1;
end
end
I thought about just overestimating the length that I would need based on the length of 's' and an average length of 'data', but the actual length of each 'data' field/substructure varies widely. Would I be better off just overestimating the heck out of it and trimming the resulting array afterward? Zero timestamps are impossible with the data set I'm working with, so that shouldn't be a problem.
This will work if every structure array data has the same fields and are row vectors (i.e. 1-by-N):
allData = [s.data]; %# Concatenate all data arrays into one
timestamp = [allData.timestamp]; %# Collect all the time stamps
If the data structure arrays are column vectors (i.e. N-by-1), you need to use vertcat instead:
allData = vertcat(s.data); %# Concatenate all data arrays into one
timestamp = [allData.timestamp]; %# Collect all the time stamps
The above solutions work due to the fact that accessing a single field of a structure array returns a comma-separated list.

How to sort structure arrays in MATLAB?

I'm working with an image retrieval system using color histogram intersection in MATLAB. This method gives me the following data: a real number which represents the histogram intersection distance, and the image file name. Because they are different data types, I store them in structure array with two fields, and then I save this structure in a .mat file. Now I need to sort this structure according to the histogram intersection distance in descending order in order to retrieve the image with the highest histogram intersection distance. I've tried many methods to sort this data but without result. Please can you help me solve this problem?
It's also possible to sort the entire structure.
To build off of gnovice's example...
% Create a structure array
s = struct('value',{1 7 4},'file',{'img1.jpg' 'img2.jpg' 'img3.jpg'});
% Sort the structure according to values in descending order
% We are only interested in the second output from the sort command
[blah, order] = sort([s(:).value],'descend');
% Save the sorted output
sortedStruct = s(order);
Here's one example of how you could do this, using the function MAX instead of having to sort:
%# First, create a sample structure array:
s = struct('value',{1 7 4},'file',{'img1.jpg' 'img2.jpg' 'img3.jpg'});
%# Next concatenate the "value" fields and find the index of the maximum value:
[maxValue,index] = max([s.value]);
%# Finally, get the file corresponding to the maximum value:
maxFile = s(index).file;
EDIT : If you would like to get the N highest values, and not just the maximum, you can use SORT instead of MAX (as Shaka suggested). For example (using the above structure):
>> N = 2; %# Get two highest values
>> [values,index] = sort([s.value],'descend'); %# Sort all values, largest first
>> topNFiles = {s(index(1:N)).file} %# Get N files with the largest values
topNFiles =
'img2.jpg' 'img3.jpg'

Resources