Choose Language Hide Translation Bar
Prompting for columns, totally modally

Prompting the user to select columns is a very common task for a JMP script. While preparing to write your script, there are some things to consider to help you decide what method is the best option.

To start, think about how you want your window to look. In addition to selecting columns, should the window allow the user to specify some other options? Most importantly, how do you want the window to behave?

Modal vs. Non-modal Windows

A modal window will cause the script to stop and wait for user interaction. Once the user interacts with and dismisses the window, the remainder of script will be executed. An example of a modal window is the Preferences window (File > Preferences). JMP will not do anything else until the Preferences window is dismissed.

With a non-modal window, the window remains open and allows the script to complete without waiting for any user interaction. Think about the Fit Model platform launch window (Analyze > Fit Model). Notice that you can leave the window open and perform other tasks in JMP. There is even a checkbox to keep the dialog open after the analysis is created. This is an example of a non-modal window. You might choose to use a non-modal window that remains open so that your user can make a different selection of columns and roles. 

So how do you decide whether to use a modal or non-modal window? The main consideration is whether you want JMP to wait for the user input or not. If the remainder of the script depends upon the user’s selections, then you would want to use a modal window. Since there are two useful methods for creating modal windows, let’s explore the options.

Column Dialog()

Column Dialog() is a built-in function that allows you to quickly generate a modal dialog to prompt users to select columns from the current data table. The script author simply selects the types of display boxes to show in the dialog but has little control over layout. Here is an example script that prompts the user to select two X columns and two Y columns.

Names Default To Here( 1 );

dt = Open( "$SAMPLE_DATA/Fitness.jmp" );
dlg = Column Dialog(
    yList = Col List( "Y",
        Min Col( 2 ), 
        Max Col( 2 ),
        Data Type( "Numeric" )
    ),
    effectList = Col List( "Effects",
        Min Col( 2 ), 
        Max Col( 3 ),
        Data Type( "Numeric" )
    )
);

The window presented to the user looks like this:

 

ColumnDialog.png

 

Notice that the script author only supplied the options for the two Col List display boxes. The list of columns from the current data table on the left is provided as part of the built-in functionality.

After the user makes their selections and clicks ok, the result is a list of the user's choices, as in:

dlg = {yList = {:Age, :Oxy}, effectList = {:RunPulse, :RstPulse}, Button(1)};

The individual expressions in the list are not evaluated. Therefore to use the columns selected, you can unload the list of columns  for use in your analysis in a couple of ways. For example, you can subscript the dlg list variable and assign the column list to a new variable, or you can use the same name:

yList = dlg["yList"];
effectList = dlg["effectList"];

Another method to unload the list of columns is to use Eval List() to evaluate the items in the dlg list variable. The last item in the dlg list is removed before evaluating the other items in the list because Button(1) does not need any evaluation.

Eval List( Remove( dlg, -1 ) )

Now if you run Show Symbols(); you will see all the variables defined and that the column selections are stored in the yList and effectList variables.

// Here

dlg = {yList = {:Age, :Oxy}, effectList = {:RunPulse, :RstPulse}, Button( 1 )};
dt = Data Table( "Fitness" );
effectList = {:RunPulse, :RstPulse};
yList = {:Age, :Oxy};

// 4 Here

Either method you choose to unload the values will allow you to use the yList and effectList variables in your analysis:

fm = dt << Fit Model(
    Y( Eval( yList ) ),
    Effects( Eval( effectList ) ),
    Personality( "Standard Least Squares" ),
    Emphasis( "Effect Leverage" ),
    Run
);

So what are the primary considerations for using Column Dialog()? 

  • A column selector of columns from the current data table is always present. While this is handy when you want the user to select columns, this limits the use of this type of modal window.
  • The amount of script code that you have to write is rather short. You may find that the built-in functionality fully meets your needs. However, the ability to customize is limited. For example, there are only three constructors to control the arrangement of the display boxes within the window, HList(), VList(), and Line Up Box().
  • The value returned from Column Dialog() is consistent. As the script author, you know that Column Dialog() will always return a list of values that must be extracted. The downside is that there is the extra step to unload the values and there is less flexibility with regard to how you retrieve the user’s selections.

For a complete list of constructors available for Column Dialog(), review the Constructors for Column Dialogs section of the Display Trees chapter in the Scripting Guide.

New Window()

New Window() is a built-in function that allows you to generate a modal or non-modal window that could be used to do anything from prompting a user to select columns, to alerting the user with important information. Thanks to  the number and variety of display boxes that are available, you can create very custom modal windows using New Window().

With the increased customization options, the amount of code to be written is also increased. The following example demonstrates a similar window to the Column Dialog() shown above. Notice that some the display boxes have similar names. For example, V List Box(), H List Box(), Panel Box(), and Lineup Box() are used to control the layout of the window. The remaining display boxes are the elements that you can see in the window, such as the buttons and the list of columns.  

Names Default To Here( 1 );

dt = Open( "$SAMPLE_DATA/Fitness.jmp" );
nw = New Window( "Launch Dialog",
    <<Modal,
    V List Box( Align( "right" ),
        H List Box(
            Panel Box( "Select Columns",
                clb = Filter Col Selector( dt, all )
            ),
            Panel Box( "Cast Selected Columns into Fit Model Roles",
                Lineup Box( N Col( 2 ), Spacing( 5 ),
                    Button Box( "Y",
                        clbY << Append( clb << Get Selected )
                    ),
                    clbY = Col List Box(
                        "Numeric",
                        MinItems( 2 ),
                        MaxItems( 2 ),
                        nlines( 3 )
                    ),
                    Button Box( "Effects",
                        clbEffects << Append( clb << Get Selected )
                    ),
                    clbEffects = Col List Box(
                        "Numeric",
                        MinItems( 2 ),
                        MaxItems( 3 ),
                        nlines( 4 )
                    ),
                    Button Box( "Remove",
                        clbY << Remove Selected;
                        clbEffects << Remove Selected;
                    )
                )
            )
        ),
        H List Box(
            Button Box( "OK",
                yVars = clby << Get Items( "Column Reference" );
                eVars = clbEffects << Get Items( "Column Reference" );
            ),
            Button Box( "Cancel" )
        )
    )
);

The window presented to the user looks like this:

 

NewWindowModal.png

 

The way that this example window is scripted, the selected columns are assigned to JSL variables in the OK button. You might be thinking that the columns could also be assigned in the button scripts for the Y and Effects buttons, as an alternative. This is true. However, since the user can drag and drop the columns into the Col List Boxes, those buttons may never actually get clicked. Thus, the button script would never be executed. For alternative methods, see the Extract Values from a Window section of the Display Trees chapter in the Scripting Guide

Running Show( yVars, eVars ); will list the values in the log (View > Log):

yVars = {:Age, :Oxy};
eVars = {:RunPulse, :RstPulse};

These variables can be used in the Fit Model launch without having to be unloaded.

fm = dt << Fit Model( 
   Y( Eval( yVars ) ),
   Effects( Eval( eVars ) ),
   Personality( "Standard Least Squares" ),
   Emphasis( "Effect Leverage" ),
   Run
); 

Don’t let the amount of script code overwhelm you. Instead, let’s look at a few of the customizations available in this modal New Window(). The following items correspond to the numbers shown in the image above.

    1. The New Window() function allows you to provide a window title that makes sense for your scripting project. In this example, the simple title of “Launch Dialog” is used.
    2. The text shown above the groupings can be customized. This allows you to provide a short instruction or description of the grouping for the user.
    3. The number of lines that are displayed can be specified as an optional argument for the Col List Box() that holds the selected columns. This allows you to control the number of columns that appear in the display box. You can also add extra room for aesthetic purposes, as shown above.
    4. The list of columns can come from any open data table, not just the table that is current. Remember, New Window() can be used for a variety of dialog messaging. So, showing the list of columns is optional.
    5. The OK button can have custom functionality. Plus, the Cancel button is optional.

New Window() has many more constructors available than were demonstrated here, such as sliders, radio buttons, pictures, graphs, and more! For a list of constructors available for New Window(), review the Constructors for New Windows section of the Display Trees chapter in the Scripting Guide.

In summary, Column Dialog() provides a quick and easy way to create your window, but has limited  support for customizing. On the other hand, a modal New Window() offers significant flexibility for customization but requires more thought and script to create. Clearly, both options have significant benefits and my guess is that you will find uses for each. Fortunately, there is room in your toolbox for both! 

Labels
Article Tags
3 Comments
Community Trekker

I see that if I create my own modal window one of the things I can do it tell the Filter Col Selector to start out filtering a certain way.  Say, I only want to select from Character columns.  I see how to do that but I'm wondering whether that is actually possible with Column Dialog.  Can I somehow talk to the Filter Col Selector built into the Column Dialog or is this a reason to take the other route.

Staff

Thanks for the question, @hardner

With Column Dialog, the column list is provided as part of the built-in functionality.  The ability to customize the columns shown is limited to interactively making the selections in the window after it is generated.  To achieve the level of customization you want, you would need to use a New Window.

Community Trekker

Thanks!  That's what I did.  Column Dialog is very compact and handy but as your nice blog highlights it's not that hard to do a New Window and customize it more.