Hacer que el controlador de estado de fila no funcione como se espera en un cuadro de contexto de filtro de datosEstimada comunidad,
Intento crear un panel de control utilizando cuadros de contexto/fuente de filtro de datos,
y funciona en algunos detalles como se esperaba.
Pero necesito características adicionales, en función de la selección necesito filtrar una tabla adicional, que se encuentra en el Cuadro de página de la pestaña Detalles1.
Que lo recreo cada vez usando Make Row State Handler en ese contexto.
Al seleccionar filas individuales en Tabular, todo está bien, pero:
- Cuando deselecciono todo, el cuadro de página de pestaña no cambia
- Cuando selecciono más de una línea en Tabular, se produce una selección incorrecta en el cuadro de página de pestaña
- Cuando selecciono puntos en GraphBuilder, la generación de tablas se realiza de forma excesiva
- ...
¿Cómo hacer este escenario más robusto?
¿Existe una forma diferente (sin controlador de estado de fila) de obtener las filas seleccionadas en Tabulate and Graph Buildeer?
¿Existe una mejor estrategia para hacer cosas como ésta?
Muchas gracias y BR
Names Default To Here( 1 );
Clear Log();
dt = Open( "$SAMPLE_DATA\Big Class.jmp" );
dt << show window( 0 );
tabulate_expr = Expr(
tb_obj = dt << Tabulate( Show Control Panel( 0 ), Add Table( Row Table( Grouping Columns( :sex, :age ) ) ) )
);
gb_expr = Expr(
gb_obj = dt << Graph Builder(
Show Control Panel( 0 ),
Variables( X( :weight ), Y( :height ) ),
Elements( Points( X, Y, Legend( 3 ) ), Smoother( X, Y, Legend( 4 ) ) )
)
);
action_expr = Expr(
Button Box( "Start Analysis", Print( pb_details << get row states() ) )
);
nw = New Window( "Dashboard",
Data Filter Context Box(
H List Box(
V List Box(
H List Box(
Panel Box( "Filter (in Data Filter Source Box)", /* Filter and GB */ dfsb =
Data Filter Source Box( tabulate_expr )
),
Panel Box( "Graph Builder (to be filtered in context", gb_expr )
),
Panel Box( "Action", /* Action */ action_expr )
),
pb_details = Panel Box( "Details (as well in data filter context box)", /* Tab Box */
Tab Box(
Tab Page Box( "Details1 (Data Grid Box, update via Make Row State Handler)", dgb = Data Grid Box() ),
Tab Page Box( "Details2 (Filtered automatically)", tabulate_expr )
)
)
)
)
);
detail_dt = dt << subset( invisible, columns( {"name", "age", "sex"} ) );
dgb << set data table( detail_dt );
dgb << close side panels;
nw << on close(
Close( dt, NoSave );
Close( detail_dt, NoSave );
For Each( {dt}, detail_dt_lst, Try( Close( dt, NoSave ) ) );
);
last_a = []; /* remember last selection to avoid double action */
detail_dt_lst = {}; /* save all table references to be able to close later */
details_update = Function( {a},
If( Is Matrix( a ) & Char( a ) != Char( last_a ),
Show( a );
detail_old = dgb << Get Data Table();
detail_dt = dt << subset( invisible, columns( {"name", "age", "sex"} ) );
Insert Into( detail_dt_lst, detail_dt );
detail_dt << select rows( a ) << delete rows();
dgb << set data table( detail_dt );
dgb << close side panels;
Close( detail_old, NoSave );
last_a = a;
);
);
rsh = pb_details << Make Row State Handler( dt, details_update );
Automatización y scriptingVentanasRe: Hacer que el controlador de estado de fila no funcione como se espera en un cuadro de contexto de filtro de datosEn mi opinión, hay tantos problemas diferentes con los controladores de estado de fila que no se pueden hacer robustos (por ejemplo, se eliminan con demasiada facilidad, se activan demasiado y muchos otros problemas). Para evitar algunos de los problemas que está viendo, no use el parámetro que puede tener en la función para el controlador de estado de fila , a en su caso, y en su lugar use << Obtener filas seleccionadas.
¿Quiere tener un panel con un generador de tablas y gráficos que filtre una tabla de datos? ¿Es necesario tener una tabla de datos que se esté filtrando? La forma más sencilla de evitar todos los problemas es utilizar un cuadro de botones para actualizar la tabla.
Re: Hacer que el controlador de estado de fila no funcione como se espera en un cuadro de contexto de filtro de datosSegún el caso de uso real, esta es una opción que podría funcionar. Se basa en actualizar el subconjunto en lugar de volver a crearlo. También comprobará las filas seleccionadas en lugar de depender del parámetro "a".
Names Default To Here(1);
dt = Open("$SAMPLE_DATA\Big Class.jmp", Invisible);
tabulate_expr = Expr(
tb_obj = dt << Tabulate(
Show Control Panel(0),
Add Table(Row Table(Grouping Columns(:sex, :age)))
)
);
gb_expr = Expr(
gb_obj = dt << Graph Builder(
Show Control Panel(0),
Variables(X(:weight), Y(:height)),
Elements(Points(X, Y, Legend(3)), Smoother(X, Y, Legend(4)))
)
);
action_expr = Expr(
Button Box("Start Analysis", Print(pb_details << get row states()))
);
nw = New Window("Dashboard",
Data Filter Context Box(
H List Box(
V List Box(
H List Box(
Panel Box("Filter (in Data Filter Source Box)",
dfsb = Data Filter Source Box(tabulate_expr)
),
Panel Box("Graph Builder (to be filtered in context",
gb_expr
)
),
Panel Box("Action",
action_expr
)
),
pb_details = Panel Box("Details (as well in data filter context box)",
Tab Box(
Tab Page Box(
"Details1 (Data Grid Box, update via Make Row State Handler)",
dgb = Data Grid Box()
),
Tab Page Box("Details2 (Filtered automatically)",
tabulate_expr
)
)
)
)
)
);
detail_dt = dt << subset(invisible, columns({"name", "age", "sex"}));
dgb << set data table(detail_dt);
dgb << close side panels;
nw << on close(
Close(dt, NoSave);
Close(detail_dt, NoSave);
);
last_rows = {}; // use list as you can compare those directly
extra_triggers = 0;
details_update = Function({a},
// Write("\!N", Round(Tick Seconds(), 2), " \!thappy state handler triggering");
// Show(dt << Get Row States);
cur_rows = As List(dt << Get Selected Rows);
If(N Items(cur_rows) == 0,
cur_rows = As List((1::N Rows(dt))`); // same as all rows selected
);
If(cur_rows == last_rows,
extra_triggers++;
return();
);
Write("\!N", extra_triggers, " unnecessary triggers occured.");
extra_triggers = 0;
last_rows = cur_rows;
If(N Rows(detail_dt) > N Items(cur_rows),
detail_dt << Delete Rows(N Items(cur_rows) + 1::N Rows(detail_dt));
, N Rows(detail_dt) < N Items(cur_rows),
detail_dt << Add Rows(N Items(cur_rows) - N Rows(detail_dt));
);
detail_dt[0, {"name", "age", "sex"}] = dt[Matrix(last_rows), {"name", "age", "sex"}];
);
rsh = pb_details << Make Row State Handler(dt, details_update);
Este no es el único método para hacerlo, pero es una opción bastante simple que puedes probar.
Elemento de la lista de deseos con la esperanza de que los controladores de estado se puedan utilizar en algún momento: Mejorar los controladores de estado de JMP (etiqueta flotante, controlador de estado de fila, controlador de estado de filtro, programador, ...)
Re: Hacer que el controlador de estado de fila no funcione como se espera en un cuadro de contexto de filtro de datosUna fuente de confusión con < < m> es cómo interpretar el argumento a . El vector representa las filas que han cambiado, pero no dice nada sobre el estado en el que se encuentran. También recibirá devoluciones de llamadas para eventos que no sean de filtro, por ejemplo: cambios en los estados de las filas de selección, etiqueta o marcador realizados en la tabla. Esto hace que sea difícil limitar la respuesta a los eventos de interés.
Con esos antecedentes, creo que los principales problemas con el script original son (1) no responder cuando la función se llama consecutivamente con los mismos argumentos (es por eso que clear no funciona) y (2) usar los números de fila como las filas que se deben eliminar.
El script a continuación (nota: solo JMP 18+) no intenta rastrear ni limitar los cambios, pero debería responder correctamente con las filas excluidas reales eliminadas del subconjunto.
Names Default To Here( 1 );
Clear Log();
//https://community.jmp.com/t5/Discussions/Make-Row-State-Handler-not-working-as-expected-in-a-Data-Filter/m-p/791520
dt = Open( "$SAMPLE_DATA\Big Class.jmp" );
dt << show window( 0 );
tabulate_expr = Expr(
tb_obj = dt << Tabulate( Show Control Panel( 0 ), Add Table( Row Table( Grouping Columns( :sex, :age ) ) ) )
);
gb_expr = Expr(
gb_obj = dt << Graph Builder(
Show Control Panel( 0 ),
Variables( X( :weight ), Y( :height ) ),
Elements( Points( X, Y, Legend( 3 ) ), Smoother( X, Y, Legend( 4 ) ) )
)
);
action_expr = Expr(
Button Box( "Start Analysis", Print( pb_details << get row states() ) )
);
nw = New Window( "Dashboard",
Data Filter Context Box(
H List Box(
V List Box(
H List Box(
Panel Box( "Filter (in Data Filter Source Box)", /* Filter and GB */ dfsb =
Data Filter Source Box( tabulate_expr )
),
Panel Box( "Graph Builder (to be filtered in context", gb_expr )
),
Panel Box( "Action", /* Action */ action_expr )
),
pb_details = Panel Box( "Details (as well in data filter context box)", /* Tab Box */
Tab Box(
Tab Page Box( "Details1 (Data Grid Box, update via Make Row State Handler)", dgb = Data Grid Box() ),
Tab Page Box( "Details2 (Filtered automatically)", tabulate_expr )
)
)
)
)
);
detail_dt = dt << subset( invisible, columns( {"name", "age", "sex"} ) );
dgb << set data table( detail_dt );
dgb << close side panels;
nw << on close(
Close( dt, NoSave );
Close( detail_dt, NoSave );
For Each( {dt}, detail_dt_lst, Try( Close( dt, NoSave ) ) );
);
detail_dt_lst = {}; /* save all table references to be able to close later */
details_update = Function( {a},
Show( a );
If( Is Matrix( a ),
detail_old = dgb << Get Data Table();
detail_dt = dt << subset( invisible, columns( {"name", "age", "sex"} ) );
Insert Into( detail_dt_lst, detail_dt );
filter_state = pb_details << Get Row States(dt);
detail_dt << select rows( Where(Excluded(As Row State(filter_state))) ) << delete rows();
dgb << set data table( detail_dt );
dgb << close side panels;
Close( detail_old, NoSave );
);
);
rsh = pb_details << Make Row State Handler( dt, details_update );
Re: Hacer que el controlador de estado de fila no funcione como se espera en un cuadro de contexto de filtro de datosGracias por tu sugerencia, el cuadro de botones sería una solución.
Tengo dos opciones:
(1) para cargar durante el inicio de la GUI todos los detalles que pueda necesitar, manteniéndolos como una tabla oculta y mostrar una parte que necesito en cierto contexto, aquí optaría por una solución dinámica con rowstate, etc.
(2) al solicitarlo, cargue los datos de la base de datos (aquí optaría por una solución de botón).
Pero el caso en general es bastante interesante para mí, porque hay muchos casos similares en los que preferiría (1) o (2), y quiero entender mejor cómo funciona JMP con él.
Re: Hacer que el controlador de estado de fila no funcione como se espera en un cuadro de contexto de filtro de datosMuchas gracias por sus aportes @jthi y @danschikore , esto me da algunas ideas geniales para mejorar mi tablero.