cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
New to using JMP? Hit the ground running with the Early User Edition of Discovery Summit. Register now, free of charge.
Register for our Discovery Summit 2024 conference, Oct. 21-24, where you’ll learn, connect, and be inspired.
Choose Language Hide Translation Bar
Creating JSL functions implemented in Python

Recently I gave an internal JMP talk on Python Tips and Tricks. There's one tip in particular that I think is powerful, so I'd like to share it with you: creating a JSL function that wraps the call to a Python function. In other words, this is utility code that can be written in Python but given a JSL interface. For ease of illustration, I've implemented a simple Python function that takes two objects and adds them together, then wraps that call in a JSL function. I start with three different types of data (numeric, string, and lists) and a function that adds the two Python objects together.

 

Names Default to Here(1);
one = 1;
two = 2;
author = "Paul Nelson";
devel = "Developer: ";
list1 = { 1, 3, 5, 7 };
list2 = { 2, 4, 6, 8 };

Python Submit("\[

def plus(a,b):
   print(a, b)
   return a+b
]\");

Any Python object that supports the "+" operator can be handled by this Python function. 

// Python Execute is an underutilized gem.  You can send a list
// of inputs and get a list of results and execute code all in one 
// JSL statement.
Python Execute( {one, two}, {result}, "result = plus(one,two)" );
show(result);

The result:

result = plus(one,two)
/*:
1.0
2.0

result = 3;

This is where things get fun! In particular, a JSL function that wraps the Python defined plus() function.

// create a JSL function that wraps the the Python function
blow_mind = Function( {first, second}, // parameters
    {pyresult}, // local variables
    Python Execute( {first, second}, {pyresult}, "pyresult = plus(first,second)");
    Return( pyresult ); // value to return
); // end of the definition

// Call the Python function through our JSL function.  Good way to extend JSL
// using code written in Python.  Could be useful for add-ins. 
// Notice the same Python function handling different types of Python objects.
show( blow_mind(devel, author) );
show( blow_mind(list1, list2) );

Giving the results:

//:*/
pyresult = plus(first,second)
/*:
Developer:  
Paul Nelson

blow_mind(devel, author) = "Developer: Paul Nelson";
//:*/
pyresult = plus(first,second)
/*:
[1, 3, 5, 7]
 [2, 4, 6, 8]

blow_mind(list1, list2) = {1, 3, 5, 7, 2, 4, 6, 8};

Our trivial plus() function handled summation of numeric values, as well as concatenation of both strings and lists, which are all callable as a JSL function. The rest of the JSL code is blissfully unaware that what was actually called occurred in Python.

 

Complete file attached.

Last Modified: Apr 30, 2024 9:30 AM
Comments
Craige_Hales
Super User

Thanks for the improved Python support @Paul_Nelson !


Browser Scripting with Python Selenium shows this

// 1: navigate to jmp.com

nav = Function( {url}, {rc},
    Python Execute( {url}, {rc}, 
"\[
try:
    driver.get(url)
    rc = "ok"
except Exception as e:
    rc = repr(e)
]\" );
    return(rc);
);

rc = nav( "https://www.jmp.com/" );
if( rc != "ok", throw("nav: "||char(rc)));

The last two lines are calling through the wrapper function to make a web browser navigate to the JMP web site. The JSL function works exactly the same way as Paul's example.

 

hogi
Level XI

global, multiline Regex search with multiple return values

 

Add Custom Functions(
	New Custom Function(
		"hogi",
		"Regex",
		Function({input, pattern},
		
			SubstituteInto(input,"\!n"," ","\!r", " ") ;
			Python Send( input );
			Python Send( pattern );

			error = Python Submit( "\[
import re
print(input)
matches = re.findall(pattern,input)
]\" );

			matches = Python Get( matches );			
		),
		<<Description(
"Regex via Python with Global setting and multiple return values
	Arguments:
	1) text
	2) pattern
		"
		),
		<<Example( Expr( hogi:Regex( input = "hello\!n hallo hol\!na", pattern = "h.*?l.*?[ao]") ) )
	)
);
Paul_Nelson
Staff

Note regarding @hogi I believe the Function() should have a return(matches); statement.

Also using Python Execute( ) does away with the need to do sends and gets.

 

Add Custom Functions(
	New Custom Function(
		"hogi",
		"Regex",
		Function({input, pattern},
		
			SubstituteInto(input,"\!n"," ","\!r", " ") ;
			Python Execute( {input, pattern}, {matches}, "\[
import re
matches = re.findall(pattern,input)
]\" );
			return( matches);
		),
		<<Description(
"Regex via Python with Global setting and multiple return values
	Arguments:
	1) text
	2) pattern
		"
		),
		<<Example( Expr( hogi:Regex( input = "hello\!n hallo hol\!na", pattern = "h.*?l.*?[ao]") ) )
	)
);

show( hogi:Regex( input = "hello\!n hallo hol\!na", pattern = "h.*?l.*?[ao]") );
hogi
Level XI

ah, right. Python Execute, much nicer : )

In JSL functions, the last expression is the return value - even without enclosing  return().