Subscribe Bookmark RSS Feed

Using subscript search for Dispatch

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Hi, I am having some trouble sending some information to a report after it gets generated.  The report contains multiple distributions, which are created in a for loop with index i. Each distribution is contained within its own outline box so that I may add lots of other stuff within each outline box and have relevant material grouped together.   I store a reference to each of these distributions (called distObj), and I can change them by addressing them as distObj[1] << ... etc, but here's the catch:   I am using radio boxes located within the report, one set of 3 radio boxes per outline box (i.e. per Distribution).  Clicking on different radio buttons will scale the axes for the i'th parameter only in 1 of 3 different manners.   After the script is completed, the variable i is no longer mapped to each box as it was for each iteration of the for because it has incremented to its final value.  I need to figure out which set of buttons was clicked (essentially, what was 'i'), and send limit scaling information to the corresponding distribution only.  I've verified that it works if I hardcode the subcript but that really won't work.

I've tried a few things, like writing a number edit box with the number i, so that i actually gets stored in the report., but I still run into problems trying to get that specific variable (it needs to be subscripted too).

There's something in the scripting guide that I think can help me, but I don't know how to use it.    Page 335 of JMP 10's scripting guide, Display Trees chapter, Subscripts.  They suggest that for a display box db, JSL can find an object with "text" by using the code db["text"] or db["text?"] using the ? as a wildcard.  The reason I think this can help me is that instead of relying on a subscript for the i'th  parameter, i would just find a match based on distObj.  I am hoping to get it so the radio button sends a command to find and walk up one node to the outline box (or stay in the same node as it may be), get the proper db reference and send the command from there.  I have tried to get this to work, but I have to wonder if I'm barking up the wrong tree with this one.

Here is the relevant part of my script.  In the radio box section, the "stored_i" variable may as well just be "i".  It was a test that didn't really work.

Any ideas?

custRpt = New Window( titleString,

            AnaNotesBox = Outline Box("Analysis Notes",

                Text Box( textString1),

            )

        );

distObj={};

rb1 = {};

rb2 = {};

rb3 = {};

paramBoxList ={};

For( i = 1, i <= AdjNumParam, i++,   

    custRpt << append(

        ParamBoxList = Outline Box( newYparamName ,

            V List Box(

                hlistbox(

                    rb1 = radioBox("Scale method 1     ", show("test1");stored_i = numBox << Get(numeric value);show(stored_i); // <-- numbox is just

                        distObj[stored_i] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( newMin[stored_i],newLSL[stored_i]), Max( newMax[stored_i],newUSL[stored_i]), Inc( 2 ),

                                Minor Ticks( 1 ), Rotated Labels( "Horizontal" )}

                            ));

                    ),

                    rb2 = radioBox("Scale method 2     ", stored_i = numBox << Get(numeric value);

                        distObj[stored_i] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( newMin[stored_i] ), Max( newMax[stored_i] ), Inc( 2 ),

                                Minor Ticks( 1 ), Rotated Labels( "Horizontal" )}

                            ));

                    ),

                    rb3 = radioBox("Scale method 3     ", stored_i = numBox << Get(numeric value);

                        distObj[stored_i] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( newLSL[stored_i] ), Max( newUSL[stored_i] ), Inc( 2 ),

                                Minor Ticks( 1 ), Rotated Labels( "Horizontal" )}

                            ));

                    ),

                    numBox = Number edit box(i),//  <-- numBox not subscripted so this won't work

                    //stored_i = numBox << Get(numeric value)

                    //numParam = numParamVal << Get(numeric value);

                ),

                rb1 << group (rb2) << group(rb3),

               

                H List Box(

                        distObj = Distribution(

                        Y( Eval List( newYparamName ) )),

                ),

                page break box();

            )

        )

    );   

);

1 ACCEPTED SOLUTION

Accepted Solutions
Solution

When building reports incrementally in a loop it is important to "hard wire" the value of i in displayboxes and their action scripts. One way to do this is to use strings  and then use Parse(Evalinsert("code")) in each iteration to update and evaluate the code. Although not pretty, strings of code often make it easier to control what's going on.

Below is an attempt at making your example code work better. I skipped the numBox stuff beause I couldn't figure out why it was there.

dtData = Open( "$SAMPLE_DATA/Big Class.jmp" ); dtData:age << modeling type( continuous );

 

newMin = {12, 15, 64};

newMax = {17, 70, 172};

newLSL = {10, 40, 50};

newUSL = {20, 80, 200};

newYparamName = {"age", "height", "weight"}; adjNumParam = 3;

{distObj, paramBoxList ,rb1, rb2, rb3} = {{},{},{},{},{}}; 

custRpt = New Window( "Title",

  AnaNotesBox = Outline Box( "Analysis Notes",

  Text Box( "Information..." ),

  )

);

For( i = 1, i <= AdjNumParam, i++,

  custRpt << append(

  ParamBoxList[i] = Outline Box( newYparamName[i],

  vlb = V List Box(

  hlb_1 = H List Box(),

  hlb_2 = H List Box(

  distObj[i] =

  Distribution( Y( Eval List( newYparamName[i] ) ) ),

  ),

  Page Break Box()

  )

  )

  );

  For( j = 1, j <= 3, j++,

  hlb_1 << append(

  Eval(Parse(Eval Insert(

  "\[^"rb"||char(j)||"["||char(i)||"]"^ = radioBox("Scale method "||char(^j^),

                        distObj[^i^] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( ^newMin^), Max( ^newMax^ )}

                            ));

  )]\"

  )))

  )

  );

  rb1[i] << group( rb2[i] ) << group( rb3[i] );

);


8 REPLIES
mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Here is a version of the above code that will run as-is, using big class as an example file.  Again, the stored_i is not getting updated, and the trick is figuring out which of the SETs of radio boxes is sending the command. I'd be grateful for any suggestions.

clear log();

names default to here(1);

clear globals();

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

//dtData = data table("Big Class.jmp");

//show(dtData);

newMin = { 12, 15, 64};

newMax = { 17, 70, 172};

newLSL = {10, 40, 50};

newUSL = {20, 80, 200};

newYparamName = {"age", "height", "weight"};

adjNumParam = 3;

custRpt = New Window( "Title",

            AnaNotesBox = Outline Box("Analysis Notes",

                Text Box( "Information..."),

            )

        );

distObj={};

rb1 = {};

rb2 = {};

rb3 = {};

paramBoxList ={};

For( i = 1, i <= AdjNumParam, i++,   

    custRpt << append(

        ParamBoxList = Outline Box( newYparamName ,

            V List Box(

                hlistbox(

                    rb1 = radioBox("Scale method 1     ", show("test1");stored_i = numBox << Get(numeric value);show(stored_i); // <-- numbox is just

                        distObj[stored_i] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( newMin[stored_i],newLSL[stored_i]), Max( newMax[stored_i],newUSL[stored_i]), Inc( 2 ),

                                Minor Ticks( 1 ), Rotated Labels( "Horizontal" )}

                            ));

                    ),

                    rb2 = radioBox("Scale method 2     ", stored_i = numBox << Get(numeric value);

                        distObj[stored_i] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( newMin[stored_i] ), Max( newMax[stored_i] ), Inc( 2 ),

                                Minor Ticks( 1 ), Rotated Labels( "Horizontal" )}

                            ));

                    ),

                    rb3 = radioBox("Scale method 3     ", stored_i = numBox << Get(numeric value);

                        distObj[stored_i] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( newLSL[stored_i] ), Max( newUSL[stored_i] ), Inc( 2 ),

                                Minor Ticks( 1 ), Rotated Labels( "Horizontal" )}

                            ));

                    ),

                    numBox = Number edit box(i),//  <-- numBox not subscripted so this won't work

                    //stored_i = numBox << Get(numeric value)

                    //numParam = numParamVal << Get(numeric value);

                ),

                rb1 << group (rb2) << group(rb3),

               

                H List Box(

                        distObj = Distribution(

                        Y( Eval List( newYparamName ) )),

                ),

                page break box();

            )

        )

    );   

);

Solution

When building reports incrementally in a loop it is important to "hard wire" the value of i in displayboxes and their action scripts. One way to do this is to use strings  and then use Parse(Evalinsert("code")) in each iteration to update and evaluate the code. Although not pretty, strings of code often make it easier to control what's going on.

Below is an attempt at making your example code work better. I skipped the numBox stuff beause I couldn't figure out why it was there.

dtData = Open( "$SAMPLE_DATA/Big Class.jmp" ); dtData:age << modeling type( continuous );

 

newMin = {12, 15, 64};

newMax = {17, 70, 172};

newLSL = {10, 40, 50};

newUSL = {20, 80, 200};

newYparamName = {"age", "height", "weight"}; adjNumParam = 3;

{distObj, paramBoxList ,rb1, rb2, rb3} = {{},{},{},{},{}}; 

custRpt = New Window( "Title",

  AnaNotesBox = Outline Box( "Analysis Notes",

  Text Box( "Information..." ),

  )

);

For( i = 1, i <= AdjNumParam, i++,

  custRpt << append(

  ParamBoxList[i] = Outline Box( newYparamName[i],

  vlb = V List Box(

  hlb_1 = H List Box(),

  hlb_2 = H List Box(

  distObj[i] =

  Distribution( Y( Eval List( newYparamName[i] ) ) ),

  ),

  Page Break Box()

  )

  )

  );

  For( j = 1, j <= 3, j++,

  hlb_1 << append(

  Eval(Parse(Eval Insert(

  "\[^"rb"||char(j)||"["||char(i)||"]"^ = radioBox("Scale method "||char(^j^),

                        distObj[^i^] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( ^newMin^), Max( ^newMax^ )}

                            ));

  )]\"

  )))

  )

  );

  rb1[i] << group( rb2[i] ) << group( rb3[i] );

);


mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Hi MS,

First of all, thank you very much for your help. numbox was an attempt at getting access to whatever instance of rbx was clicked. It didn't work.

I had to change your script around a little bit because my lists in your j-loop actually have different names so i need the whole thing typed out (see below).  With these edits, everything is working perfectly (so far). We'll see how well JMP handles the resizing for various limits.

I have a couple of questions.  Why does the i in your script get delimiters '^' but distObj does not?  It took me a bit to figure out what those special characters were doing, but I'm still confused on this point.

Where did you learn all of this?  Self study or formal JMP training through SAS?

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

dtData:age << modeling type( continuous );

newMin = {12, 50, 64};

newMax = {17, 70, 172};

newLSL = {10, 40, 50};

newUSL = {20, 80, 200};

newLSL2 = {5, 20, 0};

newUSL2 = {25, 100, 300};

newYparamName = {"age", "height", "weight"};

adjNumParam = 3;

{distObj, paramBoxList, rb1, rb2, rb3} = {{}, {}, {}, {}, {}};

custRpt = New Window( "Title",

    AnaNotesBox = Outline Box( "Analysis Notes",

        Text Box( "Information..." ),

    )

);

For( i = 1, i <= AdjNumParam, i++,

    custRpt << append(

        ParamBoxList = Outline Box( newYparamName,

            vlb = V List Box(

                hlb_1 = H List Box(),

                hlb_2 = H List Box(

                    distObj =

                    Distribution( Y( Eval List( newYparamName ) ) ),

                ),

                Page Break Box()

            )

        )

    );

    //For( j = 1, j <= 3, j++,

        hlb_1 << append(

            Eval(

            Parse(

                Eval Insert(

                        "\[^"rb1["||char(i)||"]"^ = radioBox("Scale method 1",

                        distObj[^i^] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( ^newMin^), Max( ^newMax^ )}

                            ));

                        )]\"

                )

            )

            )

        );

        hlb_1 << append(

            Eval(

            Parse(

                Eval Insert(

                        "\[^"rb2["||char(i)||"]"^ = radioBox("Scale method 2",

                        distObj[^i^] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( ^newLSL^), Max( ^newUSL^ )}

                            ));

                        )]\"

                )

            )

            )

        );

       

        hlb_1 << append(

            Eval(

            Parse(

                Eval Insert(

                        "\[

                        ^"rb3["||char(i)||"]"^ = radioBox("Scale method 3",

                        distObj[^i^] << SendToReport(

                            Dispatch(

                                {},

                                "1",

                                ScaleBox,

                                {Min( ^newLSL2^), Max( ^newUSL2^ )}

                            ));

                        )]\"

                )

            )

            )

        );       

       

       

    //);

    rb1 << group( rb2 ) << group( rb3 );

);

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Is there a way to modify a section of the code above (one of the radio boxes) to revert the axis?  I know there is a revert axis command but can't seem to get it to work, below are two attempts.

Also, what's your method for pasting code? Do you upload a jsl file? I haven't been able to duplicate your formatting.

hlb_1 << append(

    Eval(

    Parse(

        Eval Insert(

                "\[^"rb4["||char(i)||"]"^ = radioBox("Revert Axis",

    distObj[^i^] << SendToReport(

        Dispatch(

        {},

        "1",

        axis box(1),

        revert axis

         ));

                )]\"

        )

        /*

        Eval Insert(

                "\[^"rb4["||char(i)||"]"^ = radioBox("Revert Axis",

    distObj[^i^][axis box(1)] << revert axis;

                )]\"

        )*/

    )

    )

);

ms

Super User

Joined:

Jun 23, 2011

Q&A

Why does the i in your script get delimiters '^' but distObj does not?

It did not work with delimiters around distObj. Probably because a variable pointing at the object is needed (e.g. distObj[1]). Fully evaluated we would get the list Item in clear text i.e Distribution[] which is not making any sense to JMP when the string is parsed.


Is there a way to modify a section of the code above (one of the radio boxes) to revert the axis?

Not for the distribution platform it seems. It does not work, and if you doubleclick on the axis to invoke the axis-settings dialog you'll see that there is no Revert Axis checkbox.


Also, what's your method for pasting code?

I just copy and paste from the JSL editor into the browser. In the new forum most of the formatting is retained but the indenting is partly lost. In the old forum I had to first paste into MS Word and then into the browser, if I remember correctly. I use JMP 10 for Mac. On Windows it may work differently.


Where did you learn all of this? 

Self studies, lots of trial and error, and helping people here on the forum has actually taught me a lot.

Btw, I rarely use the Dispatch() method. The syntax is complicated and is mainly found in the autogenerated scripts. Much simpler is to send messages directly to the displaybox of interest (the command <<show tree structure is useful for finding out how to address a specific db; here try e.g. distObj[1]<<show tree structure).

Compare this with your script above (just an excerpt):

hlb_1 << append(

            Eval(

            Parse(

                Eval Insert(

                      "\[rb1[^i^] = radioBox("Scale method 3", report(distObj[^i^])[AxisBox(1)] << Min( ^newMin^) << Max( ^newMax^ ))]\"

                )

            )

            )

        );

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

Thanks for all the replies MS.

I've been playing around with the code here and there for a couple of days, and I'm getting a better feel for the delimiters.  I like your updated code better, and I agree that Dispatch() is messy.  I've converted over to the new code.

I thought it might be possible to use "revert axis" because even though it isn't available in the double click dialog, there is an option for it when you right click on the axis. I would think it would be more of a function rather than a boolean setting.  Not a big deal. I just removed the feature from my script.  The reason like this feature is because JMP can scale the axes much cleaner than I can.  I've tried several mathematical methods but haven't found anything to work consistently.  (I've tried many calculations of USL, LSL, spec width for setting the min(), max(), inc() ).

Quick test of copy / paste JSL into word, then out of word into FF (Win XP).  Looks good, thanks. 

hlb_1 << append(

      Eval(

      Parse(

            Eval Insert(

                        "\[^"rb1["||char(i)||"]"^ = radioBox("Scale to Data + Limits ",

                                    report(distObj[^i^])[AxisBox(1)] << Min( ^minMinLSL_scale^) << Max( ^maxMaxUSL_scale^) << Inc(^inc1_scale^);

                                    if( nitems( ^groupList^) >= 1 & groupList[1] != 0, for(k = 1, k<= nitems(^groupList^), k++,

                                                report(oneObj[^i^])[AxisBox(1)] << Min( ^minMinLSL_scale^) << Max( ^maxMaxUSL_scale^) << Inc(^inc1_scale^);

                                    ))         

                              )

                             

                        ]\"

            )

      )

      )

);

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

I have noticed a potential problem in this script, but only when running it more than once and leaving a previous report window open.  The radio boxes from a previous instance of the report will send messages to the latest report window instance. It makes sense to me why this is happening, but if the report generated iterated to 20 plots, and the second iterated to 3 plots, then the first 3 sets of radio buttons on the first window will send commands to the latest window, and sets 4 to 20 radio buttons will result in an error (in my case that distObj[4] ... distObj[20] is not defined).   Is it possible to code into that long Eval Insert() string what distObj is referring to, or is this too much to ask of JSL?

Also, is there an error handling catchall?    I suppose I could code in something in the Eval Insert () string to prevent the error from showing but I don't know what other unhandled errors may be lurking about. In excel VBA for example, using something like "on error goto errorHandler" and then a little "errorHandler:" routine at the end to exit gracefully will do the trick nicely. 

Thanks.

mikedriscoll

Community Trekker

Joined:

Jun 23, 2011

One last follow up on this thread:  The problem I noted above, where clicking radio boxes on an old version of the report will throw an error because the variables are stale, turns out not to be a problem when the script is installed as an add-in.  I have "names default to here(1)" in the .jsl so not sure why it was failing by running the .jsl directly.  But in any case, I figured I'd update this thread for posterity.

If anyone has an answer for general error handling, that would be appreciated. I'm looking for something that is a generic error catch-all, in case I failed to take into account some odd user input. I'd like the script to exit gracefully.

Thanks.