You are not authorized to post comments.

Script reusability, functions, and includes in JSL

 (or... how to avoid writing unmaintainable JSL)

One struggle I had for a long time with writing JSL code was that I was writing the code to automate multiple regression analyses across many different sets of data. Clearly this is what the JSL language was meant to do - speed up repetitive tasks - but I quickly began drowning in a sea of repetitive scripts that only changed by a few key variables throughout the very long and ugly scripts.  It took me a long while to figure out how to string different JSL scripts together to improve the modularity of my code, but once I did I found that it saved me considerable work whenever a change to each script needed to be made.

First, I like to include any global type variables in one script so that I don't have to search through scripts to update file path names, hard-coded variables, and other values that recur throughout my scripts.  I suggest calling this script "Globals.JSL" or something similar.  Next, I like to create scripts that automatically run queries off of centralized databases such as SAS or SQL Server.  I like to call this script "RunQueries.JSL".  Let's pretend this is all you wanted to do: setup global variables and then query the database, but you wanted to keep these scripts separate.  Here's how you would do it by including the following line in a new script, which for sake of argument we will call "RunMultipleScripts.JSL":

include(<path and name of the "Globals.JSL" script goes here in double quotes>);
include(<path and name of the "RunQueries.JSL" script goes here in double quotes>);

That's it! It's very simply, and there is documentation in JMP's PDF file on scripting, but it took me a long time to figure out that "include()" was the function I needed to use to run a script, from a script.  Scripts are executed in the order that you "include" them within a script, and I've found it can sometimes be easier to just maintain multiple JSL files than to try and write a ton of functions that are passing data all over the place in one singular JSL script.

Writing small, simple scripts that are focused on one thing - setting up global variables, querying data, formatting a data table, running an analysis, etc. - will allow you to troubleshoot errors much easier, and provide faster maintainability when you decide to make a change to just one part of your automated process.

Function calls in JMP

Now for some slightly more advanced JSL script "objectification"...

In addition to including scripts to improve code modularity, JSL includes mechanisms to utilize function calls throughout your code.  While this information is included in the JMP pdf file on scripting, it may not be entirely obvious for the non-programmer on how to use this feature of JSL.  Let's dissect a snippet of code from two files:

File #1: AggregateData.JSL

include(path || "reformat_tables.JSL");
dt1=Open(path || "AggregateTable.JMP");
renameColumns(dt1);

File #2: reformat_tables.JSL

renameColumns = function({dt},
	Column(1)<<Set Name("Date");
	Column(2)<<Set Name("LastName");
	Column(3)<<Set Name("Age");
);

Let's unpack what's happening here. In File 1, we first include File 2, then we open a datatable and assign it to the variable "dt1", and then make a function call to the function 'renameColumns' with the input variable of "dt1".

In File 2 we must define the function 'renameColumns'. Use the keyword "function" to define that 'renameColumns' will be defined as a function variable. In brackets you can define as many variables as you wish, delimited by commas at the beginning of your function, followed by whatever code JMP will accept as valid code. In this instance, my subsequent calls of [ Column(1)<<Set Name("Date"); ] are going to automatically attempt to act on the active datatable that the function has access to, so technically you could write [ dt<<Column(1)<<Set Name("Date"); ] for better code readability, but I was lazy and didn't do that here.

The 'renameColumns' function will perform the code that needs to run, and when completed will return control to the next line of code in File 1. In JSL, what is really happening is that by including File 2 when File 1 is run, all of the functions and code in File 2 is added to memory and becomes available to File 1. Therefore, it is good practice to not load every script that you may need at the very beginning of File 1, and only load scripts as needed to keep memory usage down. (JSL isn't a compiled language like 
C/C++, nor does it do garbage collection like Java, so it's good practice to not load as much as you can in memory up front, because you'll just slow down the computer with unnecessary memory allocation to unused code by doing so.)