Create comma-separated list from data of UITable

I want to create a list of latitude just like the format below from a UITable
latitudes = [lat1, lat2, lat3,...];
This is the data from the UITable.
I am getting this result using the following code, clearly with no commas.
m = horzcat(app.UITable.Data{:,3})
m =
'13.9524380813.9524398613.95226986 13.9475104713.94693600'
Does anyone know how to do this? Thanks

3 Comments

dpb
dpb on 14 May 2022
Edited: dpb on 14 May 2022
The simpler way would be to set the 'ColumnFormat' property to 'Double' and write a callback routine if it is editable and user enters bum data...then the .Data property will return numeric data automagically.
There is no reason to build a list of the sort used for user input physically; it won't be useful programmatically even if you do; it will be a string or cellstr, not actually a list, anyway. Passing the double array will be the way to use the results in any function or even to output if that is the end objective...you don't provide any context for why you think you need to do this, so we don't have any way to know what possilbly could be the best way to resolve whatever led you to this point, but it's a strong likelihood the above will be it.
See the details available uitable links to 'Table Properties' and the examples include showing callback functions.
Hello @dpb, I have tried your suggestion for the question but I'm getting error messages.
I am developing a program where I can generate a kml file using the extracted gps info (latitudes, longitudes) from the images. The gps info is stored in the UITable (third and fourth column as shown in the picture above) and I would like to extract those values. I am not sure of its data type (newbie here). Not all images have the gps info that I want thus the spaces in the column.
I want a list of the latitudes and longitudes just like the format below.
latitudes = [13.95243808, 13.95243986, 13.95226986];
longitudes = [121.65762189, 121.65762847, 121.65714711];
names = {'1', '2', '3'};
filename = 'test.kml';
kmlwritepoint(filename, latitudes, longitudes, 'Name', names);
The following is the code that I am working rn
for k = 1 : length(theFiles)
baseFileName = theFiles(k).name;
fullFileName = fullfile(theFiles(k).folder, baseFileName);
OrigImage = imread(fullFileName);
info = imfinfo(fullFileName);
info.GPSInfo;
latitude = info.GPSInfo.GPSLatitude;
longitude = info.GPSInfo.GPSLongitude;
lat = dms2degrees(latitude);
lon = dms2degrees(longitude);
if (row >= 1) & (col >= 1)
app.DetectionEditField.Value ='Detected';
app.LatitudeEditField.Value = sprintf('%0.8f', lat);
app.LongitudeEditField.Value = sprintf('%0.8f', lon);
else
app.DetectionEditField.Value = 'Not Detected';
app.LatitudeEditField.Value = ' ';
app.LongitudeEditField.Value = ' ';
end
app.UITable.Data{k,1}=baseFileName;
app.UITable.Data{k,2}=app.DetectionEditField.Value;
app.UITable.Data{k,3}=app.LatitudeEditField.Value;
app.UITable.Data{k,4}=app.LongitudeEditField.Value;
k = app.UITable.Data{:,3};
l = app.UITable.Data{:,4};
kmlwritepoint('test.kml', k, l)
Error using kmlwritepoint (line 271)
Expected latitude coordinates to be one of these types:
single, double
I'm getting this error message.
I hope you could help me, thanks a lot.
See the Answer...as expected, this can be simplified greatly by proper use of data types and storage.

Sign in to comment.

 Accepted Answer

dpb
dpb on 14 May 2022
Edited: dpb on 14 May 2022
>> which -all kmlwritepoint
'kmlwritepoint' not found.
>>
So this is not a MATLAB function I've got... kmlwritepoint shows it in the Mapping TB so that 'splains that.
But that very same document shows (and the error reinforces) that the input it expects is just the numeric (double) vector array.
The suggestion to set the data columns to be numeric to ensure they are and then simply
names = {'1', '2', '3'};
filename = 'test.kml';
kmlwritepoint(filename, app.UITable.Data{:,2}, app.UITable.Data{:,3}, 'Name', names);
wlll be the expected syntax.
BUT -- If you would store your data in a MATLAB table and use uitable to display it to the user in the GUI, then you could retrieve the data from it directly as the table and even use the column headers -- here's an example taken from the above doc link -- I just renamed the two variables to match yours for to have some data.
Try this for grins...
t = readtable('patients.xls'); % the uitable example dataset
vars = {'Systolic','Diastolic'}; % we just want two variables
tCoords=t(1:10,vars); % and only need a few to illustrate
tCoords.Properties.VariableNames={'Latitude','Longitude'}; % pretend they're coordinates instead...
hUF=uifigure; % make a uifigure
hUIT=uitable(hUF,'Data',tCoords); % display the table
That created the following plain vanilla figure...
Now play with that some at command line...
>> hUIT.Data
ans =
10×2 table
Latitude Longitude
________ _________
124.00 93.00
109.00 77.00
125.00 83.00
117.00 75.00
122.00 80.00
121.00 70.00
130.00 88.00
115.00 82.00
115.00 78.00
118.00 86.00
>>
Observe we got the table back as a table -- much more convenient than having to deal with the string representation...
With this you can also write
>> hUIT.Data.Latitude
ans =
124.00
109.00
125.00
117.00
122.00
121.00
130.00
115.00
115.00
118.00
>>
so your call to write the data out can be reduced to
names = {'1', '2', '3'};
filename = 'test.kml';
kmlwritepoint(filename, hUIT.Data.Latitude,hUIT.Data.Longitude, 'Name', names);
which is "much more simpler" and legible to read the code, besides.
If you're not using a table to store your data in the app, you should be! :)
NB: I don't know what the three Names are supposed to match up to here; I'm guessing that may have something to do with there being the first unshown column in the table. Would need more info to know just what to do there, not having any experience with the Mapping TB and hence "knowing nuthink!" about just what kmlwritepoint is doing.

8 Comments

In your real app, make sure you use proper handle references -- if all of this code is in a callback routine or a separate m-file function, then you can create local handles/variables for the table handle...but, if the table is created on startup and there's another callback to do the other work/write/whatever, you'll have to be sure to save the handle(s) to the uitable in the global app structure so it's available in the callback routine.
Hello @dpb, thank you very much for this solution. I was able to generate a kml file and open it in google earth as shown below.
The thing is, I am developing this program using App Designer, thus the UITable is already placed in the GUI. Is there a way to convert cell array to table so that I can apply your suggested solution in app designer?
Thank you very much.
dpb
dpb on 14 May 2022
Edited: dpb on 14 May 2022
The uitable has to be populated with the data from somewhere initially. Back in your startup code or from wherever you get the original data, create it as a MATLAB table at that point.
You can get/have the handle to the uitable object somewhere; if is/was placed on the app canvas in the designer, then it has a static handle and will be somewhere in the global app structure so you've already got it.
So then, the deal is to either read the data in using readtable or convert it to a table from whatever form it is in to put into the uitable. Would need the details on how/where the data come from to know specifics, but it won't be very difficult, but needs to be at the very beginning or in the callback that reads the data in the app.
But, in direct response to the Q? as written, see cell2table -- but I'd bet the bester solution will be to create the table to begin with at the point at which you get the cell array. We don't know where that comes from so again specific code would depend on that detail.
Going back to your earlier code (that I basically ignored as being irrelevant to the problem :) ),
tGPS=[];
vars={'GPSLatitude','GPS.Longitude'};
for k = 1:numel(theFiles) % length is somewhat flaky; best to avoid
OrigImage =imread(fullfile(theFiles(k).folder,theFiles(k).name));
info = imfinfo(fullFileName);
tGPS=[tGPS;struct2table(info,'AsArray',1)];
end
tGPS=tGPS(:,vars); % keep just lat, long
tGPS.Properties.VariablesNames={'Latitude','Longitude'}; % make names wanted
tGPS.Latitude=dms2degrees(tGPS.Latitude); % make units conversion
tGPS.Longitude=dms2degrees(tGPS.Longitude);
At this point you've got a table of the lat, long data; filling it out to yours isn't much extra effort --
tGPS=addvars(tGPS,string({theFiles(:).name}.'), ...
'NewVariableNames',{'File'},'Before',{'Latitude'});
Then you can set the uitable to that table - I ignored the 'detected' field; that will be easily filled in as well, but it wasn't clear since your code doesn't define row, col just what is the missing piece of data to look for. But, it will be easy enough with logical addressing to locate which have/don't have the required info; the struct2table 'AsArray' will put a missing indicator for any field that isn't available from which can use ismissing to locate and fix up.
It looks like this is a fairly major revamping of your code, but I don't believe it would be extensive to make the switchover and the end result would be much simpler coding downstream without having to deal with the internal data type.
Now, the one kicker I just discovered with displaying a MATLAB table in a uitable is that it ignores the formatting of columns for the default display used with table. This is unfortunate and "just plain rude!" behavior on the implementation and may be a killer if you simply must have the 8 decimal digits displayed.
If that is an absolute requirement, it may be better to stick to the regular uitable, but then at least set the data type and the desired format string for each column so your numeric values are always numeric.
Would have to do more investigating to see about a workaround with the table; that is a real kick in the teeth in not having that control available.
Well, I poked around a little more -- even the regular uitable won't accept an actual format string to set the specific wanted format -- rude!
Bestest I come up with is to retain the idea of using a table, but build a load/read routine to tranform between the wanted display format and the numeric -- a quick example back at the command line as before --
tCoords.Lat=compose('%0.8f',tCoords.Latitude);
tCoords.Lon=compose('%0.8f',tCoords.Longitude);
gives
>> tCoords
tCoords =
8×4 table
Latitude Longitude Lat Lon
________________ _________ ________________ _______________
125.772230521827 93 {'125.77223052'} {'93.00000000'}
110.870680472275 77 {'110.87068047'} {'77.00000000'}
125.284599897971 83 {'125.28459990'} {'83.00000000'}
118.8839686379 75 {'118.88396864'} {'75.00000000'}
123.589526194468 80 {'123.58952619'} {'80.00000000'}
121.582916053722 70 {'121.58291605'} {'70.00000000'}
131.078778687756 88 {'131.07877869'} {'88.00000000'}
115.688767857832 82 {'115.68876786'} {'82.00000000'}
>>
which gives you the desired precision displayed -- I just made another pair of columns rather than overwrite the data values here for demonstration.
With this you can write
hUIT=uitable(hUF,'Data',tCoords(:,{'Lat','Lon'}));
which gives the desired appearance as well as the column headings and you can get the data back via
>> hUIT.Data.Lat
ans =
8×1 cell array
{'125.77223052'}
{'110.87068047'}
{'125.28459990'}
{'118.88396864'}
{'123.58952619'}
{'121.58291605'}
{'131.07877869'}
{'115.68876786'}
>> str2double(hUIT.Data.Lat)
ans =
125.77223052
110.87068047
125.2845999
118.88396864
123.58952619
121.58291605
131.07877869
115.68876786
>>
That can still use the column names for convenience, just have to convert to double() to use for end purpose -- and to string to get the precision to display.
I was about to utilize the table function in my program.
I have inserted this code and this was the error message
Unrecognized table variable name 'Latitude'.
Am I supposed to create xls file first for this? Thank you so much for your time @dpb.
Would have to see how you created the table -- what this is saying is that you tried to reference a table variable 'Latitude' before that particular name was put into the table -- but you don't show where/how the table was created.
What I showed above was using the data from the iminfo structure to build a table -- what variable names will be in that table will be dependent upon what are the field names in that stuct -- and we/I don't have any of your images to load to know what those are -- and in going back and looking, I overlooked that the GPS coordinates are actual substructures under GPSInfo under "info" -- hence the struct2array doesn't work as intended here, it built a table ok, but that table entry is still a struct, not the end data.
>> info.GPSInfo.GPSLatitude=randi(125,1,1)+rand()
info =
struct with fields:
GPSInfo: [1×1 struct]
>> info.GPSInfo.GPSLatitude
ans =
82.1711866878116
>> struct2table(info,'AsArray',1)
ans =
table
GPSInfo
____________
[1×1 struct]
>>
shows what happened with just a made up struct here of the same field structure.
So, that would, indeed, create the error; 'Latitude' definitely is not going to be one of the table names directly.
I tried to be too clever -- probably what have to do is to build the table from the actual field names -- although if those can change from file to file, may want to use dynamic fieldnames instead of hardcoded.
But, let's see -- if go back above and look at what you loaded...
...
latitude = info.GPSInfo.GPSLatitude;
longitude = info.GPSInfo.GPSLongitude;
lat = dms2degrees(latitude);
lon = dms2degrees(longitude);
then
tGPS=[];
vars={'GPSLatitude','GPS.Longitude'};
for k = 1:numel(theFiles) % length is somewhat flaky; best to avoid
FFName=fullfile(theFiles(k).folder,theFiles(k).name); % do need temporary
OrigImage =imread(FFName);
info = imfinfo(FFName);
tGPS=[tGPS; ...
table(string(theFiles(k).name) ...
dms2degrees(info.GPSInfo.GPSLatitude), ...
dms2degrees(info.GPSInfo.GPSLongitude), ...
'VariableNames',{'File','Latitude','Longitude'})];
end
should give you the beginning table with the three columns; the fourth about "discovered" could be built at same time if knew which field to inspect...I'd set the missing values to NaN instead of empty strings or zeros; those will show up as the "NaN" string in the table when use the format string.
It would be helpful to have a couple of the image files (use the paperclip icon) so can see what actually is the content directly.
Hello @dpb, I was able to finish my project because of your help, thank you very much!

Sign in to comment.

More Answers (0)

Asked:

on 14 May 2022

Commented:

on 21 May 2022

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!