JSL 帮助:Set Function() 命令语法帮助大家好,
回到另一个 JSL 编程问题。 它与其他帖子相关,例如这里。
我想要一个 Check Box() 功能,当选中复选框(状态 = 1)时,选定的行(恰好是 R 方为负的行)被选中,然后隐藏并删除,以便更新的图形生成器显示所需的输出。 然后,如果未选中该框(状态 = 0),则取消隐藏并取消排除这些行。 我正在使用的 Set Function() 调用如下,如果我手动运行 Set Function() 的“脚本”,它就可以工作,但它不会自动执行。 我不知道我缺少什么才能让它自动更新。 我发现了一个简洁的帖子这里,我正在尝试做某物就像这个人所做的那样,但是为了图形生成器更新。
JSL 设置函数调用:
cb << Set Function(<BR />{this},<BR />this = cb << Get;<BR />If(<BR />this == 1,<BR />dt_results << Select Rows( neg_rows ) << Hide and Exclude;<BR />dt_results << Clear Select;<BR />dt_tb = dt_results << Get As Report();,<BR />this == 0,<BR />dt_results << Select Rows( neg_rows ) << Unhide;<BR />dt_results << Select Rows( neg_rows ) << Unexclude;<BR />dt_results << Clear Select;<BR />dt_tb = dt_results << Get As Report()<BR />);<BR />);cb << Set Function(
{this},
this = cb << Get;
If(
this == 1,
dt_results << Select Rows( neg_rows ) << Hide and Exclude;
dt_results << Clear Select;,
this == 0,
dt_results << Select Rows( neg_rows ) << Unhide;
dt_results << Select Rows( neg_rows ) << Unexclude;
dt_results << Clear Select;
);
);其中 cb 在代码中前面的引用为:
cb = Check Box( "Remove bad points (*'s)?", <<SET></SET>
开始输出,或每当复选框状态 = 0 时:

当复选框状态 = 1 时所需的输出:

最好将数据表更新为右侧的报告,以便从右侧的报告视图中删除任何被排除的行,但我认为这可能比听起来要困难得多。 我尝试在 Set Function() 命令中添加额外的 Get As Report 更新,但它没有执行任何操作。
如有任何反馈,我们将不胜感激,谢谢!
DS
数据混合和清理回复:JSL 帮助:Set Function() 命令语法帮助在日常工作中,我面临的更多的是相反的问题:
不是:2 个窗口共享相同的命名空间
但是: 2 个脚本仅有时 *) 共享一个共同点这里命名空间。
当我将一个 JSL 文件包含在另一个 JSL 文件中时,在运行时,包含的脚本共享这里主 jsl 文件的命名空间。
但是当我想调试一些代码行并从第二个脚本运行它们时 - 我怎样才能给出包含的内容脚本_B访问这里主脚本的命名空间? 2 秒前,当我执行 script_B 的代码时,它只能访问该命名空间。
https://community.jmp.com/t5/Discussions/Debugging-Jmp-applications/mp/701121/highlight/true#M88566
回复:JSL 帮助:Set Function() 命令语法帮助感谢, @ErraticAttack查看 Jmp 中范围界定如何工作的美丽示例。
它对我帮助很大,让我更接近理解......
到现在为止我都无法理解什么@drewfoglia意味着

在提高效率和可重复性的基本脚本:少做多做 (2019-US-TUT-290)
你的例子很好地表明这不是真的。
为什么我们在这里的经历与德鲁的说法不同?
我认为这是因为这些窗口是从同一个 JSL 编辑器窗口创建的。
打开第一个 TEST 窗口后,脚本窗口仍然可以访问引用的对象,这非常有帮助特布和待定。
打开第二个TEST窗口后,特布和待定现在引用第二个窗口中的对象 - 这显然削弱了第一个窗口的功能(输入的文本显示在待定,即在第二个窗口中)。
因此,结合 boh 的说法,如果两个 Windows 不共享通用的 JSL 编辑器,会发生什么情况。
-> 两者都将拥有独立的命名空间,就像 Drew 在他的演讲中宣布的那样。
这样做的选项:
a) 关闭脚本并再次打开它,然后创建第二个窗口
b) 从菜单调用脚本:

回复:JSL 帮助:Set Function() 命令语法帮助你好@ErraticAttack ,
感谢您的回复和详细的帖子。 我肯定需要一些时间来完成它,因为我不是专业程序员,其中大部分对我来说仍然是新的。
谢谢!,
DS
回复:JSL 帮助:Set Function() 命令语法帮助@ih作为 JMP 未按预期进行范围界定的示例(尤其是来自 Python),只需从此脚本启动两个窗口 - 名称仅链接到第二个窗口,而不链接到第一个窗口。这是我发现人们在范围界定方面遇到的最大问题(但不是唯一的问题)。JMP 提供了一些方便的伪命名空间,例如 window: 命名空间。但是,这些不是正确的命名空间变量,并且在大型脚本中不能完全按预期工作。
Names Default to Here( 1 );
New Window( "TEST",
V List box(
teb = Text Edit Box( "", <<SET hint=""></SET>
@SDF1 ,对于显式命名空间范围,我所做的是创建一个库,该库通过元编程完成所有繁琐的范围注入工作。这样做的另一个好处是能够几乎完全按照 Python 中的工作方式来定义类(减去方便的查找覆盖)。我无法共享该库,因为它是我公司工作的一部分,但这本质上就是正在发生的事情:
假设您有一个像这样的简单脚本
Names Default to Here( 1 );
/*
Doing something initialization here!!
*/
dt = Current Data Table();
New Window( "Super Useful Script",
,
<<ON close=""></ON>
该脚本有两个交互式 UI 元素、一些初始化以及可能在窗口关闭时进行的一些清理。请注意,从概念上讲,显示树和逻辑是混合的,并且存在非常深的块。当概念上不同的元素在代码中也不同时,代码看起来会更好(并且更容易维护)。如果简单地创建一个带有标题和要调用的函数名称的按钮框,那就太好了。它调用的函数将成为顶级函数(可以通过脚本的任何部分轻松调用),并且将与显示树分开。
您可以将其转换为更容易消化和使用的内容,如下所示:
/* super useful script */
initialize = Function( {}, // entry point to script
/* perform any initialization needed here */
self:dt = Current Data Table();
1
);
content = Function( {}, // this holds the display tree
V List Box(
self:one click button = meta:Button Box( "Useful 1-click function", "call one click" )
,
H List Box(
self:value teb = meta:Text Edit Box( "", "handle value change" ) << Set Hint( "Enter Value" )
)
)
);
finalize = Function( {}, // called after display tree has finalized
1
);
on close = Function( {}, // called when window wants to close
1
);
call one click = Function( {}, // called when button is pressed (line 11)
Print( "Done" )
);
handle value change = Function( {}, // called when TEB value changes(line 14)
Print( "Doing something special" )
);现在显然,如果您按正常的 JSL 运行脚本按钮,该脚本不会执行太多操作。您需要做的是首先定义元命名空间(其中包含 ButtonBox 和 TextBox 包装器,以便它们可以与脚本的其余部分很好地链接)并定义一个元编程包装器函数,该函数将执行以下操作:
采取这样的原型脚本
<SOME script="" is="" above="" me="">
do someting = Function( {},
...
);
finalize = Function( {},
...
);
<MORE script="" is="" below="" me=""></MORE></SOME>将其转换为以下原型:
<SOME script="" is="" above="" me="">
self:do someting = Function( {},
self = Namespace( "#434" );
...
);
self:finalize = Function( {},
self = Namespace( "#434" );
...
);
<MORE script="" is="" below="" me=""></MORE></SOME>
这个元编程函数将“self”定义为简单的“self = New Namespace()”,然后将 self 定义注入到每个函数中,如上所述(“#434”当然每次都会不同)。重写脚本后,只需执行以下操作(这几乎完全来自我的库)
If( self << Contains( "initialize" ), Try( self:initialize(), Print( "Error with self:initialize" ); Show( exception_msg ); ); );
Eval(
Substitute(
Expr(
self:window = New Window( self:tool name,
<<ON close="">>" ) );
Try(
self:finalize
,
Print( "Error with self:finalize" );
Show( exception_msg );
);</ON>
这是我的脚本中的一个实际示例。元编程之前的输入是这样的:
tool name = "Example";
initialize = Function( {},
{Default Local},
Show( "initialized" )
);
content = Function( {},
H List Box(
meta:Button Box( "Hello World", "run" )
,
self:n days box = meta:Number Edit Box( 30, "run" )
)
);
run = Function( {},
{var1, var2},
Show( "running" )
);
finalize = Function( {},
Show( "finalized" );
show( self:n days box << Get );
);
0;在评估脚本之前(在元编程步骤之后),它看起来像这样
self:tool name = "Example";
self:initialize = Function( {},
{Default Local},
self = Namespace( "#58" );
Show( "initialized" );
);
self:content = Function( {},
{self, this},
self = Namespace( "#58" );
H List Box(
meta:Button Box( "Hello World", "run" )
,
self:n days box = meta:Number Edit Box( 30, "run" )
);
);
self:run = Function( {},
{var1, var2, self, this},
self = Namespace( "#58" );
Show( "running" );
);
self:finalize = Function( {},
{self, this},
self = Namespace( "#58" );
Show( "finalized" );
Show( self:n days box << Get );
);
0;回顾一下——元编程需要任何乌斯科佩德顶级变量并显式将其范围限定为“self”。然后它接受任何顶级函数并添加第一行(即“self = Namespace()”)。这在概念上非常简单,事实证明,使用 JSL 这很容易实现。不幸的是,根据 `Function()` 函数的形式,有几个分支(无论是 2 个还是 3 个参数,第二个参数是 {Default Local} 还是只是一个局部变量列表)
那么,所有这些元编程会给您带来什么呢?只是为了避免做类似的事情,如下所示。请注意,下面的脚本大部分包含在 Eval( Eval Expr( ... ) ) 语句中。这会阻止您在任何函数中使用此类语句,因此对于大型项目来说并不理想。另外,显示树仍然有一些丑陋的样板(< ) ... ) ) 块又大又丑)
self = New Namespace();
self:tool name = "Example";
Eval( Eval Expr(
self:initialize = Function( {},
{Default Local},
self = Namespace( Expr( self << Get Name ) );
Show( "initialized" )
);
self:content = Function( {},
self = Namespace( Expr( self << Get Name ) );
H List Box(
Button Box( "Hello World",
<<SET function="">>" ) );
Try(
self:finalize
,
Print( "Error with self:finalize" );
Show( exception_msg );
);</SET>该脚本包含大量样板文件,但当您想要更明确的范围控制时,这是必要的。值得注意的是,当您不想告诉用户“一次仅打开一个窗口!”时。创建元编程步骤有点乏味,并且肯定需要大量学习,但一旦你弄清楚了非常有益的并且还允许更简洁和可维护的代码。
我在这里展示的是创建类(完全独立于 JMP14+ NewObject 类)的能力,这些类工作得非常好,并且允许交互式 UI 生成变得轻而易举。
我知道这是很多(更重要的是,与构建 UI 脚本的任何初始方法相去甚远),但如果您要创建超过一两个小型 UI 脚本,那么创建元编程的时间就会减少包装器(您只需要做一次)很快就会变得有价值。
回复:JSL 帮助:Set Function() 命令语法帮助你好@ErraticAttack ,
感谢您的反馈意见。 我注意到这是您第二次向我推荐 Namespace() ;-)。
因此,我花了一天半的时间在我的脚本指南中阅读了如何使用命名空间,这比脚本索引更好,但仍然没有真正给出最好的示例,例如如何使用它。关于如何在您使用命名空间的上下文中使用命名空间,您是否有比 JMP 14 脚本编写指南或脚本索引更好的入门读物?
我必须承认我不太明白你在做什么,需要更好地学习。 但是,根据您在此处的帖子以及您在我的其他帖子之一中提供的示例代码这里,我能够重写使用命名空间()调用第一个窗口的脚本部分。 但是,我仍然不太确定如何在后续窗口中编写脚本,并显示我能够通过我不太出色的脚本编写技能开始工作。 我认为在我可以切换到我想要做的编程方法之前,需要一些时间来学习如何正确使用命名空间。
我能够在选中/取消选中隐藏/排除负数据(在这种情况下毫无意义)的框时更新显示的图形生成器。 下面的脚本执行了我想要的操作(除了从图表中删除某些数据时更新表格框),但我知道从编程的角度来看它并不理想。
谢谢!,
DS
Names Default To Here( 1 );
lbWidth = 168;
dt = Open( "$SAMPLE_DATA/Boston Housing.jmp" );
// Expression to store the current settings in global variables
recallRolesS1 = Expr(
::dtchosenRecall = dtchosen
);
// Expression to clear all current settings. KW: Clear
clearRoles = Expr(
Try(
colListY << RemoveAll;
ColListX << RemoveAll;
ColListW << RemoveAll;
ColListF << RemoveAll;
colListV << RemoveAll;
)
);
// Expression to store the current settings in global variables
recallRoles = Expr(
::ycolRecall = colListY << GetItems;
::xcolRecall = colListX << GetItems;
::WcolRecall = colListW << GetItems;
::FcolRecall = colListF << GetItems;
::vcolRecall = colListV << GetItems;
::max_spRecall = max_sp_input << get;
::partVPRecall = partVP_input << Get;
);
//Function to choose the data table to model. KW: choose_data
choose_data_table = Function( {},
list = {};
For( i = 1, i <= N Table(), i++,
list[i] = Data Table( i ) << get name
);
win = New Window( "Select a data table",
<<MODAL> Training R².",
<<SET font="" size=""> 1, Throw( "Too many items selected!\!rOnly one selection possible." ),
N Items( SelRows ) == 1,
SelRows = this << Get Selected Rows;
NPCs = SelRows[1];
);
dt_results << Clear Select;
dt_results << Select rows( SelRows );
)
);
);
Part = Expr(
If(
N Items( vcols ) == 1,
dt_results = New Table( "Partition_Results",
Add Rows( max_sp ),
New Column( "Splits", Numeric, Continuous ),
New Column( "Training RSquare", Numeric, Continuous ),
New Column( "Validation RSquare", Numeric, Continuous ),
New Column( "Training RASE", Numeric, Continuous ),
New Column( "Validation RASE", Numeric, Continuous ),
New Column( "RSquare Diff", Numeric, Continuous, Formula( "Training RSquare"n - "Validation RSquare"n ) ),
New Column( "Penalized Valid RSquare", Numeric, Continuous, Formula( "Training RSquare"n - 0.05 * "Splits"n ) ),
New Column( "Training N", Numeric, Continuous ),
New Column( "Validation N", Numeric, Continuous )
),
N Items( vcols ) == 0 & Is Missing( partVP ) == 0,
dt_results = New Table( "Partition_Results",
Add Rows( max_sp ),
New Column( "Splits", Numeric, Continuous ),
New Column( "Training RSquare", Numeric, Continuous ),
New Column( "Validation RSquare", Numeric, Continuous ),
New Column( "Training RASE", Numeric, Continuous ),
New Column( "Validation RASE", Numeric, Continuous ),
New Column( "RSquare Diff", Numeric, Continuous, Formula( "Training RSquare"n - "Validation RSquare"n ) ),
New Column( "Penalized Valid RSquare", Numeric, Continuous, Formula( "Validation RSquare"n - 0.05 * "Splits"n ) ),
New Column( "Training N", Numeric, Continuous ),
New Column( "Validation N", Numeric, Continuous )
),
N Items( vcols ) == 0,
dt_results = New Table( "Partition_Results",
Add Rows( max_sp ),
New Column( "Splits", Numeric, Continuous ),
New Column( "Training RSquare", Numeric, Continuous ),
New Column( "Training RASE", Numeric, Continuous ),
New Column( "Penalized Train RSquare", Numeric, Continuous, Formula( "Training RSquare"n - 0.05 * "Splits"n ) ),
New Column( "Training N", Numeric, Continuous )
)
);
For( i = 1, i <= max_sp, i++,
dt_results:"Splits"n[i] = i
);
dt_name = dtchosen << Get Name;
For( i = 1, i <= N Rows( dt_results ), i++,
Psplit = dt_results:"Splits"n[i];
str = Eval Insert(
"report = (dtchosen<<PARTITION></PARTITION></SET></MODAL>回复:JSL 帮助:Set Function() 命令语法帮助你好@ErraticAttack ,
根据我的经验,变量范围是一致的。 它可能不直观,但我总是发现它是可预测的。如果您遇到不一致的情况,可能值得深入研究脚本指南并尝试交叉检查不同符号的作用域。
在某些情况下,我使用调用上下文函数来简化函数调用取得了巨大成功,通常用于探索性分析或交互式运行的脚本。 例如,日志函数可能会将消息发送到文件或窗口,并包含迭代器或步骤值,而不必每次都键入/复制/粘贴它们。
Names default to here(1);
lg = function({msg},
write(msg || try(", i=" || char(i), "") || "\!N")
);
lg("starting loop");
local({i},for(i=1, i<= 5, i++, lg("done")))回复:JSL 帮助:Set Function() 命令语法帮助你好@pmroz ,
感谢您的反馈。 我只想更新当前窗口而不是创建新窗口。 我已经能够使图形正常工作,以便它在 Check Box() 的选中/取消选中状态上更新。 不幸的是,我仍然无法将包含数据表的表格框作为报告进行更新,如我所愿。 这部分比我想象的要复杂得多,但实际上并不是那么重要。 最好让图形显示按预期工作。 不过,如果表格框可以更新一下就好了。
谢谢!,
DS
回复:JSL 帮助:Set Function() 命令语法帮助请注意,您不能依赖 JSL 范围行走在 <
主要是 JSL 没有像 Python 那样严格的范围控制。对于任何类型的复杂交互式 UI,您应该始终显式地确定需要在多个显示元素回调中保留的所有变量的范围。
另外,从美观和实用的代码格式的角度来看,您应该始终将逗号放在封闭栅栏的位置,如下所示。这样可以非常快速、轻松地直观地理解代码块。请注意 IF 语句的不同块所在位置的简单直观指示。
最后一点——您应该利用 NewWindow() 对象的 <
ns = <RELEVANT namespace="" with="" variables="" defined="" above="">
Eval( Eval Expr(
ns:cb << Set Function( {this},
ns = Namespace( Expr( ns << Get Name ) );
state = this << Get;
If(
state == 1,
ns:dt_results << Select Rows( ns:neg_rows ) << Hide and Exclude;
ns:dt_results << Clear Select;
,
state == 0,
ns:dt_results << Select Rows( ns:neg_rows ) << Unhide;
ns:dt_results << Select Rows( ns:neg_rows ) << Unexclude;
ns:dt_results << Clear Select;
);
);
) );</RELEVANT>回复:JSL 帮助:Set Function() 命令语法帮助尝试这样的事情:
nw = new window("Test",
one_cb = checkbox({"Turn On"},
one_value = one_cb << Get;
If (one_value,
dt_results << Select Rows( neg_rows ) << Hide and Exclude;
dt_results << Clear Select;
dt_tb = dt_results << Get As Report();
// else
,
dt_results << Select Rows( neg_rows ) << Unhide;
dt_results << Select Rows( neg_rows ) << Unexclude;
dt_results << Clear Select;
dt_tb = dt_results << Get As Report()
);
)
);