This website uses Cookies. Click Accept to agree to our website's cookie use as described in our Privacy Policy. Click Preferences to customize your cookie settings.
Created:
Aug 31, 2017 11:11 AM
| Last Modified: Jun 27, 2018 05:32 PM
PAA.jmpaddin
SVM.jmpaddin
538 KB
JMPtoRAddinBuilderWithReport.jmpaddin
SVMWithReport.jmpaddin
JMPtoRAddinBuilder.jmpaddin
Update 27Jun2018: JMPtoRAddinBuilder.jmpaddin now contains unencrypted JSL source files.
Version 2 Update
I am happy to announce that the JMP to R Add-In Builder now supports the output of all output components (table, plot, etc.) as a single report! To enable this feature, install the attached "JMPtoRAddinBuilderWithReport". When defining your output components, check the "Return all results as report" box.
To see an example of the updated output format, scroll to the corresponding section in the post below. The SVM function with the report output enabled is also attached.
What is the JMP to R Add-In Builder?
While JMP is a very powerful statistical software, JMP users may want to extend JMP beyond its included capabilities by accessing some R functionalities.
This summer, in light of the need to make R functions more accessible to JMP users without leaving the JMP platform, I created this guided configuration JMP user interface that allows users to define and use custom JMP add-ins that execute R functions. This add-in allows end users to analyze their data in JMP using R functions without writing JSL or R code.
This program utilizes the JMP to R connection, and can also be adapted to create custom add-ins for functions in other languages, such as Python and JSL itself.
See a video demo of the JMP to R Add-In Builder here or below:
If applicable, install the appropriate packages in R that you will use in your R code.
Usage Notes
If you use column selects or column lists in your add-in, be sure to open your data table prior to running the configuration UI.
Each function created will only have one column list maximum.
All the column selects will be grouped together in one column; enter the same column for all column selects.
Each of the button names for column selects must be unique.
Column selects and column lists will be placed at the top of their respective column.
In your R code, reference your data table as “dt”.
If you are appending a column to a table and are having the user select the column type, in your R code, refer to the string that contains the user’s choice as “colType”.
The values for check boxes are returned as ‘0’ (unchecked) or ‘1’ (checked).
Paste R code in as you normally would in the R console except for the following difference. When referencing the name of a variable as a string as a parameter of a function, use the eval(parse()) function in R. For example:
This evaluates the expression and uses the string stored in colnames(factor)[1] in the function operation.
How It Works: Creating a Support Vector Machine (SVM) Function as an Example
STEP 0
Install and open the JMP to R Add-In Builder.
NOTE: If you use column selects or column lists in your add-in, be sure to open your data table prior to running the configuration UI AND prior to running the add-in you create.Step 0: Install and Open Add-In
STEP 1Step 1: Enter Number of Components and ColumnsThe first screen asks for the number of components* and columns# in your add-in.
*The five types of components supported are: Check Box, Column List, Column Select, Dropdown Menu, and Numeric Value. Each column select comes with its own assignment button, so count each column select and corresponding button as one component.
#The number of columns refer to display columns in which components appear. For example, there are two display columns in the UI for this example (see below).
NOTE: The “Action” column is grouped with the column select column, meaning those two objects grouped together counts as one column.
STEP 2
Next, for each of your components, identify the type.
NOTE: Enter the components in the order you’d like them to appear on your add-in, column-wise. This means that all components in each column must be in sequential order in the dropdowns you specified, but you do not have to enter values strictly column by column.
For example, you can enter the types for component 1, column 1; then component 1, column 2; then component 2, column 1; then component 2, column 2 rather than column by column if you so desire.Step 2: Enter Component Types
STEP 3
For each component, select the column in which it should appear.
On this screen, also define the parameters for each component as follows:
Check Box: Enter the name (label) for the component.
Column List: Other than selecting the column, no action needed.
Column Select: Check all the properties that apply to your selection box.
Dropdown Menu: Enter the label for the dropdown menu and the choices for the menu. DO NOT include a space after commas (i.e. list things as a,b,c,d), but the names and choices themselves can contain spaces. The first name you write in the list will be taken as the name for the dropdown menu, and the rest will be listed as choices in the order in which you type them.
Numeric Value: Enter the name (label) for the component.
Step 3: Enter Component Parameters
STEP 4
If your add-in uses column selects, enter the names for each of the buttons for your corresponding column selects in the order they should appear. Otherwise, click ‘Next’.
Step 4: Enter Column Select Names, if Applicable
STEP 5
This screen displays a preview of the add-in UI you’ve created.
Step 5: Add-In User Interface Preview
STEP 6
On this page, name your add-in and give it a description (which will be displayed under the add-in name).Step 6: Name and Describe Add-In
STEP 7
On this screen, define the input and output variable names that will be used in your R code. These should only be one word (no spaces).
For the output variables, DO NOT include a space after commas (i.e. list variables as a,b,c).Step 7: Define Input and Output Variables
STEP 8
On this screen, enter the R code that your function will run. The R code should be in R syntax (i.e. could be run directly in an R console).
The code should reference the variable names you declared on the previous screen.
Also enter the number of output displays for the function. The four types of output displays currently supported are:
Append Column in Existing Table
Most Recent R Plot
Open Table
Results Window with Text or Numbers
Step 8: Enter R Code and Number of Output Displays
For each of the output displays you have selected, specify the type.Step 9: Select Output Display Types
STEP 10
Provide the parameters for each output display you selected as follows:
For Column Append, enter the name of the column that will be appended to the currently open table, the type of data the column contains, and the output variable specified earlier that will contain the list of values that will populate the column.
For Table, enter the output variable specified earlier that will contain the table.
For R Plot, enter the format of the graphics you want to retrieve from R (png or jpg).
For Window, enter the results text as it should appear in the results window. If you would like the values of input/output variables to be displayed, surround the variable names with the caret (^) symbol. Also enter the name of the window you’d like to be displayed.
Step 10: Provide Output Display ParametersYou can now find the add-in file in the directory you chose!
To install the add-in, double-click on the add-in and JMP should ask you whether to install it. Click “Install”. It should now appear in your Add-Ins menu in JMP.
To run the add-in, open the data table you’d like to perform the operation on (if applicable) so that it is the current table. Click on your add-in as shown above and the add-in dialog should open.
For this example, the three outputs are a prediction column, confusion matrix, and SVM plot. The results for the inputs shown above are as follows, with the first view being the newly added report output format in version 2:Output view from add-in version 2
Output view from add-in version 1
Editing Add-in
To edit your add-in, open the directory in which you saved your .jmpaddin file. Change the extension to .zip:
Open up the .txt file that has your add-in’s name:
This is your config file. If you wish to make any changes to your add-in, such as R code or variable names, you can directly edit your inputs in this document, save the .txt file and the .zip file, change the extension back to .jmpaddin, and reinstall your add-in. The changes will be reflected if you changed the values correctly.
Please see the attached documentation for a second example (Piecewise Aggregate Approximation of Time Series, R code adapted from here) and other notes. Attached are also the two examples (SVM, PAA) I created with this add-in.
What R add-ins have you created with this add-in? What improvements would you like to see? Let me know in the comments below!
@Alfredo -- this was a summer project completed by one of our interns and we ran out of summer before completing everything that we wanted to (including macOS support). Hopefully we can pick this back up next summer!
This looks like a life-changing feature, but I'm confused about how to use it. My attempt doesn't work, and I don't know why. Most likely, I'm confused about how to pass information from JSL to R or back. Can you please explain the
eval(parse(text=...))
statements? Perhaps it would help me if you colored the text in your example by which functions were JSL and which were R?
If you refer to Usage Note #9, you'll see that eval(parse... is an R function. Also near there you'll see that this only works on Windows OS, so if you're running under OSX, you might get a little frustrated - add your voice for OSX support.
There are other articles demoing how to run R under JMP. If you're needs are simple, you might consult these - passing R code and parameters under JMP is pretty straightforward.
Just a quick note to say that this add-in is now available without encryption. However there are no plans for future development of this add-in at this time. It was a summer intern project in 2017 when Julia was working in the JMP division of SAS. While no new features or bug fixes are planned, we made the source code available so if someone in the community is interested in digging into the code or debugging cases where it doesn't work properly the can do so. If you make improvements or bug fixes, I encourage you to re-post and updated version to the File Exchange for community's benefit.
Best,
Dan Valente
JMP Product Management
Regarding the NRow or NCol error above, if anyone else finds this error, I think I found the cause. A bug in the JSL code generated by the addin builder near line 140. I think the line:
I see this "can also be adapted to create custom add-ins for functions in other languages, such as Python". How would we create a plugin that uses python?
'
var data = div.getElementsByClassName("video-js");
var script = document.createElement('script');
script.src = "https://players.brightcove.net/" + data_account + "/" + data_palyer + "_default/index.min.js";
for(var i=0;i< data.length;i++){
videodata.push(data[i]);
}
}
}
for(var i=0;i< videodata.length;i++){
document.getElementsByClassName('lia-vid-container')[i].innerHTML = videodata[i].outerHTML;
document.body.appendChild(script);
}
}
catch(e){
}
/* Re compile html */
$compile(rootElement.querySelectorAll('div.lia-message-body-content')[0])($scope);
}
if (code_l.toLowerCase() != newBody.getAttribute("slang").toLowerCase()) {
/* Adding Translation flag */
var tr_obj = $filter('filter')($scope.sourceLangList, function (obj_l) {
return obj_l.code.toLowerCase() === newBody.getAttribute("slang").toLowerCase()
});
if (tr_obj.length > 0) {
tr_text = "This post originally written in lilicon-trans-text has been computer translated for you. When you reply, it will also be translated back to lilicon-trans-text.".replace(/lilicon-trans-text/g, tr_obj[0].title);
try {
if ($scope.wootMessages[$rootScope.profLang] != undefined) {
tr_text = $scope.wootMessages[$rootScope.profLang].replace(/lilicon-trans-text/g, tr_obj[0].title);
}
} catch (e) {
}
} else {
//tr_text = "This message was translated for your convenience!";
tr_text = "This message was translated for your convenience!";
}
try {
if (!document.getElementById("tr-msz-" + value)) {
var tr_para = document.createElement("P");
tr_para.setAttribute("id", "tr-msz-" + value);
tr_para.setAttribute("class", "tr-msz");
tr_para.style.textAlign = 'justify';
var tr_fTag = document.createElement("IMG");
tr_fTag.setAttribute("class", "tFlag");
tr_fTag.setAttribute("src", "/html/assets/lingoTrFlag.PNG");
tr_fTag.style.marginRight = "5px";
tr_fTag.style.height = "14px";
tr_para.appendChild(tr_fTag);
var tr_textNode = document.createTextNode(tr_text);
tr_para.appendChild(tr_textNode);
/* Woot message only for multi source */
if(rootElement.querySelector(".lia-quilt-forum-message")){
rootElement.querySelector(".lia-quilt-forum-message").appendChild(tr_para);
} else if(rootElement.querySelector(".lia-message-view-blog-topic-message")) {
rootElement.querySelector(".lia-message-view-blog-topic-message").appendChild(tr_para);
} else if(rootElement.querySelector(".lia-quilt-blog-reply-message")){
rootElement.querySelector(".lia-quilt-blog-reply-message").appendChild(tr_para);
} else if(rootElement.querySelector(".lia-quilt-tkb-message")){
rootElement.querySelector(".lia-quilt-tkb-message").appendChild(tr_para);
} else if(rootElement.querySelector(".lia-quilt-tkb-reply-message")){
rootElement.querySelector(".lia-quilt-tkb-reply-message").insertBefore(tr_para,rootElement.querySelector(".lia-quilt-row.lia-quilt-row-footer"));
} else if(rootElement.querySelector(".lia-quilt-idea-message")){
rootElement.querySelector(".lia-quilt-idea-message").appendChild(tr_para);
}else if(rootElement.querySelector(".lia-quilt-column-alley-left")){
rootElement.querySelector(".lia-quilt-column-alley-left").appendChild(tr_para);
}
else {
if (rootElement.querySelectorAll('div.lia-quilt-row-footer').length > 0) {
rootElement.querySelectorAll('div.lia-quilt-row-footer')[0].appendChild(tr_para);
} else {
rootElement.querySelectorAll('div.lia-quilt-column-message-footer')[0].appendChild(tr_para);
}
}
}
} catch (e) {
}
}
} else {
/* Do not display button for same language */
// syncList.remove(value);
var index = $scope.syncList.indexOf(value);
if (index > -1) {
$scope.syncList.splice(index, 1);
}
}
}
}
}
}
angular.forEach(mszList_l, function (value) {
if (document.querySelectorAll('div.lia-js-data-messageUid-' + value).length > 0) {
var rootElements = document.querySelectorAll('div.lia-js-data-messageUid-' + value);
}else if(document.querySelectorAll('.lia-occasion-message-view .lia-component-occasion-message-view').length >0){
var rootElements = document.querySelectorAll('.lia-occasion-message-view .lia-component-occasion-message-view')[0].querySelectorAll('.lia-occasion-description')[0];
}else {
var rootElements = document.querySelectorAll('div.message-uid-' + value);
}
angular.forEach(rootElements, function (rootElement) {
if (value == '43879' && "TkbArticlePage" == "TkbArticlePage") {
rootElement = document.querySelector('.lia-thread-topic');
}
/* V1.1 Remove from UI */
if (document.getElementById("tr-msz-" + value)) {
document.getElementById("tr-msz-" + value).remove();
}
if (document.getElementById("tr-sync-" + value)) {
document.getElementById("tr-sync-" + value).remove();
}
/* XPath expression for subject and Body */
var lingoRBExp = "//lingo-body[@id = " + "'lingo-body-" + value + "'" + "]";
lingoRSExp = "//lingo-sub[@id = " + "'lingo-sub-" + value + "'" + "]";
/* Get translated subject of the message */
lingoRSXML = doc.evaluate(lingoRSExp, doc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
for (var i = 0; i < lingoRSXML.snapshotLength; i++) {
/* Replace Reply/Comment subject with transalted subject */
var newSub = lingoRSXML.snapshotItem(i);
/*** START : extracting subject from source if selected language and source language is same **/
var sub_L = "";
if (newSub.getAttribute("slang").toLowerCase() == code_l.toLowerCase()) {
if (value == '43879') {
sub_L = decodeURIComponent($scope.sourceContent[value].subject);
}
else{
sub_L = decodeURIComponent($scope.sourceContent[value].subject);
}
} else {
sub_L = newSub.innerHTML;
}
/*** End : extracting subject from source if selected language and source language is same **/
/* This code is placed to remove the extra meta tag adding in the UI*/
try{
sub_L = sub_L.replace('<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />','');
}
catch(e){
}
// if($scope.viewTrContentOnly || (newSub.getAttribute("slang").toLowerCase() != code_l.toLowerCase())) {
if ($scope.viewTrContentOnly) {
if ("TkbArticlePage" == "IdeaPage") {
if (value == '43879') {
if( (sub_L != "") && (sub_L != undefined) && (sub_L != "undefined") ){
document.querySelector('.MessageSubject .lia-message-subject').innerHTML = sub_L;
}
}
}
if ("TkbArticlePage" == "TkbArticlePage") {
if (value == '43879') {
if( (sub_L != "") && (sub_L != undefined) && (sub_L != "undefined") ){
var subTkbElement = document.querySelector('.lia-thread-subject');
if(subTkbElement){
document.querySelector('.lia-thread-subject').innerHTML = sub_L;
}
}
}
}
else if ("TkbArticlePage" == "BlogArticlePage") {
if (value == '43879') {
try {
if((sub_L != "") && (sub_L!= undefined) && (sub_L != "undefined")){
var subElement = rootElement.querySelector('.lia-blog-article-page-article-subject');
if(subElement) {
subElement.innerText = sub_L;
}
}
} catch (e) {
}
/* var subElement = rootElement.querySelectorAll('.lia-blog-article-page-article-subject');
for (var subI = 0; subI < subElement.length; subI++) {
if((sub_L != "") && (sub_L!= undefined) && (sub_L != "undefined")){
subElement[subI].innerHTML = sub_L;
}
} */
}
else {
try {
// rootElement.querySelectorAll('.lia-blog-article-page-article-subject').innerHTML= sub_L;
/** var subElement = rootElement.querySelectorAll('.lia-blog-article-page-article-subject');
for (var j = 0; j < subElement.length; j++) {
if( (sub_L != "") && (sub_L != undefined) && (sub_L != "undefined") ){
subElement[j].innerHTML = sub_L;
}
} **/
} catch (e) {
}
}
}
else {
if (value == '43879') {
try{
/* Start: This code is written by iTalent as part of iTrack LILICON - 98 */
if( (sub_L != "") && (sub_L != undefined) && (sub_L != "undefined") ){
if(document.querySelectorAll('.lia-quilt-forum-topic-page').length > 0){
if(rootElement.querySelector('div.lia-message-subject').querySelector('h5')){
rootElement.querySelector('div.lia-message-subject').querySelector('h5').innerText = decodeURIComponent(sub_L);
} else {
rootElement.querySelector('.MessageSubject .lia-message-subject').innerText = sub_L;
}
} else {
rootElement.querySelector('.MessageSubject .lia-message-subject').innerText = sub_L;
}
}
/* End: This code is written by iTalent as part of iTrack LILICON - 98 */
}
catch(e){
console.log("subject not available for second time. error details: " + e);
}
} else {
try {
/* Start: This code is written by iTalent as part of LILICON - 98 reported by Ian */
if ("TkbArticlePage" == "IdeaPage") {
if( (sub_L != "") && (sub_L != undefined) && (sub_L != "undefined") ){
document.querySelector('.lia-js-data-messageUid-'+ value).querySelector('.MessageSubject .lia-message-subject').innerText = sub_L;
}
}
else{
if( (sub_L != "") && (sub_L != undefined) && (sub_L != "undefined") ){
rootElement.querySelector('.MessageSubject .lia-message-subject').innerText = sub_L;
/* End: This code is written as part of LILICON - 98 reported by Ian */
}
}
} catch (e) {
console.log("Reply subject not available. error details: " + e);
}
}
}
// Label translation
var labelEle = document.querySelector("#labelsForMessage");
if (!labelEle) {
labelEle = document.querySelector(".LabelsList");
}
if (labelEle) {
var listContains = labelEle.querySelector('.label');
if (listContains) {
/* Commenting this code as bussiness want to point search with source language label */
// var tagHLink = labelEle.querySelectorAll(".label")[0].querySelector(".label-link").href.split("label-name")[0];
var lingoLabelExp = "//lingo-label/text()";
trLabels = [];
trLabelsHtml = "";
/* Get translated labels of the message */
lingoLXML = doc.evaluate(lingoLabelExp, doc, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
/* try{
for(var j=0;j,';
}
trLabelsHtml = trLabelsHtml+'