2022_Q1 MakeOverChallenge: Action on mouse click in various waysThis is the Makeover Challenge Q1 2022.
The goal is to come up with an example, script or guide to fulfill one of the three tasks (all have to do with initiating some action after you click on something in JMP):
- Challenge A: (images and script to create initial data table for opening images attached: 2022Q1_ChallengeA.zip)
- You have: A data table column with images or links to a website or a file (aka expressions)
- You want: to click on one cell of this column and open the link or the image outside of JMP
- The overall goal: clicking in a data table cell should initiate something
- Challenge B: (script to open the data table and to create the report attached: 2022Q1_ChallengeB_starterScript.jsl)
- You have: Big Class and a Graph Builder report of weight by height (see script)
- You want: Closing the Graph Builder report should open a distribution report of "age", save this report as an picture and close the distribution report.
- The overall goal: Closing a window should trigger some action
- Challenge C: (script to open the data table and to create the report attached: 2022Q1_ChallengeC_starterScript.jsl)
- You have: A Graph Builder report on Growth Measurements sample data.
- You want: When clicking on a line or selecting multiple lines (or categories in the legend), you want to generate a subset of the selected rows.
- The overall goal: Clicking on a graph or report should trigger some action
You can work on as many challenges as you like. You can/should submit your answers directly as a reply to this thread.
!!! When submitting, please start in the first line with what challenge your reply refers to, e.g.
CHALLENGE A:
This is my answer...
// this is my code
...
In the next meeting (18 May 2022) we will present some of the answers and I will mark the best answers as solution to this thread.
Looking forward to your submissions 
Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysCHALLENGE C
This is my answer, see full script below.
The lower part adds a row state handler to the table, that triggers the action (see example in Scripting Index).
Names Default To Here( 1 );
// Open Data Table
dt = Open( "$SAMPLE_DATA/Growth Measurements.jmp", invisible );
// Report snapshot: Growth Measurements - Graph Builder
gb = dt << Graph Builder(
Size( 522, 452 ),
Show Control Panel( 0 ),
Legend Position( "Bottom" ),
Graph Spacing( 8 ),
Variables( X( :Age ), Y( :Growth ), Overlay( :Subject ) ),
Elements( Line( X, Y, Legend( 13 ) ) )
);
// This is my code (Georg)
// (see Scripting Index "Make Row State Handler")
// Define a function, that does the action
f = Function( {a},
Current Data Table() << Subset( Selected Rows( 1 ), Selected columns only( 0 ) )
);
// Set up a row state handler, that triggers the execution of a function on any change of row states,
// a change on row selection by clicking on a line in Graph Builder is a change of row states in the table
rs = dt << make row state handler( f );Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysCHALLENGE C
With a mouse box it was not possible to select something, so I changed to a row state handler
Names Default To Here( 1 );
// Open Data Table
dt = Open( "$SAMPLE_DATA/Growth Measurements.jmp", invisible );
// Report snapshot: Growth Measurements - Graph Builder
gb = dt << Graph Builder(
Size( 522, 452 ),
Show Control Panel( 0 ),
Legend Position( "Bottom" ),
Graph Spacing( 8 ),
Variables( X( :Age ), Y( :Growth ), Overlay( :Subject ) ),
Elements( Line( X, Y, Legend( 13 ) ) )
);
active_subset = "";
first_subset = "false";
rsh = dt << make row state handler(
Function( {a},
subtbl = dt << Subset( Selected Rows( 1 ) );
gb << Bring Window To Front;
if(
first_subset == "true",
close(active_subset, no save)
);
active_subset = subtbl;
first_subset = "true";
)
);
Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysCHALLENGE A:
NOTE: I kept this older version since some people had already seen it, but I posted a cleaner solution as a Reply to this one.
Not at all a pretty solution, but it does the job... Hoping for a more elegant one to show up!
This to be added after the starterScript:
// Defining the file name for an image placeholder for displaying on the OS when clicking:
pictFileName = Get Default Directory() || "verylonganduselessname.png"; //name for the temp image file (to be deleted at the end)
dtx:Picture << Set Property("tmpFileName", pictFileName); //saving the name so it can be retrieved from within the table
dtx << On Close( Delete File(pictFileName) ); //make sure we erase the temp image file at the end.
// Setting a Click event handler for the column of interest:
dtx:Picture << Set Property(
"Event Handler",
Event Handler(
Click(JSL Quote( Function(
{thisTable, thisColumn, iRow},
pictFileName = thisTable:thisColumn<< Get Property("tmpFileName"); //recover the path for a temp file
thisTable:thisColumn[iRow] << Save Image( pictFileName ); //save cell contents to temp file
Web( "file://" || pictFileName ) // open the image file
)
)
),
Tip(JSL Quote( Function(
{thisTable, thisColumn, iRow},
"click to open";
)
)
)
)
);
Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysCHALLENGE A
Sorry for jumping the gun with my initial solution... Here's a cleaner one.
Names Default to Here ( 1 );
//path = <YOUR full="" path="" to="" where="" the="" images="" have="" been="" saved="">;
// eg.
// path = "C:\EventHandlerImages\";
path = "$DOCUMENTS\Scripting\2022Q1\ChallengeA\2022Q1_ChallengeA\";
//==========================================================================
//Multiple File Import is new in JMP 14
{dtx} = Multiple File Import(
<<SET folder=""></SET></YOUR>Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysChallenge C
There was unfortunately little else to do as far as challenges A and B are concerned. The solutions provided seemed impeccable. In contrast, I felt that some improvement was still possible for challenge C. A few words on my answer
- I have basically stolen the necessary code from here (@txnelson is, like many other scripters, a rock star to me)
- I have slightly modified the graph by including visible data points, so it is easier to select individual rows
- After selecting the points in the graph, the data table with the subset is not opened immediately. This is done via the button added below the graph
See below the complete script, including the modified graph.
// Open Data Table
dt = Open( "$SAMPLE_DATA/Growth Measurements.jmp",invisible );
// Report snapshot: Growth Measurements - Graph Builder
gb = dt << Graph Builder(
Size( 522, 452 ),
Show Control Panel( 0 ),
Legend Position( "Bottom" ),
Graph Spacing( 8 ),
Variables( X( :Age ), Y( :Growth ), Overlay( :Subject ) ),
Elements(
Points( X, Y, Legend( 17 ), Jitter Limit( 0 ) ), // added markers
Line( X, Y, Legend( 13 ) ) ),
SendToReport( // increased markers to decent size
Dispatch(
{},
"Graph Builder",
FrameBox,
{Marker Size( 6 ), Marker Drawing Mode( "Normal" )}
)
)
);
// my solution (stolen from here: https://community.jmp.com/t5/Discussions/Creating-a-Subset-from-an-Interactive-Graph/td-p/114459)
subsetButton = Button Box( "Dear user, Please press here to create a Subset of the Selected Points immediately",
If( N Rows( dt << get selected rows ) > 0,
dt << subset( selected rows( 1 ), selected columns( 0 ) )
)
);
Report( gb )["Graph Builder"] << append( subsetButton );
Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysChallenge A:
Mostly JMP written code with Add Column Properties. Also added example how to add and open URLs
View more...
Names Default To Here(1);
// Challenge A
path = "2022Q1_ChallengeA"; // path to images
{dtx} = Multiple File Import(
<<SET folder=""></SET>
Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysCHALLENGE B
Add this to the bottom of the script:
gb << On Close(
dist = dt << Distribution( Nominal Distribution( Column( :age ) ) );
image = dist << Get Picture;
path = "$temp/age_dist.png";
image << Save Picture( path, "png" );
dist << Close Window();
Open( path );
);
Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysChallenge B:
View more...
Names Default To Here(1);
// 2022_Q1 MakeOverChallenge: Action on mouse click in various ways
// Challenge B
dt = Open("$SAMPLE_DATA/Big Class.jmp");
//Use expression to make script a bit more clean IF this were to be expanded
create_dist = Expr(
dist = dt << Distribution(Nominal Distribution(Column(:age)), Histograms Only);
wait(1); // add wait so we can see that distribution is created
dist << Save Picture("$TEMP/Big_Class_age_dist.png", png);
dist << Close Window;
);
gb = dt << Graph Builder(
Size(528, 454),
Show Control Panel(0),
Variables(X(:height), Y(:weight)),
Elements(Points(X, Y, Legend(3)), Line Of Fit(X, Y, Legend(5)))
);
gb << On Close(create_dist);
// Open("$TEMP/Big_Class_age_dist.png"); // un-comment to open the image
Re: 2022_Q1 MakeOverChallenge: Action on mouse click in various waysChallenge C:
I definitely suggest doing stuff like this with buttons as it prevents the creation of too many subsets. But here I followed the given challenge and added simple check that we won't at least create same subset twice.
View more...
Names Default To Here(1);
// Open Data Table
dt = Open("$SAMPLE_DATA/Growth Measurements.jmp", invisible);
gb = dt << Graph Builder(
Size(522, 452),
Show Control Panel(0),
Legend Position("Bottom"),
Graph Spacing(8),
Variables(X(:Age), Y(:Growth), Overlay(:Subject)),
Elements(Line(X, Y, Legend(13)))
);
//initialize some variables
prev_rows = [];
dt_list = {};
f = Function({rows_changed},
//Rowstate 1 is selected row
cur_rows = Loc(dt << Get Row States, 1);
//if no rows are selected, don't try to create subsets
If(N Items(cur_rows) == 0,
return()
);
//compare to previous to prevent opening extensive abmount of subsets
If(N Items(cur_rows) == N Items(prev_rows),
If(All(cur_rows == prev_rows),
return();
);
);
dt_subset = dt << Subset(Output table("selected_rows"), Rows(cur_rows), invisible);
Insert Into(dt_list, dt_subset); //keep list to make closing easier
//attempt to bring gb to front, this won't work perfectly without wait
gb << Bring Window To Front;
dt_subset << Show Window(1);
//it is enough if we update prev_rows only when subset was created
prev_rows = cur_rows;
);
rs = dt << make row state handler(f);
/* run this to close all data tables
For Each({dt_ref}, dt_list,
Try(Close(dt_ref, no save), Show(exception_msg));
);
Close(dt, no save);
*/
With Row State Handler we cannot access the event of mouse release so we will still create many subsets if user selects multiple lines one by one from graph (there might be a way to do this with Mouse Box(), but I think using button would be much simpler and easier).