- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
How to programmatically traverse a Graph builder tree structure and associate frameboxes with their titles.
I have a piece of analysis (see below) where I want to annotate specific charts using a script I have written. For example, I want to add annotation to XXX104 and XXX107. On both of these charts I will add a custom graphic and text to identify a cluster of points I want to draw attention to.
Using the command '<< show tree structure' I can identify the frameboxs which have each chart. However, I do not see the chart 'name' associated with them. For example, I want to be able to traverse this tree using the chart names (e.g. XXX107) as a lookup and identify the associated framebox (e.g. FrameBox(7)) so I can reference it and add my annotation in an automated fashion.
In fact in the entire tree I do not see any 'tree nodes' which have the 'chart names' such as XXX107
Ultimately the chart below is what I want to achieve
Here is the code which I used to do this manually. The file is also uploaded.
My issue is I cannot figure out how to reference a framebox by identifying it's corresponding 'title' in the display tree.
Cheers, Troy
clearLog();
try(close(DT, noSave));
DT = open("PRE_CLEAN_DATA.jmp", invisible);
DT << newColumn("ENT_CLUSTER", character, nominal, formula(:ENTITY || "_" || :CLUSTER));
Plat = newWindow("CHART",
myGraphBox = DT << Graph Builder(
Size( 1446, 747 ),
Show Control Panel( 0 ),
Variables(
X( :WW ),
Y( :ENTITY_MEAN ),
Y( :GRAND_MEAN, Position( 1 ) ),
Wrap( :ENTITY ),
Color( :CLUSTER )
),
Elements(
Points( X, Y( 1 ), Y( 2 ), Legend( 23 ) ),
Smoother( X, Y( 1 ), Y( 2 ), Legend( 24 ) )
),
SendToReport(
Dispatch(
{},
"WW",
ScaleBox,
{Min( 202301.28 ), Max( 202320.72 ), Inc( 1 ), Minor Ticks( 1 ),
Label Row(
{Automatic Tick Marks( 0 ), Label Orientation( "Vertical" ),
Show Minor Ticks( 0 )}
)}
)
)
);
summarize(DT, clusters = by(:ENT_CLUSTER));
foreach({item}, clusters,
if(contains(item, "NON_CLUSTER"), continue());
ent = word(1, item, "_");
clust = word(2, item, "_");
write("Entity = " || ent || "\!n");
write("Cluster = " || clust || "\!n");
left = min(DT:WW[DT << getRowsWhere(:ENT_CLUSTER == item)]);
right = max(DT:WW[DT << getRowsWhere(:ENT_CLUSTER == item)]);
group_mean_min = min(DT:ENTITY_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
group_mean_max = max(DT:ENTITY_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
grand_mean_min = min(DT:GRAND_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
grand_mean_max = max(DT:GRAND_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
if(group_mean_min < grand_mean_min, bot = group_mean_min, bot = grand_mean_min);
if(group_mean_max > grand_mean_max, top = group_mean_max, top = grand_mean_max);
write("Left, Right, Top, Bot = " || char(left) || ", " || char(right) || ", " || char(top) || ", " || char(bot) || "\!n");
// ##########################################################
// ## This is what I want to do:
// ##########################################################
// 1. Traverse the graphbox tree
// 2. Identify Frame Box for each of the entities found
// 3. Get the Framebox Reference
// 4. Add my annotation.
// This is a manual Example I made using the show properties and tree structure commands
//myGraphBox << Show Properties();
//myGraphBox << Show tree structure();
rep = myGraphBox << report;
framebox = rep[frame box( 7 )];
framebox << Add Graphics Script(
penColor( "Black" );
fillcolor("Blue");
Transparency(0.1);
rect( left, top, right, bot, 0 );
rect( left, top, right, bot, 1 );
);
framebox << Add Graphics Script(
textSize(9);
textColor("Blue");
text( {left, top}, "Cluster 1" );
);
write("\!n");
);
);
Accepted Solutions
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: How to programmatically traverse a Graph builder tree structure and associate frameboxes with their titles.
Quick and dirty full example:
Names Default To Here(1);
dt = Open("$DOWNLOADS/PRE_CLEAN_DATA.jmp", invisible);
dt << New Column("ENT_CLUSTER", character, nominal, formula(:ENTITY || "_" || :CLUSTER));
gb = dt << Graph Builder(
Size(1446, 747),
Show Control Panel(0),
Variables(X(:WW), Y(:ENTITY_MEAN), Y(:GRAND_MEAN, Position(1)), Wrap(:ENTITY), Color(:CLUSTER)),
Elements(Points(X, Y(1), Y(2), Legend(23)), Smoother(X, Y(1), Y(2), Legend(24))),
SendToReport(
Dispatch(
{},
"WW",
ScaleBox,
{Min(202301.28), Max(202320.72), Inc(1), Minor Ticks(1), Label Row(
{Automatic Tick Marks(0), Label Orientation("Vertical"), Show Minor Ticks(0)}
)}
)
)
);
rep = Report(gb);
fbtitles = (rep << XPath("//GraphBuilderGroupBox/text()"));
Remove From(fbtitles, Contains(fbtitles, "ENTITY")); // we "know" we have wrap variable
// or we could perform filtering using Filter Each
Summarize(dt, clusters = by(:ENT_CLUSTER));
For Each({item}, clusters,
If(Contains(item, "NON_CLUSTER"),
Continue()
);
ent = Word(1, item, "_");
clust = Word(2, item, "_");
Write("Entity = " || ent || "\!n");
Write("Cluster = " || clust || "\!n");
left = Min(DT:WW[DT << getRowsWhere(:ENT_CLUSTER == item)]);
right = Max(DT:WW[DT << getRowsWhere(:ENT_CLUSTER == item)]);
group_mean_min = Min(DT:ENTITY_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
group_mean_max = Max(DT:ENTITY_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
grand_mean_min = Min(DT:GRAND_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
grand_mean_max = Max(DT:GRAND_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
If(group_mean_min < grand_mean_min,
bot = group_mean_min,
bot = grand_mean_min
);
If(group_mean_max > grand_mean_max,
top = group_mean_max,
top = grand_mean_max
);
Write("Left, Right, Top, Bot = " || Char(left) || ", " || Char(right) || ", " || Char(top) || ", " || Char(bot) || "\!n");
framebox = rep[frame box(Contains(fbtitles, ent);)];
Eval(EvalExpr(
framebox << Add Graphics Script(
Pen Color("Black");
Fill Color("Blue");
Transparency(0.1);
Rect(Expr(left), Expr(top), Expr(right), Expr(bot), 0);
Rect(Expr(left), Expr(top), Expr(right), Expr(bot), 1);
);
));
Eval(EvalExpr(
framebox << Add Graphics Script(
Text Size(9);
Text Color("Blue");
Text({Expr(left), Expr(top)}, Expr(clust));
);
));
Write("\!n");
);
(I have done something a bit like this earlier for wafermaps)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: How to programmatically traverse a Graph builder tree structure and associate frameboxes with their titles.
GFrameBoxes are sorted in specific order (might be a good idea to force it using Value Order column property). You can get the framebox index based on that order
cluster_rows = Loc(dt[0, "ENT_CLUSTER"], "XXX104_CLUSTER1");
fb_idx = Contains(clusters, "XXX104_CLUSTER1"); // framebox idx // might not work in all cases!
fbs = Report(myGraphBox) << XPath("//FrameBox");
Eval(EvalExpr(
fbs[fb_idx] << Add Graphics Script(
Pen Color("Black");
Fill Color("Red");
Transparency(0.1);
Rect(Expr(left), Expr(top), Expr(right), Expr(bot), 0);
Rect(Expr(left), Expr(top), Expr(right), Expr(bot), 1);
);
));
Also remember to evaluate the values into graphic script, so you won't end up with this.
In general GraphBuilderGroupBox are very difficult to access/manipulate and I would try to avoid it as much as possible. You can get the titles with XPath, but there can be extra titles
(Report(myGraphBox) << XPath("//GraphBuilderGroupBox/text()"))
{"ENTITY", "XXX101", "XXX102", "XXX103", "XXX104", "XXX105", "XXX106", "XXX107","XXX112", "XXX118", "XXX119"}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: How to programmatically traverse a Graph builder tree structure and associate frameboxes with their titles.
Quick and dirty full example:
Names Default To Here(1);
dt = Open("$DOWNLOADS/PRE_CLEAN_DATA.jmp", invisible);
dt << New Column("ENT_CLUSTER", character, nominal, formula(:ENTITY || "_" || :CLUSTER));
gb = dt << Graph Builder(
Size(1446, 747),
Show Control Panel(0),
Variables(X(:WW), Y(:ENTITY_MEAN), Y(:GRAND_MEAN, Position(1)), Wrap(:ENTITY), Color(:CLUSTER)),
Elements(Points(X, Y(1), Y(2), Legend(23)), Smoother(X, Y(1), Y(2), Legend(24))),
SendToReport(
Dispatch(
{},
"WW",
ScaleBox,
{Min(202301.28), Max(202320.72), Inc(1), Minor Ticks(1), Label Row(
{Automatic Tick Marks(0), Label Orientation("Vertical"), Show Minor Ticks(0)}
)}
)
)
);
rep = Report(gb);
fbtitles = (rep << XPath("//GraphBuilderGroupBox/text()"));
Remove From(fbtitles, Contains(fbtitles, "ENTITY")); // we "know" we have wrap variable
// or we could perform filtering using Filter Each
Summarize(dt, clusters = by(:ENT_CLUSTER));
For Each({item}, clusters,
If(Contains(item, "NON_CLUSTER"),
Continue()
);
ent = Word(1, item, "_");
clust = Word(2, item, "_");
Write("Entity = " || ent || "\!n");
Write("Cluster = " || clust || "\!n");
left = Min(DT:WW[DT << getRowsWhere(:ENT_CLUSTER == item)]);
right = Max(DT:WW[DT << getRowsWhere(:ENT_CLUSTER == item)]);
group_mean_min = Min(DT:ENTITY_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
group_mean_max = Max(DT:ENTITY_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
grand_mean_min = Min(DT:GRAND_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
grand_mean_max = Max(DT:GRAND_MEAN[DT << getRowsWhere(:ENT_CLUSTER == item)]);
If(group_mean_min < grand_mean_min,
bot = group_mean_min,
bot = grand_mean_min
);
If(group_mean_max > grand_mean_max,
top = group_mean_max,
top = grand_mean_max
);
Write("Left, Right, Top, Bot = " || Char(left) || ", " || Char(right) || ", " || Char(top) || ", " || Char(bot) || "\!n");
framebox = rep[frame box(Contains(fbtitles, ent);)];
Eval(EvalExpr(
framebox << Add Graphics Script(
Pen Color("Black");
Fill Color("Blue");
Transparency(0.1);
Rect(Expr(left), Expr(top), Expr(right), Expr(bot), 0);
Rect(Expr(left), Expr(top), Expr(right), Expr(bot), 1);
);
));
Eval(EvalExpr(
framebox << Add Graphics Script(
Text Size(9);
Text Color("Blue");
Text({Expr(left), Expr(top)}, Expr(clust));
);
));
Write("\!n");
);
(I have done something a bit like this earlier for wafermaps)
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: How to programmatically traverse a Graph builder tree structure and associate frameboxes with their titles.
Thanks for the help Jarmo.
I've not done a whole pile of work on traversing these trees but the way you explain it is great.....perhaps this one could be a topic for next years scripters club
Cheers, Troy
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Get Direct Link
- Report Inappropriate Content
Re: How to programmatically traverse a Graph builder tree structure and associate frameboxes with their titles.
Going deeper into the report layer could definitely be one good topic.