Muestra rápidamente la Vista de datos con un subconjunto de filas que coinciden con la expresión regularEstoy buscando un script JSL que haga lo siguiente:
-
Obtiene las columnas seleccionadas actualmente en la tabla de datos activa.
-
Toma la primera columna seleccionada .
-
Solicita al usuario que ingrese una expresión regular .
-
Selecciona solo las filas de la tabla donde el valor de esa columna coincide con la expresión regular .
-
Abre una ventana Vista de datos que muestra sólo las filas coincidentes.
¿Es esto posible con JSL?
Automatización y scriptingAcceso a datosRe: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regularEs posible. ¿Qué has intentado?
Este es un ejemplo muy básico al que le faltan todas las comprobaciones que podrían (y probablemente deberían) implementarse.
Names Default To Here(1);
dt = Current Data Table();
col = (dt << Get Selected Columns("String"))[1]; // I suggest dropping non-character columns
run_expr = Expr(
rgx_pattern = teb << Get Text; // You could check if the pattern is valid regex
dt << Select Where(!Is Missing(Regex(Column(dt, col)[Row()], rgx_pattern)));
// add check if any rows have been selected
dt << Data View; // If linked subset is fine, that is most likely better as it can avoid using select where
dt << Clear Select;
wait(0);
);
nw = New Window("",
H List Box(
Lineup Box(N Col(2),
Text Box("Enter regex pattern"),
teb = Text Edit Box("")
),
Lineup Box(N Col(1),
Button Box("OK",
run_expr
),
Button Box("Cancel")
)
)
);
Write();
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regularEso funciona, gracias.
Para ser honesto, no incluí ningún código porque mi intento no fue muy bueno y expone algunos malentendidos fundamentales sobre JSL que probablemente surgieron cuando aprendí scripts de GUI con AppleScript y Matlab.
Habría obtenido la lista de nombres de columnas seleccionadas y elegido la primera, pero esperaba algún tipo de función de "mostrar diálogo" que devolviera una cadena, pero aparentemente no existe y te obliga a usar esta sintaxis de nueva ventana/cuadro de lista/expresión de botón. Esto me resultó bastante poco intuitivo, pero ahora que entiendo su funcionamiento tiene más sentido. Probé ChatGPT, pero creó scripts largos que no se ejecutaron.
Algunas preguntas sobre tu solución, si tienes tiempo:
- ¿Por qué el botón "Cancelar" no hace nada? Supongo que es porque no tienes un segundo argumento para su llamada a Button Box(), pero ¿qué expresión cerraría la ventana actual? ¿Cerrar()? Intenté con "Button Box ( "Cancelar" , Cerrar ())", pero me da un error que no entiendo. Imité tu método y probé con "Cerrar ventana", que parece funcionar, pero supongo que hay una forma más sencilla de hacerlo.
- Tu llamada "Obtener columnas seleccionadas()" tiene "Cadena" como argumento, pero la documentación indica que la función no acepta argumentos. ¿Qué significa "Cadena" y cómo supiste que se aceptaría o qué hace?
- Me gustaría empezar a escribir inmediatamente después de ejecutar el script, pero el foco no está en el lugar correcto. Intenté escribir "teb << SetFocus;" después de la expresión "nw=...", pero JMP indica que los cuadros de edición de texto no entienden ese mensaje.
- ¿Es posible hacer que Regex no distinga entre mayúsculas y minúsculas? Y, de ser así, ¿cómo? (Intenté agregar " " a los argumentos Regex según la documentación, pero genera un error).
- ¿Es posible hacer que al presionar Enter se active el script "Ok" con el cuadro teb enfocado?
- Si el usuario no tiene columnas seleccionadas, me gustaría usar la primera columna de caracteres, pero después de aproximadamente 20 intentos diferentes, me di por vencido en intentar averiguar cuál es esa columna.
- Preferiría que el subconjunto de la vista de datos estuviera vinculado, ¿eso cambia el enfoque?
Esto es lo que tengo hasta ahora:
Names Default To Here(1);
run_expr = Expr(
dt = Current Data Table();
selCols = dt << Get Selected Columns("String");
if(N Items(selCols)==0, selCols = dt << get column names("String") );
col = selCols[1];
rgx_pattern = teb << Get Text;
dt << Select Where(!Is Missing(Regex(Column(dt, col)[Row()], rgx_pattern)));
dt << Data View; // I prefer a linked subset, what changes here?
dt << Clear Select;
wait(0);
nw << Close Window;
);
close_expr = Expr(nw << Close Window);
nw = New Window("",
H List Box(
Lineup Box(N Col(2),
Text Box("Enter regex pattern"),
teb = Text Edit Box("", <
<SET width=""></SET>
<P>Me encantaría abrir Big Class, ejecutar el script y luego escribir "ob.+t<ENTER> " y que muestre una Vista de Datos de solo los dos Roberts. Ahora mismo está cerca: después de ejecutar el script, tengo que presionar Tab, luego OB.+T, y luego Enter dos veces.</ENTER></P>
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regular- Creé un ejemplo lo más mínimo posible, para que Cancelar no contenga expresión para cerrar la ventana.
- Acabo de probar si "String" funcionaría igual que con << get column names() y funciona. Pruébalo sin el valor "String" y observa qué obtienes (referencias en lugar de cadenas). En mi opinión, trabajar con las referencias de columnas es un desastre, así que siempre uso cadenas de nombres de columnas y las convierto según sea necesario. Pero tú decides si prefieres usar referencias (o la sintaxis de dos puntos que sea).
- Creo que estás atascado con la pestaña a menos que desees utilizar soluciones alternativas complicadas . Permitir que SetFocus se use con elementos de visualización interactivos (TextEditBox, Botón...)
- Podrías usar Lowercase() para la entrada del usuario y encapsular la referencia de la columna con Lowercase(). O bien, creo que podrías agregar el grupo de captura predeterminado a Regex() al usar INGORECASE: Expresión regular ("ABCD", "d", "\0", IGNORAR MAYÚSCULAS)
- Podrías probar la función <
-
<< Get Column Names(Character, String)[1]
-
r = dt << Get Rows Where(!Is Missing(Regex(Column(dt, col)[Row()], rgx_pattern)));
dt_subset = dt << Subset(Rows(dt), Selected Columns(0), Link to original data table(1));
Hay muchas mejoras que se podrían realizar, pero cuáles podrían ser dependerán del caso de uso real.
Editar: Se agregó un enlace a la tabla de datos original (1) para crear un subconjunto.
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regularExcelente, gracias!
Solo una pregunta más: Si se seleccionan varias columnas, me gustaría ejecutar la expresión regular en los valores de las columnas concatenados como cadenas, y si no se selecciona ninguna, me gustaría hacer lo mismo en *todas* las columnas. Esto imita eficazmente el comportamiento de egrep en la tabla. ¿Es razonablemente factible? Consulte la línea comentada a continuación para ver mi primer intento, pero no extrae solo los valores de las columnas seleccionadas, así que aún no está listo (y no funciona).
Names Default To Here( 1 );
run_expr = Expr(
dt = Current Data Table();
selCols = dt << Get Selected Columns( "String" );
If( N Items( selCols ) == 0,
selCols = dt << Get Column Names( "String" )
);
col = selCols[1];
rgx_pattern = teb << Get Text;
dt << Select Where( !Is Missing( Regex( Column( dt, col )[Row()], rgx_pattern, "1", IGNORECASE ) ) );
// dt << Select Where( !Is Missing( Regex( Concat Items( dt << get Rows(Row())," "), rgx_pattern, "1", IGNORECASE ) ) );
dt << Data View;
Wait( 0 );
);
close_expr = Expr( nw << Close Window; Wait( 0 ); );
nw = New Window( "Table Egrep",
H List Box(
lb1 = Lineup Box( N Col( 2 ),
Text Box( "Select column to Enter regex pattern" ),
teb = Text Edit Box( "", Set Script( run_expr ), <
<SET width=""></SET>
<P>Para su información, el comando "Establecer script" mencionado anteriormente gestiona la ejecución inmediata al presionar Enter, lo cual funciona de maravilla. El único comportamiento deseado que falta es el mencionado anteriormente y la necesidad de presionar Tab para enfocar el cuadro de edición de texto.</P>
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regularEs posible que comience a volverse lento en algún momento y debería agregar una verificación para que solo se seleccionen las columnas de caracteres, pero puede crear una expresión para crear la concatenación.
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
dt << Select Columns({:name, :sex});
rgx_patter = "EF";
cols = dt << Get Selected Columns("String");
conc_expr = Expr(Concat());
For Each({colname}, cols,
Insert Into(conc_expr, Name Expr(As Column(dt, colname)));
);
regex_expr = Substitute(
Expr(!Is Missing(Regex(_conc_expr_, _rgx_pattern_, "\0", IGNORECASE))),
Expr(_conc_expr_), Name Expr(conc_expr),
Expr(_rgx_pattern_), rgx_pattern
);
rows_of_interest = dt << Get Rows Where(regex_expr);
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regularTambién puedes forzar que el foco esté en la ventana usando la Ventana Modal pero esto puede ser bastante malo para la experiencia del usuario.
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regularJusto cuando pensé que estaba empezando a entender…
La documentación indica que Expr() "devuelve su argumento sin evaluar", lo cual, sinceramente, no me dice nada. Parece que simplemente devuelve lo que se le pasa.
En tu código anterior, parecía una subrutina, lo cual tenía sentido en aquel momento. Pero ahora veo Expr(Concat()) y no logro entender qué se está concatenando. Luego, insertas Into() en ese objeto Expr(), pero ¿cómo sabe JMP dónde insertar los valores? Ni siquiera ChatGPT me ayuda a entenderlo.
Se siente como intentar recrear un truco de mago simplemente copiando los movimientos de la mano; frustrante, especialmente porque la documentación de Get Row() parece prometer exactamente el comportamiento que estoy tratando de obtener.
Nada de esto es culpa tuya, por supuesto, y agradezco mucho tu ayuda. Creo que lo que tengo ahora funcionará bastante bien. ¡Gracias!
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regularNo se concatena nada aquí: Expr(Concat()). En este caso, se puede considerar como un recopilador de argumentos que se concatenarán una vez que se haya terminado de construir la expresión. También se podría construir con una lista y luego sustituirla por concat.
Names Default To Here(1);
dt = open("$SAMPLE_DATA/Big Class.jmp");
val1 = "name";
val2 = "sex";
c = {};
Insert Into(c, Name Expr(As Column(dt, val1)));
Insert Into(c, Name Expr(As Column(dt, val2)));
show(c);
Substitute Into(c, Expr(List()), Expr(Concat()));
Show(c);
// Example use
Eval(EvalExpr(
dt << New Column("Concat", Character, Nominal, Formula(
Expr(Name Expr(c))
));
));
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regularBueno, creo que lo he resuelto: este script es básicamente el equivalente tabular del comando "egrep" de Unix/Linux/Mac, es decir, selecciona/muestra solo las filas que coinciden con una expresión regular ingresada por el usuario (cadena de búsqueda):
Names Default To Here( 1 );
If(
ex = New Window( "Enter search regex",
<
<MODAL></MODAL>
<P>Todos los botones funcionan correctamente y es bastante rápido incluso con miles de filas. Personalmente, creé un complemento y lo vinculé a cmd-shift-e (egrep) y ahora lo uso constantemente. Por supuesto, estoy abierto a sugerencias para mejorarlo. ¡Espero que esto le sea útil!</P> <BR /> <P>(¡Y muchas gracias a <A href="https://community.jmp.com/t5/user/viewprofilepage/user-id/14366" target="_blank">@jthi</A> por su paciencia y perspicacia!)</P>
Re: Mostrar rápidamente la vista de datos con un subconjunto de filas que coinciden con la expresión regular¡Se ve bien! Le haría algunos pequeños cambios:
- Antes de abrir la nueva ventana verifique que haya una tabla abierta y si no hay ninguna ejecute stop();
- Si no hay coincidencias, la última fila generará un error. Puede comprobar el número de filas seleccionadas y usar "stop()" si es 0, o mostrar al usuario la información de que no hay coincidencias.
- << Obtener filas donde es más probable que sea más rápido que << Seleccionar dónde
- Probablemente se pueda obtener una aceleración adicional evaluando la referencia de la columna
- <
Ver más...
Names Default To Here(1);
If(N Table() == 0,
stop(); // display error message to user if necessary
);
dt = Current Data Table();
nw = New Window("Enter search regex",
<
<MODAL>
0, col = selCols[1]; , col = Column(dt, 1) << get name; ); selrows = Eval(EvalExpr( dt << Get Rows Where(!Is Missing(Regex(Expr(NameExpr(As Column(dt, col))), inputRegex, "1", IGNORECASE))); )); If(N Rows(selrows) == 0, stop(); // display error message if necessary, this could also be done already within modal window (<< On Validate), if you wish to let user perform new search ); dt2 = dt << Subset(Rows(selrows), Selected Columns(0), Link to original data table(1), Output Table("")); // dt2 << Select Rows(1::NRows(dt2)); // to select rows if necessary
</MODAL>