MATLAB uitable row generation from user input - matlab

I've got a GUI in MATLAB which uses uitables for input. There are a fixed number columns, and each column has a very specific format which I have stored as a cell array, like so:
columnformat = {'text', 'numeric', {#doSomething, inputArg1}, {'Option1' 'Option2'}};
The number of rows is theoretically unlimited; the user could provide as many they like. The back-end is capable of handling arbitrarily many row inputs. Right now, I'm building a large uitable initially, and just assuming the user won't use it all.
Here's the question: I want to set up the table and associated code such that any time the user has selected the final row and presses enter, it creates a new row with the same format as the rest of the table.
I've tried many different approaches, including dynamically setting 'Data', and they all seem to break the custom formatting dictated by the cell array. I'm sure someone has done this before. Thanks for your help!

This solution works on GUI created using MATLAB GUIDE. I think it's true that MATLAB GUI shows odd behaviour, but I have seen most of the odd behaviour when debugging MATLAB callbacks using something like keyboard and not properly exiting from them using dbquit. So, my advice would be to stay away from using keyboard related commands for MATLAB GUIs created with GUIDE.
Now, back to solving your problem, follow these steps.
Step 1: Add this at the start of GUINAME__OpeningFcn:
handles.row_col_prev = [1 1];
Step 2: Click on the properties of the table in context and click on CellSelectionCallback. Thus, if the tag of the table is uitable1, it would create a function named - uitable1_CellSelectionCallback.
Assuming the figure of the GUI has the tag - addrows_figure
Add these in it:
%%// Detect the current key pressed
currentkey = get(handles.addrows_figure,'CurrentCharacter')
%%// Read in previous row-col combination
prev1 = handles.row_col_prev
%%// Read in current data. We need just the size of it though.
data1 = get(handles.uitable1,'Data');
%%// Main processing where a row is appended if return is pressed
if numel(prev1)~=0
if size(data1,1)==prev1(1) & currentkey==13 %%// currentkey==13 denotes carriage return in ascii
data1(end+1,:) = repmat({''},1,size(data1,2)); %%// Append empty row at the end
set(handles.uitable1,'Data',data1); %%// Save it back to GUI
end
end
%%// Save the current row-col combination for comparison in the next stage
%%// when selected cell changes because of pressing return
handles.row_col_prev = eventdata.Indices;
guidata(hObject, handles);
Hope this works out for you!

I couldn't think of a possibility to achieve what you want with a certain key, I think it would be possible with any key (KeyPressFcn). But I'd rather recommend to introduce a toolbar with a pushbutton:
h = figure(...
u = uitable(h, ...
set(u,'Tag','myTable')
tbar = uitoolbar(h);
uipushtool(tbar,'ClickedCallback',#addRow);
In your callback function then you need to get your data, add a row and write it back:
function addRow(~,~)
u = findobj(0,'Type','uitable','Tag','myTable');
data = get(u,'Data');
%// modify your data, add a row ...
set(src,'Data',data);
end
Sorry if everything is a little simple and untested, but a good answer would require a considerable effort, I don't have time for. The tag matlab-uitable can give you a lot of further ideas.

Related

Is there any function for getpts() of MATLAB in Octave?

I load a data file and plot it in octave. But in the plot, I want to mark the periodic appearance of points on the plot. I used ginput() function for marking. But the problem I see is, if I mark a different point which was not supposed to mark and then immediately realise that i made mistake, now I want to delete my last marked point and then mark the correct point. I'm not able to do it. I found out that there is MATLAB function getpts() which does the same but octave version of getpts() is not there. Can anyone help me out please?
Example:
The sequence i want to mark is 1,2,3,4,5,6,7,8,9,10.
But accidently I mark 1,2,3,5 And realise that I did a mistake and then press delete button on the keyboard which deletes 5 and then I mark 4 and then 5.
While getpts is not implemented per se, producing a small function which gets inputs one by one via ginput and vets them to get the desired behaviour is fairly easy. E.g.
X = []; Y = [];
while true
[x, y, b] = ginput(1);
if b == 8 , X(end)=[]; Y(end)=[]; % backspace key pressed
elseif isempty(b), break; % enter key pressed
else , X(end+1)=x; Y(end+1)=y; % any other key
end
disp([X;Y]); fprintf('\n'); fflush(1); % Optional terminal output
end
This is a very flexible approach which allows you to modify and add functionality as you desire (e.g., add different markers based on specific key pressed, plot as you go, etc).

MATLAB: Permanently set "Text Update Function" for Data Cursor in figures

Problem: I use MATLAB for science, and I often need more than 4 significant digits. Every time I use Data Cursor in a figure's GUI, I need to manually right-click on the point, Select Text Update Function... or Edit Text Update Function..., and navigate to the folder where I saved the function whose callback prints more than 4 (e.g. 8) significant figures. This is annoying and there should be a way to automatically change this.
Ideal answer: I want this done permanently for all figures, e.g. in a function that changes default settings in my startup.m file.
Good enough answer: I want a wrapped function to which I give the figure handle and it fixes this for me.
I humbly await SO's infinite wisdom.
The permanent solution
would be, to edit the default_getDatatipText.m function.
You can find it in:
C:\...\MATLAB\R20xxx\toolbox\matlab\graphics\#graphics\#datacursor
There you will find the line:
DEFAULT_DIGITS = 4; % Display 4 digits of x,y position
Edit it as desired, you can't do much harm, but make a backup before if you want.
Alternative solution:
There is also the possibility of custom data tips: Tutorial at Matlab Central
It could finally look like this:
(additional text outside data-tips was post-processed)
And as you're talking about precision. The data-tip always snaps to the closest data-point. It doesn't show interpolated data at the clicked position.
The permanent answer given by thewaywewalk doesn't work anymore in R2015a, and probably later ones. So here I share my solution for both the temporary and permanent solution
Temporary solution (for a single figure):
The following function contains the update function as a nested function. Call datacursorextra to apply it to the current figure, or datacursorextra(fig) to apply it to some figure fig.
function datacursorextra(fig)
% Use current figure as default
if nargin<1
fig = gcf;
end
% Get the figure's datacursormode, and set the update function
h = datacursormode(fig);
set(h,'UpdateFcn',#myupdatefcn)
% The actual update function
function txt = myupdatefcn(~,event)
% Short-hand to write X, Y and if available Z, with 10 digit precision:
lbl = 'XYZ';
txt = arrayfun(#(s,g)sprintf('%s: %.10g',s,g), lbl(1:length(event.Position)), event.Position,'uniformoutput',false);
% If a DataIndex is available, show that also:
info = getCursorInfo(h);
if isfield(info,'DataIndex')
txt{end+1} = sprintf('Index: %d', info.DataIndex);
end
end
end
Permanent solution (apply to all figures by default):
I have not found a way to set a default UpdateFcn for the data cursor, but it is possible to add some code which will be called every time a new figure is created. Add the following line to your startup.m:
set(0,'defaultFigureCreateFcn',#(s,e)datacursorextra(s))
and make sure the datacursorextra function given above is available in your Matlab path.
#caspar's solution works very well.
You can also update the txt{} part of the solution with
if isfield(info,'DataIndex')
DataIndex = [info.DataIndex];
txt{end+1} = sprintf('Index: %d\n', DataIndex(1));
end
This will enable you to update the Index field when you have multiple pointers in the same figure.

Drag pattern in uitable matlab

I want to know if it is possible to drag pattern values in matlab uitable. In a spreadsheet, to enter values from 1 to 50, you need to enter 1,2,3 and select the cells and drag. Please can this be done in matlab uitable? Regards.
It can be done. But not as far as comfortable as with excel.
Play around a bit with the following code, you can try to improve it or change it to your needs. I think it is a good starting point for you.
function fancyTable
defaultData = randi(99,25,2);
h = figure('Position',[300 100 402 455],'numbertitle','off','MenuBar','none');
uitable(h,'Units','normalized','Position',[0 0 1 1],...
'Data', defaultData,...
'Tag','myTable',...
'ColumnName', [],'RowName',[],...
'ColumnWidth', {200 200},...
'CellSelectionCallback',#cellSelect);
end
function cellSelect(src,evt)
try
index = evt.Indices;
data = get(src,'Data');
L = size(index,1);
rows = index(:,1);
column = index(1,2);
start = data(rows(1),column);
newdata = start:(start+L-1);
data(rows,column) = newdata';
set(src,'Data',data);
end
end
It creates a table with two columns:
You can select data and your desired drag pattern is applied immediately according to the first value.
The code is just to insert an increasing series of values at the first point of selection based on the according value. The hardest part will be to detect the pattern! I just evaluated the first data value start = data(rows(1),column); you could also require a minimal selection of 3: start = data(rows(1:3),column);. You probably need to work with a lot of try/catch structures to skip all unexplained cases. Or you use switch/case structures from the beginning to evaluate the length of the selection and evaluate the pattern.
All in all it is a heavy task, I'm not sure if it's worth it. But it can be done.
In uitable you insert data (usually a matrix) to be displayed in a table. So unlike Excel the uitable function is merely a form of displaying your data instead of a tool to manipulate it. See for more information here. However, if you want to set up a row for instance running from 1 until 10 you could use the following steps:
So say one would like to display a matrix of size 10x10, e.g.
A=magic(10);
You can now set up a table t to display this matrix by
t=uitable('Data',A);
In your case if you want a row to be, e.g., 1 till 10, just change the matrix A containing your data to hold this row using
A(1,1:10)=1:10;
And re-execute the former command to bring up your table t.

MATLAB: Pushbutton callbacks to update and amend variables and cell arrays

I am new to making GUIs and this is my first attempt, but I have spent days searching for an answer to a really basic pushbutton question.There was a similar question on here but it doesn't work for me as I need to make multiple changes with a single click.
The GUI consists of a table which lists a number of images along with two blank columbs (the final GUI will have a 1000,50 table). The GUI displays the first image and then has 3 buttons,buttons 1 & 2 insert data into the table and then displays the next image,updating the Row variable within the code so you can move down the list of images, with each button press. Button 3 is different though, it takes the data from the current row and places it in a separate table for rejected data, and then once again updates the row variable. However, I can't get my callback functions to update the Row,Table and Rejected_Data variables. My code is as follows:
%Simple GUI for to show issue
%Table
Table=cell(4,3);
Table(1,1:end)=[{'File'},{'Type'},{'Value'}];
Table(2,1)={'Image1.jpg'};
Table(3,1)={'Image2.jpg'};
Table(4,1)={'Image3.jpg'};
% Rejected Images
Rejected_Data=cell(4,3);
Rejected_Data(1,1:end)=[{'File'} {'Type'} {'Value'}];
% GUI bit
Row=2;
Im=imread(Table{Row,1});
%Figure
hFig=figure;
set(hFig,'Units','Normalized','Position',[0.1 0.1 0.6 0.6]);
%Axes
hAx=axes('Parent',hFig);
set(hAx,'Units','Normalized','Position',[0.2 0.4 0.5 0.5]);
Image=imagesc(Im,'Parent',hAx);
axis off;
%button1
bh1=uicontrol('Style','pushbutton','String','Button1');
set(bh1,'Units','Normalized','Position',[0.2 0.2 0.1 0.05]);
%button2
bh2=uicontrol('Style','pushbutton','String','Button2');
set(bh2,'Units','Normalized','Position',[0.4 0.2 0.1 0.05]);
%button3
bh3=uicontrol('Style','pushbutton','String','Scrap');
set(bh3,'Units','Normalized','Position',[0.6 0.2 0.1 0.05]);
% Callbacks
set(bh1,'Callback',{#buttontest1,Table,Row,hAx});
set(bh2,'Callback',{#buttontest2,Table,Row,hAx});
set(bh3,'Callback',{#buttontest3,Table,Row,hAx,Rejected_Data});
Function for Buttons 1 & 2 is:
function buttontest1(~,~,Table,Row,hAx)
Table(Row,2)=cellstr('Tree');
Table(Row,3)=47;
Row1=Row+1;
evalin('base','Row = Row1');
evalin('base','Table = Table');
Pic=imread(Table{Row1,1});
imagesc(Pic,'Parent',hAx);
end
Function for Button 3:
function buttontest3(~,~,Table,Row,hAx,Rejected_Data)
Rejected_Data(Row,:)=Table(Row,:);
Row1=Row+1;
evalin('base','Row = Row1')
Pic=imread(Table{Row1,1});
imagesc(Pic,'Parent',hAx);
end
I tried using global instead of evalin, but as Row etc, already exists it doesn't work, I have also tried assignin, but I couldn't get that to work either. I don't want to use guide as I need the flexibility of only having a text file, I also don't use nested functions as they require my original GUI to be a function also and the final GUI will we bolted onto some pre-processing that will create the data table inputted.
Any help would be greatly appreciate.
Thanks
Use guidata to store your data. Using evalin for this purpose is not recommended.
Use handles structure to handle data transfer in gui.

How to save data using matfile Matlab

New to matlab and I need some help.
I need to create a .mat file , using matObj or save(), that has some information that will be passed from some variable. Lets say that variable x = 1,2,3,4,5
1|2|3|4|5|
Then I need to save that in test.mat
Then I need to load that file and save something like,
6|7|8|9|10|
So I get
1|2|3|4|5|
6|7|8|9|10|
and so on.
So every time I save it goes to a new row. The numbers that go inside they are not random the above numbers are just there to make things simple to see.
Can someone help me out.
You are describing two different problems here. The first is saving and loading of data.
Saving is easy:
x = 1:5;
filename = 'myFile.mat'
save(filename, 'x'); %notice that I used the string name of the variable
Likewise loading is also simple:
filename = 'myFile.mat';
data = load(filename); % loaded variables are placed in a struct to prevent overwriting workspace variables
x = data.x;
The 2nd problem can be solved using concatenation:
lets say you want to convert the vector 1 2 3 into the matrix:
1 2 3
1 2 3
You can simply call:
v = 1:3;
m = cat(1, v, v);
Likewise you can add an additional row to the existing matrix using the same command:
m = cat(1, m, v);
I'm sure any amount of googling will get you how to save a variable to a mat file - The matlab docs are absolutely spectacular, and such a simple operation will be covered along with examples showing exactly how to use the functions.
As for the second part, use the concatenation property
new = [old1 old2];
to concatenate horizontally, and
new = [old1;old2];
to concatenate vertically. Then resave the same way that you just learned via google.
Hope this helps, and in the future, i guarantee 99% of the answers to a new user's questions will be in the top two google search results if you append "matlab" to your search. The Mathworks really set the bar on documentation in my opinion. (Of course, I last used MATLAB 3 years ago)