Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Ich habe ein Fenster mit zwei Diagrammerstellern, die aus zwei verschiedenen Datensätzen ziehen, und ich möchte beide Diagramme mit einem einzigen Datenfilter filtern. Ich glaube nicht, dass das möglich ist. Ich habe darüber nachgedacht, stattdessen zwei „synchronisierte“ Datenfilter zu verwenden, bin aber nicht darauf gekommen. Letzte Woche hat mich @danschikore bei JMP Discovery auf Eventhandler als mögliche Lösung für die Verwendung von zwei synchronisierten Filtern hingewiesen. Ich glaube, ich bin kurz davor, es zum Laufen zu bringen, aber ich stecke fest.
Das folgende Skript erstellt die beiden Filter und die beiden Diagramme. Ich möchte, dass die im oberen Filter getroffenen Auswahlen automatisch im unteren Filter widergespiegelt werden. Sobald das funktioniert, verstecke ich den unteren Filter und der Benutzer sieht einen Filter, der beide Diagramme steuert.
Wenn der Benutzer jetzt eine Auswahl im oberen Filter trifft, druckt das Skript diese Where-Klausel mithilfe von „Get Where Clause“ in das Protokoll, aber ich muss diese Where-Klausel auf den unteren Filter anwenden. Ich möchte einen Befehl wie „Set Where Clause“, mit dem ich den Text der Where-Klausel in den unteren Filter einfügen kann, aber dieser scheint nicht zu existieren. Ich hoffe wirklich, das Szenario zu vermeiden, in dem ich die Textzeichenfolge (unten) „entpacken“ und in ein Format umwandeln muss, das ich an den unteren Filter weitergeben kann.
Wählen Sie Wo( :name == \!"ALICE\!" | :name == \!"BARBARA\!" )
Nur um mich selbst davon zu überzeugen, dass ich den ersten Filter irgendwie dazu bringen kann, den zweiten zu steuern, lasse ich den ersten Filter die Auswahl des zweiten Filters löschen . Das heißt, ich kann mit beiden Filtern kommunizieren; ich kann die Where-Klausel aus dem ersten extrahieren, ich kann sie nur nicht auf den zweiten anwenden.
Als Bonusfrage: Sobald diese Synchronisierung funktioniert, möchte ich den zweiten Filter ausblenden. Die letzte Zeile des Skripts blendet den ersten Filter aus. Weiß jemand, wie ich dies ändern kann, um stattdessen den zweiten Filter auszublenden?
Danke,
Tom

Automatisierung und SkriptingBetreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Eval(): führe den Code aus *)
Eval Expr: alles, was mit Expr() umschlossen ist, vorab auswerten *)
Expr(): Markierung für Code, der vorab ausgewertet werden muss *)
*) mein Gehirn: „das E-Wort“ – 3 Mal.
und der vierte ist Expr Name() ; -)
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Zustimmen : )
Für die große Klasse gibt es möglicherweise eine einfache Lösung, diese hilft jedoch möglicherweise nicht bei dem eigentlichen Problem.
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?@hogi , danke für diese Links. Eval/Eval Expr() war für mich in den letzten Jahren der frustrierendste Teil von JSL. Ich habe es ein paar Mal erfolgreich verwendet, indem ich Beispiele aus der Community kopiert und angepasst habe, aber ich hatte nie das Gefühl, es wirklich richtig verstanden zu haben. Ich freue mich darauf, die Liste der von Ihnen gesammelten Ressourcen durchzugehen, und vielleicht hilft das dabei, es endlich zu begreifen. Ich weiß, dass ich es zu meinem Toolkit hinzufügen muss.
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Ich meinte Verketten. Durch Aktualisieren/Verbinden verknüpfen Sie die Größendaten, denen kein Jahr zugeordnet ist, mit den Gewichtsdaten, die jährlich sind. Das neue Diagramm lässt es so aussehen, als ob Barbaras Größe in den Jahren 2022, 23 und 24 mit 60 Zoll gemessen wurde, was aber nicht der Fall war.
Der Trick dabei ist, dass die Daten unten mit dem Jahr verknüpft sind, die Daten oben jedoch nicht, und ich möchte einen zentrierten Balken dafür. Vielleicht hätte ich statt der Körpergröße „BIP pro Kopf, wann und wo der Schüler geboren wurde“ verwenden sollen – eindeutig nicht mit dem 22./23./24 verknüpft.
Da die zugrunde liegenden Daten für die oberen und unteren Diagramme eine unterschiedliche Struktur haben, benötige ich meiner Ansicht nach zwei separate Diagrammersteller, um das gewünschte Bild (oben) zu erstellen.
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Danke @TomF – sehr cooler Trick, um die Einschränkung der Beschriftungseinstellungen zu bekämpfen: Verwenden Sie 2 Tabellen : )
Ich frage mich, warum es nicht möglich ist, Diagramme wie dieses zu erstellen – weder in einzelnen Graphen noch kombiniert in einem Graphen.

Wenn Sie die Beschriftung für ein Diagramm festlegen, werden die Beschriftungen automatisch auch in den anderen Diagrammen angezeigt: (
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Die Kenntnis verschiedener Filtertechniken ermöglicht es, in JMP alle möglichen interessanten Dinge zu tun (manchmal sind sie auch notwendig, insbesondere wenn Sie über große Datenmengen verfügen).
Ich nehme an, dass Sie mit Verketten „Aktualisieren/Verbinden“ meinen und wir eine einzelne Tabelle wie diese haben könnten (hierfür kann ein virtueller Join verwendet werden, wenn eine eindeutige Kennung vorhanden ist).

Daraus lässt sich ein Diagramm wie dieses erstellen

Sie können dies beispielsweise durch die Verwendung von Textlets (Hover-Label) tun.
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]}"))})
)
);
Sie können den angezeigten Text bei Bedarf noch weiter anpassen, indem Sie JMP > JMP-Berichte > Hover-Labels in JMP-Diagrammen anpassen > Text zu Hover-Labels in JMP-Diagrammen hinzufügen verwenden.
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Hallo @TomF , ich habe dem Code einige Kommentare hinzugefügt, um die einzelnen Schritte zu erklären.
Ein Trick ist Extract Expr() – es scannt den Ausdruck und sucht nach einem bestimmten Muster.
Ich habe mir gerade ein altes Skript angesehen, in dem ich einen Datenfilter verwendet habe, um 4 zusätzliche Datenfilter im selben Dashboard zu steuern.
Und es sah aus wie
For( i = 1, i <= N Arg( filterScript ), i++,
If( Head( Arg( filterScript, i ) ) == Expr( Add Filter() ),
filterExpression = Arg( filterScript, i )
)
);
Der Ansatz über Extract Expr() ist viel eleganter – ich habe ihn erst letztes Jahr von @jthi in dieser Diskussion gelernt:
:folded_hands: Ausdrucksindizierung: Lese- und Schreibzugriff
Der andere Trick: Eval (Eval Expr( Expr())) - ein Schweizer Taschenmesser!
Es wird 95 % Ihrer Probleme in JSL lösen:)
Ausdrucksbehandlung in JMP: Tipps und Falltüren
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Ich fürchte, ein Großteil des Codes ist mir zu kompliziert, aber ich verstehe die Grundidee. Ich werde das bei komplizierteren Situationen im Hinterkopf behalten. Danke!
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Ja, ich möchte einen Filter, der zwei Berichte aus unterschiedlichen Tabellen filtert. Ich kann mir vorstellen, dass das mit dem einfachen Big Class-Beispiel, das ich oben geteilt habe, keinen Sinn ergibt, aber ich füge ein komplizierteres Beispiel an, das die Struktur meines tatsächlichen Datensatzes genau nachahmt.
Stellen Sie sich vor, Sie haben eine Tabelle mit der aktuellen Körpergröße jedes Schülers und eine weitere Tabelle mit dem Gewicht jedes Schülers für die letzten drei Jahre. So möchte ich die Daten anzeigen:

Der Datensatz zur Körpergröße hat offensichtlich eine Zeile pro Schüler. Die Gewichtsdaten beginnen mit einer Zeile pro Schüler (drei Gewichtsspalten), aber ich kenne keine Möglichkeit, im Graph Builder dieses untere Diagramm zu erstellen, ohne die Gewichte zu stapeln. Meine Gewichtstabelle hat jetzt dreimal so viele Zeilen wie die Größentabelle.
Da ein Datenfilter nicht zwei verschiedene Tabellen filtern kann, bestand meine Lösung bisher darin, die Tabellen zu verknüpfen, nur um dieses Diagramm erstellen zu können. Das ist nicht elegant, funktioniert aber gut.
Wirklich in Schwierigkeiten geriet ich, als ich beim Bewegen der Maus über die Körpergröße im Popup anzeigen lassen wollte, ob während der Messung Schuhe getragen wurden, und beim Bewegen der Maus über das Gewicht die Seriennummer der verwendeten Waage wissen wollte. Wenn sich alle Daten in einer Tabelle befinden und ich für beide Spalten Label(1) einstelle, fehlen beim Bewegen der Maus über die Tabelle Werte (weil bei einer Gewichtsmessung keine Waagenseriennummer angegeben ist) … das lässt sich zwar auch beheben, aber es wurde dann immer chaotischer.
Ich denke, die Lösung, die Daten in zwei Tabellen mit zwei synchronisierten Filtern (einer davon ausgeblendet) zu belassen, wird viel besser funktionieren. Aber wenn es eine bessere Möglichkeit gibt, dieses Diagramm zu erstellen, bin ich für Vorschläge offen.
Nur ein allgemeines Lob an Graph Builder und die Möglichkeit, es mit JSL zu steuern. Diese nahtlose Verschmelzung zweier verschiedener Diagramme ist nur möglich, weil wir die Möglichkeit haben, alles unten im oberen Diagramm und oben im unteren Diagramm auszuschalten und sie direkt nebeneinander zu bringen. Dadurch konnten wir in unserer spezifischen Situation eine sehr individuelle und sehr datenreiche Grafik erstellen. Und jetzt können wir sie auch elegant filtern:) Vielleicht finden andere dies in Zukunft nützlich.
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Für so etwas gibt es viele verschiedene Optionen und alles hängt davon ab, was wirklich gemacht wird (wie die Daten aussehen, können Zeilenzustände manipuliert werden, was wird gefiltert (und warum), ...). Hier ist eine Option, die (normalerweise) in vielen Fällen recht gut funktioniert, aber für den Handler eine recht komplizierte Funktion hat (das Hinzufügen einer festen Größe (mithilfe von Spacer Box()) ist für so etwas im Allgemeinen eine gute Idee, um ein störendes Blinken des Fensters zu vermeiden).
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();Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?@hogi Ich verstehe nicht ganz, was Ihr Code macht, aber ich habe ihn eingegeben und er hat perfekt funktioniert. Danke!
Ehrlich gesagt bin ich der Falltür nicht wirklich entkommen. Ich bin hineingefallen und habe mich dann wieder herausgezogen. Ich folgteDasCommunity-Beitrag, aber ich sah keinen Grund, den Event-Handler als Variable zu speichern, also tat ich es nicht. Es funktionierte nicht, ich befolgte den Beitrag genauer und speicherte ihn als Variable, es funktionierte und ich machte weiter, ohne zu verstehen, was passiert war. Ich habe Kommentare mit Ihren beiden Falltüren in meinen Code eingefügt, in der Hoffnung, jemandem in Zukunft blaue Flecken zu ersparen.
In diesem Fall ist meine Filterung einfach – immer eine Spalte – und beide meiner Tabellen enthalten dieselben X-Werte, also besteht in dieser Hinsicht kein Grund zur Sorge.
Ich habe den aktualisierten Code oben gepostet.
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?
@jthi schrieb:
Wenn es lokal sein muss, gibt es immer noch andere Optionen als die Verwendung von zwei lokalen Datenfiltern (was auch möglich ist).
Der Filterstatus-Handler wird nicht nur durch Änderungen des Datenfilters ausgelöst.
Ihre Balkendiagramme sind sicher – aber bei Punktdiagrammen wird der State Handler ausgelöst, wenn die Maus einen Datenpunkt berührt!
Daher kann es je nach Diagrammtyp sinnvoll sein, die aktuellen Filtereinstellungen mit den vorherigen zu vergleichen – und die Einstellungen erst dann auf das zweite Diagramm anzuwenden, wenn Sie eine Änderung feststellen.
vielleicht kannst du hier abstimmen:
Verbessern Sie die Statushandler von JMP (Hover-Label, Zeilenstatushandler, Filterstatushandler, Scheduler, …)
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Stellen Sie sicher, dass beide Tabellen die gleichen Werte enthalten!
Wenn der Datenfilter keine passende Zeile findet, wird er zurückgesetzt und zeigt alle Zeilen an:

Dieses Problem wird in JMP19 behoben über :folded_hands: Spalteneigenschaft: Inklusive/erzwungene Werte
Als Workaround für <=JMP18 können Sie Dummyzeilen mit fehlenden Daten in den verbleibenden Spalten hinzufügen
-> wird nicht im Diagramm angezeigt, verhindert aber, dass der Datenfilter zurückgesetzt wird.
Mehr anzeigen...
//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)))))
);
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Sie können zwei (oder mehr) Diagramme mit einem einzigen Filter filtern, indem Sie das Feld Datenfilterkontext/Quelle verwenden, ABER sie müssen dieselbe Quelltabelle haben
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)
)
)
)
);
Meine Frage ist nun, was Sie versuchen zu tun? Sie möchten einen Filter haben, der zwei Berichte AUS unterschiedlichen Tabellen filtert? Ich würde einen lokalen Datenfilter verwenden und diesen dann verwenden, um Zeilen aus der zweiten Tabelle auszublenden/auszuschließen (wenn Sie zulassen, dass die Tabelle geändert wird, anstatt nur lokal zu sein). Wenn es lokal sein muss, gibt es immer noch andere Optionen als die Verwendung von zwei lokalen Datenfiltern (was auch möglich ist).
Betreff: Wie kann ich einen Datenfilter so einrichten, dass er einen anderen spiegelt?Hübsch : )
Als ich meinen ersten State Handler erstellte, vergaß ich, den Filter-State-Handler in einer Variablen zu speichern – und er wurde sofort zerstört.
Und dann hat es nicht funktioniert, weil ich eine Funktion mit 0 Argumenten verwendet habe. -> gut gemacht, Sie sind beiden Falltüren entkommen : )
Es gibt keine Set Where-Klausel – die Where-Klausel ist keine Nachricht, die ein Datenfilter verstehen würde. Sie können sie an die Tabelle senden, um die Zeilen auszuwählen. Außerdem gibt << Get Where Clause () eine Zeichenfolge zurück. Sie müssen Parse verwenden, um sie in einen Ausdruck umzuwandeln.
Das Entpacken ist weniger aufwändig als Sie vielleicht erwarten - fragen Sie einfach den Datenfilter nach dem Skript, extrahieren Sie den Teil „Add Filter()“ über „Extract Expr()“ und wenden Sie ihn auf den zweiten Filter an - funktioniert für einfache Auswahlen *)
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
)
)
);
)
);
*) Wenn Sie mehrere Filter über OR() kombinieren, enthält das Skript mehrere add Filter() - und Extract Expr() gibt nur den ersten zurück.
Um eine ultimative Klonfunktion zu erhalten, können Sie das DF-Skript analysieren, alle AddFilter() sammeln und sie nacheinander auf den zweiten Datenfilter anwenden.