2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作这是 2022 年第一季度的改造挑战。
目标是提供一个示例、脚本或指南来完成三个任务之一(所有任务都与在 JMP 中单击某项后启动某些操作有关):
- 挑战A: (用于创建用于打开附加图像的初始数据表的图像和脚本:2022Q1_ChallengeA.zip)
- 您有: 数据表列,其中包含图像或网站或文件的链接(也称为表达式)
- 您想要: 单击该列的一个单元格并在 JMP 外部打开链接或图像
- 总体目标:单击数据表单元格应该启动一些操作
- 挑战B : (用于打开数据表并创建附加报告的脚本:2022Q1_ChallengeB_starterScript.jsl)
- 您有:大类和按身高体重计算的图形生成器报告(参见脚本)
- 您想要:关闭图形生成器报告应打开“年龄”的分布报告,将此报告另存为图片并关闭分布报告。
- 总体目标:关闭窗口应该触发一些操作
- 挑战C: (用于打开数据表并创建附加报告的脚本:2022Q1_ChallengeC_starterScript.jsl)
- 您有: 关于生长测量样本数据的图形生成器报告。
- 您想要:当单击一行或选择多行(或图例中的类别)时,您希望生成所选行的子集。
- 总体目标:单击图表或报告应触发某些操作
您可以尝试任意数量的挑战。 您可以/应该直接提交您的答案作为对此主题的回复。
!!! 提交时,请在第一行开始说明您的回复所指的挑战,例如
挑战A:
这就是我的答案...
// this is my code
...
在下次会议(2022 年 5 月 18 日)中,我们将提出一些答案,我将标记最佳答案作为该主题的解决方案。
期待您的来稿:)
回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作我将简要概述我今天在会议上谈到的内容。 您可以在本主题的早期帖子中查看我的完整解决方案。 我将修改我的挑战 A 解决方案以使用 JMP 的 SAMPLE_IMAGE 文件夹,因此您应该能够直接运行它。
挑战 A:单击数据表单元格应该启动一些操作<BR />
概念:使用事件处理程序列属性
通过让 JMP 为您编写脚本,这相当容易做到。 例如,为网页添加事件处理程序,然后修改脚本以更好地满足您的需求。 下面是我关于如何在单元格中打开图像的示例解决方案。
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]);
)))
)
)
);
事件处理程序可以相当强大,例如您可以在单元格单击时从数据库查询数据。
挑战 B:关闭窗口应该触发一些操作
概念:使用<< 关闭时()</CODE></P>
<P><CODE class=" language-jsl">
此挑战的想法是在图形生成器关闭时执行操作。 这是使用 << On Close() 执行的相当简单的任务。 以下是由 提供的解决方案的稍微修改版本@罗布
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();
);
需要考虑的一件事是,当您使用对数据表(在本例中为 dt)的引用时,如果您在关闭 gb 之前打开新表,则很可能会关闭错误的表。
您可以在此示例脚本中看到此问题:
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");
此脚本通过使用 Eval(EvalExpr()) 和 Expr() 来获取对表的显式引用提供了一种可能的解决方案
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)
);
));
您也可以将函数与 On Close 一起使用,但在这种情况下,它将生成更复杂的代码,因为您将无法访问双变量平台的引用,而是访问具有双变量的窗口,因此您必须解析窗口可能有效也可能无效的名称(可能有一种方法可以获取窗口内平台的引用)。
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);
);
));
挑战 C:单击图表或报告应触发某些操作
概念:使用<< 创建行状态处理程序()
</CODE></P>
<P>这有很多不同的解决方案,而且都有点不同。 <STRONG>此类脚本的一大挑战是决定如何管理不断变化的行状态。</STRONG> 一种选择是使用按钮来触发操作(例如<A href="https://community.jmp.com/t5/user/viewprofilepage/user-id/15435" target="_blank">@雷塞尔</A>did)而不是行状态处理程序,我认为这是这种情况下最强大的选择。</P>
<P> </P>
<P>其余的解决方案确实使用行状态处理程序和不同的方式(或不使用)管理始终更改的选定行。 <STRONG>行状态处理程序需要注意的一件事是它将返回修改后的行,</STRONG>不仅仅是选定的行。 因此,如果您只对选定的列感兴趣,则必须考虑到这一点。</P>
<P> </P>
<P>在大多数简单的情况下,您可以使用类似的东西<A href="https://community.jmp.com/t5/user/viewprofilepage/user-id/9474" target="_blank">@乔治</A>给出了答案。</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);
管理行的一种选择是创建关联数组( JMP 允许使用矩阵作为关联数组中的键),其中收集已创建子集的行。 只要您不更改行顺序或添加/删除行,这就应该有效。
下面是一个使用关联数组来收集已子集化的行的快速示例。 在示例中,我正在检查行状态为 1(所选行)的行,然后创建这些行的子集(如果尚未创建)。 这样做的一个好处是,您还可以将数据表引用保存到关联数组,并通过以下方式快速访问它们: aa_subset_rows << 获取值;但如果通过按住鼠标并将鼠标拖动到多行上来选择多行,则此解决方案可能仍然有点问题。
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);
回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战C:
我绝对建议使用按钮做这样的事情,因为它可以防止创建太多子集。 但在这里,我遵循了给定的挑战,并添加了简单的检查,确保我们至少不会创建相同的子集两次。
查看更多...
使用行状态处理程序,我们无法访问鼠标释放事件,因此如果用户从图中逐条选择多行,我们仍然会创建许多子集(可能有一种方法可以使用 Mouse Box() 来做到这一点,但我认为使用按钮会变得更加简单和容易)。
回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战B:
查看更多...
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
名称默认为此处(1); // 2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作 // 挑战 B dt = Open("$SAMPLE_DATA/Big Class.jmp"); //使用表达式使脚本更加简洁,如果要扩展的话 create_dist = Expr( dist = dt << Distribution(Nominal Distribution(Column(:age)), Histograms Only); wait(1); // 添加等待,我们可以看到分布已创建 dist << Save Picture("$TEMP/Big_Class_age_dist.png", png); dist << Close Window; ); gb = dt << 图形生成器( 大小(528, 454), 显示控制面板(0), 变量(X(:高度), Y(:重量)), 元素(点(X, Y, 图例(3)) , 拟合线(X, Y, 图例(5))) ); gb << 关闭时(create_dist); // 打开("$TEMP/Big_Class_age_dist.png"); // 取消注释以打开图像
回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战A:
主要是使用“添加列属性”编写的 JMP 代码。 还添加了如何添加和打开 URL 的示例
查看更多...
Names Default To Here(1);
// Challenge A
path = "2022Q1_ChallengeA"; // path to images
{dtx} = Multiple File Import(
<<SET folder=""></SET>
名称默认为此处(1); // 挑战A路径 = "2022Q1_ChallengeA"; // 图像路径 {dtx} = 多个文件导入( <<设置文件夹( path ), <<设置名称过滤器( "*.jpg; *.png;" ), <<设置名称启用( 1 ), <<设置添加文件名列( 1 ), <<设置添加文件大小列( 1 ) // 用于在末尾显示大小 ) << 导入数据; // 因为图像已经在数据表中,所以我们不需要从驱动器中打开它们,我们只需将图像加载到新窗口即可 Column(dtx, "Picture") << Add Column Properties( Set Property( "Event Handler ", 事件处理程序( Click(JSL Quote(Function({thisTable, thisColumn, iRow}, {}, New Window(Char(thisTable:"文件名"n[iRow]), New Image(thisTable:thisColumn[iRow])) ); ))), Tip(JSL Quote(Function({thisTable, thisColumn, iRow}, {}, "放大图像" || Char(thisTable:"文件名"n[iRow]); ))) ) ) ) ; // 带有一些 URL 的新列 new_col = dtx << New Column("URL", Character, Nominal, Values( {"
www.jmp.com","
www.google.com","community.jmp.com", “
https://www.jmp.com/support/help/en/16.2/”} )); // 为我们创建的代码 jmp,只是删除了过多的注释 new_col << Add Column Properties( 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}, {}, "打开" || Char(thisTable:thisColumn[iRow]) || "在您的浏览器中。"; ))), Color(JSL Quote(Function({thisTable, thisColumn, iRow}, {}, RGBColor("link"); ))) ) ) );写(); // 避免烦人的打印最后执行行的日志
使用 SAMPLE_IMAGES 路径变量(这也可以作为一个示例,说明在编写脚本时进行更改是多么容易,只需更改一个变量,脚本仍然有效(我从列表中删除了一个 URL,因此不会将空行添加到其他列中) )):
Names Default To Here(1);
// Challenge A
path = Get Path Variable("$SAMPLE_IMAGES");
{dtx} = Multiple File Import(
<<SET folder=""></SET>
回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战C
不幸的是,就挑战 A 和 B 而言,没有什么其他可做的。 提供的解决方案似乎无可挑剔。 相比之下,我觉得挑战C还是有一些改进的可能。 我的回答简单说几句
- 我基本上已经窃取了必要的代码从这里( @tx尼尔森和许多其他编剧一样,对我来说是摇滚明星)
- 我通过包含可见数据点对图表进行了轻微修改,因此更容易选择单独的行
- 选择图中的点后,不会立即打开包含子集的数据表。 这是通过图表下方添加的按钮完成的
请参阅下面的完整脚本,包括修改后的图表。
// 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 );
回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战A
抱歉,我最初的解决方案太仓促了...... 这是一个更干净的。
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>回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战A:
笔记:我保留了这个旧版本,因为有些人已经看过它,但我发布了一个更干净的解决方案作为回复到这个。
根本不是一个漂亮的解决方案,但它确实完成了工作...... 期待更优雅的出现!
这要添加到 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";
)
)
)
)
);
回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战C
使用鼠标框无法选择某些内容,因此我更改为行状态处理程序
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";
)
);
回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战C
这是我的答案,请参阅下面的完整脚本。
下半部分向表添加行状态处理程序,该处理程序触发操作(请参阅脚本索引中的示例)。
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 );回复:2022_Q1 MakeOverChallenge:以各种方式单击鼠标的操作挑战B
将其添加到脚本的底部:
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 );
);