cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
Browse apps to extend the software in the new JMP Marketplace
Choose Language Hide Translation Bar
mjoner
Level VI

JSL: When analyses are dependent on temporary data, closing data when analysis is closed...

Hi all,

 

Background: I am currently writing an add-in where I am needing to create a temporary data table to hold some data points that are then being fed into Graph Builder. When the user closes the Graph Builder, I want the temporary data to go away. Easy enough, if I save the Graph Builder call to a variable, I can add an << On Close() to also close the temporary data.

 

However, strange things happen if my user wants to run the add-in twice against two different inputs, thus creating two temporary data tables and two Graph Builders. Now in this case, closing one of the Graph Builders may close the wrong temporary table (bringing down the other Graph Builder with it).

 

I imagine there must be a simple solution to this. I think the solution should be with Namespaces, but I can't figure out how to keep everything linked together! It seems that each time I make a new Namespace, the "ns" gets overwritten. The conundrum I have is in figuring out how to keep each separate instance of the add-in using its own "ns" value, and in such a way that I can feed the correct "ns" value into each of the several "On Close" codes that end up getting created.

 

Here's a simplified version of what I'm trying to do. The idea would be that if I run this, and then click the "Make Another One" button one or more times, and then dismiss one of the Graph Builders, the other one(s) will stay intact - without any concern about which Graph Builder I choose to dismiss first.

 

 

Names Default to Here(1);
MyFunction = Function({},
	ns = New Namespace();
	ns:dt = New Table("Test Table",
		<< New Column("Random X", << Formula(Random Normal())),
		<< New Column("Random Y", << Formula(Random Normal())),
		<< Add Rows(10),
		invisible
	);
	ns:gb = New Window("Test Output",
		Button Box("Make Another One",MyFunction()),
		Graph Builder(
			Show Control Panel( 0 ),
			Show Legend( 0 ),
			Variables( X( :Random X ), Y( :Random Y ) ),
			Elements( Points( X, Y, Legend( 4 ) ) )
		);
	);
	ns:gb << On Close(Try(Close(ns:dt, No Save)); ns << Delete);
);
MyFunction();

 

 

Looking for wisdom: What should I try next?

1 ACCEPTED SOLUTION

Accepted Solutions
txnelson
Super User

Re: JSL: When analyses are dependent on temporary data, closing data when analysis is closed...

I am, at times, frustrated that "Names Default to Here()" does not have separate namespaces upon each invocation of the code.  But, I also take advantage of that fact when debugging code.  So I see both advantages.  But here is an off-the-wall idea that does create separate "Here" name spaces.

If you take your original JSL, and add //! as the first line, that code will automatically run when opened from your hard drive.  When that script is opened, it has it's unique "Here" names space.  If you open the file a second time, it has it's own unique "Here" namespace.

On a couple of occasions in the past, I have used this ???? feature ????.  My main program uses a Save Text File(), to save the JSL in question to a $TEMP location, and then whenever the subsequent code needs to execute the code in the saved JSL, you use an Open() to run the file.  The passing of values to and from the saved JSL is done through a namespace defined in both the main program, and in the saved JSL program.

Here is your original example code setup in this way, and when run, each instance is independent in it's execution

names default to here(1);

graphJSL = "//!
Names Default to Here(1);
MyFunction = Function({},
	ns = New Namespace();
	ns:dt = New Table(\!"Test Table\!",
		<< New Column(\!"Random X\!", << Formula(Random Normal())),
		<< New Column(\!"Random Y\!", << Formula(Random Normal())),
		<< Add Rows(10),
		invisible
	);
	ns:gb = New Window(\!"Test Output\!",
		Button Box(\!"Make Another One\!",MyFunction()),
		Graph Builder(
			Show Control Panel( 0 ),
			Show Legend( 0 ),
			Variables( X( :Random X ), Y( :Random Y ) ),
			Elements( Points( X, Y, Legend( 4 ) ) )
		);
	);
	ns:gb << On Close(Try(Close(ns:dt, No Save)); ns << Delete);
);
MyFunction();";

Save Text File( "$TEMP/Graph1.jsl", graphJSL );
open("$TEMP/Graph1.jsl");
open("$TEMP/Graph1.jsl");

 

Jim

View solution in original post

4 REPLIES 4
txnelson
Super User

Re: JSL: When analyses are dependent on temporary data, closing data when analysis is closed...

The issue is that your variable "ns" gets replaced on the second and subsequent runs of the function.  Therefore you need to use a unique reference to the data table.  Below is a version of your code, that uses the name of the data table to close it.

Names Default To Here( 1 );
MyFunction = Function( {},
	ns = New Namespace();
	ns:dt = New Table( "Test Table",
		<<New Column( "Random X", <<Formula( Random Normal() ) ),
		<<New Column( "Random Y", <<Formula( Random Normal() ) ),
		<<Add Rows( 10 ),
		invisible
	);
	ns:gb = New Window( "Test Output",
		Button Box( "Make Another One", MyFunction() ),
		Graph Builder(
			Show Control Panel( 0 ),
			Show Legend( 0 ),
			Variables( X( :Random X ), Y( :Random Y ) ),
			Elements( Points( X, Y, Legend( 4 ) ) )
		)
	);
	Eval(
		Substitute(
				Expr(
					ns:gb << On Close(
						Try( Close( __dt__, No Save ) );
						ns << Delete;
					)
				),
			Expr( __dt__ ), Parse( "data table(\!"" || Char( ns:dt << get name ) || "\!")" )
		)
	);
);
MyFunction();

 

Jim
mjoner
Level VI

Re: JSL: When analyses are dependent on temporary data, closing data when analysis is closed...

Thanks. This is useful for simple solutions like this one.

 

I may be in for a huge code rewrite and even then I'm not sure it's possible to do what I want to do. My actual add-in stores a bunch of DisplayBox references into ns as well, and the DisplayBoxes trigger various additional actions both in platforms and in the data table. All of the DisplayBox references get cannibalized when the add-in re-launches as well. I suppose if I'm lucky I can convert most of my DisplayBoxes to trigger functions so I can hit this << Parent and drill back down to other boxes to update outputs, etc. It is sounding like I am going to have to seriously rethink what I'm doing.

 

I had hoped that Names Default to Here would create a separate Here namespace each time the code was re-run but that doesn't seem to be the case...

 

Any other good options before I start down this other road?

txnelson
Super User

Re: JSL: When analyses are dependent on temporary data, closing data when analysis is closed...

I am, at times, frustrated that "Names Default to Here()" does not have separate namespaces upon each invocation of the code.  But, I also take advantage of that fact when debugging code.  So I see both advantages.  But here is an off-the-wall idea that does create separate "Here" name spaces.

If you take your original JSL, and add //! as the first line, that code will automatically run when opened from your hard drive.  When that script is opened, it has it's unique "Here" names space.  If you open the file a second time, it has it's own unique "Here" namespace.

On a couple of occasions in the past, I have used this ???? feature ????.  My main program uses a Save Text File(), to save the JSL in question to a $TEMP location, and then whenever the subsequent code needs to execute the code in the saved JSL, you use an Open() to run the file.  The passing of values to and from the saved JSL is done through a namespace defined in both the main program, and in the saved JSL program.

Here is your original example code setup in this way, and when run, each instance is independent in it's execution

names default to here(1);

graphJSL = "//!
Names Default to Here(1);
MyFunction = Function({},
	ns = New Namespace();
	ns:dt = New Table(\!"Test Table\!",
		<< New Column(\!"Random X\!", << Formula(Random Normal())),
		<< New Column(\!"Random Y\!", << Formula(Random Normal())),
		<< Add Rows(10),
		invisible
	);
	ns:gb = New Window(\!"Test Output\!",
		Button Box(\!"Make Another One\!",MyFunction()),
		Graph Builder(
			Show Control Panel( 0 ),
			Show Legend( 0 ),
			Variables( X( :Random X ), Y( :Random Y ) ),
			Elements( Points( X, Y, Legend( 4 ) ) )
		);
	);
	ns:gb << On Close(Try(Close(ns:dt, No Save)); ns << Delete);
);
MyFunction();";

Save Text File( "$TEMP/Graph1.jsl", graphJSL );
open("$TEMP/Graph1.jsl");
open("$TEMP/Graph1.jsl");

 

Jim
mjoner
Level VI

Re: JSL: When analyses are dependent on temporary data, closing data when analysis is closed...

This is a great "feature". Much faster to implement for my code, only took an hour or two to make the adjustments this way, making sure I had a namespace to work with, etc., rather than figuring out how to replace all of my DisplayBox variables (which I was not looking forward to).

 

In this solution I also added a Wait() and then a Delete File() after the Open() since my Button Box that triggers a new run will simply write a new Temp file out each time it is clicked.