帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败你好,
我创建了一个脚本,通过分析 M 个因素对 N 个指标的单独统计影响来汇总数据表。
摘要表显示了具有 M 个因素(列)的 N 个指标(行)矩阵,具体影响包括:均值偏移、Cpk 退化或两者兼有)
我想添加一个功能,使用列公式绘制每个选定行的分布图。
我受到这篇文章的启发:
将单元格(在 JMP 表中)链接到脚本?
问题是,我的脚本在新脚本窗口中使用固定选定行(本例中为 [5])运行良好,但当我将脚本包含在 :Graph 列公式中时,脚本会失败。我不明白为什么……
你能帮我调试一下吗?
附有 2 个表格:datatable_test.jmp 包含原始数据,Summary.jmp 包含列公式。思路是单击要在 :Graph 列中绘制的单元格。
目前错误显示:“行 [ ] 处的非法引用(递归)”

当我在打开两个表的情况下运行以下脚本时,它会按预期工作(见下文)。但是,当直接从表中运行时(单击 Graph 列中的单元格),脚本会失败。

提前谢谢您,
- 传教士
// this script works from a Script window
// All features related to the column formula are commented
// here the row selected is row 5 : rn1 = [5]
Names Default To Here( 1 );
dt = Data Table( "datatable_test" );
dt2 = Data Table( "Summary" );
//If( Selected( Row State() ),
Eval(
Parse(
rn1 = [5]/*dt2 << get selected rows*/;
rn = rn1[1];
Factors = dt2 << get column names( "string" );
show(rn1, rn);
Eval(
Eval Expr(
For( i = N Items( Factors ), i >= 1, i--,
CurrCol = Column( dt2, Factors[i] );
If(Char( CurrCol[ rn ] ) == "Ok" | Factors[i] == "Metric"| Factors[i] == "Graph",
Remove From( Factors, i, 1 )
);
)
)
);
FactorA = "X( :" || Char( Factors[1] ) || ", Position( 1 ))";
FactorB = "X(1)";
For( j = 2, j <= N Items( Factors ), j++,
FactorA = Char( FactorA ) || ",X( :" || Char( Factors[j] ) ||
", Position( 1 ))";
FactorB = Char( FactorB ) || ",X( " || Char( j ) || " ) ";
);
Show( dt2:Metric[rn], FactorA, FactorB );
Key = dt2:Metric[rn];
Eval Insert(
" dt << Graph Builder(
Size( 534, 464 ),
Show Control Panel( 0 ),
Show Legend( 0 ),
Variables(
Y( ^Key^ ), ^FactorA^),
Elements( Box Plot( Y, Legend( 18 ), ^FactorB^ ) ),
SendToReport(
Dispatch(
{},
ScaleBox,
{Min( -0.485125992718803 ), Max( 5.53364268893602 ), Inc( 1 ),
Minor Ticks( 0 )}
)
)
) "
);
)
//)
);自动化和脚本回复:帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败使用列公式执行此操作是否有特定原因?例如,自定义一个带有表框和按钮的窗口将更容易构建和管理。或者在摘要表上使用行状态处理程序(尽管如果可能的话我会避免这样做)。
回复:帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败嗨,贾莫,
没有特别的原因,我只是以这种方式创建了我的原始脚本,使用数据表来生成摘要。
我没有想到这一点:打开一个表格框并添加按钮似乎是个好主意,我可以考虑到这一点来修改我未来的版本。
但与此同时,您认为让列公式发挥作用是否值得?这样我就能在下一个版本之前更快地获得一个可用的版本?我担心更改结构以生成表格框而不是数据表会花费我一些时间,因为我还不太熟悉显示/表格框。
我想包含在列公式中的脚本片段可以独立运行,但在列公式中运行时会失败。我肯定做错了什么,但不确定是什么...
回复:帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败编辑:
我实际上发现将表格转换为显示框很容易:
nw = New Window("Report",
dt << Get As Report()
);报告生成如下

当单击行时,我没想到公式会在报告中起作用(并且它不起作用......)。
但现在我不确定您会建议如何实施您的建议。
(再次强调,我还不熟悉显示框操作)
提前致谢
回复:帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败编辑2:
我最终按照 Jarmo 和这篇文章的建议让脚本运行起来:
JSL 帮助:获取报告和表格框
现在,当我单击报告中的一行时,它会根据所选行运行脚本,这正是我所需要的:)

下面的脚本需要打开我在第一条消息中加入的 2 个表
谢谢
- 传教士
Names Default To Here( 1 );
dt7 = Data Table("Summary");
dt = Data Table("datatable_test");
dt7 << clear select;
dt7 << Clear Column Selection();
RptWin = New Window( "Data Table as report",
Outline Box("Data Table as Report",
dt7_Rpt = dt7 << Get as Report();
)
);
tb = dt7_Rpt[Table Box( 1 )];
tb << Set Heading Column Borders( 1 );
tb << Set Selectable Rows( 1 );
tb << Set Row Change Function(
Function( {this},
{SelRows},
SelRows = this << Get Selected Rows;
If(
N Items( SelRows ) > 1, Throw( "Too many items selected!\!rOnly one selection possible." ),
N Items( SelRows ) == 1,
SelRows = this << Get Selected Rows;
);
dt7 << Clear Select;
rn = dt7 << Select rows( SelRows ) << get selected rows;
show (rn[1], dt7:Metric[rn]);
Factors = dt7 << get column names( "string" );
Eval(
Eval Expr(
For( i = N Items( Factors ), i >= 1, i--,
CurrCol = Column( dt7, Factors[i] );
If(Char( CurrCol[ rn[1] ] ) == "Ok" | Factors[i] == "Metric"| Factors[i] == "Graph",
Remove From( Factors, i, 1 )
);
)
)
);
show (Factors);
Try(FactorA = "X( :" || Char( Factors[1] ) || ", Position( 1 ))");
FactorB = "X(1)";
For( j = 2, j <= N Items( Factors ), j++,
Try(FactorA = Char( FactorA ) || ",X( :" || Char( Factors[j] ) || ", Position( 1 ))");
FactorB = Char( FactorB ) || ",X( " || Char( j ) || " ) ";
);
Show( dt7:Metric[rn], FactorA, FactorB );
Key = dt7:Metric[rn];
If (Factors != {},
Eval(Parse(Eval Insert(
" dt << Graph Builder(
Size( 534, 464 ),
Show Control Panel( 0 ),
Show Legend( 0 ),
Variables(Y( ^Key^ ), ^FactorA^),
Elements(
Box Plot( Y, Legend( 18 ), ^FactorB^ ),
Caption Box(X, Y, Legend(20), Summary Statistic( \!"N\!" ),Location( \!"Graph per factor\!" ))),
SendToReport(
Dispatch(
{},
ScaleBox,
{Min( -0.485125992718803 ), Max( 5.53364268893602 ), Inc( 1 ),
Minor Ticks( 0 )}
)
)
) "
))),
Eval(Parse(Eval Insert(
" dt << Graph Builder(
Size( 534, 464 ),
Show Control Panel( 0 ),
Show Legend( 0 ),
Variables(Y( ^Key^ )),
Elements(
Box Plot( Y, Legend( 18 )),
Caption Box(Y, Legend(20), Summary Statistic( \!"N\!" ))),
SendToReport(
Dispatch(
{},
ScaleBox,
{Min( -7.06199976676385 ), Max( 26.8097086791615 ), Inc( 5 ),
Minor Ticks( 0 )}
)
)
) "
)))
)
));回复:帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败我还想尝试做的另一项改进是摆脱 Eval(Parse())(这通常会使脚本更容易调试,并且您不会养成坏习惯)。但这需要一些努力和不同的技巧,因此您可以慢慢来。
我还可以在大约 12 小时内查看一下,这样您就可以了解您可能做什么。
回复:帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败同意。我会更进一步,替换Eval Insert() 。
关于Eval(Parse()) - 你可以跳过它:

Parse 期望一个字符串作为参数。
将评估一个表达式,然后解析结果字符串并将其作为表达式返回。
Parse(Print(1);"a"||"b")
所以,
Parse(Print(1);Eval Insert(Graph Builder());"a")
将打印 1,创建图形并返回 a 作为表达式。如果您只对中间部分感兴趣,则可以跳过Parse 。
使用Eval()包装Parse(Eval Insert())仍会对其进行评估。
另一方面, Eval(Eval Expr())只需要评估里面的Expr() 。
如果没有Expr() ,您可以将其从代码中删除而不会造成任何损害。
一般来说,我建议发布基于来自帮助/示例数据文件夹的数据集的代码。
然后代码可以立即执行,而无需通过互联网下载文件。
额外的好处:使代码适应不同的输入通常有助于理解问题。
通常,当我有正确的代码来发布问题时,问题就消失了:)

回复:帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败这确实看起来很复杂(事实也确实如此),但这是我最有可能采用的方法(这不是唯一的方法,您还可以利用<<添加变量/<<添加元素)
Names Default To Here(1);
dt_summary = Open("$DOWNLOADS/Summary.jmp");
dt = Open("$DOWNLOADS/datatable_test.jmp");
dt << New Column("Ones", Numeric, Nominal, Set Each Value(1));
dt_summary << clear select;
dt_summary << Clear Column Selection();
possible_factors = dt_summary << get column names("string");
Remove From(possible_factors, Contains(possible_factors, "Metric"));
Remove From(possible_factors, Contains(possible_factors, "Graph"));
create_report = function({sel_row}, {Default Local},
valid_factor_idx = Loc(dt_summary[sel_row, possible_factors], "Ok");
valid_factors = possible_factors[valid_factor_idx];
key = dt_summary[sel_row, "Metric"];
If(N Items(valid_factors) == 0,
valid_factors = {"Ones"};
);
variables_expr = Expr(Variables());
bp_expr = Expr(Box Plot(Y, Legend(18)));
dt = dt; // JMP being JMP
For Each({valid_factor, idx}, valid_factors,
x_expr = EvalExpr(X(Expr(Name Expr(AsColumn(dt, valid_factor))), Position(1)));
Insert Into(variables_expr, Name Expr(x_expr));
Insert Into(bp_expr, Eval Expr(X(Expr(idx))));
);
y_expr = EvalExpr(Y(Expr(Name Expr(AsColumn(dt, key)))));
Insert Into(variables_expr, Name Expr(y_expr));
gb_expr = Substitute(
Expr(dt << Graph Builder(
Size(534, 464),
Show Control Panel(0),
Show Legend(0),
_variables_,
Elements(
_boxplot_,
Caption Box(X, Y, Legend(20), Summary Statistic("N"), Location("Graph per factor"))
),
SendToReport(
Dispatch({}, ScaleBox, {Min(-7.06199976676385), Max(26.8097086791615), Inc(5), Minor Ticks(0)})
)
)),
Expr(_variables_), Name Expr(variables_expr),
Expr(_boxplot_), Name Expr(bp_expr)
);
gb = Eval(gb_expr);
return();
);
nw = New Window("Data Table as report",
Outline Box("Data Table as Report",
summary_report = dt_summary << Get as Report();
)
);
report_tb = summary_report[Table Box(1)];
report_tb << Set Heading Column Borders(1);
report_tb << Set Selectable Rows(1);
report_tb << Set Row Change Function(Function({this},
selrows = this << Get Selected Rows;
If(N Items(selrows) > 1,
Throw("Too many items selected!\!rOnly one selection possible.")
);
create_report(selrows[1]);
));
Write();
当这一切顺利之后,我可能会开始考虑用户体验:
- 也许我应该使用一个按钮,按下后会为选定的行创建报告?
- 我可以允许用户选择多行吗?
- 在这种情况下,我应该将所有报告创建到同一个窗口吗?
- 如果图表已经创建,我需要重新创建吗?
- 当用户关闭窗口时,我也应该关闭数据表吗?
- ..
查看更多...Names Default To Here(1);
dt_summary = Open("$DOWNLOADS/Summary.jmp");
dt = Open("$DOWNLOADS/datatable_test.jmp");
dt << New Column("Ones", Numeric, Nominal, Set Each Value(1));
dt_summary << clear select;
dt_summary << Clear Column Selection();
possible_factors = dt_summary << get column names("string");
Remove From(possible_factors, Contains(possible_factors, "Metric"));
Remove From(possible_factors, Contains(possible_factors, "Graph"));
create_report = function({sel_row}, {Default Local},
valid_factor_idx = Loc(dt_summary[sel_row, possible_factors], "Ok");
valid_factors = possible_factors[valid_factor_idx];
key = dt_summary[sel_row, "Metric"];
If(N Items(valid_factors) == 0,
valid_factors = {"Ones"};
);
variables_expr = Expr(Variables());
bp_expr = Expr(Box Plot(Y, Legend(18)));
dt = dt; // JMP being JMP
For Each({valid_factor, idx}, valid_factors,
x_expr = EvalExpr(X(Expr(Name Expr(AsColumn(dt, valid_factor))), Position(1)));
Insert Into(variables_expr, Name Expr(x_expr));
Insert Into(bp_expr, Eval Expr(X(Expr(idx))));
);
y_expr = EvalExpr(Y(Expr(Name Expr(AsColumn(dt, key)))));
Insert Into(variables_expr, Name Expr(y_expr));
gb_expr = Substitute(
Expr(dt << Graph Builder(
Size(534, 464),
Show Control Panel(0),
Show Legend(0),
_variables_,
Elements(
_boxplot_,
Caption Box(X, Y, Legend(20), Summary Statistic("N"), Location("Graph per factor"))
),
SendToReport(
Dispatch({}, ScaleBox, {Min(-7.06199976676385), Max(26.8097086791615), Inc(5), Minor Ticks(0)})
)
)),
Expr(_variables_), Name Expr(variables_expr),
Expr(_boxplot_), Name Expr(bp_expr)
);
return(gb_expr);
);
nw = New Window("Data Table as report",
H List Box(
Outline Box("Data Table as Report",
summary_report = dt_summary << Get as Report();
),
Outline Box("Actions",
Button Box("Create Reports",
sel_rows = report_tb << Get Selected Rows;
lub_collector = Lineup Box(N Col(2));
For Each({selrow}, sel_rows,
lub_collector << Append(create_report(selrow));
);
nw_graphs = New Window("Graphs",
lub_collector
);
wait(0);
),
Button Box("Close Window", summary_report << close window);
)
)
);
report_tb = summary_report[Table Box(1)];
report_tb << Set Heading Column Borders(1);
report_tb << Set Selectable Rows(1);
I will edit and add images here if JMP Community ever lets me do it...
Edit: Images


回复:帮助,我的脚本在脚本窗口中运行正常,但在列公式中运行时失败非常感谢 Jarmo 和 Hogi。
我回复得很晚,很抱歉我没有回复,过去几个月我不得不把注意力集中在其他优先事项上,但现在我可以回来做这件事了!
我会对此进行反思并尝试您的建议。
最好的,
-牧师