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()
);
)
);