Come faccio a far sì che un filtro dati ne rispecchi un altro?Ho una finestra contenente due grafici builder, che estraggono da due set di dati diversi, e voglio filtrare entrambi i grafici con un singolo filtro dati. Non credo che sia possibile. Ho pensato di usare invece due filtri dati "sincronizzati", ma non ci sono riuscito. La scorsa settimana a JMP Discovery, @danschikore mi ha indicato i gestori di eventi come possibile soluzione per usare due filtri sincronizzati. Penso di essere vicino a farlo funzionare, ma sono bloccato.
Lo script qui sotto crea i due filtri e i due grafici. Voglio che le selezioni effettuate nel filtro superiore si riflettano automaticamente nel filtro inferiore. Una volta che funziona, nasconderò il filtro inferiore e l'utente vedrà un filtro che controlla entrambi i grafici.
Così com'è ora, quando l'utente fa una selezione nel filtro superiore, lo script stampa quella clausola Where nel log usando "Get Where Clause", ma devo applicare questa clausola where al filtro inferiore. Voglio un comando come "Set Where Clause" che mi permetta di spingere quel testo della clausola where nel filtro inferiore, ma non sembra esistere. Spero davvero di evitare lo scenario in cui devo "decomprimere" la stringa di testo (sotto) e trasformarla in un formato che posso passare al filtro inferiore.
Seleziona Dove( :name == \!"ALICE\!" | :name == \!"BARBARA\!" )
Solo per convincermi che posso far sì che il primo filtro controlli il secondo in qualche modo, ho il primo filtro che cancella la selezione del secondo filtro. Ciò significa che posso parlare con entrambi i filtri; posso estrarre la clausola where dal primo; semplicemente non posso applicarla al secondo.
Domanda bonus: una volta che questa sincronizzazione funziona, voglio nascondere il secondo filtro. L'ultima riga dello script nasconde il primo filtro. Qualcuno sa come potrei modificarlo per nascondere il secondo filtro?
Grazie,
ragazzo

Automazione e scriptingR: Come faccio a far sì che un filtro dati ne rispecchi un altro?Eval(): esegui il codice *)
Eval Expr: pre-valuta tutto ciò che è racchiuso con Expr() *)
Expr(): marcatore per il codice che deve essere pre-valutato *)
*) il mio cervello: "la parola che inizia per E" - 3 volte.
e il quarto è Expr Name() ; -)
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Essere d'accordo : )
Per la Big Class potrebbe esserci una soluzione semplice, ma questa soluzione potrebbe non risolvere il problema reale.
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?@hogi , grazie per questi link. Eval/Eval Expr() è stata la parte più frustrante di JSL per me negli ultimi anni. L'ho usata con successo un paio di volte copiando e modificando esempi dalla Community, ma non ho mai avuto la sensazione di averla effettivamente capita bene. Non vedo l'ora di esaminare l'elenco delle risorse che hai raccolto e forse questo ti aiuterà a capirla finalmente. So che è qualcosa che devo aggiungere al mio toolkit.
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Volevo dire concatenare. Facendo update/join stai associando i dati di altezza, che non hanno un anno associato, con i dati di peso, che sono annuali. Il nuovo grafico fa sembrare che l'altezza di Barbara sia stata misurata a 60 pollici nel 2022, 23 e 24, il che non era.
Il trucco qui è che i dati in basso sono associati all'anno, ma quelli in alto no, e voglio una barra centrata per loro. Forse invece di altezza avrei dovuto usare "PIL pro capite quando e dove è nato lo studente" -- chiaramente non associato a 22/23/24.
Poiché i dati sottostanti per i grafici in alto e in basso hanno una struttura diversa, penso di aver bisogno di due generatori di grafici separati per creare l'immagine che desidero (sopra).
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Grazie @TomF - un trucco davvero interessante per combattere la restrizione delle impostazioni delle etichette: usa 2 tabelle : )
Mi chiedo perché non sia possibile generare grafici come questo, né in grafici separati, né combinati in un unico grafico.

impostando l'etichetta per un grafico si forza automaticamente anche gli altri grafici a mostrare le etichette: (
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Conoscere diverse tecniche di filtraggio consente di fare tante cose interessanti in JMP (a volte sono anche necessarie, soprattutto se si hanno molti dati).
Immagino che per concatenare tu possa intendere aggiornare/unire e potremmo avere una tabella singola come questa (l'unione virtuale può essere utilizzata per questo se c'è un identificatore univoco)

Da questo è possibile creare un grafico come questo

Puoi farlo ad esempio utilizzando Textlets (etichetta al passaggio del mouse)
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]}"))})
)
);
Se necessario, puoi personalizzare ulteriormente il testo visualizzato, utilizzando JMP > Report JMP > Personalizza etichette di passaggio del mouse nei grafici JMP > Aggiungi testo alle etichette di passaggio del mouse nei grafici JMP
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Ciao @TomF , ho aggiunto alcuni commenti al codice per spiegare i singoli passaggi.
Un trucco è Extract Expr() : analizza l'espressione e cerca uno schema specifico.
Ho appena dato un'occhiata a un vecchio script in cui ho utilizzato un filtro dati per controllare altri 4 filtri dati nella stessa Dashboard.
E sembrava che
For( i = 1, i <= N Arg( filterScript ), i++,
If( Head( Arg( filterScript, i ) ) == Expr( Add Filter() ),
filterExpression = Arg( filterScript, i )
)
);
L'approccio tramite Extract Expr() è molto più elegante: l'ho appena imparato l'anno scorso da @jthi in questa discussione:
:folded_hands: Indicizzazione delle espressioni: accesso in lettura e scrittura
L'altro trucco: Eval (Eval Expr( Expr())) - un coltellino svizzero!
Risolverà il 95% dei tuoi problemi in JSL:)
Gestione delle espressioni in JMP: suggerimenti e trappole
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Temo che molto di quel codice sia al di là delle mie possibilità, ma ho capito l'idea generale. Lo terrò a mente per situazioni più complicate. Grazie!
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Sì, voglio un filtro che filtri due report da tabelle diverse. Immagino che non abbia senso con il semplice esempio Big Class che ho condiviso sopra, ma allego un esempio più complicato che imita da vicino la struttura del mio set di dati effettivo.
Immagina di avere una tabella con l'altezza attuale di ogni studente e un'altra tabella con il peso di ogni studente negli ultimi tre anni. Ecco come voglio visualizzare quei dati:

Il set di dati altezza ha ovviamente una riga per studente. I dati peso iniziano con una riga per studente (tre colonne di peso), ma non conosco alcun modo in Graph Builder per creare quel grafico in basso senza impilare i pesi. La mia tabella peso ora ha 3 volte più righe della tabella altezza.
Poiché un filtro dati non può filtrare due tabelle diverse, la mia soluzione finora è stata quella di concatenare le tabelle, solo per poter creare questo grafico. Non è elegante, ma funziona bene.
Dove mi sono davvero cacciato nei guai è stato quando passo il mouse sull'altezza voglio che il pop-up mostri se indossavano scarpe durante la misurazione, e quando passo il mouse sul peso voglio sapere il numero di serie della bilancia che è stata utilizzata. Quando tutti i dati sono in una tabella e creo Label(1) per entrambe le colonne, finisci con valori mancanti quando passi il mouse (perché non c'è un numero di serie della bilancia su una misurazione del peso)... il che può anche essere risolto, ma ha appena iniziato a diventare molto disordinato.
Penso che la soluzione di lasciare i dati in due tabelle con due filtri sincronizzati (uno nascosto) funzionerà molto meglio. Ma se c'è un modo migliore per creare questo grafico, sono aperto ai suggerimenti.
Solo un saluto generale a Graph Builder e alla possibilità di controllarlo con JSL. Questa fusione senza soluzione di continuità di due grafici diversi è possibile solo perché abbiamo la possibilità di disattivare tutto ciò che si trova in basso nel grafico superiore e in alto nel grafico inferiore e di avvicinarli l'uno all'altro. Questo ci ha permesso di creare un grafico molto personalizzato e molto denso di dati nella nostra situazione specifica. E ora possiamo anche filtrarlo in modo elegante
Forse altri lo troveranno utile in futuro.
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Ci sono molte opzioni diverse per qualcosa del genere e tutto dipende da cosa si sta realmente facendo (come appaiono i dati, gli stati delle righe possono essere manipolati, cosa si sta filtrando (e perché), ...). Ecco un'opzione che funziona (di solito) abbastanza bene in molti casi, ma ha una funzione piuttosto complicata per il gestore (aggiungere una dimensione fissa (con l'aiuto di Spacer Box()) per qualcosa del genere è generalmente una buona idea per evitare il fastidioso lampeggiamento della finestra).
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();R: Come faccio a far sì che un filtro dati ne rispecchi un altro?@hogi Non ho capito bene cosa fa il tuo codice, ma l'ho inserito e ha funzionato perfettamente. Grazie!
Per essere onesti, non sono proprio scappato dalla botola. Ci sono caduto dentro e poi mi sono tirato fuori. Stavo seguendoQuestopost della community, ma non ho visto alcun motivo per memorizzare il gestore eventi come variabile, quindi non l'ho fatto. Non ha funzionato, ho seguito il post con più attenzione, memorizzandolo come variabile, ha iniziato a funzionare e ho continuato senza capire cosa fosse successo. Ho inserito commenti nel mio codice con le tue due trapdoor, sperando di risparmiare a qualcuno i lividi in futuro.
In questo caso, il mio filtraggio è semplice (sempre una colonna) ed entrambe le mie tabelle contengono gli stessi valori x, quindi non ci sono problemi.
Ho pubblicato il codice aggiornato qui sopra.
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?
@jthi ha scritto:
Se deve essere locale, ci sono ancora altre opzioni oltre all'utilizzo di due filtri dati locali (che è anche possibile).
Il gestore dello stato del filtro non viene attivato solo dalle modifiche del filtro dati.
I grafici a barre sono salvati, ma per i grafici a punti, lo State Handler verrà attivato ogni volta che il mouse tocca un punto dati!
Quindi, a seconda del tipo di grafico, potrebbe essere una buona idea confrontare le impostazioni del filtro correnti con quelle precedenti e applicare le impostazioni al secondo grafico quando si rileva una modifica.
forse vota qui:
Migliorare i gestori di stato di JMP (etichetta di passaggio del mouse, gestore di stato di riga, gestore di stato di filtro, scheduler, ...)
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Assicuratevi che entrambe le tabelle contengano gli stessi valori!
Se il filtro dati non trova una riga corrispondente, verrà reimpostato e verranno visualizzate tutte le righe:

Questo problema verrà risolto in JMP19 tramite :folded_hands: Proprietà colonna: valori inclusivi/forzati
Come soluzione alternativa per <=JMP18, puoi aggiungere righe fittizie con dati mancanti nelle colonne rimanenti
-> non verrà visualizzato nel grafico ma impedirà la reimpostazione del filtro dati.
Vedi altro...
//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)))))
);
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?È possibile filtrare due (o più) grafici con un singolo filtro utilizzando la casella Contesto/Origine del filtro dati MA devono avere la stessa tabella di origine
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)
)
)
)
);
Ora la mia domanda è: cosa stai cercando di fare? Vuoi avere un filtro che filtri due report DA tabelle diverse? Io userei un filtro dati locale e poi lo userei per nascondere/escludere righe dalla seconda tabella (se gli permetti di modificare la tabella invece di essere solo locale). Se deve essere locale, ci sono ancora altre opzioni oltre a usare due filtri dati locali (che è anche possibile).
R: Come faccio a far sì che un filtro dati ne rispecchi un altro?Carino : )
Quando ho creato il mio primo gestore di stato, ho dimenticato di memorizzare il gestore di stato del filtro in una variabile, e questo è stato immediatamente distrutto.
E poi non ha funzionato perché ho usato una funzione con 0 argomenti. -> ben fatto, sei riuscito a superare entrambe le trappole : )
Non c'è una clausola Set where - la clausola Where non è un messaggio che un filtro dati capirà, puoi inviarlo alla tabella per selezionare le righe. Oltre a ciò << Get Where Clause () restituisce una stringa. Devi usare Parse per convertirla in un'espressione.
Unpack richiede meno sforzo di quanto potresti aspettarti: basta chiedere al filtro dati lo script, estrarre la parte Add Filter() tramite Extract Expr() e applicarla al secondo filtro: funzionerà per selezioni semplici *)
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
)
)
);
)
);
*) Quando si combinano più filtri tramite OR(), lo script conterrà più add Filter() e Extract Expr() restituirà solo il primo.
Per ottenere una funzione clone definitiva, puoi analizzare lo script DF, raccogliere tutti gli AddFilter() e applicarli uno dopo l'altro al secondo filtro dati.