Subscribe Bookmark RSS Feed

Question on getting data from a plot output using objects in tree structure

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Hi, I want to get fallout data for various scenarios of spec limits.  I've done it previously in another script looping through the columns, getting each column as a list, select_where() data is above / below the spec limits, but I wanted this time to use native JMP information.

JMP's distribution platform will show the cpk analysis and fallout when limits are present.  When I examine the tree structure, the fallout information shows up in a object / list called "numbercolbox(4)".  I've figured out how to grab the fallout data, and I can populate the spec limits and re-run distribution for each of my limit sets, but I would like to know how reliable this solution is.  For example, if someone else has a different set of preferences, is numbercolbox(4) always going to pull the fallout data?

I suppose an alternate to this is xpaths, but I don't have much info on this. If this is a decent solution and someone has documentation on it, please let me know.

Attached is a script that does what I want, and works for me. You can run it and see what I'm talking about. It uses sample data.

To see the tree structure on a JMP output (plot, etc), make the window bigger than it is natively, then ctrl-shift-right-click in the very bottom or very right-most area, and select show tree structure. See below.

Thanks,

-Mike

10120_pastedImage_0.png

1 ACCEPTED SOLUTION

Accepted Solutions
ms

Super User

Joined:

Jun 23, 2011

Solution

I don't know how robust the numbering would be for this particular platform or node. But in general, the numbering is not fixed but can change with the overall complexity of the report.

An alternative method to adress a particular display box is to use its name. Wild cards are supported too. I think names are more robust than numbering, because they rarely change between JMP versions whereas the layout and default number of options may vary with version and with preferences.


In the context of your example script, all three lines below would all return the same result:

Report(distObj)[Number Col Box(4)] << get;

Report(distObj)[Number Col Box("% Actual")] << get;

Report(distObj)[Number Col Box("%?")] << get;

9 REPLIES
ms

Super User

Joined:

Jun 23, 2011

Solution

I don't know how robust the numbering would be for this particular platform or node. But in general, the numbering is not fixed but can change with the overall complexity of the report.

An alternative method to adress a particular display box is to use its name. Wild cards are supported too. I think names are more robust than numbering, because they rarely change between JMP versions whereas the layout and default number of options may vary with version and with preferences.


In the context of your example script, all three lines below would all return the same result:

Report(distObj)[Number Col Box(4)] << get;

Report(distObj)[Number Col Box("% Actual")] << get;

Report(distObj)[Number Col Box("%?")] << get;

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Thanks, the fact that that number (in my case 4) could change is kind of what I expected. Your solution works perfectly.

I'm also having problems setting the upper and lower spec limits with variables (lists).  When I use a hard coded list as I did in the example it works fine, but I can't just use a simple list element. I'm probably not using the eval(substitute()) correctly, but in my experience this is one of the most confusing parts of JSL.

Any suggestions on how to fix this?

.

mySpecsExpr = expr(as column(yParamNames) << set property("Spec Limits", {aaa,bbb}));
show(eval(dList[1]), eval(dList[2])); // <- these evaluate fine in the log window
eval(substitute( mySpecsExpr, expr(aaa), eval(dList[1]), expr(bbb), eval(dList[2])));

Edit:  Actually I was able to to figure it out based on this how to: 46953 - How to script Column Properties using variables

This works.  But if anyone has a simpler answer, I would appreciate it.

   Eval(
   Eval Expr(
   as column(yParamNames) << Set Property(
   "Spec Limits",
   {LSL( Expr( eval(dList[1]) ) ), USL( Expr( eval(dList[2])) ) }//, Target( Expr( tLimit ) ),Show Limits( 0 )}
   )
   )
   );
ian_jmp

Staff

Joined:

Jun 23, 2011

Stating the obvious perhaps, but please be aware that if the script needs to run in multiple locales, you have to be careful when indexing display boxes by their names.

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Thanks! It is obvious to me now. ;-)   I'll see if any users are using other languages and put some hooks in there for any other languages being used.  It won't be bulletproof but it should be ok for our purposes.  Thanks.

vince_faller

Super User

Joined:

Mar 17, 2015

There was a pretty good poster on XPath this year at the conference.

https://community.jmp.com/docs/DOC-8116

They go through a few real life examples with JMPs structure. 

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Thanks, I've been looking for documentation like that for awhile. I'll play around with it a bit and see how it goes. Seems straightforward but also language dependent, which is probably ok for what I need.

Why xpath is more efficient than display tree scripting?  Is it just more efficient coding is does it get information back faster? For the purposes of this question, let's assume it is just one object that is being returned, like a distribution picture box and that you know its name or number. If you do this 100 or 1000 times, is one noticeably faster than the other?  Seems generating the report itself (before extracting the object back) is where the execution time is.

Phil_Brown

Super User

Joined:

Mar 20, 2012

One clear advantage of xpath is when there are multiple displaybox objects in a JMP Report window. For example, say you did some analysis and ended up

with 100 Outlineboxes, with xpath you can do:

rpt << xpath("//OutlineBox")

and a list of references to ALL of the outline boxes is returned. (where rpt references the JMP Report window)

With traditional displaybox scripting you would have to first know how many were generated, then loop from 1 to N, and access each outlinebox via its index. Indexing can be a problem especially if the sequence is not clear (nested outlineboxes for instance). This can be many more steps of coding.

As far as speed, there was a discernible difference to me with XPath executing much faster, especially with large groups. I don't think it makes a difference with "single shot" scenario you describe, however a formal timing study would have to be done.

PDB
mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Hi Philip,

I finally got around to checking out xpath code, and I'm having trouble with it. I used your poster as a reference.  Can you help figure out what I'm doing wrong?

Also, I think I've seen this before, but I don't recall... what is the '.' in the "list_testSS.Key" variable name for?

Seems reminiscent of a structure in C but I couldn't find jsl documentation on it. I wasn't sure if it was set up properly in my code.

Thanks,

Mike

names default to here(1);

open("$SAMPLE_DATA\Semiconductor Capability.jmp");

myDist =

Distribution(

      Stack( 1 ),

      Continuous Distribution(

            Column( :NPN1 ),

            Horizontal Layout( 1 ),

            Vertical( 0 ),

            Axes on Left( 1 ),

            Customize Summary Statistics(

                  Std Err Mean( 0 ),

                  Upper Mean Confidence Interval( 0 ),

                  Lower Mean Confidence Interval( 0 ),

                  N Missing( 1 ),

                  Range( 1 ),

                  Robust Mean( 1 ),

                  Robust Std Dev( 1 )

            )

      )

);

reportObj=myDist<<xpath( "//OutlineBox[ text() = 'Summary Statistics']/ancestor::OutlineBox[last()]");   

list_groupName=reportObj<<GetTitle;

list_testSS.Key=(reportObj<<xpath("//*[contains( text(), 'Summary Statistics')]/following-sibling::*//StringColBox")) <<Get;

list_testSS.Val=(reportObj<<xpath("//*[contains( text(), 'Summary Statistics')]/following-sibling::*//NumberColBox")) <<Get;

list_levelString=(reportObj<<xpath("//OutlineBox[ text() = 'Long Term Sigma']//StringColBoxHeader[text()='Capability']/..")) << get;

list_levelMeans=(reportObj<<xpath("//OutlineBox[ text() = 'Long Term Sigma']//NumberColBoxHeader[text()='Index']/..")) << get;

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

I changed the xpath code to make it simpler (at least for me), and this works for what I need it to do.  However, I am still curious why the code I posted above isn't working, as the more general usage structure / code you have would be really useful.

Thanks,
Mike

names default to here(1);

testVar = 0;

testVar = 1; // comment out for subsequent runs

if(testVar,

      open("$SAMPLE_DATA\Semiconductor Capability.jmp");

      myDist = Distribution(

            Stack( 1 ),

            Continuous Distribution(

                  Column( :NPN1 ),

                  Customize Summary Statistics(

                        Robust Mean( 1 ),

                        Robust Std Dev( 1 )

                  )

            ),

            Continuous Distribution(

                  Column( :PNP1 ),

                  Customize Summary Statistics(

                        Robust Mean( 1 ),

                        Robust Std Dev( 1 )

                  )

            ),

            Continuous Distribution(

                  Column( :PNP2 ),

                  Customize Summary Statistics(

                        Robust Mean( 1 ),

                        Robust Std Dev( 1 )

                  )

            )

      );

);

reportObj=myDist<<xpath( "//OutlineBox[ text() = 'Summary Statistics']");

for(i = 1, i<=nitems(reportObj), i++, show(reportObj[i]<<get title););

strList = {};

reportObj=myDist<<xpath( "//OutlineBox[ text() = 'Summary Statistics']//StringColBox");

//for(i = 1, i<=nitems(reportObj), i++, show(reportObj<<get); strList = reportObj << get;);

show(reportObj[1]<<get);

strList = reportObj[1] << get;

try(rMnIndx = loc(strList, "Robust Mean"), rMnIndx = -1);

try(rStdIndx = loc(strList, "Robust Standard Deviation"), rStdIndx = -1);

statList = {};

reportObj=myDist<<xpath( "//OutlineBox[ text() = 'Summary Statistics']//NumberColBox");

//for(i = 1, i<=nitems(reportObj), i++, show(reportObj<<get); statList = reportObj<< get;);

show(reportObj[1]<<get);

statList = reportObj[1]<< get;

if(rMnIndx > 0 & rStdIndx > 0,

      robustMean = statList[rMnIndx];

      robustStd = statList[rStdIndx];

      ,

      robustMean = -999;

      robustStd = -999;

);

show(robustMean, robustStd);