Translate VBA syntax to Matlab for Activex control of Word document - matlab

I am a newbie to using activex controls in matlab. Am trying to control a word document. I need help translating between VBA syntax and Matlab, I think. How would one code the following in matlab?
Sub macro()
With CaptionLabels("Table")
.NumberStyle = wdCaptionNumberStyleArabic
.IncludeChapterNumber = True
.ChapterStyleLevel = 1
.Separator = wdSeparatorHyphen
End With
Selection.InsertCaption Label:="Table", TitleAutoText:="", Title:="", _
Position:=wdCaptionPositionAbove, ExcludeLabel:=0
End Sub
Thanks, I looked at the help and the source but I am still feeling dense. I want to be able to control caption numbering and caption text in an automated report. Am using Tables and figures. I just can't quite get my head around how to code the addition of the captions.
The following code gets me part way there. But I don't have control over numbering style, etc,. I have tried to figure out the activex structure but I can't make sense of it. In particular, In particular the first bit the VB subroutine above.
% Start an ActiveX session with Word
hdlActiveX = actxserver('Word.Application');
hdlActiveX.Visible = true;
hdlWordDoc = invoke(hdlActiveX.Documents, 'Add');
hdlActiveX.Selection.InsertCaption('Table',captiontext);

After some fiddling, I think I got it to work:
%# open Word
Word = actxserver('Word.Application');
Word.Visible = true;
%# create new document
doc = Word.Documents.Add;
%# set caption style for tables
t = Word.CaptionLabels.Item(2); %# 1:Figure, 2:Table, 3:Equation
t.NumberStyle = 0; %# wdCaptionNumberStyleArabic
t.IncludeChapterNumber = false;
t.ChapterStyleLevel = 1;
t.Separator = 0; %# wdSeparatorHyphen
%# insert table caption for current selection
Word.Selection.InsertCaption('Table', '', '', 0, false) %# wdCaptionPositionAbove
%# save document, then close
doc.SaveAs2( fullfile(pwd,'file.docx') )
doc.Close(false)
%# quit and cleanup
Word.Quit
Word.delete
Refer to the MSDN documentation to learn how to use this API. For example, the order of arguments of the InsertCaption function used above.
Note that I had to set IncludeChapterNumber to false, otherwise Word was printing "Error! No text of specified style in document" inside the caption text...
Finally, to find out the integer values of the wd* enums, I am using the ILDASM tool to disassemble the Office Interop assemblies (as this solution suggested). Simply dump the whole thing to text file, and search for the strings you are looking for.

Have a look at the help for actxserver and the source code for xlsread.m in the base MATLAB toolbox. If you're still stuck, then update your question with your progress.
EDIT:
You'll need to check the VBA help, but the first part ought to be possible via something like:
o = hdlWordDoc.CaptionLabels('Table');
o.NumberStyle = <some number corresponding to wdCaptionNumberStyleArabic>;
o.IncludeChapterNumber = true;
o.ChapterStyleLevel = 1;
o.Separator = <some number corresponding to wdSeparatorHyphen>;
In my experience, you have to get the values from the enumerations, such as wdCaptionNumberStyleArabic and wdSeparatorHyphen from a VBA script then hard-code them. You can try the following, but I don't think it works:
o.NumberStyle = 'wdCaptionNumberStyleArabic';
o.Separator = 'wdSeparatorHyphen';

Instead of hard-coding the text values into the code, you can use the enum constants. This will help when a different language of Word is installed.
A list of the Enums can be found here: https://learn.microsoft.com/en-us/office/vba/api/word(enumerations)
So instead of:
Word.Selection.InsertCaption('Table', '', '', 0, false) %# wdCaptionPositionAbove
you can use this:
NET.addAssembly('Microsoft.Office.Interop.Word')
Word.Selection.InsertCaption(...
Microsoft.Office.Interop.Word.WdCaptionLabelID.wdCaptionTable.GetHashCode,...
' My custom table caption text', '', ...
Microsoft.Office.Interop.Word.WdCaptionPosition.wdCaptionPositionAbove.GetHashCode, false)

Related

dicom header personal information conversion to a .txt file

I have a series of DICOM Images which I want to anonymize, I found few Matlab codes and some programs which do the job, but none of them export a .txt file of removed personal information. I was wondering if there is a function which can also save removed personal information of a DICOM images in .txt format for features uses. Also, I am trying to create a table which shows the corresponding new images ID to their real name.(subjects real name = personal-information-removed image ID)
Any thoughts?
Thanks for considering my request!
I'm guessing you only want to output to your text file the fields that are changed by anonymization (either modified, removed, or added). First, you may want to modify some dicomanon options to reduce the number of changes, in particular passing the arguments 'WritePrivate', true to ensure private extensions are kept.
First, you can perform the anonymization, saving structures of pre- and post-anonymization metadata using dicominfo:
preAnonData = dicominfo('input_file.dcm');
dicomanon('input_file.dcm', 'output_file.dcm', 'WritePrivate', true);
postAnonData = dicominfo('output_file.dcm');
Then you can use fieldnames and setdiff to find fields that are removed or added by anonymization, and add them to the post-anonymization or pre-anonymization data, respectively, with a nan value as a place holder:
preFields = fieldnames(preAnonData);
postFields = fieldnames(postAnonData);
removedFields = setdiff(preFields, postFields);
for iField = 1:numel(removedFields)
postAnonData.(removedFields{iField}) = nan;
end
addedFields = setdiff(postFields, preFields);
for iField = 1:numel(addedFields)
preAnonData.(addedFields{iField}) = nan;
end
It will also be helpful to use orderfields so that both data structures have the same ordering for their field names:
postAnonData = orderfields(postAnonData, preAnonData);
Finally, now that each structure has the same fields in the same order we can use struct2cell to convert their field data to a cell array and use cellfun and isequal to find any fields that have been modified by the anonymization:
allFields = fieldnames(preAnonData);
preAnonCell = struct2cell(preAnonData);
postAnonCell = struct2cell(postAnonData);
index = ~cellfun(#isequal, preAnonCell, postAnonCell);
modFields = allFields(index);
Now you can create a table of the changes like so:
T = table(modFields, preAnonCell(index), postAnonCell(index), ...
'VariableNames', {'Field', 'PreAnon', 'PostAnon'});
And you could use writetable to easily output the table data to a text file:
writetable(T, 'anonymized_data.txt');
Note, however, that if any of the fields in the table contain vectors or structures of data, the formatting of your output file may look a little funky (i.e. lots of columns, most of them empty, except for those few fields).
One way to do this is to store the tags before and after anonymisation and use these to write your text file. In Matlab, dicominfo() will read the tags into a structure:
% Get tags before anonymization
tags_before = dicominfo(file_in);
% Anoymize
dicomanon(file_in, file_out); % Need to set tags values where required
% Get tags after anonymization
tags_after = dicominfo(file_out);
% Do something with the two structures
disp(['Patient ID:', tags_before.PatientID ' -> ' tags_after.PatientID]);
disp(['Date of Birth:', tags_before.PatientBirthDate ' -> ' tags_after.PatientBirthDate]);
disp(['Family Name:', tags_before.PatientName.FamilyName ' -> ' tags_after.PatientName.FamilyName]);
You can then write out the before/after fields into a text file. You'd need to modify dicomanon() to choose your own values for the removed fields, since by default they are set to empty.

Saving figure without providing filename [duplicate]

this question about matlab:
i'm running a loop and each iteration a new set of data is produced, and I want it to be saved in a new file each time. I also overwrite old files by changing the name. Looks like this:
name_each_iter = strrep(some_source,'.string.mat','string_new.(j).mat')
and what I#m struggling here is the iteration so that I obtain files:
...string_new.1.mat
...string_new.2.mat
etc.
I was trying with various combination of () [] {} as well as 'string_new.'j'.mat' (which gave syntax error)
How can it be done?
Strings are just vectors of characters. So if you want to iteratively create filenames here's an example of how you would do it:
for j = 1:10,
filename = ['string_new.' num2str(j) '.mat'];
disp(filename)
end
The above code will create the following output:
string_new.1.mat
string_new.2.mat
string_new.3.mat
string_new.4.mat
string_new.5.mat
string_new.6.mat
string_new.7.mat
string_new.8.mat
string_new.9.mat
string_new.10.mat
You could also generate all file names in advance using NUM2STR:
>> filenames = cellstr(num2str((1:10)','string_new.%02d.mat'))
filenames =
'string_new.01.mat'
'string_new.02.mat'
'string_new.03.mat'
'string_new.04.mat'
'string_new.05.mat'
'string_new.06.mat'
'string_new.07.mat'
'string_new.08.mat'
'string_new.09.mat'
'string_new.10.mat'
Now access the cell array contents as filenames{i} in each iteration
sprintf is very useful for this:
for ii=5:12
filename = sprintf('data_%02d.mat',ii)
end
this assigns the following strings to filename:
data_05.mat
data_06.mat
data_07.mat
data_08.mat
data_09.mat
data_10.mat
data_11.mat
data_12.mat
notice the zero padding. sprintf in general is useful if you want parameterized formatted strings.
For creating a name based of an already existing file, you can use regexp to detect the '_new.(number).mat' and change the string depending on what regexp finds:
original_filename = 'data.string.mat';
im = regexp(original_filename,'_new.\d+.mat')
if isempty(im) % original file, no _new.(j) detected
newname = [original_filename(1:end-4) '_new.1.mat'];
else
num = str2double(original_filename(im(end)+5:end-4));
newname = sprintf('%s_new.%d.mat',original_filename(1:im(end)-1),num+1);
end
This does exactly that, and produces:
data.string_new.1.mat
data.string_new.2.mat
data.string_new.3.mat
...
data.string_new.9.mat
data.string_new.10.mat
data.string_new.11.mat
when iterating the above function, starting with 'data.string.mat'

Adding specific letters to a string MATLAB

I'm a neuroscience/biomedical engineering major struggling with this whole MATLAB programming ordeal and so far, this website is the best teacher available to me right now. I am currently having trouble with one of my HW problems. What I need to do is take a phrase, find a specific word in it, then take a specific letter in it and increase that letter by the number indicated. In other words:
phrase = 'this homework is so hard'
word = 'so'
letter = 'o'
factor = 5
which should give me 'This homework is sooooo hard'
I got rid of my main error, though I really don;t know how. I exited MATLAB, then got back into it. Lo and behold, it magically worked.
function[out1] = textStretch(phrase, word, letter, stretch)
searchword= strfind(phrase, word);
searchletter strfind(hotdog, letter); %Looks for the letter in the word
add = (letter+stretch) %I was hoping this would take the letter and add to it, but that's not what it does
replace= strrep(phrase, word, add) %This would theoretically take the phrase, find the word and put in the new letter
out1 = replace
According to the teacher, the ones() function might be useful, and I have to concatenate strings, but if I can just find it in the string and replace it, why do I need to concatenate?
Since this is homework I won't write the whole thing out for you but you were on the right track with strfind.
a = strfind(phrase, word);
b = strfind(word, letter);
What does phrase(1:a) return? What does phrase(a+b:end) return?
Making some assumptions about why your teacher wants you to use ones:
What does num = double('o') return?
What does char(num) return? How about char([num num])?
You can concatenate strings like this:
out = [phrase(1:a),'ooooo',phrase(a+b:end)];
So all you really need to focus on is how to get a string which is letter repeated factor times.
If you wanted to use strrep instead you would need to give it the full word you are searching for and a copy of that word with the repeated letters in:
new_phrase = strrep(phrase, 'so', 'sooooo');
Again, the issue is how to get the 'sooooo' string.
See if this works for you -
phrase_split = regexp(phrase,'\s','Split'); %// Split into words as cells
wordr = cellstr(strrep(word,letter,letter(:,ones(1,factor))));%// Stretched word
phrase_split(strcmp(phrase_split,word)) = wordr;%//Put stretched word into place
out = strjoin(phrase_split) %// %// Output as the string cells joined together
Note: strjoin needs a recent MATLAB version, which if unavailable could be obtained from here.
Or you can just use a hack obtained from the m-file itself -
out = [repmat(sprintf(['%s', ' '], phrase_split{1:end-1}), ...
1, ~isscalar(phrase_split)), sprintf('%s', phrase_split{end})]
Sample run -
phrase =
this homework is so hard and so boring
word =
so
letter =
o
factor =
5
out =
this homework is sooooo hard and sooooo boring
So, just wrap the code into a function wrapper like this -
function out = textStretch(phrase, word, letter, factor)
Homework molded edit:
phrase = 'this homework is seriously hard'
word = 'seriously'
letter = 'r'
stretch = 6
out = phrase
stretched_word = letter(:,ones(1,stretch))
hotdog = strfind(phrase, word)
hotdog_st = strfind(word,letter)
start_ind = hotdog+hotdog_st-1
out(start_ind+stretch:end+stretch-1) = out(start_ind+1:end)
out(hotdog+hotdog_st-1:hotdog+hotdog_st-1+stretch-1) = stretched_word
Output -
out =
this homework is serrrrrriously hard
As again, use this syntax to convert to function -
function out = textStretch(phrase, word, letter, stretch)
Well Jessica first of all this is WRONG, but I am not here to give you the solution. Could you please just use it this way? This surely run.
function main_script()
phrase = 'this homework is so hard';
word = 'so';
letter = 'o';
factor = 5;
[flirty] = textStretchNEW(phrase, word, letter, factor)
end
function [flirty] = textStretchNEW(phrase, word, letter, stretch)
hotdog = strfind(phrase, word);
colddog = strfind(hotdog, letter);
add = letter + stretch;
hug = strrep(phrase, word, add);
flirty = hug
end

Create an array of strings

Is it possibe to create an array of strings in MATLAB within a for loop?
For example,
for i=1:10
Names(i)='Sample Text';
end
I don't seem to be able to do it this way.
You need to use cell-arrays:
names = cell(10,1);
for i=1:10
names{i} = ['Sample Text ' num2str(i)];
end
You can create a character array that does this via a loop:
>> for i=1:10
Names(i,:)='Sample Text';
end
>> Names
Names =
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
However, this would be better implemented using REPMAT:
>> Names = repmat('Sample Text', 10, 1)
Names =
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Sample Text
Another option:
names = repmat({'Sample Text'}, 10, 1)
New features have been added to MATLAB recently:
String arrays were introduced in R2016b (as Budo and gnovice already mentioned):
String arrays store pieces of text and provide a set of functions for
working with text as data. You can index into, reshape, and
concatenate strings arrays just as you can with arrays of any other
type.
In addition, starting in R2017a, you can create a string using double quotes "".
Therefore if your MATLAB version is >= R2017a, the following will do:
for i = 1:3
Names(i) = "Sample Text";
end
Check the output:
>> Names
Names =
1×3 string array
"Sample Text" "Sample Text" "Sample Text"
No need to deal with cell arrays anymore.
Another solution to this old question is the new container string array, introduced in Matlab 2016b. From what I read in the official Matlab docs, this container resembles a cell-array and most of the array-related functions should work out of the box. For your case, new solution would be:
a=repmat('Some text', 10, 1);
This solution resembles a Rich C's solution applied to string array.
As already mentioned by Amro, the most concise way to do this is using cell arrays. However, Budo touched on the new string class introduced in version R2016b of MATLAB. Using this new object, you can very easily create an array of strings in a loop as follows:
for i = 1:10
Names(i) = string('Sample Text');
end
one of the simplest ways to create a string matrix is as follow :
x = [ {'first string'} {'Second parameter} {'Third text'} {'Fourth component'} ]

How to convert a numeric variable to a string in MATLAB

A=rand(10)
B=find(A>98)
How do you have text saying "There were 2 elements found" where the 2 is general i.e. it isn't text, so that if I changed B=find(A>90) it would automatically no longer be 2.
some_number = 2;
text_to_display = sprintf('There were %d elements found',some_number);
disp(text_to_display);
Also, if you wanted to count the number of elements greater than 98 in A, you should one of the following:
numel(find(A>98));
Or
sum(A>98);
sprintf is a very elegant way to display such data and it's quite easy for a person with a C/C++ background to start using it. If you're not comfortable with the format-specifier syntax (check out the link) then you can use:
text_to_display = ['There were ' num2str(some_number) ' elements found'];
But I would recommend sprintf :)