parameter passing in imagej macro - macros

I turn to you all after many hours and visiting lots of websites and tutorials. I need to apply a radial polynomial function to a circular roi. The parameters for the polynomial are calculated for each image elsewhere in my imagej macro.
I have tried process>math>macro and the plugin "Expression" by Ditmer, but I cannot get the syntax correct to pass the variables. Clearly, I am not finding something about passing parameters, despite using & and even full concatenation. In particular, I cannot find an example of Expression being used in macro mode to get the syntax of its arguments.
Here is a sample of code that runs on a single open image:
run("32-bit");
rename("working");
//setTool("oval");
makeOval(30, 37, 444, 444);
p0=1.31061
p1=-0.0023456;
p2=-0.000017459;
selectWindow("working");
//run("Macro...", "code=v=v*(1.31061-0.0023456*d-0.00001745*pow(d,2))");
//run("Macro...", "code=v=v*(&p0+&p1*d+&p2*pow(d,2))");
//run("Expression ", "preset='Radial_cutdown'");
//run("Expression ", "preset='Radial_cutdown_parampass'");
The first run command works. The second does not.
The third uses Ditmer's Expression plugin with the preset code as follows:
i*(1.31061-0.0023456*d-0.00001745*d*d)
0
0
0
maxval
0
0
0
w
h
0
100
This also works. However a preset containing the macro parameters instead of numbers does not:
Radial_cutdown_parampass
i*(&p0+&p1*d+&p2*d*d)
0
0
0
maxval
0
0
0
w
h
0
100
I apologize for asking what should be a simple question, but I admit to being stumped.

Use String concatenation syntax:
run("Macro...", "code=v=v*(" + p0 + "+" + p1 + "*d+" + p2 + "*pow(d,2))");

Related

SPSS/macro: split string into multiple variables

I am trying to split a string variable into multiple dummy coded variables. I used these sources to get an idea of how one would achieve this task in SPSS:
https://www.ibm.com/support/pages/making-multiple-string-variables-single-multiply-coded-field
https://www.spss-tutorials.com/spss-split-string-variable-into-separate-variables/
But when I try to adapt the first one to my needs or when I try to convert the second one to a macro, I fail.
In my dataset I have (multiple) variables that contain a comma seperated string that represents different combinations of selected items (as well as missing values). For each item of a specific variable I want to create a dummy variable. If the item was selected, it should be represented with a 1 in the new dummy variable. If it was not selected, that case should be represented with a 0.
Different input variables can contain different numbers of items.
For example:
ID
VAR1
VAR2
DMMY1_1
DMMY1_2
DMMY1_3
1
1, 2
8
1
1
0
2
1
1, 3
1
0
0
3
3, 1
2, 3, 1
1
0
1
4
2, 8
0
0
0
Here is what I came up with so far ...
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* MACRO SYNTAX.
* DEFINE VARIABLES (in the long run these should/will be inside the macro function, but for now I will leave them outside).
NUMERIC v1 TO v3 (F1).
VECTOR v = v1 TO v3.
STRING #char (A1).
DEFINE split_var(vr = TOKENS(1)).
!DO !#pos=1 !TO char.length(!vr).
COMPUTE #char = char.substr(!vr, !#pos, 1).
!IF (!#char !NE "," !AND !#char !NE " ") !THEN
COMPUTE v(NUMBER(!#char, F1)) = 1.
!IFEND.
!DOEND.
!ENDDEFINE.
split_var vr=VAR1.
EXECUTE.
As I got more errors than I can count, it's hard to narrow down my problem. But I think the problem has something to do with the way I use the char.length() function (and I am a bit confused when to use the bang operator).
If anyone has some insights, I would really appreciate some help :)
There is a fundamental issue to understand about SPSS macro - the macro does not read or interact in any way with the data. All the macro does is manipulate text to write syntax. The syntax created will later work on the actual data when you run it.
So, for example, Your first error is using char.length(!vr) within the syntax. You are trying to get the macro to read the data, calculate the length and use, but that simply can't be done - the macro can only work with what you gave it.
Another example in your code: you calculate #char and then try to use it in the macro as !#char. So that obviously won't work. ! precedes only macro functions or arguments. #char, in your code, is neither, and it can't become one - can't read the data into the macro...
To give you a litte push forward: I understand you want the macro loop to run a different number of times for each variable, but you can't use char.length(!vr). I suggest instead have the macro loop as many times as necessary to be sure you can deal with the longest variable you'll need to work with.
And another general strategy hint - first, create syntax to deal with one specific variable and one specific delimiter. Once this works, start working on a macro, keeping in mind that the only purpose of the macro is to recreate the same working syntax, only changing the parameters of variable name and delimiter.
With my new understanding of the SPSS macro logic (thanks to #eli-k) the problem was quite easy to solve. Here is the working solution.
* DEFINE DATA.
DATA LIST /ID 1 (F) VAR1 2-5 (A) VAR2 6-12 (A).
BEGIN DATA
11, 28
21 1, 3
33, 12, 3, 1
4 2, 8
END DATA.
* DEFINE MACRO.
DEFINE #split_var(src_var = !TOKENS(1)
/dmmy_var_label = !DEFAULT(dmmy) !TOKENS(1)
/dmmy_var_lvls = !TOKENS(1))
NUMERIC !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (F1).
VECTOR #dmmy_vec = !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls).
STRING #char (A1).
LOOP #pos=1 TO char.length(!src_var).
COMPUTE #char = char.substr(!src_var, #pos, 1).
DO IF (#char NE "," AND #char NE " ").
COMPUTE #index = NUMBER(#char, F1).
COMPUTE #dmmy_vec(#index) = 1.
END IF.
END LOOP.
RECODE !CONCAT(!dmmy_var_label,1) TO !CONCAT(!dmmy_var_label, !dmmy_var_lvls) (SYSMIS=0) (ELSE=COPY).
EXECUTE.
!ENDDEFINE.
* CALL MACRO.
#split_var src_var=VAR2 dmmy_var_lvls=8.

Interpretation of # in a string argument to Matlab's quad

One of my students made the following simple error:
f = '#(x)sqrt(1-x^2)';
quad(f,0,1)
which led to a very unexpected (to me) result:
ans =
0 + 1.7119i
Presumably # is getting interpreted as some complex function, but which?

Error running matlab code after compiling

It looks like this has been asked many times, but none of the past posts seem to solve my question. All those had to do with matrix/vector while my code does not have any of these, just simple variables. It takes three variables as arguments. It works perfectly fine within the Matlab environment. I only got the error when I compiled it with mcc -m Normal.m and tried to run with the executable like this "./Normal 1 5 0.5". The complete error message is:
Error using /
Matrix dimensions must agree.
Error in Normal (line 4)
MATLAB:dimagree
It is complaining about line 4: N=2/dt, what is wrong with this?
Here is the code:
function val=Normal(l1,l2,dt)
const=(l2/l1-1);
N=2/dt;
S=1.0/sqrt(l2/l1);
Z(1)=S;
for i=2:N
t= -1+(i-1)*dt;
Z(i)=1.0/sqrt(const*t*t+1);
S=S+2*Z(i);
end
Z(21)=1.0/(l2/l1);
S=S+1.0/sqrt(l2/l1);
val=dt*S/2;
end
But dt is not a scalar when passed into the standalone through the command ./Normal 1 5 0.5. It is a character array with 3 elements ('0', '.','5')!
When passing numerical arguments to a standalone, they are passed as strings. Thus, inside the function, you need to convert '0.5' into a double, and similarly for l1 and l2:
dt = str2num(dt);
l1 = str2num(l1);
l2 = str2num(l2);
Note that you can use isdeployed to determine at runtime if the function is a standalone:
if isdeployed, dt = str2num(dt); end
And you might need to display the result:
if isdeployed, disp(val); end
Result:
>> system('Normal 1 5 0.5');
1.4307
>> Normal(1,5,0.5) % .m function for comparison
ans =
1.4307

Matlab: How do I check the length string got more than certain number

I want to check the length of string got more than 20 characters, if more than 20 then will return 1 else return 0 in matrix form [n x 1]. But now, I get the answer of [1x1]. How do I modify my code in if-else statement to get the ans?
str = {'http://www.mathworks.com/matlabcentral/newsreader/view_thread/324182',
'http://jitkomut.lecturer.eng.chula.ac.th/matlab/text.html',
'http://www.ee.ic.ac.uk/pcheung/teaching/ee2_signals/Introduction%20to%20Matlab2.pdf'};
a = cellfun(#length,str)
if a > 20
'1'
else
'0'
end
Output:
a =
68
57
83
ans =
1
I want the output of, lets say
ans =
1
1
1
In Matlab, you can simply use (no if statement is needed):
a = cellfun(#length,str)
(a>20)'
This will give you:
a =
68 57 83
ans =
1
1
1
As #herohuyongtao mentions, you don't actually need an if, the if will only consider the first element of the matrix that it returns, hence giving you only a single value.
But you could actually do this all in your cellfun by using an anonymous function:
cellfun(#(x)(length(x) > 20), str)
And get the result in one shot.
As there is no equivalent of the c ternary operator (?:) in matlab, you can use the following two statements to replace your if then else statement, and achieve what you ask for:
b(a==a)='0'
b(a>20)='1'
The first line initializes the result array, where all value b defaults to the value of the else branch, i.e. '0',
the second line changes the elements for which the conditional > 20 holds to the value in the then branch, i.e. '1'.
If the output values are boolean, you can simply do:
(a>20)
as #herohuyongtao suggested or use #Dan's answer.

Variable variables in Matlab

I have 30 txt files with data
And I want to create on the fly vectors from that files with the name of "file name"
pathforindependents = 'C:\MatLab\independent\'
independents = dir(fullfile(pathforindependents,'ind*.txt'))
for i = 1:length(independents)
filename = independents(i).name;
r=regexp(filename,'\.','split');
qnumber = r(2)
qtitle=r(3)
qpath = strcat(pathforindependents,filename)
qdata = load(qpath)
mtrxPrefix = 'mtrx_';
v = strcat(mtrxPrefix,qtitle);
eval(???????????????????????)
end
But I dont know how can I do it. No matter what I try Matlab gives me "Undefined function 'eval' for input arguments of type 'cell'." Error?
My data file structure is like
ind.01.AGE.txt
0
1
0
0
0
1
1
0
1
...
At the end I want to reach this
mtrx_AGE =
0
1
0
0
0
1
1
0
1
...
How can I do it ? Thank you.
To put the variables in the base workspace, use assignin:
assignin('base', v, qdata);
As you can see in the assignin documentation, for certain assignment cases you may want to use evalin.
you can use fields within structures with sprintf to name variables on the fly:
for i = 1:100
my_struct.(sprintf('A%s%i','filename',i)) = i^2
end
would make
my_struct.Afilename1 = 1
my_struct.Afilename2 = 4
my_struct.Afilename3 = 9
Read Mathworks TechNote 1103 on why you should avoid using EVAL the way you do. Alternatives include cell arrays or structures.