BookmarkSubscribeSubscribe to RSS Feed
robot

Community Trekker

Joined:

Feb 27, 2012

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
ian_jmp

Staff

Joined:

Jun 23, 2011

Solution

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);


11 REPLIES
ian_jmp

Staff

Joined:

Jun 23, 2011

Solution

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);


robot

Community Trekker

Joined:

Feb 27, 2012

Re: Find All Display Tree Elements

Thanks Ian.

robot

Community Trekker

Joined:

Feb 27, 2012

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.

ian_jmp

Staff

Joined:

Jun 23, 2011

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.

robot

Community Trekker

Joined:

Feb 27, 2012

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;

       )

);

ms

Super User

Joined:

Jun 23, 2011

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;

);

robot

Community Trekker

Joined:

Feb 27, 2012

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.

robot

Community Trekker

Joined:

Feb 27, 2012

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;

);

ms

Super User

Joined:

Jun 23, 2011

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().