Subscribe Bookmark RSS Feed

Find All Display Tree Elements

robot

Community Trekker

Joined:

Feb 27, 2012

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

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

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

Thanks Ian.

robot

Community Trekker

Joined:

Feb 27, 2012

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

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

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

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

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

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

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