BookmarkSubscribeRSS Feed
Choose Language Hide Translation Bar
dqr2
Community Trekker

Adding & Removing Graphics Scripts

I've written a JSL routine in which several graphics scripts are being added to - and removed from - the Graph Builder during a relatively complex animation sequence. The scripts that need to be added and removed depend on the data set being analyzed, so I'm having to script a lot of stuff like the following (where gb is my GraphBuilder object, and myScript1 and myScript2 are both expressions I've defined elsewhere):

 

 

If( k == 5, Report( gb ) << dispatch( {}, "Graph Builder", FrameBox, {Add Graphics Script( 1, Description( "Script" ), myScript1 )} ));
If( k == 10, Report( gb ) << dispatch( {}, "Graph Builder", FrameBox, {Remove Graphics Script( 2 )} ));
If( k == 15, Report( gb ) << dispatch( {}, "Graph Builder", FrameBox, {Add Graphics Script( 1, Description( "Script" ), myScript2 )} ));

 

 

My problem is that I'm losing track of which scripts I'm supposed to be deleting, because I'm referring to them by number - and the numbers allocated to them by the Graph Builder change each time each time a script is removed.

I know I should potentially be able to combine all the graphics scripts into a single large script in which the control is switched between the various sections by if-then-else clauses, but there are potentially dozens of them and the whole thing would probably get very messy.

Is it possible to refer to graphics scripts by name? Essentially I want to be able to do something like this:

 

report(gb) << dispatch( {}, "Graph Builder", FrameBox, {Remove Graphics Script( myScript2 )} );

 

 

The above doesn't work (obviously, or I wouldn't have a problem), but I'm wondering if there's something similar that I've missed.

Many thanks for any suggestions.

0 Kudos
1 ACCEPTED SOLUTION

Accepted Solutions
gzmorgan0
Super User

Re: Adding & Removing Graphics Scripts

Congratulations or writing your script. From your syntax, I'm guessing you are pretty new to JSL.

 

I have 2 example scripts that might help.  The first uses the script expression reference(name). After you add your scripts right click on the framebox and select customize.  The JSL for your graphics script is not visible, only the expr reference. This works. However, if you or the user journals the graph, then later closes the journal.  If you open the journal in a new session, those expressions are not defned and the graphics will not be drawn. This method will work if there are no variable collisions in your graphics scripts and the graph is only relevant in the current session. Xpath is used to find the framebox TopSeq, the graphics added by the user, and in this case only the script reference.

 

Names Default To Here( 1 );
Open( "$SAMPLE_DATA/Big Class.jmp" );
orangepoly = Expr(	Transparency( 0.5 );
	Fill Color( {1.0, 0.5, 0.0} );
	Polygon( [60, 72, 57], [75, 120, 120] );
);
bluepoly = Expr(
	Transparency( 0.5 );
	Fill Color( {0.0, 0.5, 1.0} );
	Polygon( [60, 72, 57], [150, 120, 120] );
);
biv = Bivariate( Y( :weight ), X( :height ), FitLine );
rbiv = biv << report;
rbiv_fb = rbiv[frame box( 1 )];
rbiv_fb << Add Graphics Script(orangepoly);
rbiv_fb << Add Graphics Script(bluepoly);
//right click on the framebox and select Customize 
/*just the expr reference is visible
  If this graph is journaled, the journal is closed and reopened the graphics from the script 
  will not appear. look up Freeze All for the journal. */
   
glist = (rbiv_fb << XPath("//TopSeg")) << get script; 
idx = contains(glist, expr(bluepoly));
Wait( 3 );
rbiv_fb << Remove Graphics Script( idx );

This second method embeds the script into the framebox. After the scripts are added, right click in the framebox and select customize, click on a script to see the difference in the two methods. After adding a script inset into a list the script name. And when removing a script, remove it from the list. The list is a dynamic accounting of which scripts are active, and a function is used to locate its position.

Names Default To Here( 1 );
Open( "$SAMPLE_DATA/Big Class.jmp" );
glist={};
orangepoly = Expr(	
    Transparency( 0.5 );
	Fill Color( {1.0, 0.5, 0.0} );
	Polygon( [60, 72, 57], [75, 120, 120] );
);
bluepoly = Expr(
	Transparency( 0.5 );
	Fill Color( {0.0, 0.5, 1.0} );
	Polygon( [60, 72, 57], [150, 120, 120] );
);
addgraph  = Function({gnme}, {gexpr}, //"orangepoly")
   Eval(Parse("gexpr = NameExpr("||gnme||")" ) );
   Eval(Substitute(Expr(rbiv_fb << Add Graphics Script(_xxx)), Expr(_xxx), NameExpr(gexpr) ) );
   insert into(glist, gnme );
); //end addgraph 
rmvgraph  = Function({gnme}, {idx},
   idx = contains(glist, gnme);
   if(idx>0, 
        rbiv_fb << Remove Graphics Script(idx);
        removefrom(glist, idx)
   );
); //end rmvgrph
biv = Bivariate( Y( :weight ), X( :height ), FitLine );
rbiv = biv << report;
rbiv_fb = rbiv[frame box( 1 )];
addgraph("orangepoly");
addgraph("bluepoly");
//right click on the framebox and select Customize 
//the actual script is embedded
 
Wait( 3 );
rmvgraph("bluepoly");

I agree with your wish list item: add a Description/Name tag to these scripts (TopSegs)  framebox <<Add Graphics Script(name, script) is a definite nice to have.     

4 REPLIES 4
gzmorgan0
Super User

Re: Adding & Removing Graphics Scripts

Congratulations or writing your script. From your syntax, I'm guessing you are pretty new to JSL.

 

I have 2 example scripts that might help.  The first uses the script expression reference(name). After you add your scripts right click on the framebox and select customize.  The JSL for your graphics script is not visible, only the expr reference. This works. However, if you or the user journals the graph, then later closes the journal.  If you open the journal in a new session, those expressions are not defned and the graphics will not be drawn. This method will work if there are no variable collisions in your graphics scripts and the graph is only relevant in the current session. Xpath is used to find the framebox TopSeq, the graphics added by the user, and in this case only the script reference.

 

Names Default To Here( 1 );
Open( "$SAMPLE_DATA/Big Class.jmp" );
orangepoly = Expr(	Transparency( 0.5 );
	Fill Color( {1.0, 0.5, 0.0} );
	Polygon( [60, 72, 57], [75, 120, 120] );
);
bluepoly = Expr(
	Transparency( 0.5 );
	Fill Color( {0.0, 0.5, 1.0} );
	Polygon( [60, 72, 57], [150, 120, 120] );
);
biv = Bivariate( Y( :weight ), X( :height ), FitLine );
rbiv = biv << report;
rbiv_fb = rbiv[frame box( 1 )];
rbiv_fb << Add Graphics Script(orangepoly);
rbiv_fb << Add Graphics Script(bluepoly);
//right click on the framebox and select Customize 
/*just the expr reference is visible
  If this graph is journaled, the journal is closed and reopened the graphics from the script 
  will not appear. look up Freeze All for the journal. */
   
glist = (rbiv_fb << XPath("//TopSeg")) << get script; 
idx = contains(glist, expr(bluepoly));
Wait( 3 );
rbiv_fb << Remove Graphics Script( idx );

This second method embeds the script into the framebox. After the scripts are added, right click in the framebox and select customize, click on a script to see the difference in the two methods. After adding a script inset into a list the script name. And when removing a script, remove it from the list. The list is a dynamic accounting of which scripts are active, and a function is used to locate its position.

Names Default To Here( 1 );
Open( "$SAMPLE_DATA/Big Class.jmp" );
glist={};
orangepoly = Expr(	
    Transparency( 0.5 );
	Fill Color( {1.0, 0.5, 0.0} );
	Polygon( [60, 72, 57], [75, 120, 120] );
);
bluepoly = Expr(
	Transparency( 0.5 );
	Fill Color( {0.0, 0.5, 1.0} );
	Polygon( [60, 72, 57], [150, 120, 120] );
);
addgraph  = Function({gnme}, {gexpr}, //"orangepoly")
   Eval(Parse("gexpr = NameExpr("||gnme||")" ) );
   Eval(Substitute(Expr(rbiv_fb << Add Graphics Script(_xxx)), Expr(_xxx), NameExpr(gexpr) ) );
   insert into(glist, gnme );
); //end addgraph 
rmvgraph  = Function({gnme}, {idx},
   idx = contains(glist, gnme);
   if(idx>0, 
        rbiv_fb << Remove Graphics Script(idx);
        removefrom(glist, idx)
   );
); //end rmvgrph
biv = Bivariate( Y( :weight ), X( :height ), FitLine );
rbiv = biv << report;
rbiv_fb = rbiv[frame box( 1 )];
addgraph("orangepoly");
addgraph("bluepoly");
//right click on the framebox and select Customize 
//the actual script is embedded
 
Wait( 3 );
rmvgraph("bluepoly");

I agree with your wish list item: add a Description/Name tag to these scripts (TopSegs)  framebox <<Add Graphics Script(name, script) is a definite nice to have.     

dqr2
Community Trekker

Re: Adding & Removing Graphics Scripts

Hi - that's very helpful indeed - especially the second method you describe, which is ingenious. Examples which illustrate how eval(substitute(expr(...))) constructions work in the context I'd want to use them are rather hard to come by, so I tend to end up writing more readable (at least to me) but far less smart scripts. However in this instance I'm evidently going to need something a lot closer to your example, which I'll adapt.

Often the most important thing in situations like this is just ensuring at the outset that a simple trick hasn't been missed before turning the heavy guns onto the problem :)

Many thanks

0 Kudos

Re: Adding & Removing Graphics Scripts

I also like @gzmorgan0 2nd approach. Here's another idea that searches for the script rather than maintaining a list. In a JSL script an expression like 0; or "fred"; doesn't do anything; it is evaluated and thrown away. So a graphics script like

"red"; fill color(...); circle(...);

can have an identifier at the beginning that can be studied later, using the arg( script, 1 ) function to get back "red".

dt = Open( "$sample_data/big class.jmp" );

gb = dt << Graph Builder(
    Size( 525, 452 ),
    Show Control Panel( 0 ),
    Variables( X( :weight ), Y( :height ) ),
    Elements( Points( X, Y, Legend( 6 ) ) )
);

colors = {"red", "green", "blue", "yellow", "cyan", "magenta", "orange", "purple", "gray"};

For( i = 1, i <= N Items( colors ), i++,
    Eval( // the "i" variable needs to be cast-in-stone so it will not be needed if the graph
        Eval Expr( // is saved in a journal. EvalExpr will pre-eval the expr() below...
            (Report( gb )[framebox( 1 )]) << addGraphicsScript(
                1,
                Expr( colors[i] ); // this will be the identifier for the script
                Fill Color( Expr( colors[i] ) ); // pre-eval the color name, not just the subscript
                Circle( {80 + 5 * Expr( i ), 50 + 2 * Expr( i )}, 1, "FILL" );
            )
        )
    )
);

findSegById = Function( {frame, id}, // locate a graphics script by an id string
    {child = frame << childSeg, script}, // the frame has a list of graphics scripts
    While( !Is Empty( child ),
        If( child << className == "TopSeg", // TopSeg is the className of a graphics script
            script = child << getscript; // check the script to see if the first
            If( Arg( script, 1 ) == id, // statement is the id name
                Return( child )
            );
        );
        child = child << sib;
    );
    Return( child ); // empty, not found
);

Wait( 1 );

thisOne = findSegById( Report( gb )[framebox( 1 )], colors[5] ); // the cyan script
thisOne << delete;

Wait( 1 );

thisOne = findSegById( Report( gb )[framebox( 1 )], "green" );
thisOne << delete;

Wait( 1 );

thisOne = findSegById( Report( gb )[framebox( 1 )], colors[9] ); // the gray script
thisOne << delete;

Wait( 1 );

// if needed, you can retrieve, edit, and replace the script
thisOne = findSegById( Report( gb )[framebox( 1 )], "blue" );
oldScript = thisOne << getscript;
newScript = Substitute( Name Expr( oldScript ), "FILL", Empty() ); // hollow black outline remains
Eval( Eval Expr( thisOne << setscript( Expr( Name Expr( newscript ) ) ) ) );
// gb << inval; 

Print( If( Is Empty( findSegById( Report( gb )[framebox( 1 )], "argyle" ) ), "Good", "Bad" ) );

Capture.PNGThree filled circles removed and one hollowed out

Capture1.PNGUse the customize popup menu item to see the scripts; this is the edited script

Craige
gzmorgan0
Super User

Re: Adding & Removing Graphics Scripts

Craige,

Thank you for the detailed example. The edit script example should be useful to many.

 

However, I am fixating on how nice it would be to have a decscription tag and getting a handle to the script would be as simple as

thisOne = rbiv_fb << Xpath( "//TopSeg[@description='bluepoly'] " );

 

Maybe JMP 15?

0 Kudos