You can create a customized legend from graph boxes inside of a col box inside of a table box.
For example, here I create a table holding the fail codes and the row-states to use for each one (you would probably want to set this in a global namespace for re-use in your code, and make the table private so it doesn't show).
Next I create two example data tables, one of which has only half of the fail codes defined.
Next I create two functions -- one does a smart sort so that consecutive legend entries are consecutive (i.e., so that "FailCode_1, FailCode_10, FailCode_2" gets sorted properly). The second function plots the bivariates and adds a custom legend.
When you run this, notice how the colors and markers for each plot are the same for the same FailCode. You would probably want to set the colors and markers for your code, this is simply an example.
Names Default to Here( 1 );
colors = {
//{r,g,b}
{1,0.5,0},
{1,0,1},
{0,1,1},
{1,0,0},
{0,1,0},
{0,0,1},
{0.7, 0.5, 0.3},
{0.3, 0.5, 0.7},
{0.5, 0.3, 0.7},
{0.5, 0.7, 0.3},
{0.7, 0.5, 0.7},
{0.5, 0.7, 0.5},
{0.3, 0.7, 0.7},
{0.9, 0.1, 0.2},
{0.3, 0.5, 0.6},
{0.1, 0.3, 0.9},
{0.5, 0.2, 0.0},
{0.0, 0.7, 0.3},
{0.4, 0.1, 0.2},
{0.8, 0.5, 0.2},
{0.2, 0.8, 0.5}
};
names = {
"FailCode_0",
"FailCode_1",
"FailCode_2",
"FailCode_3",
"FailCode_4",
"FailCode_5",
"FailCode_6",
"FailCode_7",
"FailCode_8",
"FailCode_9",
"FailCode_10",
"FailCode_11",
"FailCode_12",
"FailCode_13",
"FailCode_14",
"FailCode_15",
"FailCode_16",
"FailCode_17",
"FailCode_18",
"FailCode_19",
"FailCode_20"
};
Eval( Eval Expr(
color table = New Table("Colors",
<<New Column( "FailCode", "Character", <<Set Values( names ) ),
<<New Column( "States", "Row State", <<Set Each Value( Combine States( colors = Expr( colors ); Color State( colors[Row()] ), Marker State( Row() ) ) ) )
)
) );
color table:States << Copy to Row States();
table 1 = New Table( "DataExample1",
<<New Column( "rows", "Numeric", <<Set Values( 1::1000 ) ),
<<New Column( "Wafer", "Character", <<Set Each Value( "WAFER_" || Char( Random Integer( 1, 4 ) ) ) ),
<<New Column( "FailCode", "Character", <<Set Each Value( "FailCode_" || Char( 2 * Random Integer( 1, 10 ) ) ) ),
<<New Column( "Time", "Numeric", <<Set Each Value( Today() + Random Integer( 1, 1000 ) * 60 ), << Format( "y/m/d h:m:s", 22, 0 ) ),
<<New Column( "Data", "Numeric", <<Set Each Value( Random Exp() ) )
);
table 2 = New Table( "DataExample1",
<<New Column( "rows", "Numeric", <<Set Values( 1::5000 ) ),
<<New Column( "Wafer", "Character", <<Set Each Value( "WAFER_" || Char( Random Integer( 1, 4 ) ) ) ),
<<New Column( "FailCode", "Character", <<Set Each Value( "FailCode_" || Char( Random Integer( 1, 20 ) ) ) ),
<<New Column( "Time", "Numeric", <<Set Each Value( Today() + Random Integer( 1, 1000 ) * 60 ), << Format( "y/m/d h:m:s", 22, 0 ) ),
<<New Column( "Data", "Numeric", <<Set Each Value( Random Exp() ) )
);
//Here is where we set the row-states for the tables to plot. We don't want the bivariate function setting the row states.
table 1 << Update( With( color table ),
Match Columns( :FailCode = :FailCode ),
Add Columns From Update Table( :States )
);
table 1:States << Copy to Row States();
table 1 << Delete Columns( "States" );
//again for the second table
table 2 << Update( With( color table ),
Match Columns( :FailCode = :FailCode ),
Add Columns From Update Table( :States )
);
table 2:States << Copy to Row States();
table 2 << Delete Columns( "States" );
smart sort = Function( {list, return sort index = 0},
{args, function name, doc string, sorted list, i, j, var, val, ret},
sorted list = {};
For( i = 1, i <= N Items( list ), i++,
j = 0;
var = "";
While( Not( Is Missing( val = Num( Substr( list[i], Length( list[i] ) - j ) ) ) ) & j < Length( list[i] ),
var = val;
j++;
);
sorted list[i] = Eval List( {Substr( list[i], 1, Length( list[i] ) - j ), var, i, j} );
);
sorted list = Sort List( sorted list );
If( return sort index == 0,
For( i = 1, i <= N Items( list ), i++,
list[i] = sorted list[i][1] || Right( Char( sorted list[i][2] ), sorted list[i][4], "0" )
);
,
For( i = 1, i <= N Items( sorted list ), i++,
If( sorted list[i][1] == "BASELINE",
list[sorted list[i][3]] = 0
,
list[sorted list[i][3]] = i
)
);
);
list
);
make bivariate = Function( {table, xcol, ycol, categorical, legend},
{Default Local},
legend items = Smart Sort( Associative Array( Column( table, legend ) ) << Get Keys );
n items = N Items( legend items );
legend marker box = Col Box( "" );
names = {};
For( i = 1, i <= n items, i++,
Eval( Eval Expr(
loc = color table << Get Rows Where( :FailCode == Expr( legend items[i] ) )
) );
// here is a little fun magic to create a legend column out of graph boxes
ob = Outline Box( "",
gb = Graph Box(
Frame Size( 14, 14 ),
Y Scale( 0, 1 ),
X Scale( 0, 1 ),
SuppressAxes,
Marker Seg( [0.5], [0.5], Row States( color table, Matrix( loc ) ) )
)
);
//make sure that all the padding and borders look right
gb[Frame Box( 1 )] << Padding( Left( 0 ), Top( 0 ), Right( 0 ), Bottom( 0 ) ) << Border( Top, 0 ) << Border( Bottom, 0 ) << Border( Left, 0 ) << Border( Right, 0 ) << Marker Size( 3 ) << SetBackgroundFill( 0 );
gb[Border Box( 1 )] << Left( 0 ) << Top( 0 ) << Right( 0 ) << Bottom( 0 ) << Sides( 0 );
legend marker box << Append( ob );
Insert Into( names, legend items[i] );
);
legend name box = String Col Box( "FailCode", names );
Eval( Eval Expr(
hlb = H List Box(
Platform( table, //need to encapsulate the bivariate in a platform to ensure it uses the correct table
biv = Bivariate(
Y( Column( table, ycol ) ),
X( Column( table, xcol ) ),
By(Column( table, categorical ))
);
)
,
legend box = Table Box(
legend marker box
,
legend name box
)
);
) );
Try( hlb[List Box( 2 )] << Set Horizontal( 1 ) );
legend box << Set Selectable Rows( 1 ) << Set Shade Alternate Rows( 0 ) << Set Shade Cells( 0 ) << Set Shade Headings( 0 ) << Set Column Borders( 0 ) << Set Row Borders( 0 ) << Set Underline Headings( 0 );
If( Num( Trim( Word( 1, JMP Version(), "." ) ) ) > 12,
legend box << Set Column Group Borders( 0 ) << Set Heading Column Borders( 0 );
);
//Lastly we need to set the row change function so that clicking the legend does normal legend things.
Eval( Eval Expr(
legend box << Set Row Change Function(
Function( {this},
table = Expr( table );
items = Expr( legend items );
rows = this << Get Selected Rows();
legend column = Expr( legend );
If( N Rows( rows ) == 0,
table << Clear Select;
Return( 0 );
);
vals = Insert( {}, items[rows] );
Eval( Parse( Eval Insert( "\[
table << Select Where( Contains( ^vals^, :Name("^legend column^") ) )
]\" ) ) )
)
)
) );
hlb
);
Eval( Eval Expr(
New Window( "test",
<<On Close(
color table = Expr( color table );
table 1 = Expr( table 1 );
table 2 = Expr( table 2 );
Try( Close( table 1, No Save ) );
Try( Close( table 2, No Save ) );
Try( Close( color table, No Save ) );
)
,
V List Box(
Outline Box( "",
make bivariate( table 1, "time", "data", "Wafer", "FailCode" )
)
,
Outline Box( "",
make bivariate( table 2, "time", "data", "Wafer", "FailCode" )
)
)
)
) );
Jordan