JSL scripting for dynamic column asignment in graph builderI am attempting to create a session script to generate graphs using JMP's Graph Builder. However, a challenge arises because the number of columns in my data varies depending on the period each time the data is updated, which necessitates modifying the Graph Builder script manually for each update.
To address this, I am considering a method where column names are prefixed (e.g., A_, B_, C_). This would allow me to dynamically assign columns: for instance, columns prefixed with A_ could be directed to the Local Data Filter, those with B_ to the Column Switcher, and so forth.
I would like to know how this approach can be implemented in JSL (JMP Scripting Language), as I have not been able to write an effective script myself. You mentioned having an incomplete JSL draft in mind, but it was not included in your prompt. If you can provide the draft, I would be happy to help you refine it or suggest a solution.
I am also encountering the following error.→[For Each , Bad Argument( colName ), For Each/*###*/(colName, columnNames,...The argument must be a list.]
dt = Current Data Table();
A_list = {};
B_list = {};
columnNames = As List(dt << Get Column Names("String"));
For Each(colName, columnNames,<BR />
If(Contains(colName, "A_"),
Insert Into(A_list, colName)
);
If(Contains(colName, "B_"),
Insert Into(B_list, colName)
);
);
Graph Builder(
Variables(
X( :point ),
Y( :avg ),
Y( :stddev ),
Page( :category ),
Color(B_list[1])
),
Elements(
Position( 1, 1 ),
Points( X, Y( 1 ), Legend( 27 ) ),
Line( X, Y( 2 ), Y( 3 ), Color( 0 ), Legend( 29 ) )
),
Elements(
Position( 1, 2 ),
Points( X, Y( 1 ), Legend( 28 ) ),
Line( X, Y( 2 ), Y( 3 ), Color( 0 ), Legend( 31 ) )
),
Local Data Filter(
Conditional,
Add Filter(
columns( A_list ),
Display( A_list[1], N Items( 7 ), Find( Set Text( "" ) ) ),
Display( A_list[2], N Items( 7 ) ),
Display( :key, N Items( 12 ) )
)
),
Column Switcher(
:msr_dt,
B_list
)
);Automation and ScriptingRe: JSL scripting for dynamic column asignment in graph builderdid you consider column tags to "group" the columns?
this could provide a similar functionality - and it even allows overlapping "groups".
Something like:
Names Default to Here(1);
dt = Open( "$SAMPLE_DATA/Big Class Families.jmp" );
dt:sex << setProperty( "Tags", {"pick"} );
dt:height << setProperty( "Tags", {"pick"} );
dt:weight << setProperty( "Tags", {"pick"} );
cols = dt << Get Tagged Columns( "pick" );
dt << Distribution( Column( Eval(cols) ));
by the way, it's for each ({col}, cols, body)
Re: JSL scripting for dynamic column asignment in graph builder
Thank you for your replying, hogi.
I had not considered column tags. I will try to revise the script using column tags once again.
I will reply after doing that.
Re: JSL scripting for dynamic column asignment in graph builderDepending on your use case, you could use tags like already suggested, custom column property, prefixed column names, column groups,... all of the options do have their own pros and cons.
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Semiconductor Capability.jmp");
collist = dt << Get Column Names("String");
npn_cols = Filter Each({colname}, collist, Starts With(colname, "NPN"));
pnp_cols = Filter Each({colname}, collist, Starts With(colname, "PNP"));
gb = dt << Graph Builder(
Variables(X(:SITE), Y(:IVP1), Color(pnp_cols[1])),
Elements(
Position(1, 1),
Points(X, Y(1), Legend(27))
),
Elements(
Position(1, 2),
Points(X, Y(1), Legend(28)),
Line(X, Y(2), Y(3), Color(0), Legend(31))
)
);
filter_cols = npn_cols[1::2];
Insert Into(filter_cols, "SITE");
ldf = gb << Local Data Filter(
Conditional,
Add Filter(
columns(Eval(filter_cols)),
Display(filter_cols[1]),
Display(filter_cols[2]),
Display(filter_cols[3])
)
);
cw = gb << Column Switcher(pnp_cols[1], pnp_cols);
Also... is this some sort of hybrid of a community question and a LLM prompt (we are humans here in Community, hopefully)?
Re: JSL scripting for dynamic column asignment in graph builder
Please excuse my reply being in Japanese (I thought this would better convey my true intentions).
We are now sharing with the community instances where JMP learnBot could not resolve the issue.
Ultimately, I'm using this community to improve my own scripting skills by receiving advice and guidance on scriptwriting methods from knowledgeable individuals, and also to contribute to the skill development of other JMP users around me.
However, I am very sorry, as I am worried that I may have offended jthi, who always answers my questions so kindly. If there was anything impolite or inappropriate about the way I asked the question, I would be grateful if you could point it out for future reference.
Re: JSL scripting for dynamic column asignment in graph builderI wasn't offended by your post but more weirded out as it felt like we are being prompted here. I would clearly suggest separating the prompt if you have used one.
LearnBot isn't really that good with JSL as it isn't prompted that way. Assistant might be slightly better, but you might get better results if you prompt LLM (such as Claude, preferrably one your company has access to) so it understands what it should be doing (JSL).
Re: JSL scripting for dynamic column asignment in graph builder
As Jthi pointed out, I hadn't made a clear distinction in my mind between prompts for LLM and postings to the JMP user community.
In the future, I will carefully review the content to determine whether it is a question for LLM or an appropriate post for the JMP user community. Thank you for pointing out important points to keep in mind for smoother communication.
I look forward to your continued support.
Re: JSL scripting for dynamic column asignment in graph builderIn case you were looking at how to make the script itself work, here is an updated version that might get you started. I commented a few sections I changed, note that the most complex one involves inserting a list of columns into the local data filter which prompted the Eval( Eval Insert( ) ) functions. You might check out Insert one expression into another using Eval Insert, Eval Expr, Parse, and Substitute to see different options for that.
Names default to here(1);
Random reset(1);
msr_dt = New Table( "Example Data",
Add Rows( 200 ),
New Column( "A_1", Character, "Nominal", Formula( if(random uniform(1)<0.2,"",Substr( "ABC", floor(Random uniform( 4 )),1) ))),
New Column( "A_2", Character, "Nominal", Formula( if(random uniform(1)<0.2,"",Substr( "DEF", floor(Random uniform( 4 )),1) ))),
New Column( "B_1", Character, "Nominal", Formula( if(random uniform(1)<0.2,"",Substr( "GHI", floor(Random uniform( 4 )),1) ))),
New Column( "B_2", Character, "Nominal", Formula( if(random uniform(1)<0.2,"",Substr( "JKL", floor(Random uniform( 4 )),1) ))),
New Column( "point", Numeric, "Continuous", Format( "Best", 12 ), Formula( Row() ) ),
New Column( "avg", Numeric, "Continuous", Format( "Best", 12 ), Formula( Random Normal( 5 ) ) ),
New Column( "stddev", Numeric, "Continuous", Format( "Best", 12 ), Formula( Random Normal( 0.5 ) ) ),
New Column( "category", Character, "Nominal", Formula( Char( Floor( Row() / 101 ) ) ), Set Selected ),
New Column( "key", Character, "Nominal", Formula( Substr( "abcdefghijklmnopqrstufwxyz", floor(Random uniform( 27 )),1) )),
);
A_list = {};
B_list = {};
columnNames = As List(msr_dt << Get Column Names("String"));
For Each({colName},columnNames, // change here - note brackets
If(Contains(colName, "A_"),
Insert Into(A_list, colName)
);
If(Contains(colName, "B_"),
Insert Into(B_list, colName)
);
);
Eval(Eval expr(
Graph Builder(
Variables(
X( :point ),
Y( :avg ),
Y( :stddev ),
Page( :category ),
Color(B_list[1])
),
Show Control Panel( 0 ),
Elements(
Position( 1, 1 ),
Points( X, Y( 1 ), Legend( 27 ) ),
Line( X, Y( 2 ), Y( 3 ), Color( 0 ), Legend( 29 ) )
),
Elements(
Position( 1, 2 ),
Points( X, Y( 1 ), Legend( 28 ) ),
Line( X, Y( 2 ), Y( 3 ), Color( 0 ), Legend( 31 ) )
),
Local Data Filter(
Conditional,
Add Filter(
columns( Expr( A_list || {"key"} ) ), //this needs to be evaluated before the graph builder function is called
Display( A_list[1], N Items( 7 ) ), //removed the find term
Display( A_list[2], N Items( 7 ) ),
Display( :key, N Items( 12 ) )
)
),
Column Switcher(
B_list[1], // added reference to specific column here - was the data table
B_list
)
)
));
Re: JSL scripting for dynamic column asignment in graph builderJSL Novice here, so please forgive me if this was asked and answered earlier.
What I want to do is modify the above Graph Builder script to plot IVP columns vs NPN columns with colors from PNP columns. Enclosed is the modified script (Multiple Column Switcher.jsl) - with 3 column switchers. And I have to manually choose the combinations of IVP, NPN and PNP columns I want. If I know the IVP NPN and PNP columns are all mapped 1 to 1 (i.e. IVP3 vs NPN3 and PNP3 for example), how can I have single column switcher to do that?
Re: JSL scripting for dynamic column asignment in graph builderI had simplified version of this in my tips&tricks presentation in discovery summit (Skip, Hop, and JMP a Minute: Bite-Sized JMP Wisdom from a Super User (2026-EU-30MP-2767) , tip "Column switchers for everyone (Multiple Column Switchers)")
This is quite simple way of doing it (do note that NPN has more columns than the rest so it will use incorrect column in that case)
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Semiconductor Capability.jmp");
collist = dt << Get Column Names("String");
npn_cols = Filter Each({colname}, collist, Starts With(colname, "NPN"));
pnp_cols = Filter Each({colname}, collist, Starts With(colname, "PNP"));
ivp_cols = Filter Each({colname}, collist, Starts With(colname, "IVP"));
gb = dt << Graph Builder(
Variables(X(:NPN1), Y(:IVP1), Color(pnp_cols[1])),
Elements(
Position(1, 1),
Points(X, Y(1), Legend(27))
),
Elements(
Position(1, 2),
Points(X, Y(1), Legend(28)),
Line(X, Y(2), Y(3), Color(0), Legend(31))
)
);
cw1 = gb << Column Switcher(npn_cols[1], npn_cols);
cw2 = gb << Column Switcher(pnp_cols[1], pnp_cols);
cw3 = gb << Column Switcher(ivp_cols[1], ivp_cols);
Eval(EvalExpr(
post = Function({previousColumn, currentColumn, switcher},
c2 = Substitute((currentColumn << get name), "NPN", "PNP");
c3 = Substitute((currentColumn << get name), "NPN", "IVP");
Expr(cw2) << Set Current(c2);
Expr(cw3) << Set Current(c3);
);
));
handler = cw1 << Make Column Switch Handler(post);
// might want to hide other column switchers
cw_obs = (Report(gb) << Top Parent) << XPath("//ColumnSwitcherContextOutlineBox");
cws = cw_obs << Get Scriptable Object;
cw_obs[2] << Visibility("Collapse");
cw_obs[3] << Visibility("Collapse");
Write();
Stacked data table and local data filter can also be a good option for things such as this