Choose Language Hide Translation Bar
Highlighted
robot
Level VI

Find All Display Tree Elements

Hi,

I would like to use JSL to get a list of all the objects within a display tree for scripting purposes.  Specifically, I would like to get a list of all the FrameBoxes within a window, and then add a graphics script to each.  Or better still, I would like to return a list of available FrameBoxes to the user, and then have the user select which graphics script to add.

How can I get a list of all the FrameBoxes in a window?  I would like to get a list that is in a form suitable for scripting, and not just view the Display Tree.  Is this possible?

Thanks!

1 ACCEPTED SOLUTION

Accepted Solutions
Highlighted
ian_jmp
Staff

Re: Find All Display Tree Elements

That's perfectly possible. The code below uses pre-order traversal to walk the display tree (and was originally written by Joseph Morgan in the JMP Division, I believe). You should be able to get what you need with a few tweaks (depending on the rest of your code).

NamesDefaultToHere(1);

ClearLog();

// This function recursively traverses a display tree producing

// a pre-order listing of the names of display boxes that constitute

// the tree. It also looks for each FrameBox (whether displayed or not),

// and gets the name of the parent OutlineBox

preorder = Function({node},

   Local({chnode},

  // Inspect the current node

  nodeType = Char(node << className);

      Print("Node: "||nodeType);

      If(nodeType =="FrameBox",

// Find the title of the parent outline node of this FrameBox

parent = node << parent;

parentType = Char(parent << className);

While(parentType != "OutlineBox",

parent = parent << parent;

parentType = Char(parent << className);

);

InsertInto(fbTitles, parent << getTitle)

);

  // Do the recusrsion

      chnode = node << child;

      While(IsScriptable(chnode),     

         Recurse(chnode);

         chnode = chnode << sib;     

      );

   );

);

// Try out 'preorder' . . .

dt = Open("$SAMPLE_DATA/Big Class.jmp");

obj = dt << Fit Model(

Y( :height ),

Effects( :sex ),

Personality( "Standard Least Squares" ),

Emphasis( "Effect Leverage" ),

Run(

:height << {Lack of Fit( 0 ), Plot Actual by Predicted( 1 ),

Plot Regression( 0 ), Plot Residual by Predicted( 1 ),

Plot Effect Leverage( 1 )}

)

);

report=report(obj);

fbTitles = {};

preorder(report);

Print("\!n", fbTitles);


View solution in original post

14 REPLIES 14
Highlighted
ian_jmp
Staff

Re: Find All Display Tree Elements

That's perfectly possible. The code below uses pre-order traversal to walk the display tree (and was originally written by Joseph Morgan in the JMP Division, I believe). You should be able to get what you need with a few tweaks (depending on the rest of your code).

NamesDefaultToHere(1);

ClearLog();

// This function recursively traverses a display tree producing

// a pre-order listing of the names of display boxes that constitute

// the tree. It also looks for each FrameBox (whether displayed or not),

// and gets the name of the parent OutlineBox

preorder = Function({node},

   Local({chnode},

  // Inspect the current node

  nodeType = Char(node << className);

      Print("Node: "||nodeType);

      If(nodeType =="FrameBox",

// Find the title of the parent outline node of this FrameBox

parent = node << parent;

parentType = Char(parent << className);

While(parentType != "OutlineBox",

parent = parent << parent;

parentType = Char(parent << className);

);

InsertInto(fbTitles, parent << getTitle)

);

  // Do the recusrsion

      chnode = node << child;

      While(IsScriptable(chnode),     

         Recurse(chnode);

         chnode = chnode << sib;     

      );

   );

);

// Try out 'preorder' . . .

dt = Open("$SAMPLE_DATA/Big Class.jmp");

obj = dt << Fit Model(

Y( :height ),

Effects( :sex ),

Personality( "Standard Least Squares" ),

Emphasis( "Effect Leverage" ),

Run(

:height << {Lack of Fit( 0 ), Plot Actual by Predicted( 1 ),

Plot Regression( 0 ), Plot Residual by Predicted( 1 ),

Plot Effect Leverage( 1 )}

)

);

report=report(obj);

fbTitles = {};

preorder(report);

Print("\!n", fbTitles);


View solution in original post

Highlighted
robot
Level VI

Re: Find All Display Tree Elements

Thanks Ian.

Highlighted
robot
Level VI

Re: Find All Display Tree Elements

Hi Ian@JMP,

Thanks again for the preorder function.  Is there a way for the function to return only FrameBoxes that are actually displayed?  Or is there a way for JMP to tell which FrameBoxes are displayed or not?

I find that when my script tries to send a command to a FrameBox that is not displayed, it will cause an error.

Highlighted
ian_jmp
Staff

Re: Find All Display Tree Elements

Not really answering your question directly, but you may be able to make the failure you mention benign by using the 'Try()' function.

Highlighted
robot
Level VI

Re: Find All Display Tree Elements

Okay.  Thanks Ian.  An unfortunate side-effect of the returned hidden FrameBoxes is that the FrameBox title may not match up with the FrameBox number as shown below.  I may be able to get my script to work using some other variations on the Try() function. 

Names Default To Here( 1 );

Clear Log();

// This function recursively traverses a display tree producing

// a pre-order listing of the names of display boxes that constitute

// the tree. It also looks for each FrameBox (whether displayed or not),

// and gets the name of the parent OutlineBox

preorder = Function( {node},

       Local( {chnode},

             // Inspect the current node

             nodeType = Char( node << className );

             Print( "Node: " || nodeType );

             If( nodeType == "FrameBox",

                    // Find the title of the parent outline node of this FrameBox

                    parent = node << parent;

                    parentType = Char( parent << className );

                    While( parentType != "OutlineBox",

                           parent = parent << parent;

                           parentType = Char( parent << className );

                    );

                    Insert Into( fbTitles, parent << getTitle );

             );

             // Do the recusrsion

             chnode = node << child;

             While( Is Scriptable( chnode ),

                    Recurse( chnode );

                    chnode = chnode << sib;

             );

       )

);

// Try out 'preorder' . . .

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

obj = dt << Fit Model(

       Y( :height ),

       Effects( :sex ),

       Personality( "Standard Least Squares" ),

       Emphasis( "Effect Leverage" ),

       Run(

             :height << {Lack of Fit( 0 ), Plot Actual by Predicted( 1 ), Plot Regression( 0 ), Plot Residual by Predicted( 1 ), Plot Effect Leverage( 1 )

             }

       )

);

report = Report( obj );

fbTitles = {};

preorder( report );

Print( "\!n", fbTitles );

// Select windows.

Wait( 1 );

obj << Bring Window to Front;

For( i = 1, i <= N Items( fbTitles ), i++,

       Try(

             report[FrameBox( i )] << Select;

             win = New Window( "FrameBox Title", <<Modal, Text Box( Eval( fbTitles[i] ) ) );

             report[FrameBox( i )] << Deselect;

       )

);

Highlighted
ms
Super User ms
Super User

Re: Find All Display Tree Elements

Interesting discussion. Below is an example, borrowing heavily from the examples above, where I use an associative array to link the present numbers of displayed frame boxes with their titles.

dt = Open("$SAMPLE_DATA/Big Class.jmp");

obj = dt << Fit Model(

    Y(:height),

    Effects(:sex),

    Personality("Standard Least Squares"),

    Emphasis("Effect Leverage"),

    Run(

        :height << {Lack of Fit(0), Plot Actual by Predicted(1), Box Cox Y Transformation(1), Plot Residual by Predicted(1),

        Plot Effect Leverage(1)}

    )

);

report = Report(obj);

// Associative array linking displayed framebox numbers with titles

fbTitles = [=> ];

i = 1;

While(Is Scriptable(Try(parent = Report[Framebox(i)] << parent)),

    While(parentType = Char(parent << className) != "OutlineBox", parent = parent << parent);

    fbTitles << insert item(i, parent << getTitle);

    i++;

);

Show(fbTitles);

         

// Select windows.

obj << Bring Window to Front;

For(i = 1, i <= N Items(fbTitles), i++,

    report[FrameBox(i)] << Select;

    win = New Window("FrameBox Title", <<Modal, Text Box(Eval(fbTitles[i])));

    report[FrameBox(i)] << Deselect;

);

Highlighted
robot
Level VI

Re: Find All Display Tree Elements

Thanks MS.

If you post your reply at the separate discussion for this follow-up question, Find Hidden or Displayed FrameBoxes, I will mark it correct.

Very impressive.

Highlighted
robot
Level VI

Re: Find All Display Tree Elements

Hi MS​,

Thanks again for your script; it works beautifully for JMP12.  I am now trying to make the script compatible down to JMP10, and I have having trouble debugging the script for GraphBuilder.  Do you know how to make your script work for GraphBuilder in JMP10?

dt = Open( "$SAMPLE_DATA/Big Class.jmp" );

// Script will work for graph1.

graph1 = dt << Fit Model(

      Y( :height ),

      Effects( :sex ),

      Personality( "Standard Least Squares" ),

      Emphasis( "Effect Leverage" ),

      Run(

            :height << {Lack of Fit( 0 ), Plot Actual by Predicted( 1 ),

            Box Cox Y Transformation( 1 ), Plot Residual by Predicted( 1 ),

            Plot Effect Leverage( 1 )}

      )

);

// Script will crash for graph2.

/*

graph2 = dt << Graph Builder(

      Show Control Panel( 0 ),

      Variables( X( :height ), Y( :weight ), Wrap( :age ) ),

      Elements( Points( X, Y, Legend( 1 ) ) )

);

*/

Wait( 1 );

win = Current Window();

// Associative array linking displayed FrameBox numbers with titles

fbTitles = [=> ];

i = 1;

While( Is Scriptable( Try( parent = win[Framebox( i )] << parent ) ),

      While( parentType = Char( parent << className ) != "OutlineBox",

            parent = parent << parent

      );

      fbTitles << insert item( i, parent << getTitle );

      i++;

);

Show( fbTitles );

// Select windows.

win << Bring Window to Front;

For( i = 1, i <= N Items( fbTitles ), i++,

      win[FrameBox( i )] << Select;

      New Window( "FrameBox Title", <<Modal, Text Box( Eval( fbTitles[i] ) ) );

      win[FrameBox( i )] << Deselect;

);

Highlighted
ms
Super User ms
Super User

Re: Find All Display Tree Elements

I may not be able to help since I don't have a JMP 10 license. What goes wrong? Any messages in the log?

Graph Builder has evolved a lot for every new version of JMP. I think that Graph Builder's scripting support has improved too. Maybe there's a special display-box type in the v.10 Graph Builder report that is not (yet) "scriptable", causing the while-loop to stop before the search is completed.

You could also try to use Insert() instead of Insert Item().

Article Labels

    There are no labels assigned to this post.