uitable copy function allowing for numerical values of mixture of of numbers and chars.

4 views (last 30 days)
Hi, I have a uitable and have a copy function as below. This works fine if the table is solely numbers
function CopyTableData(app,src,event)
tbl = event.ContextObject;
% fieldnames(event)
% event.InteractionInformation
s=tbl.Data;
size_s = size(s);
str = '';
for i=1:size_s(1)
for j=1:size_s(2)
str = sprintf ( '%s%f\t', str, s(i,j) );
end
str = sprintf ( '%s\n', str );
end
clipboard('copy',str);
end
There are instances where my table will be a cell array and I have modified the function (for the str = sprintf ( '%s%f\t', str, s{i,j}) to:
function CopyTableData(app,src,event)
tbl = event.ContextObject;
% fieldnames(event)
% event.InteractionInformation
s=tbl.Data;
size_s = size(s);
str = '';
for i=1:size_s(1)
for j=1:size_s(2)
try
str = sprintf ( '%s%f\t', str, s(i,j) );
catch
str = sprintf ( '%s%f\t', str, s{i,j} );
end
end
str = sprintf ( '%s\n', str );
end
clipboard('copy',str);
end
However, when my data is as below (cellarray) in which the contents of all columns in the cellarray are numbers, but the very last column 'info" are charss
I get this when pasted into excel (notice the last column is incorrect and actually split into 2)
this is how I created my dummy data:
uit=app.UITableSummary;
dx=9437;
z1=5795;
z2=5775.2
dz=z2-z1
tilt_mrads=-2.1084
A={dx,z1,z2,dz,tilt_mrads,'info'};
d=uit.Data; % Get Current table data
uit.Data = [d; A]; %Add new row to current data
I kept on adding this and just manually replaced the 'info' value in the last column ('10', '12', etc..) and the numeric values in the 2nd from last column (-2.11, -1.59, etc..)
thanks for any help
  7 Comments
Stephen23
Stephen23 on 28 Aug 2024
Edited: Stephen23 on 28 Aug 2024
"There seems to be an erorr here with sprintf."
No, there is no error with SPRINTF. The value 105 is simply the character value of the first element of the character vector that you are providing to SPRINTF. After converting that one element (i.e. character) it continues applying the format string to the remains of the input array/s.
+'i'
ans = 105
sprintf('%f','i')
ans = '105.000000'
Here is a simpler example of what you are doing:
sprintf('%s%f','abc','ijk')
ans = 'abc105.000000jk'
dpb
dpb on 28 Aug 2024
Edited: dpb on 29 Aug 2024
if ischar(s{i,j})==1
s{i,j}=string( s{i,j});
end
converts every character in the char() arrays to a single string; thus creating an array of strings, not a string representation of the char() string content. See char documentation for how character strings work--they are a remnant of the very first implementation of MATLAB before the introduction even of cell arrays and cellstr(). The char() type is just an array of single characters that, because they are of class char, MATLAB knows to display the character representation of the content of the array as the ASCII text characters instead of as the numeric values that represent the characters, but internally it's just bytes and numbers that have a specific meaning. Carrying on from the example by @Stephen23 in a somewhat different vein,
info=['10'; '12'] % create a sample char() array mimics your info
info = 2x2 char array
'10' '12'
info(1) % what is the first element??? Nota bene!!!!
ans = '1'
info(1,:) % what is the first string (row)???
ans = '10'
info(2) % the second element in linear ordeer
ans = '1'
for i=1:height(info) % height(x) is more easier than size(x,1) now that supports arrays, too
cellstr(info(1,:)) % convert each row to a cellstr
end
ans = 1x1 cell array
{'10'}
ans = 1x1 cell array
{'10'}
info=cellstr(info) % but, it's built into cellstr() to convert rows for you
info = 2x1 cell array
{'10'} {'12'}
info=string(info) % and so does string()
info = 2x1 string array
"10" "12"
So, your above code should be taking that last column alone and converting it.
Without an actual copy of the table, specific code explicitly for your case is harder to write, but I think you should have no need for sprintf() at all, you should be able to select and convert all data from the table by column with a given builtin conversion function based on the type of the data in each column.
The above illustrates the addressing that the char() array is just an array of individual characters, and to reinforce the char() array is just an ordinary array in MATLAB, note the second element in the array in linear addressing mode is also '1'; the array is, like all arrays in MATLAB, stored in column-major order that is, array elements are stored in memory sequentially going down each column, the reason that builtin MATLAB functions operate in a vector fashion by column.
Also note that owing that it is an array, that
info=['10'; '12';'100']
Error using vertcat
Dimensions of arrays being concatenated are not consistent.
errors -- as it says you can't vertically catenate a vector of three things ('100') to an existing array of only two (of course, the prohibition is for any mismatch in sizes, not just longer). That's why there's the specific function just for the purpose--
info=strvcat('10','12','100')
info =
3×3 char array
'10 '
'12 '
'100'
but, in order to be able to add the longer string into the char() array, all the shorter strings in the array have been blank padded to the overall length. There's where the cellstr() and/or string() differ; they can hold array elements of differing lengths.
So, the question of what is actually in the array can be answered by noting
info=['10'; '12'] % get our original definition back...
info = 2x2 char array
'10' '12'
cast(info,'double') % convert internal to double to see what is
ans = 2x2
49 48 49 50
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
double(info) % can use shorthand to get some result(*)
ans = 2x2
49 48 49 50
<mw-icon class=""></mw-icon>
<mw-icon class=""></mw-icon>
char(ans) % and convert back to the char() array
ans = 2x2 char array
'10' '12'
The last shows that sprintf has not lied at all, either, when you asked to output a char() string using a numeric format, it obliged and did the same thing as did double() except you get the string representation of the internal values held in memory in the char() array.
This shows the split personality and dual nature of character datatypes mentioned at the beginning; MATLAB knows because of the class that it needs to display the variable info as text so you, the user, see the representation you want, not the internal numeric values that represent that text. Also, numeric classes know how to convert the internal representation of the zeros and ones that make up the actual number in the bytes that hold a double value and spit out those characters to make a readable number.
(*) VBA and many other languages have a specific second paired function ASC() or something similar in name to match CHAR() . MATLAB chose to forego having a redundant function for the char data type.

Sign in to comment.

Accepted Answer

dpb
dpb on 28 Aug 2024
Edited: dpb on 29 Aug 2024
I'd go at it a little bit differently, although I just discovered the clipboard only takes one line of text so one does have to build a newline delimited text string of the rows in the table.
If you'll use the MATLAB table for the input to the uitable, then it's much easier to manipulate; just return the uitable Data to a table variable and you're almost home.
info='10';
dx=9437;
z1=5795;
z2=5775.2;
dz=z2-z1;
tilt_mrads=-2.1084;
A={dx,z1,z2,dz,tilt_mrads,info};
A=repmat(A,3,1)
A = 3x6 cell array
{[9437]} {[5795]} {[5.7752e+03]} {[-19.8000]} {[-2.1084]} {'10'} {[9437]} {[5795]} {[5.7752e+03]} {[-19.8000]} {[-2.1084]} {'10'} {[9437]} {[5795]} {[5.7752e+03]} {[-19.8000]} {[-2.1084]} {'10'}
tA=cell2table(A)
tA = 3x6 table
A1 A2 A3 A4 A5 A6 ____ ____ ______ _____ _______ ______ 9437 5795 5775.2 -19.8 -2.1084 {'10'} 9437 5795 5775.2 -19.8 -2.1084 {'10'} 9437 5795 5775.2 -19.8 -2.1084 {'10'}
app.hUIT=uitable(app.hUF,'Data',tA); % populate your uitable
... % manipulate at heart's content here
To retrieve and do the clipboard thing,
tA=app.hUIT.Data; % retrieve last state of the UItable
tS=convertvars(tA,tA.Properties.VariableNames,'string'); % convert all to strings
C=table2array(tS); % retrieve as a string array
tab=char(9); % a tab charater constant
C=join(join(S,tab),newline); % join the columns w/ tab and the rows with newline
clipboard('copy',C); % and put in clipboard
Can't build a uitable here, but I did a small example that mimics yours locally...the result looks like-
>> A={dx,z1,z2,dz,tilt_mrads,info}; % I copied your variables from above...
>> A=repmat(A,3,1) % and made a small table from them...
A =
3×6 cell array
{[9437.00]} {[5795.00]} {[5775.20]} {[-19.80]} {[-2.11]} {'10'}
{[9437.00]} {[5795.00]} {[5775.20]} {[-19.80]} {[-2.11]} {'10'}
{[9437.00]} {[5795.00]} {[5775.20]} {[-19.80]} {[-2.11]} {'10'}
>> tA=array2table(A) % and converted to a MATLAB table
tA =
3×6 table
A1 A2 A3 A4 A5 A6
___________ ___________ ___________ __________ _________ ______
{[9437.00]} {[5795.00]} {[5775.20]} {[-19.80]} {[-2.11]} {'10'}
{[9437.00]} {[5795.00]} {[5775.20]} {[-19.80]} {[-2.11]} {'10'}
{[9437.00]} {[5795.00]} {[5775.20]} {[-19.80]} {[-2.11]} {'10'}
>> tS=convertvars(tA,tA.Properties.VariableNames,'string') % turn all into strings
tS =
3×6 table
A1 A2 A3 A4 A5 A6
______ ______ ________ _______ _________ ____
"9437" "5795" "5775.2" "-19.8" "-2.1084" "10"
"9437" "5795" "5775.2" "-19.8" "-2.1084" "10"
"9437" "5795" "5775.2" "-19.8" "-2.1084" "10"
>> S=table2array(tS)
S =
3×6 string array
"9437" "5795" "5775.2" "-19.8" "-2.1084" "10"
"9437" "5795" "5775.2" "-19.8" "-2.1084" "10"
"9437" "5795" "5775.2" "-19.8" "-2.1084" "10"
>> tab=char(9); % a tab charater constant
cb=join(join(S,tab),newline) % join the columns w/ tab and the rows with newline
cb =
"9437 5795 5775.2 -19.8 -2.1084 10
9437 5795 5775.2 -19.8 -2.1084 10
9437 5795 5775.2 -19.8 -2.1084 10"
>> clipboard('copy',cb)
Should be pretty close, anyways...
  2 Comments
dpb
dpb on 29 Aug 2024
Edited: dpb on 29 Aug 2024
Glad to help, always nice to be able to use the features of MATLAB as MATrix LABoratory to keep things vectorized where possible. The newer string class, while redundant in many ways(*), has some newer features built into it that are handy--the implicit conversion of numerics to their string representation is one handy one I've found, indeed, if one doesn't need a very explicit format. That means one can also do things like:
vnames="Var"+[1:3]
vnames = 1x3 string array
"Var1" "Var2" "Var3"
since the + operator is extended to mean catenation for strings and is enhanced when in an expression with a string class to do the implicit conversion.
Of course, one could always write
'A':'C'
ans = 'ABC'
or
char('A'+[0:2].')
ans = 3x1 char array
'A' 'B' 'C'
because underneath, they're "just bytes" and so MATLAB array syntax still works.
(*) Try the {} indexing on both a cellstr and a string variable and you'll see that both are just char() arrays under the hood.

Sign in to comment.

More Answers (0)

Categories

Find more on Characters and Strings in Help Center and File Exchange

Products


Release

R2023b

Community Treasure Hunt

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

Start Hunting!