¿Cómo puedo hacer que un filtro de datos refleje otro?Tengo una ventana que contiene dos generadores de gráficos, que extraen datos de dos conjuntos de datos diferentes, y quiero filtrar ambos gráficos con un único filtro de datos. No creo que esto sea posible. He pensado en utilizar dos filtros de datos "sincronizados", pero no he podido resolverlo. La semana pasada en JMP Discovery, @danschikore me señaló los controladores de eventos como una posible solución para utilizar dos filtros sincronizados. Creo que estoy cerca de conseguir que funcione, pero estoy atascado.
El script que se muestra a continuación crea los dos filtros y los dos gráficos. Quiero que las selecciones realizadas en el filtro superior se reflejen automáticamente en el filtro inferior. Una vez que eso funcione, ocultaré el filtro inferior y el usuario verá un filtro que controla ambos gráficos.
Tal como está ahora, cuando el usuario hace una selección en el filtro superior, el script imprime esa cláusula Where en el registro usando "Get Where Clause", pero necesito aplicar esta cláusula Where al filtro inferior. Quiero un comando como "Set Where Clause" que me permita insertar ese texto de cláusula Where en el filtro inferior, pero no parece existir. Realmente espero evitar el escenario en el que tenga que "descomprimir" la cadena de texto (abajo) y convertirla en un formato que pueda pasar al filtro inferior.
Seleccionar Dónde( :nombre == \!"ALICE\!" | :nombre == \!"BARBARA\!" )
Solo para convencerme de que puedo lograr que el primer filtro controle al segundo de alguna manera, hago que el primer filtro borre la selección del segundo filtro. Eso significa que puedo comunicarme con ambos filtros; puedo extraer la cláusula where del primero; pero no puedo aplicarla al segundo.
Como pregunta adicional: una vez que funcione esta sincronización, quiero ocultar el segundo filtro. La última línea del script oculta el primer filtro. ¿Alguien sabe cómo puedo modificar esto para ocultar el segundo filtro?
Gracias,
Tomás

Automatización y scriptingRe: ¿Cómo puedo hacer que un filtro de datos refleje otro?Eval(): ejecuta el código *)
Eval Expr: evalúa previamente todo lo incluido con Expr() *)
Expr(): marcador para el código que debe evaluarse previamente *)
*) mi cerebro: "la palabra E" - 3 veces.
y el cuarto es Expr Name() ; -)
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Aceptar : )
Para las clases grandes puede haber una solución fácil, pero esta solución podría no ayudar con el problema real.
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?@hogi , gracias por estos enlaces. Eval/Eval Expr() ha sido la parte más frustrante de JSL para mí en los últimos años. Lo he usado con éxito algunas veces copiando y modificando ejemplos de la Comunidad, pero nunca sentí que realmente lo comprendiera bien. Espero poder revisar la lista de recursos que has recopilado y tal vez eso ayude a asimilarlo finalmente. Sé que es algo que necesito agregar a mi conjunto de herramientas.
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Quise decir concatenar. Al hacer update/join estás asociando los datos de altura, que no tienen año asociado, con los datos de peso, que son anuales. El nuevo gráfico hace que parezca que la altura de Barbara fue de 60 pulgadas en 2022, 23 y 24, lo cual no fue así.
El truco aquí es que los datos de la parte inferior están asociados con el año, pero los de la parte superior no, y quiero una barra centrada para ello. Tal vez en lugar de altura debería haber utilizado "PIB per cápita cuando y donde nació el estudiante", que claramente no está asociado con 22/23/24.
Debido a que los datos subyacentes de los gráficos superior e inferior tienen una estructura diferente, creo que necesito dos generadores de gráficos separados para crear la imagen que quiero (arriba).
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Gracias @TomF : un truco muy bueno para luchar contra la restricción de la configuración de etiquetas: usa 2 tablas : )
Me pregunto por qué no es posible generar gráficos como éste, ni en gráficos separados ni combinados en un solo gráfico.

Al configurar la etiqueta para un gráfico, se fuerza automáticamente a los demás gráficos a mostrar también las etiquetas: (
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Conocer diferentes técnicas de filtrado permite hacer todo tipo de cosas interesantes en JMP (a veces también son necesarias, especialmente si tienes muchos datos).
Supongo que por concatenar podrías referirte a actualizar/unir y podríamos tener una sola tabla como esta (se puede usar una unión virtual para esto si hay un identificador único)

A partir de esto es posible crear un gráfico como éste

Puedes hacerlo, por ejemplo, utilizando Textlets (etiqueta flotante)
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]}"))})
)
);
Puede personalizar mucho más el texto que se muestra si es necesario, utilizando JMP > Informes JMP > Personalizar etiquetas flotantes en gráficos JMP > Agregar texto a etiquetas flotantes en gráficos JMP
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Hola @TomF , agregué algunos comentarios al código para explicar los pasos individuales.
Un truco es Extract Expr() : escanea la expresión y busca un patrón específico.
Acabo de echar un vistazo a un script antiguo en el que usé un filtro de datos para controlar cuatro filtros de datos adicionales en el mismo Tablero.
Y parecía que
For( i = 1, i <= N Arg( filterScript ), i++,
If( Head( Arg( filterScript, i ) ) == Expr( Add Filter() ),
filterExpression = Arg( filterScript, i )
)
);
El enfoque a través de Extract Expr() es mucho más elegante: lo aprendí el año pasado de @jthi en esta discusión:
:folded_hands: Indexación de expresiones: acceso de lectura y escritura
El otro truco: Eval (Eval Expr( Expr())) - ¡Una navaja suiza!
Resolverá el 95% de tus problemas en JSL:)
Manejo de expresiones en JMP: trucos y trampas
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Me temo que gran parte de ese código no lo entiendo, pero entiendo la idea general. Lo tendré en cuenta para situaciones más complicadas. ¡Gracias!
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Sí, quiero un filtro que filtre dos informes de diferentes tablas. Imagino que eso no tiene sentido con el ejemplo simple de Big Class que compartí anteriormente, pero adjunto un ejemplo más complicado que imita de cerca la estructura de mi conjunto de datos real.
Imagina que tienes una tabla con la altura actual de cada alumno y otra tabla con el peso de cada alumno durante los últimos tres años. Así es como quiero ver esos datos:

Obviamente, el conjunto de datos de altura tiene una fila por estudiante. Los datos de peso comienzan con una fila por estudiante (tres columnas de peso), pero no conozco ninguna manera en Graph Builder de crear ese gráfico inferior sin apilar los pesos. Mi tabla de pesos ahora tiene el triple de filas que la tabla de altura.
Como un filtro de datos no puede filtrar dos tablas diferentes, mi solución hasta ahora fue concatenar las tablas, solo para poder hacer este gráfico. No es elegante, pero funciona bien.
En lo que realmente me metí en problemas fue en que cuando coloco el cursor sobre la altura, quiero que la ventana emergente muestre si llevaban zapatos durante la medición, y cuando coloco el cursor sobre el peso, quiero saber el número de serie de la báscula que se utilizó. Cuando todos los datos están en una tabla y hago Label(1) para ambas columnas, terminas con valores faltantes cuando pasas el cursor (porque no hay un número de serie de la báscula en una medición de peso)... lo cual también se puede solucionar, pero comenzó a volverse muy complicado.
Creo que la solución de dejar los datos en dos tablas con dos filtros sincronizados (uno oculto) va a funcionar mucho mejor. Pero si hay una mejor manera de crear este gráfico, estoy abierto a sugerencias.
Solo un reconocimiento general a Graph Builder y la capacidad de controlarlo con JSL. Esta combinación perfecta de dos gráficos diferentes solo es posible porque tenemos la capacidad de desactivar todo lo que está en la parte inferior del gráfico superior y en la parte superior del gráfico inferior y ponerlos uno frente al otro. Esto nos ha permitido crear un gráfico muy personalizado y con una gran densidad de datos en nuestra situación específica. Y ahora también podemos filtrarlo de manera elegante
Tal vez a otros les resulte útil en el futuro.
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Hay muchas opciones diferentes para algo como esto y todo depende de lo que realmente se esté haciendo (cómo se ven los datos, se pueden manipular los estados de las filas, qué se está filtrando (y por qué), ...). Aquí hay una opción que funciona (generalmente) bastante bien en muchos casos, pero tiene una función bastante complicada para el controlador (agregar un tamaño fijo (con la ayuda de Spacer Box()) para algo como esto generalmente es una buena idea para evitar el molesto parpadeo de la ventana).
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();Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?@hogi No entiendo bien qué hace tu código, pero lo puse y funcionó perfectamente. ¡Gracias!
Para ser sincero, no logré escapar de la trampilla. Me caí y luego salí. Estaba siguiendoestePublicación de la comunidad, pero no vi ninguna razón para almacenar el controlador de eventos como una variable, así que no lo hice. No funcionó, seguí la publicación con más atención, lo almacené como una variable, comenzó a funcionar y continué sin entender qué sucedió. Puse comentarios en mi código con sus dos trampillas, con la esperanza de ahorrarle a alguien los moretones en el futuro.
En este caso, mi filtrado es simple (siempre una columna) y ambas tablas contienen los mismos valores x, por lo que no hay problemas.
He publicado el código actualizado arriba.
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?
@jthi escribió:
Si tiene que ser local, todavía hay otras opciones además de utilizar dos filtros de datos locales (lo que también es posible).
El controlador del estado del filtro no solo se activa con los cambios del filtro de datos.
Sus gráficos de barras están seguros, pero para los gráficos de puntos, el controlador de estado se activará cada vez que el mouse toque un punto de datos.
Por lo tanto, dependiendo del tipo de gráfico, puede ser una buena idea comparar las configuraciones de filtro actuales con las anteriores y simplemente aplicar las configuraciones al segundo gráfico cuando detecte un cambio.
Quizás vote aquí:
Mejorar los controladores de estado de JMP (etiqueta flotante, controlador de estado de fila, controlador de estado de filtro, programador, ...)
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?¡Asegúrese de que ambas tablas contengan los mismos valores!
Si el filtro de datos no encuentra una fila coincidente, se reiniciará y mostrará todas las filas:

Este problema se solucionará en JMP19 a través de :folded_hands: Propiedad de columna: Valores inclusivos/forzados
Como solución alternativa para <=JMP18, puede agregar filas ficticias con datos faltantes en las columnas restantes
-> no se mostrará en el gráfico, pero evitará que se restablezca el filtro de datos.
Ver más...
//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)))))
);
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Puede filtrar dos (o más) gráficos con un solo filtro utilizando el cuadro Contexto/Fuente del filtro de datos, PERO deben tener la misma tabla de origen.
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)
)
)
)
);
Ahora, mi pregunta es: ¿qué estás intentando hacer? ¿Deseas tener un filtro que filtre dos informes de diferentes tablas? Yo usaría un filtro de datos local y luego lo usaría para ocultar o excluir filas de la segunda tabla (si permites que modifique la tabla en lugar de ser solo local). Si tiene que ser local, todavía hay otras opciones además de usar dos filtros de datos locales (lo cual también es posible).
Re: ¿Cómo puedo hacer que un filtro de datos refleje otro?Lindo : )
Cuando creé mi primer controlador de estado, olvidé almacenar el controlador de estado del filtro en una variable y se destruyó inmediatamente.
Y luego no funcionó porque usé una función con 0 argumentos. -> bien hecho, escapaste de ambas trampas : )
No existe una cláusula WHERE (Set where
la cláusula WHERE no es un mensaje que un filtro de datos pueda entender, puede enviarlo a la tabla para seleccionar las filas. Además , la cláusula WHERE () devuelve una cadena. Debe utilizar Parse para convertirla en una expresión.
Desempaquetar requiere menos esfuerzo del que podría esperar: simplemente solicite el script al filtro de datos, extraiga la parte Agregar filtro() mediante Extract Expr() y aplíquela al segundo filtro: funcionará para selecciones simples *)
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
)
)
);
)
);
*) Cuando combinas varios filtros a través de OR(), el script contendrá múltiples add Filter() y Extract Expr() solo devolverá el primero.
Para obtener una función de clonación definitiva, puede analizar el script DF, recopilar todos los AddFilter() y aplicarlos uno tras otro al segundo filtro de datos.