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
Byron_JMP
Staff
Old and New Control Limits on the Same Control Chart

Byron_JMP_0-1670006845951.png

 

 

I run into a problem where I want to see what my old control limits would look like relative to the current or new fixed control limits for a set of control charts. Typically, I'd go about adding reference lines to each graph, but I think there might be a better way, using a long forgotten (at least to me) platform message. 

 

Earlier this year I was playing around with the idea of what it would look like to add a new column property, in this case Action and Alert Limts for environmental monitoring charts, and then use that column property as a reference line in control charts.   

 

While I was looking for something completely different in the Scripting Index, I ran across a function called "Add Limits".  As far as I can tell, this function has been around for a long time, before JMP 14 at least, and it can be used to send Upper and Lower Control Limits to a control chart. These limits are displayed as dashed lines, and they are listed in a table alongside the graph.  It would take me a lot of JSL to get that to happen, so it’s nice to discover such a highly useful utility.. 

 

The basic usage of "Add Limits" looks something like this, where the last line of JSL sends a message to the chart that includes the values to use as the dashed line limits.:

//Example of adding limits to a control chart
ccb = dt << Control Chart Builder( Variables( Y( :Column 1 ) ), Show Control Panel( 0 ) );
ccb << chart( position( 1 ), Add Limits( {LCL( 20 ), UCL( 30 )} ) );

 

Of course, I'd want to use "Add Limits" dynamically with any column, so that takes a little extra bit of fancy foot work.

 

First, let's set up a table to used as an example. Note that while setting up the table I delete the formula that generates some random data to work with right after the table is constructed. This fixes the values in the table.

dt=New Table( "old and new control limits",Add Rows( 50 ),
	New Column( "Column 1",Numeric,"Continuous",Format( "Best", 12 ),
	Formula( Round( Random Normal( 25, 3 ), 0 ) )));
column(dt, 1)<< Delete Formula;

 

The next step is to add a new kind of column property, something custom that doesn't natively exist in JMP. After running this line, the column in the data table now has a property called Old Control Limits

Column( dt, 1 ) << set property( "Old Control Limits", {LCL( 20 ), UCL( 30 )} );

 

Then, just to check to see if the script worked you can get a look at the values from the column property. The new variable, OCL, has two values, LCL(20), and UCL(30). I can use those values in a new control chart:

OCL = Column( dt, 1 ) << Get Property( "Old Control Limits" );Show( OCL[1], OCL[2] );

 

The next couple of lines might look really odd, but they are super robust and take advantage of function based structure of JSL.

 

First, I'm going to define a couple of empty or nearly empty arguments and then I'm going to nest them together. By setting up these expressions I can handle each part without evaluating them.  ccbe, the control chart builder expression is a function, Control Chart Builder with two arguments, Variables and Show Control Panel.

 

Next, I want to add a new argument called chart() to the Control Chart Builder function.

  • The new variable, ce is an expression with the argument chart and chart includes  an argument, position (1)
  • I want to add, add limits to the chart argument so I have variable ae, to reference an empty add limits expression.
  • Last I make an empty list called le, which will contain the limits I got from Get Property in the OCL variable from the previous step.
ccbe = Expr(Control Chart Builder( Variables( Y( :Column 1 ) ), Show Control Panel( 0 ) ));
ce = Expr( chart( position( 1 ) ) );
ae = Expr( add limits() );
le = {};

Then, I layer the pieces together to do this:

  • First, I take the list of things in OCL and insert it into le.
  • Second, I take le and insert it into ae, followed by inserting ae into ce.  In the second case I wrapped ae inside a Name Expr(). This gives me the evaluated expression of ae without evaluating it.   This NameExpr() method is super handy.
  • Third, I insert ce into the ccbe, which is the whole control chart expression. 
  • I also included a Show after each step so you can see how the function is being built in the log.
  • The last step is to get a graph. By just running ccbe all alone, that variable holding the complete expression gets evaluated, and I get a control chart with dashed lines representing the old control limits, which came from the columns properties
Insert Into( le, OCL );show( le );
Insert Into( ae, le );Show( ae );
Insert Into( ce, Name Expr( ae ) );Show( ce );
Insert Into( ccbe, Name Expr( ce ), 2 );
ccbe;

 

With a little more effort, I'm pretty sure it would be possible to start with a table that includes the current and old control limits, which could be used to populate all the column properties for a whole table of process variables.  

 

The entire script is attached.

 

 

 

 

Last Modified: Dec 6, 2022 10:19 AM
Comments
jmpstopper
Staff

Nice @Byron_JMP 

Side note - I also had no idea Set Property() allows one to just create your own. Makes sense after the fact: a column being just another object, so parallels New Table Variable for setting object (column, table) variables/values. Thanks for that nugget!