I have two editable numeric fields and a table in app designer; the user can enter the values in these editable fields and then push a button. Then, the values are added to a table. Also, I provide an option to attach an excel folder that should have two columns to reflect on the table.
Both of these work perfectly fine individually, but, if I added the values manually then attached an excel folder or vice versa, I get the following error: All tables in the bracketed expression must have the same variable names.
The function that handles the editable fields:
app.t = app.UITable.Data;
x = app.xvalueEditField.Value;
y = app.yvalueEditField.Value;
nr = table(x, y);
app.UITable.Data = [app.t; nr]; %% error happens here if I attach excel then add manually
app.t = app.UITable.Data;
The Function of the excel folder:
text = readtable([pathname filename], "Sheet",1, 'ReadVariableNames',false);
fl = cellfun(#isnumeric,table2cell(text(1,:)));
if (numel(fl(fl == false)) > 0)
flag = false;
else
flag = true;
end
if (flag)
A = [app.t; text]; %% error happens here if I add manually then attach
app.UITable.Data = A;
app.t = text;
end
Note: these are only the parts of the function, where I attempt to combine values
Can someone please help me?
Thank you
The error message is telling you that table only allows you to vertically concatenate tables when the 'VariableNames' properties match. This is documented here: https://www.mathworks.com/help/matlab/ref/vertcat.html#btxzag0-1 .
In your first code example, the table nr will have variable names x and y (derived from the names of the underlying variables you used to construct the table). You could fix that case by doing:
% force nr to have the same VariableNames as app.t:
nr = table(x, y, 'VariableNames', app.t.Properties.VariableNames);
and in the second case, you can force text to have the correct variable names like this:
text.Properties.VariableNames = app.t.Properties.VariableNames
Related
I have an excel file and I need to read it based on string values in the 4th column. I have written the following but it does not work properly:
[num,txt,raw] = xlsread('Coordinates','Centerville');
zn={};
ctr=0;
for i = 3:size(raw,1)
tf = strcmp(char(raw{i,4}),char(raw{i-1,4}));
if tf == 0
ctr = ctr+1;
end
zn{ctr}=raw{i,4};
end
data=zeros(1,10); % 10 corresponds to the number of columns I want to read (herein, columns 'J' to 'S')
ctr=0;
for j = 1:length(zn)
for i=3:size(raw,1)
tf=strcmp(char(raw{i,4}),char(zn{j}));
if tf==1
ctr=ctr+1;
data(ctr,:,j)=num(i-2,10:19);
end
end
end
It gives me a "15129x10x22 double" thing and when I try to open it I get the message "Cannot display summaries of variables with more than 524288 elements". It might be obvious but what I am trying to get as the output is 'N = length(zn)' number of matrices which represent the data for different strings in the 4th column (so I probably need a struct; I just don't know how to make it work). Any ideas on how I could fix this? Thanks!
Did not test it, but this should help you get going:
EDIT: corrected wrong indexing into raw vector. Also, depending on the format you might want to restrict also the rows of the raw matrix. From your question, I assume something like selector = raw(3:end,4); and data = raw(3:end,10:19); should be correct.
[~,~,raw] = xlsread('Coordinates','Centerville');
selector = raw(:,4);
data = raw(:,10:19);
[selector,~,grpidx] = unique(selector);
nGrp = numel(selector);
out = cell(nGrp,1);
for i=1:nGrp
idx = grpidx==i;
out{i} = cell2mat(data(idx,:));
end
out is the output variable. The key here is the variable grpidx that is an output of the unique function and allows you to trace back the unique values to their position in the original vector. Note that unique as I used it may change the order of the string values. If that is an issue for you, use the setOrderparameter of the unique function and set it to 'stable'
I have a long list of variables in my workspace.
First, I'm finding the potential variables I could be interested in using the who function. Next, I'd like to loop through this list to find the size of each variable, however who outputs only the name of the variables as a string.
How could I use this list to refer to the values of the variables, rather than just the name?
Thank you,
list = who('*time*')
list =
'time'
'time_1'
'time_2'
for i = 1:size(list,1);
len(i,1) = length(list(i))
end
len =
1
1
1
If you want details about the variables, you can use whos instead which will return a struct that contains (among other things) the dimensions (size) and storage size (bytes).
As far as getting the value, you could use eval but this is not recommended and you should instead consider using cell arrays or structs with dynamic field names rather than dynamic variable names.
S = whos('*time*');
for k = 1:numel(S)
disp(S(k).name)
disp(S(k).bytes)
disp(S(k).size)
% The number of elements
len(k) = prod(S(k).size);
% You CAN get the value this way (not recommended)
value = eval(S(k).name);
end
#Suever nicely explained the straightforward way to get this information. As I noted in a comment, I suggest that you take a step back, and don't generate those dynamically named variables to begin with.
You can access structs dynamically, without having to resort to the slow and unsafe eval:
timestruc.field = time;
timestruc.('field1') = time_1;
fname = 'field2';
timestruc.(fname) = time_2;
The above three assignments are all valid for a struct, and so you can address the fields of a single data struct by generating the field strings dynamically. The only constraint is that field names have to be valid variable names, so the first character of the field has to be a letter.
But here's a quick way out of the trap you got yourself into: save your workspace (well, the relevant part) in a .mat file, and read it back in. You can do this in a way that will give you a struct with fields that are exactly your variable names:
time = 1;
time_1 = 2;
time_2 = rand(4);
save('tmp.mat','time*'); % or just save('tmp.mat')
S = load('tmp.mat');
afterwards S will be a struct, each field will correspond to a variable you saved into 'tmp.mat':
>> S
S =
time: 1
time_1: 2
time_2: [4x4 double]
An example writing variables from workspace to csv files:
clear;
% Writing variables of myfile.mat to csv files
load('myfile.mat');
allvars = who;
for i=1:length(allvars)
varname = strjoin(allvars(i));
evalstr = strcat('csvwrite(', char(39), varname, '.csv', char(39), ', ', varname, ')');
eval(evalstr);
end
I have a large amount of .csv files from my experiments (200+) and previously I have been reading them in seperately and also for later steps in my data handling this is tedious work.
co_15 = csvread('CO_15K.csv',5,0);
co_25 = csvread('CO_25K.csv',5,0);
co2_15 = csvread('CO2_15K.csv',5,0);
co2_80 = csvread('CO2_80K.csv',5,0);
h2o_15 = csvread('H2O_15K.csv',1,0);
etc.....
So I want to make a cell at the beginning of my code looking like this and then a for loop that just reads them automatically.
input = {'co_15' 5;'co_25' 5;...
'co2_15' 5; 'co2_80' 5;...
'h2o_15' 1; 'h2o_140' 1;...
'methanol_15' 5;'methanol_120' 5;'methanol_140' 5;...
'ethanol_15' 5;'ethanol_80' 1;'ethanol_140' 5;...
'co2_ethanol_15' 5 ;'co2_ethanol_80' 5;...
'h2o_ethanol_15' 1 ;'h2o_ethanol_140' 1;...
'methanol_ethanol_15' 5;'methanol_ethanol_120' 5;'methanol_ethanol_140' 5};
for n = 1:size(input,1)
input{n,1} = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
end
The cell in this code is 19 rows and 2 columns, the rows are all the files and the columns will contain the parameters to handle the data. Now the problem I can't find a solution for is that my first column is a string name and I want that string name to be the name of the variable where csvread writes its data to but the way I set it up now it just overwrites the string in the first column of the cell with the csv data. To be extra clear I want my matlab workspace to have variables with string names in the first column containing the data of my csv files. How do I solve this?
You don't actually want to do this. Even the Mathworks will tell you not to do this. If you are trying to use variable names to keep track of related data like this, there is always a better data structure to hold your data.
One way would be to have a cell array
data = cell(size(input(:,1)));
for n = 1:size(input,1)
data{n} = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
end
Another good option is to use a struct. You could have a single struct with dynamic field names that correspond to your data.
data = struct();
for n = 1:size(input,1)
data.(input{n,1}) = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
end
Or actually create an array of structs and hold both the name and the data within the struct.
for n = 1:size(input, 1)
data(n).name = input{n,1};
data(n).data = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
end
If you absolutly insist on doing this (again, it's is very much not recommended), then you could do it using eval:
for n = 1:size(input, 1)
data = csvread(strcat(input{n,1},'k.csv'),input{n,2},0);
eval([input{n, 1}, '= data;']);
end
I'm trying to load all the images' names that exist in a particular folder that i selected using matlab GUI into a listbox.
the problem is that when i select the folder:
if it's empty, I can see the list empty with a white background color (which is the right thing).
But when i select a folder that contains images, the listbox disappears from the GUI. and i get a warning saying:
Warning: single-selection listbox control requires a scalar Value
Control will not be rendered until all of its parameter values are valid
i'm stuck in this issue for a long time, and i couldn't find a way to solve it.
here's the code i tried:
% --- Load up the listbox with tif files in folder handles.handles.ImageFolder
function handles=LoadImageList(handles)
ListOfImageNames = {};
folder = handles.ImageFolder;
if ~isempty(handles.ImageFolder)
if exist(folder,'dir') == false
warningMessage = sprintf('Note: the folder used when this program was last run:\n%s\ndoes not exist on this computer.\nPlease run Step 1 to select an image folder.', handles.ImageFolder);
msgboxw(warningMessage);
return;
end
else
msgboxw('No folder specified as input for function LoadImageList.');
return;
end
% If it gets to here, the folder is good.
ImageFiles = dir([handles.ImageFolder '/*.*']);
for Index = 1:length(ImageFiles)
baseFileName = ImageFiles(Index).name;
[folder, name, extension] = fileparts(baseFileName);
extension = upper(extension);
switch lower(extension)
case {'.png', '.bmp', '.jpg', '.tif', '.avi'}
% Allow only PNG, TIF, JPG, or BMP images
ListOfImageNames = [ListOfImageNames baseFileName];
otherwise
end
end
set(handles.lstImageList,'string',ListOfImageNames);
return
This happen to a Matlab uicontrol when some of it's parameters are set to an invalid value. Matlab choose to not display them.
In your case, the error message tells you the Value parameter is incorrect.
Your listbox is defined as a "single-selection", which means you can only have one line selected at a time. The Value parameter represent the line number which is selected. This parameter has to be a "scalar", a single number, not a vector which would represent several line selected (possible with "multi-selection" listboxes).
Note that Matlab doesn't support an empty Value either, so if your Value was set to [], it will also error when you populate the lisbox. (at least not on my R2009a version)
The simple way to overcome that, is to set the Value at the same time you populate the listbox:
set(handles.lstImageList,'string',ListOfImageNames,'Value',1);
The problem is with the way you create ListOfImageNames. The result of your code is a long string containing all the image names without any space or delimiter.
The String property of MATLAB's listbox expect a cell array with the strip of each line. You can try this:
ListOfImageNames =[];
NumOfImages = 0;
ImageFiles = dir([handles.ImageFolder '/*.*']);
for Index = 1:length(ImageFiles)
baseFileName = ImageFiles(Index).name;
[folder, name, extension] = fileparts(baseFileName);
extension = upper(extension);
switch lower(extension)
case {'.png', '.bmp', '.jpg', '.tif', '.avi'}
% Allow only PNG, TIF, JPG, or BMP images
NumOfImages = NumOfImages + 1;
ListOfImageNames{NumOfImages} = baseFileName;
otherwise
end
end
set(handles.lstImageList,'string',ListOfImageNames);
I am trying to cycle through a list of variables I have say 30+ and calculate the maximum and minimum value for each column in each variable. Save this in a new array and then export to excel.
My thoughts were to use the who function to create an array with the name of all variables which are present. Then cycling through each one using a for loop after working out the size of the array which was created. This works fine, however when I try and use the string to reference the array it does not work.
I will add in the code which I have written hopefully someone will be able to come up with an easy solution :).
variable_list = who
cell2 = input('What cell size do you want to look at? ');
STARTcell = input('What was the start cell size? ');
[num_variables, temp] = size(variable_list);
for va = 1:num_variables
variable = variable_list{va}
[max_value, max_index] = max(variable{cell2/STARTcell})
[min_value, min_index] = min(variable{cell2/STARTcell})
format_values{va} = vertcat(max_values, max_index, min_value, min_index);
end
The variables I am looking at are arrays which is why I use the cell2/STARTcell to reference them.
You need to use the eval() function to be able to get the value of a variable corresponding to a string. For example:
a = 1;
b = 2;
variable_list = who;
c = eval(variable_list{2});
results in c being 2. In your code, the following line needs to change from:
variable = variable_list{va}
to:
variable = eval(variable_list{va});
resulting in variable having the value of the variable indicated by the string variable_list{va}. If variable is of cell type, then you should be fine, otherwise you may have to revise the next two lines of code as well because it seems that you are trying to access the content of a cell.