How to get a character in a matrix using uitable - matlab

I'm creating a function that lets an user add or remove his/her input to the list. In this case, uitable. (Matlab)
In fact, the following code was a draft and just thinking about ideas.
Does anybody know a similar example?
(edit_com : add, delete_com : remove)
% to add an input to a list
function edit_com_Callback(hObject, eventdata, handles)
value = get(handles.insert_com, 'String'); %user input (char)
data = get(handles.uitable1, 'Data') % read table matrix
data(end+1,:) = 0; % add below the data matrix sequently.
% this is for test and I want to put an char input instead of numbers.
set(handles.uitable1, 'Data',data);
% cell selection function before a delete function
function uitable1_CellSelectionCallback(hObject, eventdata, handles)
% no selection
if ( numel(eventdata.Indices) == 0 )
% only one selected
elseif ( numel(eventdata.Indices) == 1 )
set(handles.delete_com, 'Enable', 'on'); % "delete" buttion activate
selected_com = eventdata.Indices(1); % read currently selected row
set(handles.edit_com, 'UserData', selected_com);
% more than 2 selected
else
set(handles.delete_come, 'Enable', 'on'); % "delete" buttion activate
selected_com = eventdata.Indices(:,1); % read currently selected rows
set(handles.edit_com, 'UserData', selected_com);
end
% deletion part
function delete_com_Callback(hObject, eventdata, handles)
if get(handles.edit_com, 'UserData') ==0 % none selected
else if get(handles.edit_com, 'UserData') ==1 % one selected
data = get(handles.uitable1, 'Data') %
data(row_1,:)=[]; % delete
else % more than one selected
data = get(handles.uitable1, 'Data')
data(row_2,:)=[]; % delete them
end
first it separates several cells from the cell and then separates them (separated by user data). I'm just trying to figure out which column is selected, and I try to erase it from a function. It's hard to deal with it
because it consists of characters and I don't know how to handle cells. What's the best way to get started?

If you want to use strings (character arrays) inside pass to your uitable a Data parameter being of type cell, for example;
data = cell(10,10); % a 10-by-10 empty cell matrix
set(handles.uitable1,'Data',data);
or:
data = repmat({'hi'},10,10); % a 10-by-10 matrix of cells containing the string "hi"
set(handles.uitable1,'Data',data);
For what concerns the main function:
% Here you should disable your delete button when nothing is selected,
% and enable it back when something is selected. Your indices data should
% always be kept up-to-date. You don't need to handle too many cases,
% "something selected" and "nothing selected" is enough.
function uitable1_CellSelectionCallback(hObject,eventdata,handles)
if (isempty(eventdata.Indices))
set(handles.delete_com,'Enable','off');
rows = [];
else
set(handles.delete_com,'Enable','on');
rows = eventdata.Indices(:,1);
end
set(handles.edit_com,'UserData',rows);
end
Now, for what concerns the addition of rows:
function edit_com_Callback(hObject, eventdata, handles)
value = get(handles.insert_com,'String');
data = get(handles.uitable1,'Data');
data(end+1,:) = {value};
set(handles.uitable1,'Data',data);
end
And for what concerns the removal of rows:
function delete_com_Callback(hObject, eventdata, handles)
data = get(handles.uitable1,'Data');
rows = get(handles.edit_com,'UserData');
idx = (1:size(data,1))';
idx(rows) = [];
data = data(idx,:);
set(handles.uitable1,'Data',data);
end

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.

Matlab guide: Adding / deleting items from listbox

I'm trying to create a listbox where I can dynamically add or remove items.
The setup looks like this:
Unfortunately - as one can see from the picture - when I delete elements the total length of the list stays the same and instead of shrinking the list the displayed list now contains holes.
Does anyone know how to avoid this kind of behavior?
This is my code for the delete button so far:
function btnDeleteLabel_Callback(hObject, eventdata, handles)
selectedId = get(handles.listbox_labels, 'Value'); % get id of selectedLabelName
existingItems = get(handles.listbox_labels, 'String'); % get current listbox list
existingItems{selectedId} = []; % delete the id
set(handles.listbox_labels, 'String', existingItems); % restore cropped version of label list
The simplest way to remove the "empty" entries is update the listbox string with the remaining items.
There are three possibilities:
the first element has been deleted: the new list will be upd_list={existingItems{2:end}}
the last element has been deleted: the new list will be upd_list={existingItems{1:end-1}}
ans intermediate element has been deleted: the new list will be upd_list={existingItems{1:selectedId-1} existingItems{selectedId+1:end}}
You can also check if all the element of the list have been deleted and, in this case, disable the "Delete" pushbutton; in this case, you have to enable it in the "Add" callback.
A possible implementation of your btnDeleteLabel_Callback could be:
% --- Executes on button press in btnDeleteLabel.
function btnDeleteLabel_Callback(hObject, eventdata, handles)
% hObject handle to btnDeleteLabel (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
selectedId = get(handles.listbox_labels, 'Value') % get id of selectedLabelName
existingItems = get(handles.listbox_labels, 'String') % get current listbox list
%
% It is not necessary
%
% existingItems{selectedId} = [] % delete the id
% Identify the items: if in the list only one item has been added the
% returned list is a char array
if(class(existingItems) == 'char')
upd_list=''
set(handles.listbox_labels, 'String', upd_list)
else
% If the returned list is a cell array there are three cases
n_items=length(existingItems)
if(selectedId == 1)
% The first element has been selected
upd_list={existingItems{2:end}}
elseif(selectedId == n_items)
% The last element has been selected
upd_list={existingItems{1:end-1}}
% Set the "Value" property to the previous element
set(handles.listbox_labels, 'Value', selectedId-1)
else
% And element in the list has been selected
upd_list={existingItems{1:selectedId-1} existingItems{selectedId+1:end}}
end
end
% Update the list
set(handles.listbox_labels, 'String', upd_list) % restore cropped version of label list
% Disable the delete pushbutton if there are no more items
existingItems = get(handles.listbox_labels, 'String')
if(isempty(existingItems))
handles.btnDeleteLabel.Enable='off'
end
Just replace the cell brackets with normal brackets:
%existingItems{selectedId} = []; % replace this with next line
existingItems(selectedId) = [];

Save data structure in existing .mat-file without nesting

I have created a simple GUI that when I press a button (SAVE), the system takes the value of some fields, calculates a certain function and saves the results in a data structure.
I would like this data structure to be external to the program, that is to say it remains at the exit of Matlab and at the next opening of the program this data structure must be available and upgradable.
To do this I used a global data variable that I save and load when needed.
The problem is that it doesn't work properly, the data structure is filled strangely.
I show you a gif that is perhaps more explanatory:
The saved structure is this:
As you can see, there is a structure within the other and not a list of elements. Why?
I would like to have a data structure that contains n elements (where n is the number of images) and each element consists of 9 fields (name, category, siftOctaves, siftLevels, siftPeak, siftEdge, numFeatures, siftFeatures, siftDescriptors).
This is a piece of code:
%% SAVE BUTTON
function pushSiftSave_Callback(hObject, eventdata, handles)
% hObject handle to pushSiftSave (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global data;
try
% Vector of string = name of all possible images
imgs = createListOfImages('../img/');
% Get selected image
imgName = get(handles.listbox, 'Value');
imgPath = strcat('../img/', imgs(imgName));
imgPath = imgPath{1};
I_or = imread(imgPath);
I = single(rgb2gray(I_or));
% Get some parameters enter by user
[siftOctaves, siftLevels, siftPeak, siftEdge] = takeSiftParameters(handles.editSiftOctaves, handles.editSiftLevels, handles.editSiftPeakTh, handles.editSiftEdgeTh, I_or);
% Sift function
[f, d] = vl_sift(I, 'Octaves', siftOctaves, 'Levels', siftLevels, 'PeakThresh', siftPeak, 'EdgeThresh', siftEdge);
% Number of features
perm = randperm(size(f, 2));
numFeatures = size(perm, 2);
% Check if file exists
if exist('../data/data.mat', 'file') == 2
data = load('../data/data');
else
data = struct;
end
% Insert information in data structure
data = saveSiftInformation(data, imgs, imgPath, siftOctaves, siftLevels, siftPeak, siftEdge, f, d, numFeatures);
catch
ErrorMessage = lasterr;
msgbox(ErrorMessage);
disp(ErrorMessage);
end
function [data] = saveSiftInformation(data, imgs, imgPath, siftOctaves, siftLevels, siftPeak, siftEdge, features, descriptors, numFeatures)
imgPath = imgPath(8 : end);
% Find index of image
i = find((ismember(imgs, imgPath)));
% Update data structure
data(i).name = imgPath;
data(i).category = imgPath(1 : end-6);
data(i).siftOctaves = siftOctaves;
data(i).siftLevels = siftLevels;
data(i).siftPeak = siftPeak;
data(i).siftEdge = siftEdge;
data(i).numFeatures = numFeatures;
data(i).siftFeatures = features;
data(i).siftDescriptors = descriptors;
% Save data
save('../data/data', 'data');
end
%% SAVE & QUIT BUTTON.
function pushQuit_Callback(hObject, eventdata, handles)
% hObject handle to pushQuit (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
global data;
assignin('base', 'data', data);
Thanks!
The problem you're facing is generated when you load the data.mat file.
Also, using data as the name of variable reurned by load contributes to generating confusion.
The instruction
data = load('../data/data')
reads the data.mat and stores the "data" it contains in a struct named data therefore, your struct is actually a filed of the struct data returned by load.
You can test it by setting a breakpoint just after the load call and inspecting the varialbe data.
You can fix the problem by extracting the data field from the structure when loading the .mat file.
if(exist('data.mat', 'file') == 2)
% data = load('data');
tmp = load('data');
data=tmp.data
else
data = struct;
end
Hope this helps,
Qapla'
By using the output variable of the load function you are storing the variable data from your .mat-file to a struct called data - so it gets nested. Just use load without any output and it will work.
if exist('data.mat', 'file') == 2
%// data = load('data'); % does not work!
load('data'); % does work!
else
data = struct;
end
data(1).a = 42;
data(2).a = 3;
data(1).b = 41;
data(2).b = 4;
%// make sure you just store what you want to store, in this case "data"
save('data.mat','data')
Also I would avoid declaring data a global variable. Instead you could use the fact, that all functions of your GUI are part of the same figure window and therefore have the figure handle available:
hFig = gcf;
It is further allowed to add dynamic properties do your instance of figure, so just store your data in the figure handle itself:
hFig = gcf;
addprop(hFig,'globalData')
data = struct;
hFig.globalData = data;
% ...
and in the next function you just do:
data = hFig.globalData

writing elements in matlab listbox

I am trying to write a list in a listbox.
code:
function listbox1_Callback(hObject, eventdata, handles)
% hObject handle to listbox1 (see GCBO)
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Hints: contents = cellstr(get(hObject,'String')) returns listbox1 contents as cell array
% contents{get(hObject,'Value')} returns selected item from listbox1
error = getappdata(0, 'error_norm');
rows = size(error,1);
for i = 1:rows
set(handles.listbox1,'string',strcat('filt_',num2str(i)));
for j = 1:length(error)
set(handles.listbox1,'string',strcat('sig_',num2str(i),'_',num2str(j)));
for k = 1:length(error{j}.main)
set(handles.listbox1,'string',strcat('seg_',num2str(i),'_',num2str(j),'_',num2str(k)));
end
end
end
Where error is a array of structure, this array contains filters, singals in these filters, segments of these signals. based on the number of all these components, i want to write the list. I want to write something like this in the listbox:
filt_1
sig_1_1
seg_1_1_1
seg_1_1_2
sig_1_2
seg_1_2_1
seg_1_2_2
But apparently, 'set' function overwrites the elements, so all i am getting is 1 element and the last element.
Any suggestion to how to overcome this problem will be appreciated.
Yes, since set always overwrites the string, it is better to firstl build the string and then pass it to set.
Example
% Sample data
rows=4;
error=cell(1,5);
for i=1:length(error)
error{i}.main=rand(1,4);
end
% Build string
str={};
for i=1:rows
str{end+1}=sprintf('filt_%i',i);
for j=1:length(error)
str{end+1}=sprintf('sig_%i_%i',i,j);
for k=1:length(error{j}.main)
str{end+1}=sprintf('seg_%i_%i_%i',i,j,k);
end
end
end
% Set data
set(handle.listbox1,'String', str);
Depending on the size of the final string it might be a good idea to preallocate str for performance.

imwrite current image on axes in MATLAB GUIDE

I have a problem in my GUI. In my opening function I defined an img_new variable to be an image I have stored.
My GUI has two axes, one displays the original image and the other one the filtered one. I have 4 filters in a panel with the 4 radiobuttons. And in the end of each one's code there's the img_new = the image created through the radiobutton filter.
Here's some code:
% --- Executes when selected object is changed in uipanel3.
function uipanel3_SelectionChangeFcn(hObject, eventdata, handles)
handles.count = handles.count + 1;
% Change filter orientation depending on which radiobutton is chosen
switch get(eventdata.NewValue,'Tag')
case 'hte'
h_te = zeros(handles.rows, handles.colums);
# code of the filter...
axes(handles.axes2);
imshow(h_te);
handles.img_new = h_te;
case 'hc'
h_c = zeros(handles.rows, handles.colums);
# code of the filter...
axes(handles.axes2);
imshow(h_c);
handles.img_new = h_c;
case 'vlr'
v_lr = zeros(handles.rows, handles.colums);
# code of the filter...
axes(handles.axes2);
imshow(v_lr);
handles.img_new = v_lr;
case 'vc'
v_c = zeros(handles.rows, handles.colums);
# code of the filter...
axes(handles.axes2);
imshow(v_c);
handles.img_new = v_c;
end
guidata(hObject, handles)
and here's the imwrite function:
% --------------------------------------------------------------------
function save_img_ClickedCallback(hObject, ~, handles)
% writing the new image
imwrite(handles.img_new, strcat('filtered_image_', num2str(handles.count), '.png'));
guidata(hObject, handles)
Here's the function to get the image to axes1 the original) and filter it to axes2 (filtered)
% --- Executes on button press in img2.
function img2_Callback(hObject, ~, handles)
% Read image 2
img = imread('./coimbra_estadio.jpg');
handles.img_d = im2double(img);
% image size
size_img = size(handles.img_d);
handles.colums = size_img(2);
handles.rows = size_img(1);
if rem(handles.rows,2) == 0
handles.row_0 = ((handles.rows/2)+1);
else
handles.row_0 = ((handles.rows/2)+0.5);
end
if rem(handles.colums,2) == 0
handles.colum_0 = ((handles.colums/2)+1);
else
handles.colum_0 = ((handles.colums/2)+0.5);
end
axes(handles.axes1);
imshow(img);
% Generate eventdata to call the radiobuttons function
eventdata_new.EventName = 'SelectionChanged';
eventdata_new.OldValue = get(handles.uipanel3,'SelectedObject');
eventdata_new.NewValue = get(handles.uipanel3,'SelectedObject');
uipanel3_SelectionChangeFcn(handles.uipanel3, eventdata_new, handles);
guidata(hObject, handles)
As you can see, in the end I call the panel function so when the image is loaded it is automatically filtered and the axes2 image changes.
The problem is when I call the save function it saves the old img_new.
If I change the radiobutton the img_new is refreshed, but if it is not changed it is not refreshed. It should be as loading an image automatically calls for the panel of radiobuttons function.
The problem is that guidata(hObject,handles); at the end of img2_Callback saves old handles object as a final gui state, updates made in uipanel3_SelectionChangeFcn are lost. You need to eitehr manually update handles after calling uipannel3_SelectionChangeFcn by putting handles = guidata(hObject,handles);
or handles=guidata(hObject);
(forgot which call to guidata updates handles, please see help for that), or simply remove the line guidata(hObject,handles); at the end of img2_callback (less safe if code is going to change later, updating handles after uipannel3_SelectionChangeFcn is safer approach...