cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Check out the JMP® Marketplace featured Capability Explorer add-in
Choose Language Hide Translation Bar
SDF1
Super User

Help Scripting an Interactive window that updates upon user choices

Dear All,

 

  I am writing a script that will be deployed to users in my organization to perform some simple quick statistics for the user without having to invoke the Distribution platform. The script is below with a screenshot of what I currently have, then a list of the things I'm having trouble with. The users will be running JMP 16.1, I am running JMP Pro 16.0. All machines are windows 10, 64-bit machines.

 

  The intended purpose of the script is to show the numerical columns (maybe later I will deal with categorical columns) and depending on which radio button is selected, it will perform some simple statistics and display the results in the same window with a column labeled Stats for the type of statistic calculated and Values for the results of said calculations. The Results panel box should update upon the selection of the radio button after they have selected the appropriate column in the Select Column panel box.

 

Current JMP script (FYI, I'm testing it out on the familiar Big Class.jmp file):

Names Default To Here( 1 );
//Clear Symbols();
//the width of the column list box in pixels
lbWidth = 100;

dt = Current Data Table();

//List of statistics to calculate
StatsListA = {"Mean", "Std Dev", "Max", "Min", "Range", "N"};
StatsListB = {"95% quantile", "50% quantile", "5% quantile"};
StatsListC = {};

//Expression to do math
MathA = Expr(
	response_col = Column( dt, Eval( Eval Expr( Expr( ycols ) ) ) );
	ymean = Col Mean( response_col );
	ystdev = Col Std Dev( response_col );
	ymin = Col Min( response_col );
	ymax = Col Max( response_col );
	yrange = ymax - ymin;
	yN = Col Number( response_col );
	NumResultsA = {ymean, ystdev, ymin, ymax, yrange, yN};
);

//Expresseion for other math
MathB = Expr(
	
);

ValueDlg = Expr(
	nwin = New Window( "GUI for quick stats",
		<<Return Result,
		<<On Validate,
		Border Box( Left( 3 ), Top( 2 ),
			V List Box(
				Text Box( "Quick Stats Window", <<Set Font Size( 12 ) ),
				H List Box(
					V List Box(
						Panel Box( "Select Columns", ColListData = Col List Box( dt, All, Grouped, width( lbWidth ), nLines( 10 ) ) ),
						Panel Box( "Choose quick stats",
							V List Box(
								qstats = Radio Box(
									{StatsListA, StatsListB, StatsListC},
									<<Set Function(
										Function( {this, index},
											{lb},
											lb = this << sib;
											((lb << child) << sib) << Set Text( Char( index ) );
											((((lb << child) << sib) << sib) << sib) << Set Text( Char( this << get selected ) );
										)
									)
								)
							)
						), 

					),
					Panel Box( "Results", Lineup Box( N Col( 1 ), H List Box( String Col Box( "Stats", {} ), Number Col Box( "Values", {} ) ) ) ),
					Panel Box( "Action",
						Lineup Box( N Col( 1 ),
							Button Box( "Cancel/End", nwin << Close Window ),
							Text Box( " " ),
							Button Box( "Help", Web( "https://www.jmp.com/en_ch/support/online-help-search.html?q=*%3A*" ) )
						)
					), 

				), 

			), 

		), 

	);

);

ValueDlg;

 

This is what I have so far:

DiedrichSchmidt_0-1632406235583.png

 

Here is the list of things I'm having trouble with:

  1. The call for the Radio Box() lists the local variable name "StatsListA", etc. instead of actually listing out the stats that will be calculated. For example, the first radio button should have the following list behind it: Mean, Std Dev, Max, Min, Range, N. This should also be for the StatsListB and StatsListC (I haven't defined the C list yet). I'm not sure how to get it to evaluate the pre-defined list I make at the top of the JSL code. I'd prefer not to have to write out each and every item as I might want to change the items in the list and it's easier to change the local variable StatsListX instead of editing the Radio Box() call each time.
  2. Right now, I'd prefer to not list ALL columns, but just numeric. When I change the option in Col List Box() from All to Numeric (with or without ""), I get an empty list of columns. Can't figure out why this is happening, when it should list only the Numeric columns when I have that option defined.
  3. This is the hardest one I think: As mentioned before, I'd like the results in the Panel box "Results" to be updated with a column on the left "Stats" (which lists the statistics from StatsListX and the calculation results for those stats in the right column "Values". This should be updated with each click of a radio button. So if you were originally looking at :height, but wanted to look at :weight, you'd select :weight and then click on one of the radio buttons to get the relevant statistical summary. I tried following the Set Function example shown here, but have been unsuccessful (I do not know the Set Function call very well).DiedrichSchmidt_1-1632406884261.png

 

  The Expr() for the MathA was intended to be called by closing the original window and opening a new one with the results, but after doing some more research in the JMP Discussions, I found that one can update fields within an existing window, which is how I prefer to approach this problem. So, I know that original coding at the top of my code is not the right code for what I intend to do.

 

  Any help on this is much appreciated.

 

Thanks!,

DS

11 REPLIES 11
ErraticAttack
Level VI

Re: Help Scripting an Interactive window that updates upon user choices

Throwing in my two cents here.  It is often best to separate the script as much as possible into logically isolated units or functions.  To that end, I find it much better to remove the logic from the display tree and to flatten the function definitions as much as possible.

 

In my example solution below you'll see that all functions are scoped to the self namespace and that the first line in each function scopes the self namespace.  In practice what I've done is to create a meta-programming wrapper that does this automatically such that I don't have to explicitly define the self namespace or include the self = Namespace( "name" ) line as the first argument of each function.  If you create many interactive GUI's you may want to do something similar as it saves a great deal of work.  This also has the benefit of not needing to wrap the script in an Eval( Eval Expr( "<CODE>" ) ) block.

 

Also, if you go down this route, I find it easiest to produce a wrapper for the Builtin display boxes that can directly call the self functions and not have a need to put so much boiler-plate within the << Set Function() messages.

 

 

/* quick stats */

self = New Namespace();
self:tool name = "Quick Stats";

Eval( Eval Expr(

self:initialize = Function( {}, // called before the display tree is generated
	self = Namespace( Expr( self << Get Name ) );
	self:table = Current Data Table();
	self:radio inputs = {
		"Mean, Std Dev, Max, Min, Range, N",
		"Quantiles: 0.05, 0.25, 0.50, 0.75, 0.95",
		"N, N Missing, N Zero, Prop 0, Prop non-0"
	};
	self:stat list = {
		{"Mean", "Std Dev", "Max", "Min", "Range", "N"},
		{"5%", "25%", "50%", "75%", "95%"},
		{"N", "N Missing", "N Zero", "Prop 0", "Prop non-0"}
	};
	1
);

self:content = Function( {},  // holds the display tree
	self = Namespace( Expr( self << Get Name ) );
	self:container = H Splitter Box(
		V List Box(
			H List Box(
				Lineup Box( N Col( 1 ), Spacing( 0 ),
					Spacer Box( <<Set Auto Stretching( 1, 0 ) )
				,
					Panel Box( "Select Column:",
						Lineup Box( N Col( 1 ), Spacing( 0 ),
							Spacer Box( <<Set Auto Stretching( 1, 0 ) )
						,
							self:column box = Col List Box( self:table, All,
								Max Selected( 1 ), Grouped, N Lines( 10 ),
								<<Set Data Type( "Numeric" ),
								<<Set Function(
									Function( {this},
										self = Namespace( Expr( self << Get Name ) );
										Try(
											self:handle column choice
										,
											Show( exception_msg )
										)
									)
								)
							)
						)
					)
				,
					Panel Box( "Choose Quick Stats:", 
						self:radio box = Radio Box( self:radio inputs,
							<<Set Function(
								Function( {this},
									self = Namespace( Expr( self << Get Name ) );
									Try(
										self:handle radio choice
									,
										Show( exception_msg )
									)
								)
							)
						)
					)
				)
			,
				Lineup Box( N Col( 1 ), Spacing( 0 ),
					Panel Box( "Results",
						self:results container box = V List Box()
					)
				)
			)
		,
			H List Box(
				Button Box( "Cancel", <<Set Function(
					Function( {this},
						self = Namespace( Expr( self << Get Name ) );
						Try( self:exit );
						1
					)
				) )
			,
				Spacer Box( <<Set Auto Stretching( 1, 0 ) )
			,
				Button Box( "Help", Web( "https://www.jmp.com/en_ch/support/online-help-search.html?q=*%3A*" ) )
			)
		)
	,
		Spacer Box( <<Set Auto Stretching( 1, 0 ) )
	)
);
self:finalize = Function( {}, // called after the display tree is generated
	self = Namespace( Expr( self << Get Name ) );
	self:column box << Set Selected( 1, 1 );
	self:container << Set Sizes( {0.01, 0.99} );
	1
);

self:handle column choice = Function( {},
	self = Namespace( Expr( self << Get Name ) );
	self:handle radio choice;
);

self:exit = Function( {},
	self = Namespace( Expr( self << Get Name ) );
	self:window << Close Window
);

self:calculate stats = Function( {},
	{Default Local},
	self = Namespace( Expr( self << Get Name ) );
	res = {};
	sel = self:radio box << Get;
	column = Insert( {}, self:column box << Get Selected );
	column = column[1];
	Match( sel,
		1,
			Insert Into( res, Col Mean( Column( self:table, column ) ) );
			Insert Into( res, Col Std Dev( Column( self:table, column ) ) );
			Insert Into( res, max = Col Max( Column( self:table, column ) ) );
			Insert Into( res, min = Col Min( Column( self:table, column ) ) );
			Insert Into( res, max - min );
			Insert Into( res, N Rows( self:table ) );
	,
		2,
			Insert Into( res, Col Quantile( Column( self:table, column ), 0.05 ) );
			Insert Into( res, Col Quantile( Column( self:table, column ), 0.25 ) );
			Insert Into( res, Col Quantile( Column( self:table, column ), 0.50 ) );
			Insert Into( res, Col Quantile( Column( self:table, column ), 0.75 ) );
			Insert Into( res, Col Quantile( Column( self:table, column ), 0.95 ) );
	,
		3,
			Insert Into( res, N Rows( self:table ) );
			Insert Into( res, Col N Missing( Column( self:table, column ) ) );
			Eval( Parse( Eval Insert( JSL Quote(
				rows = self:table << Get Rows Where( :Name("^column^" ) == 0 )
			) ) ) );
			Insert Into( res, n zero = N Rows( rows ) );
			Insert Into( res, n zero / N Rows( self:table ) );
			Insert Into( res, 1 - n zero / N Rows( self:table ) );
	);
	res
);

self:handle radio choice = Function( {},
	{Default Local},
	self = Namespace( Expr( self << Get Name ) );
	sel = self:radio box << Get;
	vals = self:calculate stats;
	name = "Stats";
	If( sel == 2, name = "Quantiles" );
	string col box = String Col Box( name, self:stat list[sel] );
	number col box = Number Col Box( "Values", vals );
	Try( self:results box << Delete );
	self:results container box << Append( self:results box = Table Box(
		string col box, number col box
	) )
);

) );

Eval( Eval Expr(

self:initialize();
self:window = New Window( self:tool name,
	<<On Close(
		self = Namespace( Expr( self << Get Name ) );
		Try( self:destroy );
		self << Delete Namespace();
		1
	)
,
	self:content
);
self:window << Update Window; self:finalize(); ) ); self << Get Name;

 

 

Jordan
Ressel
Level VI

Re: Help Scripting an Interactive window that updates upon user choices

This is so neat. Thank you for this discussion.