Faire en sorte que le gestionnaire d'état de ligne ne fonctionne pas comme prévu dans une boîte de contexte de filtre de donnéesChère communauté,
J'essaie de construire un tableau de bord en utilisant des boîtes de contexte/source de filtre de données,
et cela fonctionne dans certains détails comme prévu.
Mais j'ai besoin de fonctionnalités supplémentaires, en fonction de la sélection, je dois filtrer une table supplémentaire, située dans Tab Page Box Details1.
Que je recrée à chaque fois en utilisant Make Row State Handler dans ce contexte.
Lors de la sélection de lignes individuelles dans Tabulate, tout va bien, mais :
- lorsque je désélectionne tout, la boîte de page à onglets ne change pas
- lorsque je sélectionne plusieurs lignes dans Tabulate, une mauvaise sélection se produit dans la zone de page Tab
- lorsque je sélectionne des points dans GraphBuilder, la génération de table se fait de manière excessive
- ...
Comment rendre ce scénario plus robuste ?
Existe-t-il un moyen différent (sans gestionnaire d'état de ligne) pour obtenir les lignes sélectionnées dans Tabulate et Graph Buildeer ?
Existe-t-il une meilleure stratégie pour faire des choses comme ça ?
Merci beaucoup et 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 );
Automatisation et scriptsFenêtresRe : Faire en sorte que le gestionnaire d'état de ligne ne fonctionne pas comme prévu dans une boîte de contexte de filtre de donnéesÀ mon avis, il existe tellement de problèmes différents avec les gestionnaires d'état de ligne qu'il est impossible de les rendre robustes (par exemple, ils sont supprimés trop facilement, déclenchent trop de choses et bien d'autres problèmes). Pour éviter certains des problèmes que vous rencontrez, n'utilisez pas le paramètre que vous pouvez avoir dans la fonction pour le gestionnaire d'état de ligne , a dans votre cas, et utilisez plutôt << Get Selected Rows.
Vous souhaitez donc disposer d'un tableau de bord avec un générateur de tableaux et de graphiques et ceux-ci doivent filtrer une table de données ? Est-il nécessaire d'avoir une table de données qui est filtrée ? Le moyen le plus simple d'éviter tous les problèmes est d'utiliser une boîte à boutons pour mettre à jour le tableau.
Re : Faire en sorte que le gestionnaire d'état de ligne ne fonctionne pas comme prévu dans une boîte de contexte de filtre de donnéesEn fonction de votre cas d'utilisation réel, voici une option qui pourrait fonctionner. Elle repose sur la mise à jour du sous-ensemble au lieu de le recréer. Elle vérifiera également les lignes sélectionnées au lieu de s'appuyer sur le paramètre « 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);
Ce n’est pas la seule méthode pour y parvenir, mais c’est une option assez simple que vous pouvez essayer.
Élément de la liste de souhaits dans l'espoir que les gestionnaires d'état soient utilisables à un moment donné : améliorer les gestionnaires d'état de JMP (étiquette de survol, gestionnaire d'état de ligne, gestionnaire d'état de filtre, planificateur, ...)
Re : Faire en sorte que le gestionnaire d'état de ligne ne fonctionne pas comme prévu dans une boîte de contexte de filtre de donnéesUne source de confusion avec < < m> est la façon d'interpréter l'argument a . Le vecteur représente les lignes qui ont changé, mais il ne dit rien sur l'état dans lequel elles se trouvent. Vous recevrez également des rappels pour les événements non liés au filtre, par exemple : les modifications apportées à la sélection, à l'étiquette ou à l'état des lignes de marqueurs dans la table. Cela rend difficile la limitation de la réponse aux événements d'intérêt.
Dans ce contexte, je pense que les principaux problèmes de votre script d'origine sont (1) ne pas répondre lorsque la fonction est appelée consécutivement avec les mêmes arguments (c'est pourquoi clear ne fonctionne pas) et (2) utiliser les numéros de ligne comme lignes à supprimer.
Le script ci-dessous (Remarque : JMP 18+ uniquement) ne tente pas de suivre et de limiter les modifications, mais il devrait répondre correctement avec les lignes exclues réelles supprimées du sous-ensemble.
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 : Faire en sorte que le gestionnaire d'état de ligne ne fonctionne pas comme prévu dans une boîte de contexte de filtre de donnéesMerci pour votre suggestion, la boîte à boutons serait une solution.
J'ai deux choix :
(1) pour charger lors du démarrage de l'interface graphique tous les détails dont je pourrais avoir besoin, en les conservant sous forme de tableau caché et en affichant une partie dont j'ai besoin dans un certain contexte, ici j'opterais pour une solution dynamique avec rowstate etc.
(2) sur demande, charger les données depuis la base de données (ici, j'opterais pour une solution par bouton).
Mais le cas est généralement assez intéressant pour moi, car il existe de nombreux cas similaires, où je préférerais (1) ou (2), et je veux mieux comprendre comment JMP fonctionne avec.
Re : Faire en sorte que le gestionnaire d'état de ligne ne fonctionne pas comme prévu dans une boîte de contexte de filtre de donnéesMerci beaucoup pour votre contribution @jthi et @danschikore , cela me donne d'excellentes idées pour améliorer mon tableau de bord.