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