Cómo recorrer mediante programación una estructura de árbol del generador de gráficos y asociar cuadros de marco con sus títulos.Tengo un análisis (ver más abajo) en el que quiero anotar gráficos específicos usando un script que he escrito. Por ejemplo, quiero agregar anotaciones a XXX104 y XXX107. En ambos gráficos agregaré un gráfico y texto personalizados para identificar un grupo de puntos sobre los que quiero llamar la atención.

Usando el comando '<< mostrar estructura de árbol' puedo identificar los cuadros de marco que tiene cada gráfico. Sin embargo, no veo el 'nombre' del gráfico asociado con ellos. Por ejemplo, quiero poder recorrer este árbol usando los nombres de los gráficos (por ejemplo, XXX107) como búsqueda e identificar el cuadro de marco asociado (por ejemplo, FrameBox(7)) para poder hacer referencia a él y agregar mi anotación de forma automática.

De hecho, en todo el árbol no veo ningún 'nodo de árbol' que tenga 'nombres de gráfico' como XXX107
En última instancia, el siguiente cuadro es lo que quiero lograr.

Aquí está el código que utilicé para hacer esto manualmente. El archivo también se carga.
Mi problema es que no puedo entender cómo hacer referencia a un cuadro de marco identificando su "título" correspondiente en el árbol de visualización.
Saludos, Troya.
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");
);
);
Automatización y secuencias de comandosRe: Cómo recorrer mediante programación una estructura de árbol del generador de gráficos y asociar cuadros de marco con sus títulos.Los GFrameBoxes están ordenados en un orden específico (podría ser una buena idea forzarlo usando la propiedad de la columna Orden de valor). Puede obtener el índice del framebox según ese orden.
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);
);
));
También recuerde evaluar los valores en escritura gráfica, para no terminar con esto.

En general, es muy difícil acceder/manipular GraphBuilderGroupBox y trataría de evitarlo tanto como sea posible. Puedes obtener los títulos con XPath, pero puede haber títulos adicionales.
(Report(myGraphBox) << XPath("//GraphBuilderGroupBox/text()"))
{"ENTITY", "XXX101", "XXX102", "XXX103", "XXX104", "XXX105", "XXX106", "XXX107","XXX112", "XXX118", "XXX119"}Re: Cómo recorrer mediante programación una estructura de árbol del generador de gráficos y asociar cuadros de marco con sus títulos.Ejemplo completo rápido y sucio:
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");
);

(He hecho algo parecido a esto antes para los mapas de obleas)
Re: Cómo recorrer mediante programación una estructura de árbol del generador de gráficos y asociar cuadros de marco con sus títulos.Gracias por la ayuda Jarmo.
No he trabajado mucho para atravesar estos árboles, pero la forma en que lo explicas es genial... tal vez este podría ser un tema para el club de guionistas del próximo año 
Saludos, Troya
Re: Cómo recorrer mediante programación una estructura de árbol del generador de gráficos y asociar cuadros de marco con sus títulos.Profundizar en la capa del informe definitivamente podría ser un buen tema.