Now we create a table script that has something like this.
dt = current data table();
print(dt:timestamp == Column(dt, "timestamp"));
// 0
print(Column(dt, "timestamp")==As Column(dt, "timestamp"));
//0
In automated scripts (for example, a graph), when a user changes the name of a column, it seems to adapt the script to the new column name. This failed in custom JSL, with something like Index() appearing.
How one would use all of these methods to make a JSL script robust to column name changes?
This is a bit long post and jumping here and there, sorry about that..
As Column(), Column(), :colname, ... isn't simple in JSL and which to use depends on the case. My preferred method is to always use (except when I cannot or if I want a bit cleaner look in script) Column(datatable_reference, "string of the name of the column"). :colname does have it's benefits which can be sometimes used for scripters benefit (some are mentioned here Scripting Guide > JSL Building Blocks > Rules for Name Resolution > Rules for Resolving Names in Exceptions section).
I also like to use strings of column names instead of :colname syntax to avoid some issues that might happen here and there. For example << Get Column Names("String") instead of just << Get Column Names() and then I get the reference with Column(string) if needed.
Column(<dt>, "name", "formatted") and As Column(name) are not same. Column() returns you a reference to column and As Column "accesses" a column (what this means depends on the case...). When you first run this script dt:timestamp will return missing value, as the Row() hasn't been properly defined for JMP's indexing (it is initialized as 0).
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
//Row() = 0;
Show(Row(), dt:name, Column(dt, "name"), As Column(dt, "name"));
Row() = 1;
Show(Row(), dt:name, Column(dt, "name"), As Column(dt, "name"), Column(dt, "name")[], Column(dt, "name")[Row()]);
Print(dt:name == Column(dt, "name"));
// 0
Print(Column(dt, "name") == As Column(dt, "name"));
//0
Print(dt:name == As Column(dt, "name"));
//1
stop();
//
Show(Column("name") << get values);
Show(As Column("name") << get values);
Show(:name << get values);
stop();
col1 = "name";
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(col1), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(Eval(col1)), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(As Column(col1)), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(Column(col1)), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(Column(dt, col1)), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
@ih has some good suggestions on how to manage name changes in columns. Also when inserting columns to for example Graph Builder, you can use Insert one expression into another using Eval Insert, Eval Expr, Parse, and Substitute and sometimes Eval(). << Get Name can also be helpful from time to time or building user interface with Filter Col Selector / Col List Box for example (like @pauldeen suggested).
How would you know which column the script should reference? If you really need to monitor for column name changes you could do that by subscribing to changes in the table and recording those column names somewhere, but I think that would be pretty complex. Could you instead define a column property and search for that?
Subscribe example from Scripting Guide:
Names Default To Here( 1 );
dt = Open( "$SAMPLE_DATA/Big Class.jmp" );
f = Function( {dtab, col, oldname},
Print( dtab << getname() );
Print( "new column name", (col << getname()) );
Print( "old name", oldname );
);
sub = dt << Subscribe( "", OnRenameColumn( f ) );
Column( dt, 1 ) << set name( "test" );
Wait( 1 );
dt << unsubscribe( sub, on rename column );
Use column property
Names Default To Here( 1 );
dt = Open( "$Sample_data/big class.jmp" );
dt:height << Set Property( "My Script Identifier", X );
XVar = Filter Each({c}, dt << Get Column References,
ident = char(c << Get Property( "My Script Identifier" ));
if( is empty(ident), 0, ident == "X", 1, 0)
)[1];
This is a bit long post and jumping here and there, sorry about that..
As Column(), Column(), :colname, ... isn't simple in JSL and which to use depends on the case. My preferred method is to always use (except when I cannot or if I want a bit cleaner look in script) Column(datatable_reference, "string of the name of the column"). :colname does have it's benefits which can be sometimes used for scripters benefit (some are mentioned here Scripting Guide > JSL Building Blocks > Rules for Name Resolution > Rules for Resolving Names in Exceptions section).
I also like to use strings of column names instead of :colname syntax to avoid some issues that might happen here and there. For example << Get Column Names("String") instead of just << Get Column Names() and then I get the reference with Column(string) if needed.
Column(<dt>, "name", "formatted") and As Column(name) are not same. Column() returns you a reference to column and As Column "accesses" a column (what this means depends on the case...). When you first run this script dt:timestamp will return missing value, as the Row() hasn't been properly defined for JMP's indexing (it is initialized as 0).
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
//Row() = 0;
Show(Row(), dt:name, Column(dt, "name"), As Column(dt, "name"));
Row() = 1;
Show(Row(), dt:name, Column(dt, "name"), As Column(dt, "name"), Column(dt, "name")[], Column(dt, "name")[Row()]);
Print(dt:name == Column(dt, "name"));
// 0
Print(Column(dt, "name") == As Column(dt, "name"));
//0
Print(dt:name == As Column(dt, "name"));
//1
stop();
//
Show(Column("name") << get values);
Show(As Column("name") << get values);
Show(:name << get values);
stop();
col1 = "name";
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(col1), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(Eval(col1)), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(As Column(col1)), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(Column(col1)), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
gb = dt << Graph Builder(
Size(529, 466),
Show Control Panel(0),
Variables(X(Column(dt, col1)), Y(:height)),
Elements(Points(X, Y, Legend(6)))
);
@ih has some good suggestions on how to manage name changes in columns. Also when inserting columns to for example Graph Builder, you can use Insert one expression into another using Eval Insert, Eval Expr, Parse, and Substitute and sometimes Eval(). << Get Name can also be helpful from time to time or building user interface with Filter Col Selector / Col List Box for example (like @pauldeen suggested).
I don't usually like +1 posts, but @jthi this is the exact same methodology I do for production scripts. I usually think about it like
Names default to here( 1 );
dt = open("$SAMPLE_DATA\Big Class.jmp");
col_name = "age";
show(ismissing(AsColumn(dt, col_name)) & ismissing(dt:age)); // these are both the same as far as I know
cols = dt << get column references; // these are the actual references
show(cols[2] == Column(dt, col_name)); // these are references