Ayuda JSL: Ayuda para la sintaxis del comando Set Function()Hola a todos,
Volvemos con otra pregunta sobre programación JSL. Está relacionado con las otras publicaciones a través de, por ejemplo aquí .
Me gustaría tener una funcionalidad Check Box() que cuando la casilla de verificación está marcada (estado = 1), las filas seleccionadas (resultan ser filas donde RSquare es negativo) se seleccionan y luego se ocultan y se eliminan para que el generador de gráficos actualizado muestra el resultado deseado. Luego, si la casilla no está marcada (estado = 0), se muestran y excluyen esas filas. La llamada Set Function() que estoy usando se encuentra a continuación y funciona si ejecuto el "script" de Set Function() manualmente, pero no lo hace automáticamente. No puedo entender lo que me falta para que se actualice automáticamente. Encontré una publicación interesante aquí , y estoy tratando de hacer algo como lo que hizo esta persona, pero para la actualización del generador de gráficos.
Llamada de función de configuración JSL:
cb << Set Function(<BR />{this},<BR />this = cb << Get;<BR />If(<BR />this == 1,<BR />dt_results << Select Rows( neg_rows ) << Hide and Exclude;<BR />dt_results << Clear Select;<BR />dt_tb = dt_results << Get As Report();,<BR />this == 0,<BR />dt_results << Select Rows( neg_rows ) << Unhide;<BR />dt_results << Select Rows( neg_rows ) << Unexclude;<BR />dt_results << Clear Select;<BR />dt_tb = dt_results << Get As Report()<BR />);<BR />);cb << Set Function(
{this},
this = cb << Get;
If(
this == 1,
dt_results << Select Rows( neg_rows ) << Hide and Exclude;
dt_results << Clear Select;,
this == 0,
dt_results << Select Rows( neg_rows ) << Unhide;
dt_results << Select Rows( neg_rows ) << Unexclude;
dt_results << Clear Select;
);
);Donde cb se menciona anteriormente en el código como:
cb = Check Box( "Remove bad points (*'s)?", <<SET></SET>
Salida inicial, o siempre que la casilla de verificación tenga el estado = 0.:

Salida deseada siempre que la casilla de verificación tenga el estado = 1:

Sería bueno actualizar también la tabla de datos como Informe a la derecha para que cualquiera de las filas que se excluyeron se eliminaran de la vista Informe a la derecha, pero creo que eso podría ser mucho más difícil de lo que parece. Intenté agregar una actualización adicional de Obtener como informe en el comando Establecer función(), pero no hace nada.
Cualquier comentario es apreciado, ¡gracias!
DS
Combinación y limpieza de datosRe: Ayuda JSL: Ayuda de sintaxis del comando Set Function()En mi trabajo diario me enfrento más bien al problema opuesto:
No: 2 ventanas que comparten el mismo espacio de nombres
pero: 2 scripts que sólo a veces *) comparten un común Aquí Espacio de nombres.
Cuando incluyo un archivo JSL en otro, en tiempo de ejecución , el guión incluido comparte el Aquí espacio de nombres del archivo jsl principal.
Pero cuando quiero depurar algunas líneas de código y ejecutarlas desde el segundo script, ¿cómo puedo proporcionar el código incluido? guión_B acceso al Aquí espacio de nombres del script principal? Hace 2 segundos, cuando ejecuté el código de script_B, simplemente TENÍA acceso a ese espacio de nombres.
https://community.jmp.com/t5/Discussions/Debugging-Jmp-applications/mp/701121/highlight/true#M88566
Re: Ayuda JSL: ayuda con la sintaxis del comando Set Function()Gracias, @ErraticAttack por el hermoso ejemplo de cómo funciona el alcance en Jmp.
Me ayudó mucho a acercarme a la comprensión...
Hasta ahora no he podido entender qué quiso decir @drewfoglia con

en Guiones esenciales para la eficiencia y la reproducibilidad: hacer menos para hacer más (2019-US-TUT-290)
Su ejemplo demuestra claramente que esto no es cierto.
¿Por qué nuestra experiencia aquí difiere de la declaración de Drew?
Creo que es porque las ventanas se crean desde la misma ventana del editor JSL.
Después de abrir la primera ventana TEST, es muy útil que la ventana de script aún tenga acceso a los objetos referenciados teb y tb .
Después de abrir la segunda ventana TEST, teb y tb ahora hacen referencia a los objetos de la segunda ventana, lo que aparentemente afecta la funcionalidad de la primera ventana (el texto ingresado aparece en tb , es decir, en la segunda ventana).
Entonces, al vincular ambas reclamaciones, ¿qué sucede si ambas ventanas no comparten un editor JSL común?
-> Ambos tendrán un NameSpace independiente, como anunció Drew en su charla.
Opciones para hacerlo:
a) cierra el Script y ábrelo nuevamente, luego crea la segunda ventana
b) llamar al script desde un menú:

Re: Ayuda JSL: Ayuda de sintaxis del comando Set Function()Hola @ataqueerrático ,
Gracias por tu respuesta y publicación detallada. Seguramente me llevará algo de tiempo resolverlo, ya que no soy un programador profesional y gran parte de esto todavía es nuevo para mí.
¡Gracias!,
DS
Re: Ayuda JSL: Ayuda de sintaxis del comando Set Function()@ih , como ejemplo de JMP que no realiza el alcance como cabría esperar (especialmente si proviene de Python, por ejemplo), simplemente inicie dos ventanas desde este script; los nombres solo se vinculan a la segunda ventana, no a la primera.Este es el mayor problema que he encontrado que tiene la gente con el alcance (pero no el único problema).JMP proporciona algunos pseudoespacios de nombres convenientes, como el espacio de nombres ventana:.Sin embargo, estas no son variables de espacio de nombres adecuadas y no funcionan completamente como se espera en scripts grandes.
Names Default to Here( 1 );
New Window( "TEST",
V List box(
teb = Text Edit Box( "", <<SET hint=""></SET>
@SDF1 , para el alcance explícito del espacio de nombres, lo que he hecho es crear una biblioteca que realiza todas las tareas tediosas de inyección de alcance a través de metaprogramación.Esto tiene el beneficio adicional de poder definir clases casi exactamente como funcionan en Python (menos las convenientes anulaciones de búsqueda).No puedo compartir la biblioteca porque es parte del trabajo de mi empresa, pero esto es esencialmente lo que está sucediendo:
Digamos que tienes un script simple como este
Names Default to Here( 1 );
/*
Doing something initialization here!!
*/
dt = Current Data Table();
New Window( "Super Useful Script",
,
<<ON close=""></ON>
Este script tiene dos elementos de interfaz de usuario interactivos, algo de inicialización y potencialmente algo de limpieza al cerrar la ventana.Tenga en cuenta que conceptualmente el árbol de visualización y la lógica están entremezclados y hay bloques muy profundos.El código se ve mejor (y es más fácil de mantener) cuando los elementos conceptualmente distintos también son distintos dentro del código.Sería bueno simplemente crear un cuadro de botón con un título y un nombre de función para llamar.La función que llame será entonces una función de nivel superior (que puede ser llamada fácilmente por cualquier parte del script) y estará separada del árbol de visualización.
Puedes transformar esto en algo _mucho_ más fácil de digerir y trabajar, similar a lo siguiente:
/* super useful script */
initialize = Function( {}, // entry point to script
/* perform any initialization needed here */
self:dt = Current Data Table();
1
);
content = Function( {}, // this holds the display tree
V List Box(
self:one click button = meta:Button Box( "Useful 1-click function", "call one click" )
,
H List Box(
self:value teb = meta:Text Edit Box( "", "handle value change" ) << Set Hint( "Enter Value" )
)
)
);
finalize = Function( {}, // called after display tree has finalized
1
);
on close = Function( {}, // called when window wants to close
1
);
call one click = Function( {}, // called when button is pressed (line 11)
Print( "Done" )
);
handle value change = Function( {}, // called when TEB value changes(line 14)
Print( "Doing something special" )
);Ahora claramente este script no hará mucho si presiona el botón de ejecución de script JSL normal.Lo que debe hacer con esto es definir primero el meta espacio de nombres (que contiene el contenedor ButtonBox y TextBox para que puedan vincularse bien con el resto del script) y definir una función contenedora de metaprogramación que hará lo siguiente:
Tome un script prototipo como este
<SOME script="" is="" above="" me="">
do someting = Function( {},
...
);
finalize = Function( {},
...
);
<MORE script="" is="" below="" me=""></MORE></SOME>Transfórmalo a este prototipo:
<SOME script="" is="" above="" me="">
self:do someting = Function( {},
self = Namespace( "#434" );
...
);
self:finalize = Function( {},
self = Namespace( "#434" );
...
);
<MORE script="" is="" below="" me=""></MORE></SOME>
Esta función de metaprogramación definirá `self` simplemente como `self = New Namespace()` y luego inyectará la autodefinición en cada función como se indicó anteriormente (el "#434", por supuesto, será diferente cada vez).Después de reescribir el script, simplemente haga lo siguiente (esto está tomado casi exactamente de mi biblioteca)
If( self << Contains( "initialize" ), Try( self:initialize(), Print( "Error with self:initialize" ); Show( exception_msg ); ); );
Eval(
Substitute(
Expr(
self:window = New Window( self:tool name,
<<ON close="">>" ) );
Try(
self:finalize
,
Print( "Error with self:finalize" );
Show( exception_msg );
);</ON>
Aquí hay un ejemplo real que tengo en mi guión.La entrada antes de la metaprogramación es esta:
tool name = "Example";
initialize = Function( {},
{Default Local},
Show( "initialized" )
);
content = Function( {},
H List Box(
meta:Button Box( "Hello World", "run" )
,
self:n days box = meta:Number Edit Box( 30, "run" )
)
);
run = Function( {},
{var1, var2},
Show( "running" )
);
finalize = Function( {},
Show( "finalized" );
show( self:n days box << Get );
);
0;justo antes de evaluar el script (después del paso de metaprogramación) se ve así
self:tool name = "Example";
self:initialize = Function( {},
{Default Local},
self = Namespace( "#58" );
Show( "initialized" );
);
self:content = Function( {},
{self, this},
self = Namespace( "#58" );
H List Box(
meta:Button Box( "Hello World", "run" )
,
self:n days box = meta:Number Edit Box( 30, "run" )
);
);
self:run = Function( {},
{var1, var2, self, this},
self = Namespace( "#58" );
Show( "running" );
);
self:finalize = Function( {},
{self, this},
self = Namespace( "#58" );
Show( "finalized" );
Show( self:n days box << Get );
);
0;En resumen: la metaprogramación requiere cualquier uscopado variable de nivel superior y la aplica explícitamente a "self".Luego toma cualquier función de nivel superior y agrega una primera línea (que es `self = Namespace( )`).Esto es bastante simple conceptualmente y resulta que con JSL es bastante fácil de implementar.Desafortunadamente, existen varias ramas dependiendo de la forma de la función `Function()` (ya sean 2 o 3 argumentos, si el segundo argumento es {Default Local} o simplemente una lista de variables locales).
Entonces, ¿qué te aporta toda esta metaprogramación?Simplemente para evitar hacer algo equivalente, como a continuación.Tenga en cuenta que el siguiente script está envuelto principalmente en declaraciones Eval (Eval Expr (...)).esto le impide poder utilizar dichas declaraciones dentro de cualquiera de las funciones y, por lo tanto, no es ideal para proyectos grandes.Además, el árbol de visualización todavía tiene algunos elementos repetitivos feos (el bloque < ) ... ) ) es grande y feo)
self = New Namespace();
self:tool name = "Example";
Eval( Eval Expr(
self:initialize = Function( {},
{Default Local},
self = Namespace( Expr( self << Get Name ) );
Show( "initialized" )
);
self:content = Function( {},
self = Namespace( Expr( self << Get Name ) );
H List Box(
Button Box( "Hello World",
<<SET function="">>" ) );
Try(
self:finalize
,
Print( "Error with self:finalize" );
Show( exception_msg );
);</SET>Este script contiene mucha información repetitiva, pero es necesario cuando desea tener un control de alcance más explícito.En particular, cuando no desea decirles a los usuarios "¡Abra solo una ventana a la vez!".Crear el paso de metaprogramación es un poco tedioso y definitivamente requiere mucho aprendizaje, pero una vez que lo hayas descubierto, es muy gratificante y también permite un código mucho más conciso y fácil de mantener.
Lo que he mostrado aquí es la capacidad de crear clases (completamente separadas de las clases JMP14+ NewObject) que funcionan muy, muy bien y permiten que la generación de UI interactiva sea muy sencilla.
Sé que esto es mucho (y más concretamente, muy lejos de cualquier enfoque inicial para crear un script de UI), pero si estás creando más de uno o dos scripts de UI pequeños, entonces el tiempo perdido en la creación de la metaprogramación El envoltorio (que solo necesitas hacer una vez) valdrá la pena rápidamente.
Re: Ayuda JSL: Ayuda de sintaxis del comando Set Function()Hola @ataqueerrático ,
Gracias por tus comentarios. He notado que esta es la segunda vez que me recomiendas Namespace() ;-).
Como resultado, pasé el último día y medio leyendo sobre el uso de NameSpace en mi guía de secuencias de comandos, que es mejor que el Índice de secuencias de comandos, pero todavía no brinda los mejores ejemplos de cómo se usa.¿Tiene algún manual que sea mejor que la Guía de secuencias de comandos JMP 14 o el Índice de secuencias de comandos sobre cómo usar el espacio de nombres en el contexto de cómo lo está usando?
Debo admitir que no entiendo lo que estás haciendo y necesito aprenderlo mejor. Sin embargo, según su publicación aquí y el código de ejemplo que proporcionó en una de mis otras publicaciones aquí , Pude reescribir mi sección del script que llama a la primera ventana usando Namespace(). Pero todavía no estoy muy seguro de cómo escribiría secuencias de comandos: en las ventanas y pantallas siguientes puedo ponerme a trabajar gracias a mis no tan buenas habilidades de secuencias de comandos. Creo que me llevará algún tiempo aprender a utilizar Namespace correctamente antes de poder cambiar a ese método programático, lo cual me gustaría hacer.
Pude hacer que el generador de gráficos de la pantalla se actualizara al marcar/desmarcar la casilla para ocultar/excluir los datos negativos (en este caso, sin sentido). El siguiente script hace lo que quiero (excepto actualizar el cuadro de la tabla cuando se eliminan ciertos datos del gráfico), pero entiendo que no es ideal desde el punto de vista de la programación.
¡Gracias!,
DS
Names Default To Here( 1 );
lbWidth = 168;
dt = Open( "$SAMPLE_DATA/Boston Housing.jmp" );
// Expression to store the current settings in global variables
recallRolesS1 = Expr(
::dtchosenRecall = dtchosen
);
// Expression to clear all current settings. KW: Clear
clearRoles = Expr(
Try(
colListY << RemoveAll;
ColListX << RemoveAll;
ColListW << RemoveAll;
ColListF << RemoveAll;
colListV << RemoveAll;
)
);
// Expression to store the current settings in global variables
recallRoles = Expr(
::ycolRecall = colListY << GetItems;
::xcolRecall = colListX << GetItems;
::WcolRecall = colListW << GetItems;
::FcolRecall = colListF << GetItems;
::vcolRecall = colListV << GetItems;
::max_spRecall = max_sp_input << get;
::partVPRecall = partVP_input << Get;
);
//Function to choose the data table to model. KW: choose_data
choose_data_table = Function( {},
list = {};
For( i = 1, i <= N Table(), i++,
list[i] = Data Table( i ) << get name
);
win = New Window( "Select a data table",
<<MODAL> Training R².",
<<SET font="" size=""> 1, Throw( "Too many items selected!\!rOnly one selection possible." ),
N Items( SelRows ) == 1,
SelRows = this << Get Selected Rows;
NPCs = SelRows[1];
);
dt_results << Clear Select;
dt_results << Select rows( SelRows );
)
);
);
Part = Expr(
If(
N Items( vcols ) == 1,
dt_results = New Table( "Partition_Results",
Add Rows( max_sp ),
New Column( "Splits", Numeric, Continuous ),
New Column( "Training RSquare", Numeric, Continuous ),
New Column( "Validation RSquare", Numeric, Continuous ),
New Column( "Training RASE", Numeric, Continuous ),
New Column( "Validation RASE", Numeric, Continuous ),
New Column( "RSquare Diff", Numeric, Continuous, Formula( "Training RSquare"n - "Validation RSquare"n ) ),
New Column( "Penalized Valid RSquare", Numeric, Continuous, Formula( "Training RSquare"n - 0.05 * "Splits"n ) ),
New Column( "Training N", Numeric, Continuous ),
New Column( "Validation N", Numeric, Continuous )
),
N Items( vcols ) == 0 & Is Missing( partVP ) == 0,
dt_results = New Table( "Partition_Results",
Add Rows( max_sp ),
New Column( "Splits", Numeric, Continuous ),
New Column( "Training RSquare", Numeric, Continuous ),
New Column( "Validation RSquare", Numeric, Continuous ),
New Column( "Training RASE", Numeric, Continuous ),
New Column( "Validation RASE", Numeric, Continuous ),
New Column( "RSquare Diff", Numeric, Continuous, Formula( "Training RSquare"n - "Validation RSquare"n ) ),
New Column( "Penalized Valid RSquare", Numeric, Continuous, Formula( "Validation RSquare"n - 0.05 * "Splits"n ) ),
New Column( "Training N", Numeric, Continuous ),
New Column( "Validation N", Numeric, Continuous )
),
N Items( vcols ) == 0,
dt_results = New Table( "Partition_Results",
Add Rows( max_sp ),
New Column( "Splits", Numeric, Continuous ),
New Column( "Training RSquare", Numeric, Continuous ),
New Column( "Training RASE", Numeric, Continuous ),
New Column( "Penalized Train RSquare", Numeric, Continuous, Formula( "Training RSquare"n - 0.05 * "Splits"n ) ),
New Column( "Training N", Numeric, Continuous )
)
);
For( i = 1, i <= max_sp, i++,
dt_results:"Splits"n[i] = i
);
dt_name = dtchosen << Get Name;
For( i = 1, i <= N Rows( dt_results ), i++,
Psplit = dt_results:"Splits"n[i];
str = Eval Insert(
"report = (dtchosen<<PARTITION></PARTITION></SET></MODAL>Re: Ayuda JSL: Ayuda de sintaxis del comando Set Function()Hola @ataqueerrático ,
Desde mi experiencia, el alcance variable es consistente. Puede que no sea intuitivo, pero siempre me ha parecido predecible.Si se encuentra con inconsistencias, podría valer la pena profundizar en la guía de secuencias de comandos e intentar verificar el alcance de los diferentes símbolos.
En algunas situaciones, he tenido gran éxito al utilizar las funciones de contexto de llamada para simplificar las llamadas a funciones, normalmente para análisis exploratorios o scripts que se ejecutan de forma interactiva. Por ejemplo, una función de registro podría enviar mensajes a un archivo o ventana e incluir valores de iterador o de paso sin tener que escribirlos, copiarlos o pegarlos cada vez.
Names default to here(1);
lg = function({msg},
write(msg || try(", i=" || char(i), "") || "\!N")
);
lg("starting loop");
local({i},for(i=1, i<= 5, i++, lg("done")))Re: Ayuda JSL: Ayuda de sintaxis del comando Set Function()Hola @pmroz ,
Gracias por la respuesta. Estaba buscando simplemente actualizar la ventana actual y no crear una nueva. He podido hacer que las cosas funcionen para el gráfico para que se actualice en el estado de marcar/desmarcar la casilla de verificación(). Desafortunadamente, todavía no puedo actualizar el cuadro de tabla que contiene la tabla de datos como informe como quisiera. Esta parte está resultando mucho más complicada de lo que hubiera pensado, pero en realidad no es tan importante. Es mejor que la pantalla gráfica funcione como se esperaba. Aún así, sería bueno si se pudiera actualizar el cuadro de la tabla.
¡Gracias!,
DS
Re: Ayuda JSL: Ayuda de sintaxis del comando Set Function()Tenga en cuenta que no puede confiar en que el recorrido del alcance JSL sea coherente en las funciones <
Principalmente se debe a que JSL no tiene un control de alcance riguroso como lo tendría, por ejemplo, Python.Para cualquier tipo de interfaz de usuario interactiva complicada, siempre debe abarcar explícitamente todas las variables que deben persistir en múltiples devoluciones de llamada de elementos de visualización.
Además, como cuestión de formato de código tanto estético como práctico, siempre debes colocar comas al nivel de la valla circundante, como se muestra a continuación.Esto permite una comprensión visual muy rápida y sencilla de los bloques de código.Observe la sencilla indicación visual de dónde están los diferentes bloques de la declaración IF.
Como nota final, debe vincular el cierre de la ventana de la interfaz de usuario con la eliminación del espacio de nombres utilizando el método <
ns = <RELEVANT namespace="" with="" variables="" defined="" above="">
Eval( Eval Expr(
ns:cb << Set Function( {this},
ns = Namespace( Expr( ns << Get Name ) );
state = this << Get;
If(
state == 1,
ns:dt_results << Select Rows( ns:neg_rows ) << Hide and Exclude;
ns:dt_results << Clear Select;
,
state == 0,
ns:dt_results << Select Rows( ns:neg_rows ) << Unhide;
ns:dt_results << Select Rows( ns:neg_rows ) << Unexclude;
ns:dt_results << Clear Select;
);
);
) );</RELEVANT>Re: Ayuda JSL: Ayuda de sintaxis del comando Set Function()Pruebe algo como esto:
nw = new window("Test",
one_cb = checkbox({"Turn On"},
one_value = one_cb << Get;
If (one_value,
dt_results << Select Rows( neg_rows ) << Hide and Exclude;
dt_results << Clear Select;
dt_tb = dt_results << Get As Report();
// else
,
dt_results << Select Rows( neg_rows ) << Unhide;
dt_results << Select Rows( neg_rows ) << Unexclude;
dt_results << Clear Select;
dt_tb = dt_results << Get As Report()
);
)
);