MATLAB: Cannot parse multiple floating-point values - matlab

I have a GUI with a UITable (built in GUIDE). I read in two numerical values and through a series of steps convert the floating-point value to a string. I want the user to have the ability to click on a specific cell in the UITable containing the two values (now as strings), and read those values back as floating-point values. For whatever reason, I can only ever get my code to read in the first floating-point value. My code (in order) is below.
Step 1: Access data and convert to string and place string in corresponding column.
function fillAnnotRangeInfo(obj, selectedAxes)
selectedAxesTag = selectedAxes.Tag;
rawAxesTag = obj.rawDataDisplayAxes.Tag;
psdAxesTag = obj.psdDataDisplayAxes.Tag;
% Depending on which axes the user clicks on, the units will either be Hz or s
if strcmp(selectedAxesTag, rawAxesTag)
dataRange = strcat(num2str(obj.t1), {'s'}, {' - '}, num2str(obj.t2), {'s'});
elseif strcmp(selectedAxesTag, psdAxesTag)
dataRange = strcat(num2str(obj.t1), {'Hz'}, {' - '}, num2str(obj.t2), {'Hz'});
end
obj.nextRow.AnnotRange = dataRange;
end
Step 2: Determine if user clicked in correct cell and attempt to read two floating-point values out.
% --- Executes when selected cell(s) is changed in existingAnnotationsTable.
function existingAnnotationsTable_CellSelectionCallback(hObject, eventdata, handles)
% hObject handle to existingAnnotationsTable (see GCBO)
% eventdata structure with the following fields (see MATLAB.UI.CONTROL.TABLE)
% Indices: row and column indices of the cell(s) currently selecteds
% handles structure with handles and user data (see GUIDATA)
% AE = handles.UserData;
Indices = eventdata.Indices;
% Determine if column is column of interest
if Indices(2) == 4
rangeData = handles.existingAnnotationsTable.Data;
rangeData = rangeData{Indices(1), Indices(2)};
annoRange = sscanf(rangeData, '%f')
else
end
return
Ultimately, the result I get is if I have a string exactly as follows: "7.4250Hz - 32.502Hz" (or replace Hz with "s"), my program will only produce "7.4250". Nothing more nothing less. I've tried textscan, sscanf, and strread. Each one I explicitly set my filter to floating-point (%f). With strread I tried setting it to cycle through more than once (strread('string', %f, 2)). I have no idea what else to do or try or change.
REGARDING THE ANSWERS BELOW FOR FUTURE READERS: Technically any one of the answers is "correct" (I tried them). They all are applicable to a slightly different situation. Ben's answer is good for getting a result in a single step if you have a fixed format. My own answer works to break down a string across multiple steps giving access to the data each step (useful for performing multiple operations) whilst still being able to deal with varying formats. Andras' answer is useful for getting it done in one step providing a result instantly whilst still being able to deal with varying formats.

Have a look at the sscanf documentation here, if you want a set of floats from a string you need to specify the format. Here is an example from this page similar to yours:
tempString = '78°F 72°F 64°F 66°F 49°F';
degrees = char(176);
tempNumeric = sscanf(tempString, ['%d' degrees 'F'])'
tempNumeric =
78 72 64 66 49
In your specific case you could try:
val = sscanf(rangedata,'%fHz - %fHz')

Ben's answer is the correct answer in the case of a fixed format. However, in my case, my format changes. Therefore my proposed solution (tested and verified) is to use strtokto "break-down" the string into two separate strings, making it much more manageable and easier to parse. Code below. Thoughts?
% --- Executes when selected cell(s) is changed in existingAnnotationsTable.
function existingAnnotationsTable_CellSelectionCallback(hObject, eventdata, handles)
% hObject handle to existingAnnotationsTable (see GCBO)
% eventdata structure with the following fields (see MATLAB.UI.CONTROL.TABLE)
% Indices: row and column indices of the cell(s) currently selecteds
% handles structure with handles and user data (see GUIDATA)
% AE = handles.UserData;
Indices = eventdata.Indices;
% Determine if column is column of interest
if Indices(2) == 4
rangeData = handles.existingAnnotationsTable.Data;
rangeData = rangeData{Indices(1), Indices(2)};
[dataStart, dataRemain] = strtok(rangeData);
% In this case, since there will be just a '-' as the token...
% ...we don't care about the token and only save the remainder.
[~, dataEnd] = strtok(dataRemain);
dataStart = sscanf(dataStart, '%f')
dataEnd = sscanf(dataEnd, '%f')
else
end

Motivated by my own comment about using regexp before sscanf, here's a solution which only uses the former:
str=regexp(data,'(?<dataStart>[\d\.]+)[^\d\.]+(?<dataEnd>[\d\.]+)','names');
after which str will have the fields dataStart and dataEnd as strings (so you'll need num2str afterwards). Note that this only works for simple floating point numbers (but of course the regexp could be further complicated ad nauseam if necessary). The upside is that it can be adapted to more tricky input strings, for instance the above will treat any number and kind of non-numeric (and non-dot) text between the first two numbers. The downside is regexp.

Related

How to pass the value of a table to a matrix

Im trying to do a GUI in matlab that accepts the values in a table to converting it to a matrix, but the idea is that a user can set the number of rows and columns first.
The panel looks like this
and the code for the push button is
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
rows =str2double(get(handles.edit_rows,'String'));
cols=str2double(get(handles.edit_cols,'String'));
num_elem=cell(rows,cols);
num_elem(:,:)={"};
set(handles.uitable1,'Data',num_elem)
set(handles.uitable1,'ColumnEditable',true(1,cols))
But then, how can export or convert to a matrix so I can apply functions to it?
UPDATE
With the help of byetisener I updated the code to
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject handle to pushbutton1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
filas=str2double(get(handles.edit_fila,'String'));
column=str2double(get(handles.edit_col,'String'));
num_elem=cell(filas,column);
num_elem(:,:)={''};
set(handles.uitable1,'Data',num_elem)
set(handles.uitable1,'ColumnEditable',true(1,column))
handles.uitable1.Data = cell(filas, column);
matrix = cell2mat(handles.uitable1.Data);
matrix
but this is giving an empty matrix
It is not taking the values of the cells, it is supposed that the button resizes and copy the values at the same time, if not how con copy in another button once the matrix is resized?
There are some problems about your code:
You do not really assign values here, you are just setting the Data of the uitable to an array of empty cells.
num_elem =
1×2 cell array
{0×0 char} {0×0 char}
If you ever succeed, you code will write everything you want to only the first column of the uitable. Because you are not iterating through rows. The pushbutton only adds to the first row.
cell2mat() function won't work if you have different data types in your table. You may think that you do not have different data types, but empty cells are type cell and the data you enter is type double, so there it is.
To solve all of this I have rewritten a callback function for you. You may directly paste this code to your callback, replacing yours. I should give you the matrix you want at the end, it does in my computer.
filas = str2double(handles.edit_fila.String);
column = str2double(handles.edit_col.String);
% This loop looks for an empty row to write new data
for i = 1:length(handles.uitable1.Data)
if isempty(handles.uitable1.Data{i,1})
handles.uitable1.Data(i,1) = {filas};
handles.uitable1.Data(i,2) = {column};
break;
else
disp('Error occured');
end
end
% This double for loop check if there are any empty cells
% if it finds one, it changes it to 0, so all the cells have the same type
for i = 1:length(handles.uitable1.Data)
for j = 1:2
if isempty(handles.uitable1.Data{i,j})
handles.uitable1.Data(i,j) = {0};
else
disp('Error occured');
end
end
end
matrix = cell2mat(handles.uitable1.Data); % The matrix you want
Just check if all the variable names are the same and do not forget to accept is as an answer. Hope it helps.
I am not sure if this answers you question but you can follow this approach.
First of all, if you are interested, using dot notation is faster in MATLAB than setter and getter methods.
So, what you can do is:
handles.uitable1.Data = cell(rows, cols);
or, of course, alternatively:
set(handles.uitable1, 'Data', cell(rows,cols));
If what you want to is to convert the data in uitable to a matrix, you can use:
matrix = cell2mat(handles.uitable1.Data);
If you table contains non-numeric values:
tableData = handles.uitable1.Data;
tableData = [str2double(tableData(:, 1)), cell2mat(tableData(:, 2))];
Hope this helps. Let me know if you solve your problem.

Error using legappend()

I am writing a function that iterates through a loop and adds entries to a plot. When I try to use legappend(), though, I get the error below. I am passing it a string variable.
Error using legend>process_inputs (line 526)
Invalid argument. Type 'help legend' for more information.
Error in legend>make_legend (line 303)
[orient,location,position,children,listen,strings,propargs] =
process_inputs(ha,argin); %#ok
Error in legend (line 257)
[~,msg] = make_legend(ha,args(arg:end),version);
Error in legappend (line 74)
[legend_h,object_h,plot_h,text_strings] = legend(h,allDatah,str);
Here is a minimal example, taken from the MATLAB site
% Some data and old models:
x = (1:10)';
y = [x-5+x.^1.05 x-2 x-3 x-4 x-5];
% Plot the data and old models:
figure
plot(x,y(:,1),'mo','markersize',10);
hold on;
plot(x,y(:,2),'r');
plot(x,y(:,3),'b');
plot(x,y(:,4),'k');
plot(x,y(:,5),'kp');
box off
axis([1 10 -5 20])
legend('data','model 1','model 2','model 3','model 4','location','northwest')
legend boxoff
myNewModel = x - 5.5 + x.^1.1;
plot(x,myNewModel,'m','linewidth',2);
legappend('my new amazing model!')
As mentioned in my comment, MATLAB's graphics engine was significantly overhauled in R2014b. While it brought a plethora of very welcome changes, like any major code overhaul it broke functionality in the existing code base. Relevant here is implementing legends as their own object class rather than as a cobbled together axes object. Given its July 2014 release date, legappend was likely created using R2014a and the logic in the code assumes that the legend is an axes object. This unfortunately breaks in the new graphics system.
Fortunately, the fix isn't as complex as I was anticipating. If you take a look at the properties of the new legend object, there's no documented property for the linked data. Attempting to set the 'String' property manually also has no effect. However, if you look at the final syntax in the function description ([l,icons,plots,txt] = legend(___)), it seems clear that legend has a way to access the appropriate internal properties. And indeed, if you poke around in the legend source, you'll find the 'PlotChildren' property, which is an array of object handles.
Putting it all together we get something like the following:
function legappend_HG2(newStrings)
% Quick & dirty fork of legappend specific to MATLAB versions >= R2014b
% Only supports appending strings to the existing legend handle
% Assumes only one legend is in the current figure
% Add multiple strings by passing it a 1D cell array of strings
% Find our legend object
h = findobj(gcf, 'Type', 'legend');
if ~isempty(h)
% Get existing array of legend strings and append our new strings to it
oldstr = h.String;
if ischar(newStrings)
% Input string is a character array, assume it's a single string and
% dump into a cell
newStrings = {newStrings};
end
newstr = [oldstr newStrings];
% Get line object handles
ploth = flipud(get(gca, 'Children'));
% Update legend with line object handles & new string array
h.PlotChildren = ploth;
h.String = newstr;
end
end
Swapping legappend for legappend_HG2 in the above MWE we get the desired result:
Was getting wrong result in R2016b for exkaza's solution. Hence changed the code in a line a little bit.
function legappend_HG2(newStrings)
% Quick & dirty fork of legappend specific to MATLAB versions >= R2016b
% Only supports appending strings to the existing legend handle
% Assumes only one legend is in the current figure
% Add multiple strings by passing it a 1D cell array of strings
% Find our legend object
h = findobj(gcf, 'Type', 'legend');
if ~isempty(h)
% Get existing array of legend strings and append our new strings to it
oldstr = h.String;
%disp(oldstr);
if ischar(newStrings)
% Input string is a character array, assume it's a single string and
% dump into a cell
newStrings = {newStrings};
end
newstr = [oldstr newStrings];
%disp(newstr);
% Get line object handles
ploth = flipud(get(gca, 'Children'));
% Update legend with line object handles & new string array
%h.PlotChildren = ploth;
h.PlotChildren = [h.PlotChildren; ploth];
h.String = newstr;
end
end

Performing find and replace functions on elements of a table in Matlab

I am working with a 400x1200 imported table (readtable generated from an .xls) which contains strings, doubles, dates, and NaNs. Each column is typed consistently. I am looking for a way to locate all instances in the table of any given string ('Help me please') and replace them all with a double (1). Doing this in Matlab will save me loads of work making changes to the approach used on the rest of this project.
Unfortunately, all of the options I've looked at (regexp, strrep, etc) can only take a string as a replacement. Strfind was similarly unhelpful, because of the typing across the table. The lack of cellfun has also made this harder than it should be. I know the solution should have something to do with finding the indices of the strings I want and then just looping DataFile{subscript} = [1], but I can't find a way to do it.
First you should transform your table at a cell array.
Then, you can use the strrep along with str2num, e.g.
% For a given cell index
strrep(yourCellIndexVariable, "Help me please", "1");
str2num(yourCellIndexVariable);
This will replace the string "Help me please" with the string "1" (the strrep function) and the str2num will change the cell index to the double value according to the string.
By yourCellIndexVariable I mean an element from the cell array. There are several ways to get all cells from a cell array, but I think that you have solved that part already.
What you can do is as follows:
[rows, cols] = size(table); % Get the size of your table
YourString = 'Help me please'; % Create your string
Strmat = repmat(YourString,rows,cols); % Stretch to fill a matrix of table size
TrueString = double(strcmp(table,Strmat)); % Compares all entries with one another
TrueString now contains logicals, 1 where the string 'Help me please' is located, and 0 where it is not.
If you have a table containing multiple classes it might be handy to switch to cells though.
Thank you very much everyone for helping think through to a solution. Here's what I ended up with:
% Reads data
[~, ~, raw] = xlsread ( 'MyTable.xlsx');
MyTable = raw;
% Makes a backup of the data in table form
MyTableBackup = readtable( 'MyTable.xlsx' );
% Begin by ditching 1st row with variable names
MyTable(1,:) = [];
% wizard magic - find all cells with strings
StringIndex = cellfun('isclass', MyTable, 'char');
% strrep goes here to recode bad strings. For example:
MyTable(StringIndex) = strrep(MyTable(StringIndex), 'PlzHelpMe', '1');
% Eventually, we are done, so convert back to table
MyTable = cell2table(MyTable);
% Uses backup Table to add variable names
% (the readtable above means the bad characters in variable names are already escaped!)
MyTable.Properties.VariableNames = MyTableBackup.Properties.VariableNames;
This means the new values exist as strings ('1', not 1 as a double), so now I just str2double when I access them for analysis. My takeaway - Matlab is for numbers. Thanks again all!

explanation for matlab code

Am new to matlab.
Can someone explain me the following code. this code is used for training the neural network
N = xlsread('data.xls','Sheet1');
N = N(1:150,:);
UN = xlsread('data.xls','Sheet2');
UN = UN(1:150,:);
traindata = [N ; UN];
save('traindata.mat','traindata');
label = [];
for i = 1 : size(N,1)*2
if( i <= size(N,1))
% label = [label ;sum(traindata(i,:))/size(traindata(i,:),2)];
label = [label ;sum(traindata(i,:))/10];
else
% label = [label ;sum(traindata(i,:))/size(traindata(i,:),2)];
label = [label ;sum(traindata(i,:))/10];
end
end
weightMat = BpTrainingProcess(4,0.0001,0.1,0.9,15,[size(traindata,1) 1],traindata,label);
I cannot find a Neural Network toolbox built-in that corresponds to BpTrainingProcess(), so this must be a file you have access to locally (or you need to obtain from the person who gave you this code). It likely strings together several function calls to Neural Network toolbox functions, or perhaps is an original implementation of a back-propagation training method.
Otherwise, the code has some drawbacks. For one, it doesn't appear that the interior if-else statement actually does anything. Even the lines that are commented out would leave a totally useless if-else setup. It looks like the if-else is intended to let you do different label normalization for the data loaded from Sheet1 of the Excel file vs. data loaded from Sheet2. Maybe that is important for you, but it's currently not happening in the program.
Lastly, the code uses an empty array for label and the proceeds to append rows to the empty array. This is unneeded because you already know how many rows there will be (it will total up to size(N,1)*2 = 150*2 = 300 rows. You could just as easily set label=zeros(300,1) and then use usual indexing at each iteration of the for-loop: label(i) = .... This saves time and space, but arguably won't matter much for a 300-row data set (assuming that the length of each row is not too large).
I put documentation next to the code below.
% The functionn 'xlsread()' reads data from an Excel file.
% Here it is storing the values from Sheet 1 of the file 'data.xls'
% into the variable N, and then using the syntax N = N(1:150,:) to
% change N from being all of the data into being only the first
% 150 rows of the data
N = xlsread('data.xls','Sheet1');
N = N(1:150,:);
% Now do the same thing for Sheet 2 from the Excel file.
UN = xlsread('data.xls','Sheet2');
UN = UN(1:150,:);
% This concatenates the two different data arrays together, making
% one large array where N is the top half and UN is the bottom half.
% This is basically just stacking N on top of UN into one array.
traindata = [N ; UN];
% This saves a copy of the newly stacked array into the Matlab data file
% 'traindata.mat'. From now on, you should be able to load the data from
% this file, without needing to read it from the Excel sheet above.
save('traindata.mat','traindata');
% This makes an empty array which will have new things appended to it below.
label = [];
% Because UN and N have the same number of rows, then the training data
% has twice as many rows. So this sets up a for loop that will traverse
% all of these rows of the training data. The 'size()' function can be
% used to get the different dimensions of an array.
for i = 1 : size(N,1)*2
% Here, an if statement is used to check if the current row number, i,
% is less than or equal to than the number of rows in N. This implies
% that this part of the if-statement is only for handling the top half
% of 'trainingdata', that is, the stuff coming from the variable N.
if( i <= size(N,1))
% The line below was already commented out. Maybe it had an old use
% but is no longer needed?
% label = [label ;sum(traindata(i,:))/size(traindata(i,:),2)];
% This syntax will append new rows to the variable 'label', which
% started out as an empty array. This is usually bad practice, memory-wise
% and also for readability.
% Here, the sum of the training data is being computed, and divided by 10
% in every case, and then appended as a new row in 'label'. Hopefully,
% if you are familiar with the data, you will know why the data in 'N'
% always needs to be divided by 10.
label = [label ;sum(traindata(i,:))/10];
% Otherwise, if i > # of rows then handle the data differently.
% Really this means the code below treats only data from the variable UN.
else
% The line below was already commented out. Maybe it had an old use
% but is no longer needed?
% label = [label ;sum(traindata(i,:))/size(traindata(i,:),2)];
% Just like above, the data is being divided by 10. Given that there
% is nothing different about the code here, and how it modifies 'label'
% there is no need for the if-else statements, and they only waste time.
label = [label ;sum(traindata(i,:))/10];
% This is needed to show the end of the if-else block.
end
% This is needed to show the end of the for-loop.
end
% This appears to be a Back-Propagation Neural Network training function.
% This doesn't match any built-in Matlab function I can find, but you might
% check in the Neural Network toolbox to see if the local function
% BpTrainingProcess is a wrapper for a collection of built-in training functions.
weightMat = BpTrainingProcess(4, 0.0001, 0.1, 0.9, 15,
[size(traindata,1) 1], traindata,label);
Here is a link to an example Matlab Neural Network toolbox function for back-propagation training. You might want to look around the documentation there to see if any of it resembles the interior of BpTrainingProcess().

How to read multiple lines by individual in an edit text with a value of Max=5 in Matlab?

I have in my gui an edit text field that accepts multiple lines with a Max value of 5, and i can't find a way to display a matrix with the input values...something like this:
m=[m(1) m(2) m(3) m(4) m(5)];
set(handles.show,'string',m)
how can i store the values in the calculate callback..every time i run this, it brings me an error..
function masa_Callback(hObject, eventdata, handles)
% hObject handle to masa (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
%h_edit is the handle to the edit box
m=str2double(get(hObject,'String'));
function calculate_Callback(hObject, eventdata, handles)
% hObject handle to agregarm (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
f = str2double(get(h_fuerza,'string')); %h_edit is the handle to the edit box
m = str2double(get(h_masa,'string')); %h_edit is the handle to the edit box
[row, column] = size(m);
for i = 1:row
eval(m{i,:}) %evaluate each line as in MATLAB command prompt
end
I have the masa_callback,rigidez_callback and fuerza_callback i try to read the user input in the edit text box...so i want to pass those values to the calculate_callback as an array to perform certain operations according to the value of n...the error that i am getting is that when for example n=2, i add two values in the masa_callback column and fuerza_callback and 3 values in the rigidez_callback, those values are passed to the case n==2, and when my program tries to display for example the matrix m, it displays all the values i enter together in the spaces of m(1) and m(2)...i want to put only each separated value, not joined together!...How can i fix this,, i believe that is whith an array and a loop but i dont know how, and how to pass the array values to the equation to perform operations(as numbers) and display it as string
To fix the problem with the input (assuming you have your data in some cell array, and that handles.show refers to a text box), use strvcat:
someCellArray = {'a','b'};
m = strvcat(someCellArray{:});
set(handles.show,'string',m)
Your problem stems from the line
m = str2double(get(h_masa,'string'));
You do not want to convert the string to double.
Since the String property actually returns a multiline string, you have to modify your code like this:
m = get(h_masa,'String');
nRows = size(m,1);
for iRow = 1:nRows
eval(m(i,:));
end