uitable copy function allowing for numerical values of mixture of of numbers and chars.
6 views (last 30 days)
Show older comments
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
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'
sprintf('%f','i')
Here is a simpler example of what you are doing:
sprintf('%s%f','abc','ijk')
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(1) % what is the first element??? Nota bene!!!!
info(1,:) % what is the first string (row)???
info(2) % the second element in linear ordeer
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
info=cellstr(info) % but, it's built into cellstr() to convert rows for you
info=string(info) % and so does string()
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...
cast(info,'double') % convert internal to double to see what is
double(info) % can use shorthand to get some result(*)
char(ans) % and convert back to the char() array
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.
Accepted Answer
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)
tA=cell2table(A)
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
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]
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'
or
char('A'+[0:2].')
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.
More Answers (0)
See Also
Categories
Find more on Characters and Strings in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!