如何使一個資料過濾器鏡像另一個資料過濾器?我有一個包含兩個圖形生成器的窗口,從兩個不同的數據集提取數據,並且我想使用單個數據過濾器來過濾這兩個圖形。我認為這是不可能的。我曾考慮過使用兩個「同步」資料過濾器,但無法弄清楚。上週在 JMP Discovery 上, @danschikore向我指出事件處理程序是使用兩個同步過濾器的可能解決方案。我想我已經快要讓它發揮作用了,但我陷入了困境。
下面的腳本建立兩個過濾器和兩個圖表。我希望在頂部過濾器中所做的選擇自動反映在底部過濾器中。一旦成功,我將隱藏底部過濾器,用戶將看到一個過濾器控制兩個圖表。
現在,當使用者在頂部過濾器中進行選擇時,腳本會使用「GetWhere 子句」將該Where 子句列印到日誌中,但我需要將此where 子句應用於底部過濾器。我想要一個像“Set Where Clause”這樣的命令,它可以讓我將 where 子句文字推入底部過濾器,但它似乎不存在。我真的希望避免這樣的情況:我必須「解壓縮」文字字串(如下)並將其轉換為可以傳遞給較低過濾器的形式。
選擇Where( :name == \!"ALICE\!" | :name == \!"BARBARA\!" )
只是為了說服自己,我可以讓第一個過濾器以某種方式控制第二個過濾器,我讓第一個過濾器清除第二個過濾器的選擇。這意味著我可以與兩個過濾器對話;我可以從第一個子句中提取 where 子句;我只是無法將其應用於第二個。
作為一個額外的問題:一旦同步有效。我想隱藏第二個過濾器。腳本的最後一行隱藏了第一個過濾器。有誰知道我如何修改它以隱藏第二個過濾器?
謝謝,
湯姆

自動化和腳本編寫回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?Eval():運行程式碼*)
Eval Expr:預先評估所有用Expr() 包裝的內容 *)
Expr():必須預先評估的代碼標記*)
*) 我的大腦:「E 字」 - 3 次。
第四個是Expr Name() ; -)
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?同意 : )
對於 Big Class 可能有一些簡單的解決方案,但該解決方案可能對解決實際問題沒有幫助。
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?@hogi ,感謝這些連結。在過去的幾年裡,Eval/Eval Expr() 一直是 JSL 中最令我沮喪的部分。我透過複製和調整社群中的範例成功地使用了它幾次,但從未感覺我真正掌握了它。我期待著瀏覽您收集的資源列表,也許這會幫助您最終理解它。
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?我的意思是串聯。透過執行更新/連接,您可以將沒有關聯年份的身高資料與每年的體重資料相關聯。新圖表顯示,芭芭拉在 2022 年、23 日和 24 日測量的身高為 60 英寸,但事實並非如此。
這裡的技巧是底部的數據與年份相關,但頂部的數據則不然,我想要一個居中的條形。也許我應該使用「學生出生時間和地點的人均 GDP」來代替身高——顯然與 22/23/24 無關。
由於頂部圖和底部圖的基礎資料具有不同的結構,因此我認為我需要兩個單獨的圖產生器來創建我想要的圖片(上圖)。
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?謝謝@TomF - 對抗標籤設定限制的非常酷的技巧:使用 2 個表:)
我想知道為什麼不可能生成這樣的圖 - 既不能在單獨的圖中生成,也不能合併在一張圖中。

為一個圖表設定標籤會自動強制其他圖表也顯示標籤:(
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?了解不同的過濾技術可以在 JMP 中完成各種不錯的事情(有時它們也是必要的,特別是如果您有大量數據)。
我假設透過連接你可能意味著更新/連接,我們可以有這樣的單一表(如果有唯一標識符,則可以使用虛擬連接)

由此可以創建這樣的圖表

例如,您可以使用 Textlet(懸停標籤)來做到這一點
Graph Builder(
Size(1085, 688),
Show Control Panel(0),
Show Legend(0),
Variables(X(:Name), X(:Year, Position(1)), Y(:Height), Y(:Weight), Overlay(:Name)),
Elements(Position(1, 1), Bar(X(1), X(2), Y, Overlay(0), Legend(13))),
Elements(Position(1, 2), Line(X(1), X(2), Y, Legend(15)), Points(X(1), X(2), Y, Legend(16))),
Local Data Filter(
Add Filter(
columns(:Name),
Where(
:Name == {"AMY", "BARBARA", "CAROL", "CHRIS", "CLAY", "DANNY", "DAVID", "EDWARD", "ELIZABETH", "FREDERICK", "HENRY", "JACLYN"}
),
Display(:Name, N Items(15), Find(Set Text("")))
)
),
SendToReport(
Dispatch({}, "Name", ScaleBox, {Label Row(2, Show Major Grid(1))}),
Dispatch({}, "Graph Builder", FrameBox, {Set Textlet(Markup("Serial Number: {:Serial No.[local:_firstRow]}"))}),
Dispatch({}, "Graph Builder", FrameBox(2), {Set Textlet(Markup("Serial Number: {:Serial No.[local:_firstRow]}"))})
)
);
如有必要,您可以自訂更多顯示的文本, 使用 JMP > JMP 報表 > 自訂 JMP 圖形中的懸停標籤 > 將文字新增至 JMP 圖形中的懸停標籤
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?@TomF ,您好,我在程式碼中添加了一些註釋來解釋各個步驟。
一個技巧是Extract Expr() - 它掃描表達式並蒐索特定模式。
我剛剛查看了一個舊腳本,其中我使用一個資料過濾器來控制同一個儀表板中的 4 個附加資料過濾器。
它看起來像
For( i = 1, i <= N Arg( filterScript ), i++,
If( Head( Arg( filterScript, i ) ) == Expr( Add Filter() ),
filterExpression = Arg( filterScript, i )
)
);
透過Extract Expr() 的方法要優雅得多 - 我去年剛剛在這次討論中從@jthi那裡學到了它:
:folded_hands: 表達式索引:讀寫訪問
另一個技巧: Eval (Eval Expr( Expr())) - 瑞士軍刀!
它將解決您 JSL 95% 的問題:)
JMP 中的表達式處理:Tipps 和 Trapdoors
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?恐怕很多程式碼都超出了我的理解範圍,但我明白了整體思路。對於更複雜的情況,我會記住這一點。謝謝!
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?是的,我想要一個過濾器來過濾來自不同表的兩個報告。我認為這對於我上面分享的簡單的大類別範例沒有意義,但我附加了一個更複雜的範例,它非常模仿我的實際資料集的結構。
想像一下,您有一張表包含每個學生目前的身高,另一張表包含每個學生過去三年的體重。這就是我想要查看該數據的方式:

身高資料集顯然每個學生只有一行。體重數據從每個學生一行(三列體重)開始,但據我所知,在圖形生成器中無法在不堆疊權重的情況下製作底部圖表。我的體重表現在的行數是身高表的 3 倍。
因為資料過濾器無法過濾兩個不同的表,所以到目前為止我的解決方案是連接表,只是為了能夠製作此圖表。這並不優雅,但效果很好。
我真正遇到麻煩的是,當我將滑鼠懸停在高度上時,我希望彈出視窗顯示他們在測量過程中是否穿了鞋,而當我將滑鼠懸停在體重上時,我想知道秤的序號被使用了。當所有資料都在一個表中,並且我為兩列製作標籤(1)時,當您懸停時,您最終會丟失值(因為重量測量上沒有秤序號)......這也可以解決,但是它剛開始變得非常混亂。
我認為將資料保留在兩個帶有兩個同步過濾器(一個隱藏)的表中的解決方案會效果更好。但如果有更好的方法來創建這個圖表,我願意接受建議。
只是對 Graph Builder 以及使用 JSL 控制它的能力表示一般性的讚揚。兩個不同圖表的無縫融合之所以成為可能,是因為我們能夠關閉頂部圖表底部和底部圖表頂部的所有內容,並使它們彼此相對。這使我們能夠根據我們的具體情況創建非常客製化且數據非常密集的圖形。現在我們也可以優雅地過濾它:)也許其他人會發現這很有用。
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?對於這樣的事情有很多不同的選擇,所有這些都取決於真正要做的事情(資料看起來如何,可以操作行狀態,正在過濾什麼(以及為什麼),...)。這是一個在許多情況下(通常)運作良好的選項,但它對於處理程序來說具有相當複雜的功能(添加固定大小(在Spacer Box() 的幫助下),這樣的事情通常是避免煩人的閃爍的好主意)的視窗)。
Names Default To Here(1);
dt1 = Open("$SAMPLE_DATA/Probe.jmp");
dt2 = dt1 << Subset(All Rows, Selected Columns(0));
dt2 << Delete Rows(dt2 << get rows where(:Process == "Old"));
nw = New Window("",
Data Filter Context Box(
H List Box(
Data Filter Source Box(
df1 = dt1 << Data Filter(
Local,
Show Controls(0),
Show Modes(0),
Mode(Include(1)),
Add Filter(Columns(:Site, :Process)), Display(:Site, N Items(5))
),
),
V List Box(
gb1 = dt1 << Graph Builder(
Size(525, 458),
Show Control Panel(0),
Variables(X(:Lot ID), Y(:DELL_RPNBR)),
Elements(Bar(X, Y, Legend(4)))
),
gb2_collector = V List Box()
)
)
)
);
create_gb2 = function({a},
c = df1 << Get where clause;
If(Is Missing(c), // could also just use dt2 instead of dt2_private
dt2_privatenew = dt2 << Subset(All Rows, Selected columns only(0), Link to original data table(1), private);
,
where = Arg(Parse(df1 << Get where clause));
dt2_privatenew = Eval(EvalExpr(dt2 << Subset(
Filtered Rows(Expr(Name Expr(where))),
Selected columns only(0),
Link to original data table(1),
private
)));
If(Is Empty(dt2_privatenew), // no rows left -> pick first row and remove it, no linking
dt2_privatenew = dt2 << Subset(Rows(1), Selected columns only(0), Link to original data table(0), private);
dt2_privatenew << Delete Rows(1);
);
);
nw << inval;
Try(Close(dt2_private, no save)); // will also remove old graph builder
dt2_private = dt2_privatenew;
gb2_collector << Append(
gb2 = dt2_private << Graph Builder(
Size(528, 458),
Show Control Panel(0),
Variables(X(:Lot ID), Y(:DELL_RPNBR)),
Elements(Bar(X, Y, Legend(20)))
)
);
wait(0);
nw << Update Window;
);
create_gb2(.);
nw:handler = df1 << Make Filter Change Handler(
create_gb2();
);
Eval(EvalExpr(
nw << On Close(
Try(Close(Expr(dt1), no save));
Try(Close(Expr(dt2), no save));
Try(Close(Expr(dt2_private), no save));
);
));
Write();回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?@hogi我不完全理解你的代碼的作用,但我把它放進去了,它工作得很好。謝謝你!
說實話,我並沒有真正逃過陷阱門。我掉進去然後又把自己拉了出來。我正在關注這社區帖子,但我認為沒有理由將事件處理程序存儲為變量,所以我沒有。它不起作用,我更仔細地關注了該帖子,將其存儲為一個變量,它開始起作用,並且我在不了解發生了什麼的情況下繼續進行。我用你的兩個活板門在我的程式碼中加入了註釋,希望將來能避免某人受傷。
在本例中,我的過濾很簡單——始終是一列——並且我的兩個表都包含相同的 x 值,因此無需擔心。
我已經在上面發布了更新的程式碼。
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?
@jthi寫道:
如果它必須是本地的,那麼除了使用兩個本地資料過濾器(這也是可能的)之外,還有其他選擇。
過濾器狀態處理程序不僅僅由資料過濾器的變更觸發。
您的長條圖已儲存 - 但對於點圖,只要滑鼠觸控資料點就會觸發狀態處理程序!
因此,根據繪圖類型,將當前過濾器設定與先前的過濾器設定進行比較可能是個好主意 - 並在檢測到變更時將設定應用於第二個繪圖。
也許在這裡投票:
改進 JMP 的狀態處理程序(懸停標籤、行狀態處理程序、篩選狀態處理程序、調度程序等)
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?確保兩個表包含相同的值!
如果資料過濾器找不到匹配的行,它將重置並顯示所有行:

此問題將透過:folded_hands: 列屬性:包含/強制值在 JMP19 中修復
作為 <=JMP18 的解決方法,您可以在剩餘列中新增缺少資料的虛擬行
-> 不會顯示在圖中,但會阻止資料過濾器重設。
看更多...
//Data Filter Event Handler Test.jsl
//2024-10-31
dtHeight = Open( "$SAMPLE_DATA/Big Class.jmp" );
dtHeight << delete columns({"age", "sex", "weight"});
dtHeight << Set Name ("Height");
dtWeight = Open( "$SAMPLE_DATA/Big Class.jmp" );
dtWeight << delete columns({"age", "sex", "height"});
dtWeight << Set Name ("Weight");
dtHeight << select where(:Name == "ALFRED") << delete rows(); // <- dangerous !!!!
Try(win << Close Window);
win = New Window("Height and Weight",
Data Filter Context Box(
H List Box (
V List Box(
df1_Wt = dtWeight << Data Filter( Local,
Show Controls( 0 ), Show Modes( 0 ), Mode( Include( 1 ) ),
Add Filter(Columns(:name)),
Display( :name, N Items( 4 ))
),
df2_Ht = dtHeight << Data Filter( Local,
Show Controls( 0 ), Show Modes( 0 ), Mode( Include( 1 ) ),
Add Filter(Columns(:name)),
Display( :name, N Items( 4 ))
)
),
V List Box (
gbWt = dtWeight << Graph Builder(
Size( 612, 250 ),
Show Control Panel( 0 ), Show Legend (0), Show Title (0),
Show X Axis (0), Show X Axis Title (0), Show Footer( 0 ),
Variables( X( :name ), Y( :weight ) ),
Elements( Bar( X, Y, Legend( 6 ) ) ),
//Dispatch( {}, "Graph Builder", OutlineBox, {Set Title( "" )} ),
Dispatch({},"weight",ScaleBox,{ Max( 200 )})
),
H List Box(
Spacer Box(Size(25,200)),
gbHt = dtHeight << Graph Builder(
Size( 600, 300 ),
Show Control Panel( 0 ), Show Legend (0), Show Title (0),
Variables( X( :name ), Y( :Height ) ),
Elements( Bar( X, Y, Legend( 6 ) ) ),
Dispatch( {}, "Graph Builder", OutlineBox, {Set Title( "" )} )
)
)
)
)
)
);
eh = df1_Wt << MakeFilterChangeHandler(
function({x},
dfscript = df1_Wt << get script();
filter = Extract Expr(dfscript, Add Filter(Wild List()));
Eval(Eval Expr(df2_Ht << delete all() << Expr (Name Expr(filter)))))
);
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?您可以使用資料篩選器上下文/來源框使用單一篩選器過濾兩個(或更多)圖表,但它們必須具有相同的來源表
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
nw = New Window("Selection Filter",
Data Filter Context Box(
H List Box(
dfsb = Data Filter Source Box(
dt << Data Filter(
Local,
Add Filter(columns(:age), Display(:age, N Items(6)))
),
),
Graph Builder(
Size(208, 207),
Show Control Panel(0),
Show Legend(0),
Variables(X(:age)),
Elements(Bar(X, Legend(3)))
),
Bubble Plot(
X(:weight),
Y(:height),
Sizes(:age),
Title Position(0, 0)
)
)
)
);
現在我的問題是你想做什麼?您希望擁有一個篩選器來篩選不同表中的兩份報告嗎?我將使用一個本地資料過濾器,然後使用它來隱藏/排除第二個表中的行(如果您允許它修改表而不僅僅是本地表)。如果它必須是本地的,那麼除了使用兩個本地資料過濾器(這也是可能的)之外,還有其他選擇。
回覆:如何讓一個資料過濾器鏡像另一個資料過濾器?好的 : )
當我創建第一個狀態處理程序時,我忘記將過濾器狀態處理程序儲存在變數中 - 它立即被銷毀。
然後它不起作用,因為我使用了帶有 0 個參數的函數。 -> 幹得好,你逃出了兩個活板門:)
沒有Set where 子句-Where子句不是資料篩選器能夠理解的訊息,您可以將其傳送到表格以選擇行。除此之外<< GetWhere子句()傳回一個字串。您必須使用Parse將其轉換為表達式。
解包比您想像的要省力 - 只需向資料過濾器詢問腳本,透過Extract Expr()提取Add Filter()部分並將其應用到第二個過濾器 - 將適用於簡單的選擇 *)
eh = df1_Wt << MakeFilterChangeHandler(
Function( {x},
dfscript = df1_Wt << get script(); // store the code to create DF1 - with all the settings
filter = Extract Expr(
dfscript, // take the code which is stored in dfscript and ...
Add Filter( Wild List() ) // search for the part with Add Filter(something). Wild List() - like magic :)
);
Eval( // run the code
Eval Expr( // search for any Expr() and execute it (*)
df2_Ht << delete all() // remove all previous settings
<< Expr( // (*) find this Expr() and execute it
Name Expr( filter ) // take the code which is stored in "filter" and replace filter with the actual code
)
)
);
)
);
*) 當您透過 OR() 組合多個篩選器時,腳本將包含多個add Filter() - 並且Extract Expr()將只傳回第一個。
要獲得最終的克隆功能,您可以解析 DF 腳本,收集所有AddFilter()並將它們一個接一個地應用到第二個資料過濾器。