! Demo about graphical objects. ! Author: Francois Tonneau size 20 10 ! ========== ! Our figure has two panels. We start with panel (a). set font ss hei 0.80 color black just bl amove 0.7 9.0 write "a." ! This panel depicts a psychological model of timing called LeT (Machado A 1997 ! Psychol Rev 104:241-265). We will draw a simplified diagram of the model with ! four connected nodes and two possible decisions, 'left' versus 'right'. ! We start our figure in basic GLE, no graphical objects involved: set lwidth 0.05 color gray50 cap round set font ss hei 0.6 just bc amove 1.5 7.5 write "t{_0}" rmove 0 -0.2 rline 0 -1 rline 0.6 0 arrow end ! Next we use diagram facilities. A first facility is the 'begin object ... end ! object' definition block. Here we define an object that we call, 'node', and ! that consists of an ellipse. The object is a generic one -- no drawing is ! done at this stage: begin object node ellipse 0.5 0.4 end object ! Now we use a loop and the 'draw' commmand to draw our node object four times. ! Each node is left-center justified ('node.lc') and is assigned a unique name ! by combining the "node_" prefix with the loop index (we could have used any ! other names). String concatenation with '+' automatically converts numbers ! to strings: for num = 1 to 4 draw node.lc name "node_"+num rmove 1.5 0 next num ! The last command in the loop ('rmove 1.5 0') moved us to the right of the ! fourth node. We use the 'save' command to assign the name, 'border', to this ! position (again, we could have used any other name): save border ! Now we join named objects/positions with single arrows ('->'). We could have ! used double arrows ('<->') or plain line segments ('-') instead: set arrowstyle empty join node_1 -> node_2 join node_2 -> node_3 join node_3 -> node_4 join node_4 -> border ! To complete our diagram we need to define another generic object, 'decision', ! made of a labeled ellipse and an arrow. Aside from objects and positions, GLE ! lets us name any rectangular region we are drawing with a 'begin name ... end ! name' construct. This construct can also be used within an object definition ! to identify a *part* of the object. ! Here we use this technique to identify a 'ring' part of 'decision' which puts ! a padding of 0.1 cm ('add 0.1') around the visible ellipse. Our definition of ! 'decision' involves two parameters, 'hue$' and 'label$': begin object decision hue$ label$ begin name ring add 0.1 set lwidth 0.05 color hue$ ellipse 0.6 0.5 set just cc write label$ end name rmove 0 -0.5 set arrowstyle filled rline 0 -1.0 arrow end end object ! We now draw two 'decision' objects, one in blue and one in red. Each object ! is center-center justified ('decision.cc') and is drawn with suitable values ! of the hue$ and label$ parameters: amove 3.6 2.8 draw decision.cc name left hue "#004e58" label "L" rmove 2.5 0 draw decision.cc name right hue "#cd5c5c" label "R" ! GLE lets us define our own arrow styles with subroutines of the form: ! arrow_XXX param_1 param_2 param_3 ! Here 'param_1' is the angle in degrees (counted counterclockwise from the x ! axis) of the line to which the arrow is attached; 'param_2' and 'param_3' are ! the values of the 'arrowangle' and 'arrowsize' settings, as determined at run ! time by the 'set arrowangle ...' and 'set arrowsize ...' commands. The newly ! defined arrow style, XXX, is invoked with the 'set arrowstyle XXX' command. ! In this example, we will create an arrow style that looks like a small fan. ! Our arrow_fan subroutine will make no use of the 'arrowangle' setting (which ! would determine the opening angle of the arrow tips), but we still need to ! declare three parameters, so we put 'constant' as a placeholder (any other ! name would do): sub arrow_fan lineangle constant fansize set join round begin rotate lineangle-90 begin path stroke fill white rline -fansize/2 0 rline fansize/2 fansize rline fansize/2 -fansize closepath end path end rotate end sub ! We now use a loop and our 'fan' arrow style to connect all nodes to the rings ! inside the 'left' and 'right' decisions, 'left.ring' and 'right.ring'. We use ! the circular/elliptic joining mode ('.c') to have the arrows reach elliptic ! boundaries instead of stopping at the enclosing rectangles: set color gray50 lstyle 22 arrowstyle fan arrowsize 0.25 for num = 1 to 4 join "node_"+num+".c" -> left.ring.c join "node_"+num+".c" -> right.ring.c next num ! Finally, we connect the two rings with a standard double arrow ('<->'), again ! using the circular/elliptic joining mode ('.c'): set lstyle 1 arrowstyle filled arrowsize 0.35 arrowangle 15 join left.ring.c <-> right.ring.c ! ========== ! Now we turn to panel (b), which reproduces a part of Fig. 16 in Machado A, ! Guilhardi P 2000 J Exp Anal Behav 74:25-54. set font ss hei 0.80 color black just bl amove 9.4 9.0 write "b." set color black hei 0.5 ! We define a subroutine for curve fitting. Note that GlE allows us to declare ! local variables inside a subroutine: sub sigmoid x a b local value = 1/(1 + exp(-(x - a)/b)) return value end sub amove 11.5 1.5 begin graph size 8 6.5 fullsize xaxis min 0 max 60 dticks 15 yaxis min 0 max 1 dticks 0.2 format "fix 1" x2axis off y2axis off xtitle "Time into trial (s)" dist 0.4 ytitle "Proportion second key" dist 0.5 data "objects.dat" d1 marker fcircle msize 0.33 d1 err d2 errwidth 0.001 d3 marker wcircle msize 0.40 d3 err d4 errwidth 0.001 ! GLE has basic facilities for curve fitting. The 'let dn = fit dm ...' ! fills a dataset dn with the best fit of an x-expression to dataset dm. ! As usual, spaces are not allowed in the x-expression. The parameters to ! be fitted ('a' and 'b', in our example) should preferably be set to 0 ! before calling the 'fit' command. ! *Note*: GLE's fitting facilities are limited, and best suited for informal ! data exploration. For more exact results, the use of a program specialized ! in nonlinear fitting is recommended. a = 0 b = 0 let d5 = fit d1 with sigmoid(x,a,b) let d6 = fit d3 with sigmoid(x,a,b) begin layer 300 d5 line d6 line lstyle 12 end layer end graph ! Finally, we add labels to the plot area: set just bl hei 0.50 amove xg(7) yg(0.9) write "Group DIF" set just cl hei 0.40 amove xg(5) yg(0.6) write "40-120/40-120" amove xg(32) yg(0.4) write "120-40/120-40" ! ========== ! Done. We have learned about diagram facilities (including named objects and ! the 'join' command) and custom arrow styles.