2022_Q1 MakeOverChallenge : action sur un clic de souris de différentes manièresIl s’agit du Makeover Challenge Q1 2022.
L'objectif est de proposer un exemple, un script ou un guide pour accomplir l'une des trois tâches (toutes liées au lancement d'une action après avoir cliqué sur quelque chose dans JMP) :
- Défi A : (images et script pour créer la table de données initiale pour l'ouverture des images ci-jointes : 2022Q1_ChallengeA.zip)
- Vous disposez de : Une colonne de tableau de données avec des images ou des liens vers un site Web ou un fichier (alias expressions)
- Vous souhaitez : cliquer sur une cellule de cette colonne et ouvrir le lien ou l'image en dehors de JMP
- L'objectif général : cliquer dans une cellule du tableau de données devrait lancer quelque chose
- Défi B : (script pour ouvrir le tableau de données et créer le rapport ci-joint : 2022Q1_ChallengeB_starterScript.jsl)
- Vous avez : Big Class et un rapport Graph Builder du poids par taille (voir script)
- Vous voulez : La fermeture du rapport Graph Builder devrait ouvrir un rapport de distribution de "âge", enregistrer ce rapport sous forme d'image et fermer le rapport de distribution.
- L'objectif global : la fermeture d'une fenêtre devrait déclencher une action
- Défi C : (script pour ouvrir le tableau de données et créer le rapport ci-joint : 2022Q1_ChallengeC_starterScript.jsl)
- Vous disposez des éléments suivants : Un rapport Graph Builder sur des exemples de données de mesures de croissance.
- Vous voulez : Lorsque vous cliquez sur une ligne ou que vous sélectionnez plusieurs lignes (ou catégories dans la légende), vous souhaitez générer un sous-ensemble des lignes sélectionnées.
- L'objectif global : cliquer sur un graphique ou un rapport devrait déclencher une action
Vous pouvez relever autant de défis que vous le souhaitez. Vous pouvez/devriez soumettre vos réponses directement en réponse à ce fil.
!!! Lors de la soumission, veuillez commencer par la première ligne par le défi auquel votre réponse fait référence, par exemple
DÉFI A :
C'est ma réponse...
// this is my code
...
Lors de la prochaine réunion (18 mai 2022), nous présenterons certaines des réponses et je marquerai les meilleures réponses comme solution à ce fil.
J'attends avec impatience vos propositions 
Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresJe vais écrire un bref aperçu de ce dont j'ai parlé aujourd'hui lors de la réunion. Vous pouvez voir mes solutions complètes dans mes articles précédents sur ce sujet. Je vais modifier ma solution Challenge A pour utiliser le dossier SAMPLE_IMAGE de JMP, vous devriez donc pouvoir l'exécuter directement.
Défi A : cliquer dans une cellule du tableau de données devrait déclencher quelque chose<BR />
Concept : Utilisation de la propriété de colonne du gestionnaire d'événements
C'est assez facile à faire en laissant JMP écrire cela pour vous. Ajoutez un gestionnaire d'événements pour une page Web par exemple, puis modifiez le script pour mieux répondre à vos besoins. Vous trouverez ci-dessous mon exemple de solution sur la façon d'ouvrir une image dans une cellule.
Column(dtx, "Picture") << Add Column Properties(
Set Property(
"Event Handler",
Event Handler(
Click(JSL Quote(Function({thisTable, thisColumn, iRow}, {},
New Window(Char(thisTable:"File Name"n[iRow]), New Image(thisTable:thisColumn[iRow]));
))),
Tip(JSL Quote(Function({thisTable, thisColumn, iRow}, {},
"Enlarge image " || Char(thisTable:"File Name"n[iRow]);
)))
)
)
);
Les gestionnaires d'événements peuvent être assez puissants, car vous pouvez par exemple interroger les données de la base de données en cliquant sur une cellule.
Défi B : la fermeture d'une fenêtre devrait déclencher une action
Concept : Utilisation << À la fermeture()</CODE></P>
<P><CODE class=" language-jsl">
L'idée de ce défi était d'effectuer une action lorsque Graph Builder est fermé. C'est une tâche assez simple à réaliser en utilisant << On Close(). Vous trouverez ci-dessous une version légèrement modifiée de la solution fournie par @Robb
gb << On Close(
dist = dt << Distribution(Nominal Distribution(Column(:age)));
image = dist << Get Picture;
image << Save Picture($temp/age_dist.png, "png");
dist << Close Window();
);
Une chose à considérer est que lorsque vous utilisez des références à une table de données (dans ce cas, dt), si vous ouvrez une nouvelle table avant de fermer gb, vous fermerez probablement une mauvaise table.
Vous pouvez voir ce problème dans cet exemple de script :
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
biv = dt << Bivariate(Y(:Weight), X(:Height), Nonpar Density);
biv << On Close(
close(dt, no save);
);
dt = Open("$SAMPLE_DATA/Semiconductor Capability.jmp");
Et ce script fournit une solution possible en utilisant Eval(EvalExpr()) et Expr() pour obtenir une référence explicite à la table
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
biv = dt << Bivariate(Y(:Weight), X(:Height), Nonpar Density);
dt = Open("$SAMPLE_DATA/Semiconductor Capability.jmp");
Eval(EvalExpr(
biv << On Close(
Close(Expr(biv << Get Data Table), no save)
);
));
Vous pouvez aussi éventuellement utiliser la fonction avec On Close, mais dans ce cas cela générera du code plus compliqué, car vous n'aurez pas accès à la référence de la plateforme bivariée mais plutôt à la fenêtre qui a la bivariée, vous devrez donc analyser la fenêtre nom qui pourrait ou non fonctionner (il pourrait y avoir un moyen d'obtenir une référence à la plate-forme à l'intérieur de la fenêtre).
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Big Class.jmp");
biv = dt << Bivariate(Y(:Weight), X(:Height), Nonpar Density);
biv << On Close(function({this},
table_name = Trim Whitespace(Word(1, (this << Get Window Title), "-"));
If(Contains(Get Data Table List() << get name, table_name),
Close(Datatable(table_name), no save);
);
));
Défi C : cliquer sur un graphique ou un rapport devrait déclencher une action
Concept : Utilisation << Créer un gestionnaire d'état de ligne ()
</CODE></P>
<P>Cela avait des solutions très différentes et toutes étaient un peu différentes. <STRONG>Le grand défi avec ce type de script consiste à décider de la manière dont vous souhaitez gérer les états de ligne en constante évolution.</STRONG> Une option consiste à utiliser un bouton pour déclencher l'action (comme<A href="https://community.jmp.com/t5/user/viewprofilepage/user-id/15435" target="_blank"> @Ressel</A> did) au lieu de Row State Handler, c'est à mon avis l'option la plus robuste dans ce cas.</P>
<P> </P>
<P>Le reste des solutions utilisaient un gestionnaire d'état de ligne et différentes manières (ou non) de gérer les lignes sélectionnées modifiées à tout moment. <STRONG>Une chose à noter avec Row State Handler est qu'il renverra les lignes modifiées,</STRONG> pas seulement les lignes sélectionnées. Donc, si vous n’êtes intéressé que par des colonnes sélectionnées, vous devez en tenir compte.</P>
<P> </P>
<P>Dans la plupart des cas simples, vous pouvez utiliser quelque chose comme<A href="https://community.jmp.com/t5/user/viewprofilepage/user-id/9474" target="_blank"> @Georg</A> donné comme réponse.</P>
<PRE><CODE class=" language-jsl">f = Function({a},
dt << Subset(Selected Rows(1), Selected columns only(0))
);
rs = dt << make row state handler(f);
Une option pour gérer les lignes serait de créer un tableau associatif ( JMP permet d'utiliser Matrix comme clé dans un tableau associatif ) dans lequel vous collectez les lignes pour lesquelles un sous-ensemble a déjà été créé. Cela devrait fonctionner tant que vous ne modifiez pas l'ordre des lignes ni n'ajoutez/supprimez des lignes.
Vous trouverez ci-dessous un exemple rapide utilisant un tableau associatif pour collecter les lignes qui ont été sous-ensemblees. Dans l'exemple, je vérifie les lignes qui ont l'état de ligne 1 (ligne sélectionnée), puis je crée un sous-ensemble de celles-ci s'il n'a pas déjà été créé. L'un des avantages de ceci est que vous pouvez également enregistrer les références datatables dans le tableau associatif et y accéder rapidement avec aa_subset_rows << Obtenir les valeurs ; mais cette solution peut encore être un peu boguée si de nombreuses lignes sont sélectionnées en maintenant et en faisant glisser la souris dessus.
Names Default To Here(1);
// Open Data Table
dt = Open("$SAMPLE_DATA/Growth Measurements.jmp", invisible);
gb = dt << Graph Builder(
Size(522, 452),
Show Control Panel(0),
Legend Position("Bottom"),
Graph Spacing(8),
Variables(X(:Age), Y(:Growth), Overlay(:Subject)),
Elements(Line(X, Y, Legend(13)))
);
aa_subset_rows = Associative Array();
f = Function({rows_changed},
//Rowstate 1 is selected row
cur_rows = Loc(dt << Get Row States, 1);
//if no rows are selected, don't try to create subsets
If(N Items(cur_rows) == 0,
return()
);
//compare to previous to prevent opening extensive abmount of subsets
If(Contains(aa_subset_rows , cur_rows),
return();
);
dt_subset = dt << Subset(Output table("selected_rows"), Rows(cur_rows));
aa_subset_rows[cur_rows] = dt_subset;
);
rs = dt << make row state handler(f);
Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDéfi C :
Je suggère définitivement de faire des choses comme celle-ci avec des boutons car cela évite la création de trop de sous-ensembles. Mais ici, j'ai suivi le défi donné et ajouté une simple vérification que nous ne créerons pas au moins deux fois le même sous-ensemble.
Voir plus...
Avec Row State Handler, nous ne pouvons pas accéder à l'événement de relâchement de la souris, nous allons donc toujours créer de nombreux sous-ensembles si l'utilisateur sélectionne plusieurs lignes une par une dans le graphique (il pourrait y avoir un moyen de le faire avec Mouse Box(), mais je pense qu'utiliser le bouton le ferait être beaucoup plus simple et plus facile).
Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDéfi B :
Voir plus...
Names Default To Here(1);
// 2022_Q1 MakeOverChallenge: Action on mouse click in various ways
// Challenge B
dt = Open("$SAMPLE_DATA/Big Class.jmp");
//Use expression to make script a bit more clean IF this were to be expanded
create_dist = Expr(
dist = dt << Distribution(Nominal Distribution(Column(:age)), Histograms Only);
wait(1); // add wait so we can see that distribution is created
dist << Save Picture("$TEMP/Big_Class_age_dist.png", png);
dist << Close Window;
);
gb = dt << Graph Builder(
Size(528, 454),
Show Control Panel(0),
Variables(X(:height), Y(:weight)),
Elements(Points(X, Y, Legend(3)), Line Of Fit(X, Y, Legend(5)))
);
gb << On Close(create_dist);
// Open("$TEMP/Big_Class_age_dist.png"); // un-comment to open the image
Noms par défaut ici (1); // 2022_Q1 MakeOverChallenge : Action sur le clic de souris de différentes manières // Challenge B dt = Open("$SAMPLE_DATA/Big Class.jmp"); //Utiliser l'expression pour rendre le script un peu plus propre SI cela devait être développé create_dist = Expr( dist = dt << Distribution(Nominal Distribution(Column(:age)), Histograms Only); wait(1); // add attendez que nous puissions voir que la distribution est créée dist << Save Picture("$TEMP/Big_Class_age_dist.png", png); dist << Close Window; ); gb = dt << Générateur de graphiques (taille (528, 454), afficher le panneau de configuration (0), variables (X (: hauteur), Y (: poids)), éléments (points (X, Y, légende (3)) , Ligne d'ajustement (X, Y, Légende (5))) ); gb << À la fermeture (create_dist); // Ouvrir("$TEMP/Big_Class_age_dist.png"); // dé-commenter pour ouvrir l'image
Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDéfi A :
Principalement du code écrit JMP avec ajouter des propriétés de colonne. Exemple également ajouté sur la façon d'ajouter et d'ouvrir des URL
Voir plus...
Names Default To Here(1);
// Challenge A
path = "2022Q1_ChallengeA"; // path to images
{dtx} = Multiple File Import(
<<SET folder=""></SET>
Noms par défaut ici (1); // Chemin du défi A = "2022Q1_ChallengeA" ; // chemin d'accès aux images {dtx} = Importation de fichiers multiples ( << Définir le dossier ( chemin ), << Définir le filtre de nom ( "*.jpg; *.png; " ), << Définir le nom activé ( 1 ), << Définir la colonne Ajouter le nom du fichier ( 1 ), << Définir la colonne Ajouter la taille du fichier ( 1 ) // pour afficher les tailles à la fin ) << Importer les données ; // comme les images sont déjà dans la table de données, nous n'avons pas besoin de les ouvrir depuis le lecteur, nous pouvons simplement charger l'image dans une nouvelle fenêtre Column(dtx, "Picture") << Ajouter des propriétés de colonne (Set Property( "Event Handler ", Gestionnaire d'événements (Cliquez sur (Citation JSL (Fonction ({thisTable, thisColumn, iRow}, {}, Nouvelle fenêtre (Char (thisTable:"Nom du fichier" n [iRow]), Nouvelle image (thisTable: thisColumn [iRow]) ); ))), Tip(JSL Quote(Function({thisTable, thisColumn, iRow}, {}, "Agrandir l'image " || Char(thisTable:"File Name"n[iRow]); ))) ) ) ) ; // nouvelle colonne avec quelques URL new_col = dtx << Nouvelle colonne("URL", Caractère, Nominal, Valeurs( {"
www.jmp.com","
www.google.com","community.jmp.com", "
https://www.jmp.com/support/help/en/16.2/"} )); // code jmp créé pour nous, vient de supprimer la quantité excessive de commentaires new_col << Ajouter des propriétés de colonne ( Set Property( "Event Handler", Event Handler( Click(JSL Quote(Function({thisTable, thisColumn, iRow}, {} , Web(Char(thisTable:thisColumn[iRow])); ))), Tip(JSL Quote(Function({thisTable, thisColumn, iRow}, {}, "Open " || Char(thisTable:thisColumn[iRow]) || " dans votre navigateur."; ))), Couleur(JSL Quote(Function({thisTable, thisColumn, iRow}, {}, RGBColor("link"); ))) ) ) ); Écrire(); // pour éviter d'imprimer ennuyeuse dans le journal de la dernière ligne exécutée
Utilisation de la variable de chemin SAMPLE_IMAGES (cela fonctionne également comme exemple de la facilité avec laquelle il peut être d'apporter des modifications lorsque vous créez un script, il suffit de changer une variable et le script fonctionne toujours (j'ai supprimé une URL de la liste afin qu'aucune ligne vide ne soit ajoutée aux autres colonnes). )):
Names Default To Here(1);
// Challenge A
path = Get Path Variable("$SAMPLE_IMAGES");
{dtx} = Multiple File Import(
<<SET folder=""></SET>
Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDéfi C
Il n’y avait malheureusement pas grand-chose d’autre à faire en ce qui concerne les défis A et B. Les solutions apportées semblaient impeccables. En revanche, j’ai senti qu’une certaine amélioration était encore possible pour le défi C. Quelques mots sur ma réponse
- J'ai essentiellement volé le code nécessaire d'ici ( @txnelson est, comme beaucoup d'autres scénaristes, une rock star pour moi)
- J'ai légèrement modifié le graphique en incluant des points de données visibles, il est donc plus facile de sélectionner des lignes individuelles
- Après avoir sélectionné les points dans le graphique, le tableau de données avec le sous-ensemble ne s'ouvre pas immédiatement. Cela se fait via le bouton ajouté sous le graphique
Voir ci-dessous le script complet, y compris le graphique modifié.
// Open Data Table
dt = Open( "$SAMPLE_DATA/Growth Measurements.jmp",invisible );
// Report snapshot: Growth Measurements - Graph Builder
gb = dt << Graph Builder(
Size( 522, 452 ),
Show Control Panel( 0 ),
Legend Position( "Bottom" ),
Graph Spacing( 8 ),
Variables( X( :Age ), Y( :Growth ), Overlay( :Subject ) ),
Elements(
Points( X, Y, Legend( 17 ), Jitter Limit( 0 ) ), // added markers
Line( X, Y, Legend( 13 ) ) ),
SendToReport( // increased markers to decent size
Dispatch(
{},
"Graph Builder",
FrameBox,
{Marker Size( 6 ), Marker Drawing Mode( "Normal" )}
)
)
);
// my solution (stolen from here: https://community.jmp.com/t5/Discussions/Creating-a-Subset-from-an-Interactive-Graph/td-p/114459)
subsetButton = Button Box( "Dear user, Please press here to create a Subset of the Selected Points immediately",
If( N Rows( dt << get selected rows ) > 0,
dt << subset( selected rows( 1 ), selected columns( 0 ) )
)
);
Report( gb )["Graph Builder"] << append( subsetButton );
Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDÉFI A
Désolé d'avoir sauté le pas avec ma solution initiale... En voici un plus propre.
Names Default to Here ( 1 );
//path = <YOUR full="" path="" to="" where="" the="" images="" have="" been="" saved="">;
// eg.
// path = "C:\EventHandlerImages\";
path = "$DOCUMENTS\Scripting\2022Q1\ChallengeA\2022Q1_ChallengeA\";
//==========================================================================
//Multiple File Import is new in JMP 14
{dtx} = Multiple File Import(
<<SET folder=""></SET></YOUR>Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDÉFI A :
NOTE: J'ai conservé cette ancienne version car certaines personnes l'avaient déjà vue, mais j'ai posté une solution plus propre en guise de Répondre à celui-ci.
Ce n'est pas du tout une jolie solution, mais ça fait le travail... En espérant qu’un modèle plus élégant apparaisse !
Ceci à ajouter après le starterScript :
// Defining the file name for an image placeholder for displaying on the OS when clicking:
pictFileName = Get Default Directory() || "verylonganduselessname.png"; //name for the temp image file (to be deleted at the end)
dtx:Picture << Set Property("tmpFileName", pictFileName); //saving the name so it can be retrieved from within the table
dtx << On Close( Delete File(pictFileName) ); //make sure we erase the temp image file at the end.
// Setting a Click event handler for the column of interest:
dtx:Picture << Set Property(
"Event Handler",
Event Handler(
Click(JSL Quote( Function(
{thisTable, thisColumn, iRow},
pictFileName = thisTable:thisColumn<< Get Property("tmpFileName"); //recover the path for a temp file
thisTable:thisColumn[iRow] << Save Image( pictFileName ); //save cell contents to temp file
Web( "file://" || pictFileName ) // open the image file
)
)
),
Tip(JSL Quote( Function(
{thisTable, thisColumn, iRow},
"click to open";
)
)
)
)
);
Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDÉFI C
Avec une boîte de souris, il n'était pas possible de sélectionner quelque chose, j'ai donc changé pour un gestionnaire d'état de ligne
Names Default To Here( 1 );
// Open Data Table
dt = Open( "$SAMPLE_DATA/Growth Measurements.jmp", invisible );
// Report snapshot: Growth Measurements - Graph Builder
gb = dt << Graph Builder(
Size( 522, 452 ),
Show Control Panel( 0 ),
Legend Position( "Bottom" ),
Graph Spacing( 8 ),
Variables( X( :Age ), Y( :Growth ), Overlay( :Subject ) ),
Elements( Line( X, Y, Legend( 13 ) ) )
);
active_subset = "";
first_subset = "false";
rsh = dt << make row state handler(
Function( {a},
subtbl = dt << Subset( Selected Rows( 1 ) );
gb << Bring Window To Front;
if(
first_subset == "true",
close(active_subset, no save)
);
active_subset = subtbl;
first_subset = "true";
)
);
Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDÉFI C
C'est ma réponse, voir le script complet ci-dessous.
La partie inférieure ajoute un gestionnaire d'état de ligne à la table, qui déclenche l'action (voir exemple dans Scripting Index).
Names Default To Here( 1 );
// Open Data Table
dt = Open( "$SAMPLE_DATA/Growth Measurements.jmp", invisible );
// Report snapshot: Growth Measurements - Graph Builder
gb = dt << Graph Builder(
Size( 522, 452 ),
Show Control Panel( 0 ),
Legend Position( "Bottom" ),
Graph Spacing( 8 ),
Variables( X( :Age ), Y( :Growth ), Overlay( :Subject ) ),
Elements( Line( X, Y, Legend( 13 ) ) )
);
// This is my code (Georg)
// (see Scripting Index "Make Row State Handler")
// Define a function, that does the action
f = Function( {a},
Current Data Table() << Subset( Selected Rows( 1 ), Selected columns only( 0 ) )
);
// Set up a row state handler, that triggers the execution of a function on any change of row states,
// a change on row selection by clicking on a line in Graph Builder is a change of row states in the table
rs = dt << make row state handler( f );Re: 2022_Q1 MakeOverChallenge : Action sur un clic de souris de différentes manièresDÉFI B
Ajoutez ceci au bas du script :
gb << On Close(
dist = dt << Distribution( Nominal Distribution( Column( :age ) ) );
image = dist << Get Picture;
path = "$temp/age_dist.png";
image << Save Picture( path, "png" );
dist << Close Window();
Open( path );
);