cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Browse apps to extend the software in the new JMP Marketplace
Choose Language Hide Translation Bar
Agustin
Level IV

How to pass columns as arguments for a function

I'm trying to create a function that creates a new column and sets a formula:

 

 

my_function = Function( {name, col1, col2},
	dt << New Column( name, Character);
	Column(dt,name) << Set Formula(
	If(
		:col1 == "Positive" & :col2 ==
		"TRUE",
		"True Positive",
		If(
			:col1 == "Negative" & :col2== "TRUE",
			"False Positive",
			If(
				:col1 == "Negative" & :col2 == "FALSE",
				"True Negative",
				If(
					:col1 == "Positive" & :col2 == "FALSE",
					"False Negative",
					"?"
				)
			)
		)
	)
);
);

 

But when I look at the formula created it passes on col1 rather than the string behind it.

 

Calling the function as:

my_function("New Column", Column("column_1"), Column("column_2"));

 

1 ACCEPTED SOLUTION

Accepted Solutions
jthi
Super User

Re: How to pass columns as arguments for a function

I always pass in columns with names (and table reference). And if you need formula use Insert one expression into another using Eval Insert, Eval Expr, Parse, and Substitute methods to build it (I prefer Eval(EvalExpr()) but in your case I would use Eval(Substitute()). Here is one option how you could handle this

Names Default To Here(1);

dt = Open("$SAMPLE_DATA/Big Class.jmp");


my_function = Function({dt, name, col1, col2},
	new_col = Eval(Substitute(
		Expr(dt << New Column(name, Character, Formula(
			If(_col1_ == "Positive" & _col2_ == "TRUE",
				"True Positive",
				If(_col1_ == "Negative" & _col2_== "TRUE",
					"False Positive",
					If(_col1_ == "Negative" & _col2_ == "FALSE",
						"True Negative",
						If(_col1_== "Positive" & _col2_ == "FALSE",
								"False Negative",
								"?"
						)
					)
				)
			)
		))),
		Expr(_col1_), Name Expr(AsColumn(dt, col1)),
		Expr(_col2_), Name Expr(AsColumn(dt, col2))
	));
	
	return(new_col)
);

col = my_function(dt, "test", "name", "sex");

Also JMP does have option to use elseif (even though it isn't written) and it might work in your case instead if nesting multiple if-statements

View more...
Names Default To Here(1);

dt = Open("$SAMPLE_DATA/Big Class.jmp");


my_function = Function({dt, name, col1, col2},
	new_col = Eval(Substitute(
		Expr(dt << New Column(name, Character, Formula(
			If(_col1_ == "Positive" & _col2_ == "TRUE",
				"True Positive",
			_col1_ == "Negative" & _col2_== "TRUE",
				"False Positive",
			_col1_ == "Negative" & _col2_ == "FALSE",
				"True Negative",
			_col1_== "Positive" & _col2_ == "FALSE",
				"False Negative"
			,
				"?"
			),
		))),
		Expr(_col1_), Name Expr(AsColumn(dt, col1)),
		Expr(_col2_), Name Expr(AsColumn(dt, col2))
	));
	
	return(new_col)
);

col = my_function(dt, "test", "name", "sex");
-Jarmo

View solution in original post

4 REPLIES 4
jthi
Super User

Re: How to pass columns as arguments for a function

I always pass in columns with names (and table reference). And if you need formula use Insert one expression into another using Eval Insert, Eval Expr, Parse, and Substitute methods to build it (I prefer Eval(EvalExpr()) but in your case I would use Eval(Substitute()). Here is one option how you could handle this

Names Default To Here(1);

dt = Open("$SAMPLE_DATA/Big Class.jmp");


my_function = Function({dt, name, col1, col2},
	new_col = Eval(Substitute(
		Expr(dt << New Column(name, Character, Formula(
			If(_col1_ == "Positive" & _col2_ == "TRUE",
				"True Positive",
				If(_col1_ == "Negative" & _col2_== "TRUE",
					"False Positive",
					If(_col1_ == "Negative" & _col2_ == "FALSE",
						"True Negative",
						If(_col1_== "Positive" & _col2_ == "FALSE",
								"False Negative",
								"?"
						)
					)
				)
			)
		))),
		Expr(_col1_), Name Expr(AsColumn(dt, col1)),
		Expr(_col2_), Name Expr(AsColumn(dt, col2))
	));
	
	return(new_col)
);

col = my_function(dt, "test", "name", "sex");

Also JMP does have option to use elseif (even though it isn't written) and it might work in your case instead if nesting multiple if-statements

View more...
Names Default To Here(1);

dt = Open("$SAMPLE_DATA/Big Class.jmp");


my_function = Function({dt, name, col1, col2},
	new_col = Eval(Substitute(
		Expr(dt << New Column(name, Character, Formula(
			If(_col1_ == "Positive" & _col2_ == "TRUE",
				"True Positive",
			_col1_ == "Negative" & _col2_== "TRUE",
				"False Positive",
			_col1_ == "Negative" & _col2_ == "FALSE",
				"True Negative",
			_col1_== "Positive" & _col2_ == "FALSE",
				"False Negative"
			,
				"?"
			),
		))),
		Expr(_col1_), Name Expr(AsColumn(dt, col1)),
		Expr(_col2_), Name Expr(AsColumn(dt, col2))
	));
	
	return(new_col)
);

col = my_function(dt, "test", "name", "sex");
-Jarmo
Agustin
Level IV

Re: How to pass columns as arguments for a function

Thanks a lot, exactly what I needed. Also the elseif is so much better! Thanks for sharing

hogi
Level XII

Re: How to pass columns as arguments for a function

If you prefer to use column (aka :age) instead of Strings ("age") to reference the columns, there are 2 problems to be solved:

  1. a manually generated function evaluates it's arguments.
    So if you use a column as a function argument, Jmp will evaluate it  (i.e. return the value of the current row *)
    to prevent it:
    wrap the column with Name Expr()

  2. In most of the cases Jmp doesn't replace variables (like  "col1") with their value (the respective column),
    e.g. in new column() or << set formula
    →  to force Jmp to do so:
    use Eval(Eval Expr( .... Expr(xyz) ...) to evalute xyz before evaluating the remaining part.

    2b) to prevent Jmp from over-evaluating the column reference (like in *), use Name Expr()again,
    so, in combination, use
    Expr(Name Expr(colX))
    ... wherever you want to use the column 

 

in total:

Names Default To Here(1);

dt = Open("$SAMPLE_DATA/Big Class.jmp");


my_function = Function({name, col1, col2},
	new_col = Eval(Eval Expr(New Column(name, Character, Formula(Expr(Name Expr(col1)) /* #2b */  - Expr(Name Expr(col2))/* #2b */ )))); // #2
);

col = my_function("diff", Name Expr(:height), Name Expr(:weight)); //#1

 

txnelson
Super User

Re: How to pass columns as arguments for a function

Here is one way to handle this

txnelson_0-1717499322110.png

Names Default To Here( 1 );
dt = New Table( "Example",
	Add Rows( 5 ),
	New Column( "a",
		Character,
		"Nominal",
		Set Values( {"Positive", "Positive", "Negative", "Negative", "unknown"} )
	),
	New Column( "b",
		Character,
		"Nominal",
		Set Values( {"TRUE", "FALSE", "TRUE", "FALSE", ""} )
	)
);

my_function = Function( {name, col1, col2},
	dt << New Column( name, Character );
	Eval(
		Eval Expr(
			Column( dt, name ) << Set Formula(
				If(
					as Column( Expr( col1 ) ) == "Positive" & as Column( Expr( col2 ) )
					 == "TRUE", "True Positive",
					as Column( Expr( col1 ) ) == "Negative" & as Column( Expr( col2 ) )
					 == "TRUE", "False Positive",
					as Column( Expr( col1 ) ) == "Negative" & as Column( Expr( col2 ) )
					 == "FALSE", "True Negative",
					as Column( Expr( col1 ) ) == "Positive" & as Column( Expr( col2 ) )
					 == "FALSE", "False Negative",
					"?"
				)
			)
		)
	);
);

my_function( "new column", "a", "b" );
Jim