*! version 2.26 (4Nov2023), by Mead Over *! Enhanced version of -grc1leg- version 1.0.5 02jun2010, by Vince Wiggins program grc1leg2 version 13.1 syntax [anything(id="graph list")] [, LEGendfrom(string) /// POSition(string) RING(integer -1) SPAN /// NAME(passthru) SAVing(string asis) /// XTOB1title XTItlefrom(string) XTSize(string) /// These and following options by MO LABSize(string) LSize(string) /// lsize() is retained fo backward compatibility YTOL1title y1tol1title YTItlefrom(string) YTSize(string) /// y2tor1title y2titlefrom(string) y2tsize(string) /// l1tol1title l1titlefrom(string) /// l2tol2title l2titlefrom(string) /// r1tor1title r1titlefrom(string) /// r2tor2title r2titlefrom(string) /// MAINTOtoptitle MAINTItlefrom(string) MAINFrom(string) MTSize(string) /// SUBTOsubtitle SUBFrom(string) STSize(string) /// NOTETOnote SUBTONote NOTEFrom(string) NTSize(string) /// SYMXsize(string) SYMYsize(string) LMSize(string) /// LTItle(string) LTSize(string) LSUBTItle(string) LSUBTSize(string) /// LEGScale(string) /// LXOffset(real 0) LYOffset(real 0) LOFF HIDElegendfrom /// LCols(string) LRows(string) LHoles(string) /// ysize(passthru) xsize(passthru) margins(passthru) scale(passthru) scheme(passthru) /// holes(string) /// GRAPHon DOTS DEBUG notrap noAUTOsize * ] if strpos(`"`anything'"',"*") | strpos(`"`anything'"',"?") { di as err `"The "wildcard" characters "*" and "?" are not permitted in the list of graph names to be combined."' error 198 } local Npnls : list sizeof anything if "`holes'"~="" { local Nholes : list sizeof holes local Npnls = `Npnls' + `Nholes' local holes holes(`holes') } // For compatibility with version 2.13, allow only one or neither of following two options local opt1 = cond("`labsize'"~="","labsize","") local opt2 = cond("`lsize'"~="","lsize","") // Allow only one of these options (lsize is retained for backward compatibility) opts_exclusive "`opt1' `opt2'" local labsize `lsize'`labsize' // For compatibility with version 2.13, allow only one or neither of following two options local opt1 = cond("`maintitlefrom'"~="","maintitlefrom()","") local opt2 = cond("`mainfrom'"~="","mainfrom()","") opts_exclusive "`opt1' `opt2'" // Allow only one of these options local mainfrom `maintitlefrom'`mainfrom' if "`mainfrom'"~="" local maintotoptitle maintotoptitle if "`dots'"=="dots" { nois _dots 0, title(-grc1leg2- working...) global grc1leg2_stage 1 } else { di as txt "-grc1leg2- working..." } if strpos(`"`saving'"',"asis") { local isasis isasis } // If -grc1leg2- has previously set graphics off, // and exited without setting graphics back on, // set graphics on now. if "${grc1leg2_set_graph}"=="off" { set graphics on global grc1leg2_set_graph } local usergrset "`c(graphics)'" if "`graphon'"=="" & "`usergrset'"=="on" { set graphics off global grc1leg2_set_graph off } gr_setscheme , refscheme // So we can have temporary styles // location and alignment in cell tempname clockpos if ("`position'" == "") local position 6 .`clockpos' = .clockdir.new , style(`position') local location `.`clockpos'.relative_position' // specify -ring()- for combined legend if `ring' > -1 { if (`ring' == 0) { local location "on" local ring "" } else local ring "ring(`ring')" } else local ring "" if "`span'" != "" { if "`location'" == "above" | "`location'" == "below" { local span spancols(all) } else local span spanrows(all) } // allow legend to be from any graph if `"`legendfrom'"' != "" { local lfrom : list posof `"`legendfrom'"' in anything if `lfrom' == 0 { di as err `"-`legendfrom'- not found in graph name list"' error 198 } } else { // use graph 1 for legend by default local lfrom 1 gettoken legendfrom : anything } if "`dots'"=="dots" make10dots , stage(${grc1leg2_stage}) if "`debug'"~="" { di _n as txt "DEBUG: Displaying -debug- output" di _n as txt "DEBUG: -grc1leg2- is executing -gr combine- on component graphs" di _n as txt `"DEBUG: Options not parsed by -syntax- and passed through to -gr combine- are:"' /// _n as txt `"`options'"' _n local noi noisily } // When editing component panels below, panels are identified by their sequence in this combined graph graph combine `anything' , `holes' `name' nodraw `options' // combine graphs if "`name'" != "" { // get graph name local 0 `", `name'"' syntax [, name(string) ] local 0 `"`name'"' syntax [anything(name=name)] [, replace] } else local name Graph // Options for -gr combine- if "`ysize'`xsize'`margins'`scale'`scheme'"~="" { graph display `name' , `ysize' `xsize' `margins' `scale' `scheme' graph rename `name' `name', replace if "`dots'"=="dots" make10dots , stage(${grc1leg2_stage}) } // Determine from which type of graph the legend is borrowed chk_legend `name' , lfrom(`lfrom') legendfrom(`"`legendfrom'"') `trap' `debug' // Double quotes added ver. 2.12 if "`debug'"~="" { di _n as txt "DEBUG: The subroutine -chk_legend- returns:" return list matlist r(keystyledex) } local Nkeys `r(Nkeys)' local Nlabels `r(Nlabels)' local labelwidth `r(labelwidth)' local legendtype `r(legendtype)' local legendclass `r(legendclass)' local NkeysEqNlabels `r(NkeysEqNlabels)' local NminofKeysLabels `r(NminofKeysLabels)' local NmaxofKeysLabels `r(NmaxofKeysLabels)' // The matrix consisting of the value of -styledex- for all the legend keys tempname keystyledex mat define `keystyledex' = r(keystyledex) local SmlstEqLrgst = `r(SmlstEqLrgst)' // turn off legends & optionally titles, etc on component graphs forvalues i = 1/`Npnls' { // Suppress legend on a -combined- graph, version 1.34 forvalues g = 1/30 { cap classutil describe .`name'.plotregion1.graph`i'.plotregion1.graph`g'.legend if _rc == 0 { _gm_edit .`name'.plotregion1.graph`i'.plotregion1.graph`g'.legend.draw_view.set_false _gm_edit .`name'.plotregion1.graph`i'.plotregion1.graph`g'.legend.fill_if_undrawn.set_false _gm_edit .`name'.plotregion1.graph`i'.plotregion1.graph`g'.legend.draw_view.setstyle, style(no) } else { continue, break } } cap classutil describe .`name'.graphs[`i'].legend if _rc == 0 { _gm_edit .`name'.graphs[`i'].legend.draw_view.set_false _gm_edit .`name'.graphs[`i'].legend.fill_if_undrawn.set_false // Suppress legend on a -by- graph _gm_edit .`name'.graphs[`i'].legend.draw_view.setstyle, style(no) } cap classutil describe .`name'.graphs[`i'].plotregion1.atlegend if _rc == 0 { _gm_edit .`name'.graphs[`i'].plotregion1.atlegend.draw_view.setstyle, style(no) } if "`xtob1title'"~="" { // turn off xaxis1 titles cap classutil describe .`name'.graphs[`i'].xaxis1.title if _rc == 0 { _gm_edit .`name'.graphs[`i'].xaxis1.title.draw_view.set_false } } if "`ytol1title'"~="" | "`y1tol1title'"~="" { // turn off yaxis1 titles (by M. Over) cap classutil describe .`name'.graphs[`i'].yaxis1.title if _rc == 0 { _gm_edit .`name'.graphs[`i'].yaxis1.title.draw_view.set_false } } if "`l1tol1title'"~="" { // turn off l1 titles cap classutil describe .`name'.graphs[`i'].l1title if _rc == 0 { _gm_edit .`name'.graphs[`i'].l1title.draw_view.set_false } } if "`y2tor1title'"~="" { // turn off yaxis2 titles cap classutil describe .`name'.graphs[`i'].yaxis2.title if _rc == 0 { _gm_edit .`name'.graphs[`i'].yaxis2.title.draw_view.set_false } } if "`r1tor1title'"~="" { // turn off yaxis2 titles cap classutil describe .`name'.graphs[`i'].r1title if _rc == 0 { _gm_edit .`name'.graphs[`i'].r1title.draw_view.set_false } } // suppress main title, subtitle and/or note in component panels // no provision for suppressing other titles such as caption, b1title, b2title, l1title, etc. /* Option: Graph from and text size option names: -maintotoptitle- -maintitlefrom- or -mainfrom-, -mtsize()- -subtosubtitle- -subfrom-, -stsize()- -notetonote- -notefrom-, -ntsize()- -subtotoptitle- <-- Not implemented -maintosubtitle- <-- Not implemented -subtonote- <-- Not implemented */ if "`debug'"~="" { di as txt "DEBUG: In line 237, -options- local macro is: -" as res `"`options'"' } // suppress the main, sub or note title from -mainfrom- -subfrom- or -notefrom- // if they are to be moved to the combined graph's main, sub and/or note title foreach ttl in main sub note { local ttlopt = /// cond("`ttl'"=="main","maintotoptitle", /// cond("`ttl'"=="sub","subtosubtitle", /// cond("`ttl'"=="note","notetonote","noneofabove"))) local ttltype = /// cond("`ttl'"=="main","title", /// cond("`ttl'"=="sub","subtitle", /// cond("`ttl'"=="note","note","noneofabove"))) if "`ttltype'"=="noneofabove" { di as err "Error in grc1leg2, Line 247: This error should never occur." } if "``ttlopt''"~="" { // turn off `ttl' title in component graphs cap classutil describe .`name'.graphs[`i'].`ttltype' if _rc == 0 { _gm_edit .`name'.graphs[`i'].`ttltype'.draw_view.set_false _gm_edit .`name'.graphs[`i'].`ttltype'.fill_if_undrawn.set_false } } } if "`dots'"=="dots" make10dots , stage(${grc1leg2_stage}) } // legend is from a single graph if "`legendtype'"=="legend" { // insert overall legend .`name'.insert (legend = .`name'.graphs[`lfrom'].legend) /// `location' plotregion1 , `ring' `span' _gm_log .`name'.insert (legend = .graphs[`lfrom'].legend) /// `location' plotregion1 , `ring' `span' } // if not and if legend is from -graph ..., by()- // (with -else- here ... , -grc1leg2- is recursive) else if "`legendtype'"=="atlegend" { // insert overall legend .`name'.insert (legend = .`name'.graphs[`lfrom'].plotregion1.atlegend) /// `location' plotregion1 , `ring' `span' _gm_log .`name'.insert (legend = .graphs[`lfrom'].plotregion1.atlegend) /// `location' plotregion1 , `ring' `span' } // if not and if legend is from -gr combine- // (and with -else- here, -grc1leg2- is recursive) else if "`legendtype'"=="combined" { // insert overall legend .`name'.insert (legend = .`name'.plotregion1.graph`lfrom'.plotregion1.graph1.legend) /// `location' plotregion1 , `ring' `span' _gm_log .`name'.insert (legend = .plotregion1.graph`lfrom'.plotregion1.graph1.legend) /// `location' plotregion1 , `ring' `span' } // Display combined legend _gm_edit .`name'.legend.style.box_alignment.setstyle , /// style(`.`clockpos'.compass2style') _gm_edit .`name'.legend.draw_view.setstyle, style(yes) // use -xtitlefrom- xtitle as overall b1title if "`xtob1title'"=="" & "`xtitlefrom'"~="" { local xtob1title xtob1title } if "`xtob1title'"~="" { // allow b1title to be from any graph if "`xtitlefrom'" != "" { local xfrom : list posof "`xtitlefrom'" in anything if `xfrom' == 0 { di as error `"`xtitlefrom' not found in graph name list"' error 198 } } else local xfrom 1 // use graph 1 for xtitle by default .`name'.b1title = .`name'.graphs[`xfrom'].xaxis1.title _gm_log .`name'.b1title = .graphs[`xfrom'].xaxis1.title _gm_edit .`name'.b1title.draw_view.set_true } // use -ytitlefrom- ytitle as overall l1title if "`ytol1title'"=="" & "`ytitlefrom'"~="" { local ytol1title ytol1title } if "`ytol1title'"~="" { // allow l1title to be from any graph if "`ytitlefrom'" != "" { local yfrom : list posof "`ytitlefrom'" in anything if `yfrom' == 0 { di as error `"`ytitlefrom' not found in graph name list"' error 198 } } else local yfrom 1 // use graph 1 for ytitle by default .`name'.l1title = .`name'.graphs[`yfrom'].yaxis1.title _gm_log .`name'.l1title = .graphs[`yfrom'].yaxis1.title _gm_edit .`name'.l1title.draw_view.set_true } // use -y2titlefrom-'s y2title as overall r1title if "`y2tor1title'"=="" & "`y2titlefrom'"~="" { local y2tor1title y2tor1title } if "`y2tor1title'"~="" { // allow r1title to be from any graph if "`y2titlefrom'" != "" { local y2from : list posof "`y2titlefrom'" in anything if `y2from' == 0 { di as error `"`y2titlefrom' not found in graph name list"' error 198 } } else local y2from 1 // use graph 1 for ytitle by default .`name'.r1title = .`name'.graphs[`y2from'].yaxis2.title _gm_log .`name'.r1title = .graphs[`y2from'].yaxis2.title _gm_edit .`name'.r1title.draw_view.set_true } foreach t in l1 l2 r1 r2 { // use -`t'titlefrom-'s `t'title as overall `t'title if "``t'to`t'title'"=="" & "``t'titlefrom'"~="" { local `t'to`t'title `t'to`t'title } if "``t'to`t'title'"~="" { // allow `t'title to be from any graph if "``t'titlefrom'" != "" { local yfrom : list posof "``t'titlefrom'" in anything if `yfrom' == 0 { di as error `"``t'titlefrom' not found in graph name list"' error 198 } } else local yfrom 1 // use graph 1 for `t'title by default .`name'.`t'title = .`name'.graphs[`yfrom'].`t'title _gm_log .`name'.`t'title = .graphs[`yfrom'].`t'title _gm_edit .`name'.`t'title.draw_view.set_true } } // use the main, sub or note title from -mainfrom- -subfrom- or -notefrom- // as the combined graph's main, sub and/or note title foreach ttl in main sub note { local ttlopt = /// cond("`ttl'"=="main","maintotoptitle", /// cond("`ttl'"=="sub","subtosubtitle", /// cond("`ttl'"=="note","notetonote","noneofabove"))) if "``ttlopt''"=="" & "``ttl'from'"~="" { local `ttlopt' `ttlopt' } if "``ttlopt''"~="" { // allow `ttl' title to be from any graph if "``ttl'from'" != "" { local `ttl'from : list posof "``ttl'from'" in anything if ``ttl'from' == 0 { di as error `"``ttl'from' not found in graph name list"' error 198 } } else local `ttl'from 1 // use graph 1 for `ttl' title by default local ttltype = /// cond("`ttl'"=="main","title", /// cond("`ttl'"=="sub","subtitle", /// cond("`ttl'"=="note","note","noneofabove"))) if "`ttltype'"=="noneofabove" { di as err "Error in grc1leg2, Line 420: This error should never occur." } .`name'.`ttltype' = .`name'.graphs[``ttl'from'].`ttltype' _gm_log .`name'.`ttltype' = .graphs[``ttl'from'].`ttltype' _gm_edit .`name'.`ttltype'.draw_view.set_true } } _gm_edit .`name'.legend.draw_view.set_true // VW's code to maintain serset reference counts // must pick up sersets by reference, they were // -.copy-ied when the legend was created above if "`legendtype'"=="legend" { forvalues i = 1/`.`name'.legend.keys.arrnels' { if "`.`name'.legend.keys[`i'].view.serset.isa'" != "" { _gm_edit .`name'.legend.keys[`i'].view.serset.ref_n + 99 .`name'.legend.keys[`i'].view.serset.ref = /// .`name'.graphs[`lfrom'].legend.keys[`i'].view.serset.ref _gm_log .`name'.legend.keys[`i'].view.serset.ref = /// .graphs[`lfrom'].legend.keys[`i'].view.serset.ref } if "`.`name'.legend.plotregion1.key[`i'].view.serset.isa'" != "" { _gm_edit /// .`name'.legend.plotregion1.key[`i'].view.serset.ref_n + 99 .`name'.legend.plotregion1.key[`i'].view.serset.ref = /// .`name'.graphs[`lfrom'].legend.keys[`i'].view.serset.ref _gm_log /// .`name'.legend.plotregion1.key[`i'].view.serset.ref = /// .graphs[`lfrom'].legend.keys[`i'].view.serset.ref } if "`dots'"=="dots" make10dots , stage(${grc1leg2_stage}) } } // Fix the serset numbering when source is a -gr, by()- graph if "`legendtype'"=="atlegend" { forvalues i = 1/`.`name'.legend.keys.arrnels' { if "`.`name'.legend.keys[`i'].view.serset.isa'" != "" { _gm_edit .`name'.legend.keys[`i'].view.serset.ref_n + 99 .`name'.legend.keys[`i'].view.serset.ref = /// .`name'.graphs[`lfrom'].plotregion1.atlegend.keys[`i'].view.serset.ref _gm_log .`name'.legend.keys[`i'].view.serset.ref = /// .graphs[`lfrom'].plotregion1.atlegend.keys[`i'].view.serset.ref } if "`.`name'.legend.plotregion1.key[`i'].view.serset.isa'" != "" { _gm_edit /// .`name'.legend.plotregion1.key[`i'].view.serset.ref_n + 99 .`name'.legend.plotregion1.key[`i'].view.serset.ref = /// .`name'.graphs[`lfrom'].plotregion1.atlegend.keys[`i'].view.serset.ref _gm_log /// .`name'.legend.plotregion1.key[`i'].view.serset.ref = /// .graphs[`lfrom'].plotregion1.atlegend.keys[`i'].view.serset.ref } if "`dots'"=="dots" make10dots , stage(${grc1leg2_stage}) } } // Fix the serset numbering when source is a -gr_combine- graph if "`legendtype'"=="combined" { forvalues i = 1/`.`name'.legend.keys.arrnels' { if "`.`name'.legend.keys[`i'].view.serset.isa'" != "" { _gm_edit .`name'.legend.keys[`i'].view.serset.ref_n + 99 .`name'.legend.keys[`i'].view.serset.ref = /// .`name'.plotregion1.graph`lfrom'.plotregion1.graph1.legend.keys[`i'].view.serset.ref _gm_log .`name'.legend.keys[`i'].view.serset.ref = /// .plotregion1.graph`lfrom'.plotregion1.graph1.legend.keys[`i'].view.serset.ref } if "`.`name'.legend.plotregion1.key[`i'].view.serset.isa'" != "" { _gm_edit /// .`name'.legend.plotregion1.key[`i'].view.serset.ref_n + 99 .`name'.legend.plotregion1.key[`i'].view.serset.ref = /// .`name'.plotregion1.graph`lfrom'.plotregion1.graph1.legend.keys[`i'].view.serset.ref _gm_log /// .`name'.legend.plotregion1.key[`i'].view.serset.ref = /// .plotregion1.graph`lfrom'.plotregion1.graph1.legend.keys[`i'].view.serset.ref } if "`dots'"=="dots" make10dots , stage(${grc1leg2_stage}) } } if "`dots'"=="dots" { make10dots , stage(${grc1leg2_stage}) di _n } // Optionally suppress display of the combined legend if "`loff'"~="" { .`name'.legend.draw_view.setstyle, style(no) _gm_log .`name'.legend.draw_view.setstyle, style(no) } // Modify the legend contents else { .`name'.legend.xoffset = `lxoffset' _gm_log .`name'.legend.xoffset = `lxoffset' .`name'.legend.yoffset = `lyoffset' _gm_log .`name'.legend.yoffset = `lyoffset' if "`ltitle'"~="" { .`name'.legend.title.text = {} .`name'.legend.title.text.Arrpush `ltitle' _gm_log .`name'.legend.title.text.Arrpush `ltitle' } if "`lsubtitle'"~="" { .`name'.legend.subtitle.text = {} .`name'.legend.subtitle.text.Arrpush `lsubtitle' _gm_log .`name'.legend.subtitle.text.Arrpush `lsubtitle' } if "`lholes'"~="" { GetHoles , lholes(`lholes') local lholes `r(holes)' .`name'.legend.Edit , cmd(.holes = "`lholes'") keepstyles _gm_log .`name'.legend.Edit , cmd(.holes = "`lholes'") keepstyles } // Don't draw the panel from which legend is borrowed // Try to fill in the hole left by the undrawn panel. Rarely works. if "`debug'"~="" di as txt _n "DEBUG: Number of panels (including holes) is: -"as res "`Npnls'" as txt "-" if "`hidelegendfrom'"~="" { opts_exclusive "`loff' `hidelegendfrom'" .`name'.plotregion1.graph`lfrom'.draw_view.setstyle, style(no) .`name'.plotregion1.graph`lfrom'.fill_if_undrawn.setstyle, style(no) _gm_log .`name'.plotregion1.graph`lfrom'.draw_view.setstyle, style(no) _gm_log .`name'.plotregion1.graph`lfrom'.fill_if_undrawn.setstyle, style(no) local Npnls = `Npnls' - 1 } ****** Resize legend elements ****** if "`debug'"~="" { di _n as txt "DEBUG: User supplied legend re-sizing options:" di as txt _col(10) "-legscale({help size}): -" as res "`legscale'" as txt "-" di as txt _col(10) "-ltsize({help textsizestyle}): -" as res "`ltsize'" as txt "-" di as txt _col(10) "-lsubtsize({help size}): -" as res "`lsubtsize'" as txt "-" di as txt _col(10) "-lmsize({help markersizestyle}): -" as res "`lmsize'" as txt "-" di as txt _col(10) "-symxsize({help size}): -" as res "`symxsize'" as txt "-" di as txt _col(10) "-symysize({help size}): -" as res "`symysize'" as txt "-" di as txt _col(10) "-labsize({help textsizestyle}): -" as res "`labsize'" as txt "-" di as txt _col(10) "-autosize-: -" as res "`autosize'" as txt "-" } // Default -legscale- to shrink all legend elements not explicitly sized if "`legscale'"=="" & "`autosize'"~="noautosize" { // Default defined to be a multiplicative expresson such as *.7 tempname scale_opts // No. of panels 1 2 3 4 5 6 7 8 9 10 11 12 matrix define `scale_opts' = [1, .8, .7, .7, .6, .6, .6, .6, .6, .4, .4, .4] local legscale = "*" + strofreal(cond(`Npnls'>12,.3,`scale_opts'[1,`Npnls'])) if "`debug'"~="" { di as txt _n "DEBUG: Since user did not suppress automatic resizing of legend elements " /// _n "with option -noautosize- or specify the option -legscale-, -grc1leg2- notes" /// _n "that the number of panels (including any holes and excluding any hidden panel)" /// _n as txt "is Npnls = " as res "`Npnls'" as txt " and shrinks all legend elements accordingly by setting" /// _n as txt "-legscale to: -" as res "`legscale'" as txt "-." } } if "`debug'"~="" { di _n as txt "DEBUG: Legend attributes from suroutine -chk_legend-:" di as txt "Number of keys is: -" as res "`Nkeys'" as txt "-" di as txt "Number of labels is: -" as res "`Nlabels'" as txt "-" di as txt "NkeysEqNlabels is: -" as res "`NkeysEqNlabels'" as txt "-" di as txt "SmlstEqLrgst is: -" as res "`SmlstEqLrgst'" as txt "-" di as txt "labelwidth is: -" as res "`labelwidth'" as txt "-" di as txt "legendclass is: -" as res "`legendclass'" as txt "-" di as txt "NminofKeysLabels is: -" as res "`NminofKeysLabels'" as txt "-" di as txt "legendtype is: -" as res "`legendtype'" as txt "-" } // Start legend resizing // The size of each legend element (labsize, symxsize, symysize, ltsize, lsubtsize, lmsize): // . starts as specified in the source legend from a component graph specified by -legendfrom()- // . if the legend element's size is NOT user specified and ... // a. -autosize- is not equal to -noautosize- (the default), // the element's starting size is modified by -legscale-, or // b. user has set -autosize- to -noautosize-, // the element's starting size is NOT modified // (i.e. legscale is set to "*1") // . if the element's size is user specified, this specification modifies the element's size, // regardless of the settings of -legscale- or -autosize- // The following parts of the legend accept any of the size types // listed in -help size-. (i.e. #pt, #in, #cm, #rs, #, *#) // and apply to all keys and labels in the legend. foreach legpart in labsize symxsize symysize ltsize lsubtsize { // -legpart- is NOT user-specified if "``legpart''"=="" { if "`autosize'" ~= "noautosize" { local `legpart' `legscale' } } // -labsize- is user-specified or defaults to -legscale- if "`legpart'"=="labsize" { if "``legpart''"~="" { .`name'.legend.Edit, style(labelstyle(size(`labsize'))) _gm_log .`name'.legend.Edit, style(labelstyle(size(`labsize'))) } } // -sym`xy'size- is user-specified or defaults to -legscale- foreach xy in x y { if "`legpart'"=="sym`xy'size" { if "``legpart''"~="" { .`name'.legend.Edit, style(key_`xy'size(`sym`xy'size')) keepstyles _gm_log .`name'.legend.Edit, style(key_`xy'size(`sym`xy'size')) keepstyles } } } // -ltsize- is user-specified or defaults to -legscale- if "`legpart'"=="ltsize" { if "``legpart''"~="" { .`name'.legend.title.style.editstyle size(`ltsize') editcopy _gm_log .`name'.legend.title.style.editstyle size(`ltsize') editcopy } } // -lsubtsize- is user-specified or defaults to -legscale- if "`legpart'"=="lsubtsize" { if "``legpart''"~="" { .`name'.legend.subtitle.style.editstyle size(`lsubtsize') editcopy _gm_log .`name'.legend.subtitle.style.editstyle size(`lsubtsize') editcopy } } } // Size specifications for the marker symbols that appear in legends accept any of the size types // listed in -help size-. (i.e. #pt, #in, #cm, #rs, #, *#), but also the size designations: // vtiny, tiny, vsmall, small, medsmall, medium, medlarge, large, vlarge, huge, vhuge, ehuge. // Allow resizing of markers in the legend only if they exist (_rc~=4018) & NminofKeysLabels > 0 // For example, neither -graph pie- nor -graph bar- has markers. if `NminofKeysLabels' <= 0 { di as txt `"Warning: Because the legend borrowed for the combined graph is not "complete","' /// _n "automatic resizing of legend markers is disabled and {cmd:grc1leg2} ignores the option -lmsize-." /// _n `"See the discussion of "known issues" in {cmd:grc1leg2}'s help file {help grc1leg2##known:here}."' } else { // `NminofKeysLabels' > 0 // Define mata string matrices: origkeysizes newkeysizes if "`debug'"~="" { tempname origkeysizes newkeysizes mata : `origkeysizes' = J(`Nkeys',3,"") mata : `newkeysizes' = J(`Nkeys',3,"") } if "`lmsize'"=="" { local lmsize `legscale' } forvalues i = 1/`Nkeys' { // If there are markers, resize them using -lmsize- or -legscale-, using relative sizes cap `noi' classutil describe .`name'.legend.plotregion1.key[`i'].view.style.marker.size if _rc==0 { local origlmsize = `.`name'.legend.plotregion1.key[`i'].view.style.marker.size.val' orig2newsize , lmsize("`lmsize'") origsize(`origlmsize') `debug' local newlmsize = r(newsize) .`name'.legend.plotregion1.key[`i'].view.style.editstyle marker(size(`newlmsize')) editcopy _gm_log .`name'.legend.plotregion1.key[`i'].view.style.editstyle marker(size(`newlmsize')) editcopy } else { if "`debug'"~="" di as txt "DEBUG: _rc = " as res _rc local origlmsize = . local newlmsize = . } // If there are keys that have a -xsize, resize them using -lmsize- or -legscale-, using relative sizes cap `noi' classutil describe .`name'.legend.plotregion1.key[`i'].xsz if _rc==0 { local origxsize = `.`name'.legend.plotregion1.key[`i'].xsz.val' orig2newsize , lmsize("`lmsize'") origsize(`origxsize') `debug' local newxsize = r(newsize) .`name'.legend.plotregion1.key[`i'].xsz.editstyle `newxsize' editcopy _gm_log .`name'.legend.plotregion1.key[`i'].xsz.editstyle `newxsize' editcopy } else { if "`debug'"~="" di as txt "DEBUG: _rc = " as res _rc local origxsize = . local newxsize = . } // If there are keys that have a -ysize, resize them using -lmsize- or -legscale-, using relative sizes cap `noi' classutil describe .`name'.legend.plotregion1.key[`i'].ysz if _rc==0 { local origysize = `.`name'.legend.plotregion1.key[`i'].ysz.val' orig2newsize , lmsize("`lmsize'") origsize(`origysize') `debug' local newysize = r(newsize) .`name'.legend.plotregion1.key[`i'].ysz.editstyle `newysize' editcopy _gm_log .`name'.legend.plotregion1.key[`i'].ysz.editstyle `newysize' editcopy } else { if "`debug'"~="" di as txt "DEBUG: _rc = " as res _rc local origysize = . local newysize = . } if "`debug'"~="" { mata : `origkeysizes'[`i', . ] = ("`origlmsize'", "`origxsize'" , "`origysize'") mata : `newkeysizes'[`i', . ] = ("`newlmsize'", "`newxsize'", "`newysize'") } local rnms `rnms' key_`i' } if "`debug'"~="" { di _n as txt "DEBUG: Key sizes before and after re-sizing options are applied:" di _n as txt "Matrix: origkeysizes" /// _n as txt " Column names: " as res "origlmsize, origxsize , origysize" /// _n as txt " Row names: " as res "`rnms'" mata : `origkeysizes' di _n as txt "Matrix: newkeysizes" /// _n as txt " Column names: " as res "newlmsize, newxsize , newysize" /// _n as txt " Row names: " as res "`rnms'" mata : `newkeysizes' } } if "`debug'"~="" { mata : mata drop `origkeysizes' mata : mata drop `newkeysizes' } // End of legend resizing // Resize the overall titles only with options, not automatically if "`xtob1title'"~="" & "`xtsize'"~="" { .`name'.b1title.style.editstyle size(`xtsize') editcopy _gm_log .`name'.b1title.style.editstyle size(`xtsize') editcopy } if ("`ytol1title'"~="" | "`l1tol1title'"~="") & "`ytsize'"~="" { .`name'.l1title.style.editstyle size(`ytsize') editcopy _gm_log .`name'.l1title.style.editstyle size(`ytsize') editcopy } if ("`y2tor1title'"~="" | "`r1tor1title'"~="") & "`y2tsize'"~="" { .`name'.r1title.style.editstyle size(`y2tsize') editcopy _gm_log .`name'.r1title.style.editstyle size(`y2tsize') editcopy } if "`maintotoptitle'"~="" & "`mtsize'"~="" { .`name'.title.style.editstyle size(`mtsize') editcopy _gm_log .`name'.title.style.editstyle size(`mtsize') editcopy } if "`subtosubtitle'"~="" & "`stsize'"~="" { .`name'.subtitle.style.editstyle size(`stsize') editcopy _gm_log .`name'.subtitle.style.editstyle size(`stsize') editcopy } if "`notetonote'"~="" & "`ntsize'"~="" { .`name'.note.style.editstyle size(`ntsize') editcopy _gm_log .`name'.note.style.editstyle size(`ntsize') editcopy } **** Rearranging the rows and columns of the borrowed legends using options -lcols()- and -lrows()- **** Logging these changes with _gm_log is not sufficient to assure they are preserved in a saved .gph file if "`lcols'"~="" | "`lrows'"~="" { chkrowcol , lrows("`lrows'") lcols("`lcols'") if "`lcols'"~="" { .`name'.legend.Edit, style(cols(`r(nrowsorcols)')) style(rows(0)) keepstyles _gm_log .`name'.legend.Edit, style(cols(`r(nrowsorcols)')) style(rows(0)) keepstyles } else { .`name'.legend.Edit, style(cols(0)) style(rows(`r(nrowsorcols)')) keepstyles _gm_log .`name'.legend.Edit, style(cols(0)) style(rows(`r(nrowsorcols)')) keepstyles } graph rename `name' `name', replace // This line does not fix the saved file if "`isasis'"=="" { di _n as txt "Note: To preserve in a saved graphics file the legend's row and column rearrangements" /// _n "made with the options -lrows()- and/or -lcols()-, specify the suboption -asis-" /// _n "for the {help saving_option:saving()} option or for the {help gr save:graph save} command." _n } } } if "`graphon'"=="" { set graphics `usergrset' global grc1leg2_set_graph } cap gr draw `name' // redraw graph if _rc > 0 { // Trap if the -gr draw- fails, presumably because of a bad legend local exitrc = _rc badlegend , lfrom(`lfrom') legendfrom(`"`legendfrom'"') exitrc(`exitrc') `trap' } if `"`saving'"' != `""' { cap noi gr save `"`name'"' `saving' if _rc>0 { di as err "-grc1leg2-'s {help saving_option:saving()} option has failed." if "`isasis'"=="" { di as err "Try specifying {help saving_option:saving(filename,asis)}" _n } exit _rc } gettoken fname : saving , parse(", ") if ("`lcols'"~="" | "`lrows'"~="") & "`isasis'"=="" { di as txt _n `"Warning: After using -grc1leg2- options -lrows()- or -lcols()-, a "live" .gph file"' /// _n "saved to disk may not retain those edits. To retain a changed row/column configuration," /// _n "try specifying {help saving_option:saving(filename,asis)}" _n } di as txt `"To view and verify the .gph file saved to disk, click {stata graph use `"`fname'"':here}."' } end /* End of main -grc1leg2 program */ program GetHoles, rclass syntax , lholes(numlist ascending >0) return local holes `lholes' end /* End of subroutine -GetHoles- */ program chkrowcol, rclass syntax , [lcols(string) lrows(string)] if "`lcols'"~="" & "`lrows'"~="" { di as err "Specify only one of the two options: lcols() lrows()" error 198 } if "`lcols'"~="" { local rc cols } else { local rc rows } local rl`rc' = real("`l`rc''") cap confirm integer number `rl`rc'' if _rc > 0 { di as err "The option -l`rc'()- requires an integer." exit 7 } return scalar nrowsorcols = `rl`rc'' end /* End of subroutine -chkrowcol- */ prog define make10dots , rclass syntax [, stage(integer -1)] if `stage' < 0 { di as err "Error in -grc1leg2-'s subroutine -make10dots-" exit 199 } local start = `stage' + 1 local end = `stage' + 10 foreach dot of numlist `start'/`end' { nois _dots `dot' 0 } global grc1leg2_stage `end' end /* End of subroutine -make10dots- */ program badlegend * syntax: badlegend , lfrom(`lfrom') legendfrom(`"`legendfrom'"') exitrc(`exitrc') `trap' syntax , lfrom(string) legendfrom(string) [notrap exitrc(integer 198)] di as err _n "The legend in graph #`lfrom', -`legendfrom'-, has too few keys" /// _n "or some keys have been suppressed by, for example, the -legend(order())- suboption." if "`trap'" == "notrap" { di as err _n "Captured return code _rc = {stata search r(`exitrc'),local:r(`exitrc');}" _n } else { graph drop _all serset clear set graph on di as err _n "Possible remedies include specifying the option -noautosize-" /// _n as err "or using a hidden auxiliary graph for the legend as demonstrated" /// _n as err "in Examples 3.10 of the help file {help grc1leg2##ex_3_10:here}." _n di as err _n "-grc1leg2- has cleared the graph space by executing" /// _n "-graph drop _all- and -serset clear- before exiting." /// _n `"For further information, see the discussion "' /// _n `"of "known issues" in {cmd:grc1leg2}'s help file {help grc1leg2##known:here}."' _n error `exitrc' } end /* End of subroutine -badlegend- */ prog define chk_legend, rclass * Check the legend selected for use in the combined graph * Calling command: * chk_legend `name' , lfrom(`lfrom') legendfrom(`"`legendfrom'"') `trap' `debug' syntax name , lfrom(integer) legendfrom(string) [trap debug] local name `namelist' local exitrc 0 if "`debug'"~= "" { local noi noisily di _n as txt `"DEBUG: Description of the legend's "class" using -classutil describe-:"' } cap `noi' classutil describe .`name'.graphs[`lfrom'].legend if _rc == 0 { local legend legend local legendclass .graphs[`lfrom'].legend local Nkeys `.`name'`legendclass'.keys.arrnels' local Nlabels `.`name'`legendclass'.labels.arrnels' local Nmap `.`name'`legendclass'.map.arrnels' local labelwidth `.`name'`legendclass'.labelwidth.val' local NminofKeysLabels = min(`Nkeys',`Nlabels') local NmaxofKeysLabels = max(`Nkeys',`Nlabels') } cap `noi' classutil describe .`name'.graphs[`lfrom'].plotregion1.atlegend if _rc == 0 { local atlegend atlegend local legend local legendclass .graphs[`lfrom'].plotregion1.atlegend local Nkeys `.`name'`legendclass'.keys.arrnels' local Nlabels `.`name'`legendclass'.labels.arrnels' local Nmap `.`name'`legendclass'.map.arrnels' local labelwidth `.`name'`legendclass'.labelwidth.val' local NminofKeysLabels = min(`Nkeys',`Nlabels') local NmaxofKeysLabels = max(`Nkeys',`Nlabels') } cap `noi' classutil describe .`name'.plotregion1.graph`lfrom'.plotregion1.graph1.legend if _rc == 0 { local combined combined local legend local atlegend local legendclass .plotregion1.graph`lfrom'.plotregion1.graph1.legend local Nkeys `.`name'`legendclass'.keys.arrnels' local Nlabels `.`name'`legendclass'.labels.arrnels' local Nmap `.`name'`legendclass'.map.arrnels' local labelwidth `.`name'`legendclass'.labelwidth.val' local NminofKeysLabels = min(`Nkeys',`Nlabels') local NmaxofKeysLabels = max(`Nkeys',`Nlabels') } if ("`legend'"=="legend") + ("`atlegend'"=="atlegend") + ("`combined'"=="combined") > 1 { // Type -combined- overrides type -atlegend-, which overrides type -legend- di as err "Legend types are " as res "`legend'" "`atlegend'" "`combined'" di as err "The legend is of more than one type. This error should never occur." local exitrc 198 } if ("`legend'"=="legend") + ("`atlegend'"=="atlegend") + ("`combined'"=="combined") ==0 { badlegend , lfrom(`lfrom') legendfrom(`"`legendfrom'"') `trap' // Double quotes added ver. 2.12 } // Hypothesis: // Resizing legend elements fails when the values of -styledex- vary over the keys // If so, detecting variation among the -styledex- values could be a way to trap // prior use of a legend(order())- option which prevents -gr draw- // from constructing the combined graph and thus crashes Stata and scrambles the sersets. tempname keystyledex local smallest . local largest -9999999999 foreach key of numlist 1/`Nkeys' { cap classutil describe .`name'`legendclass'.keys[`key'].pos.styledex if _rc==0 { local this_styledex `.`name'`legendclass'.keys[`key'].pos.styledex' mat define `keystyledex' = (nullmat(`keystyledex') , `this_styledex') local smallest = min(`this_styledex', `smallest') local largest = max(`this_styledex', `largest') local cnms `cnms' key`key' mat colnames `keystyledex' = `cnms' } } return matrix keystyledex = `keystyledex' return scalar smallest = `smallest' return scalar largest = `largest' return local SmlstEqLrgst = `smallest' == `largest' return local legendtype `legend'`atlegend'`combined' return local legendclass `legendclass' return local NkeysEqNlabels = (`Nkeys' == `Nlabels') return local NminofKeysLabels `NminofKeysLabels' return local NmaxofKeysLabels `NmaxofKeysLabels' foreach lcl in Nkeys Nlabels Nmap { confirm integer number ``lcl'' return scalar `lcl' = ``lcl'' } confirm number `labelwidth' return scalar labelwidth = `labelwidth' if `exitrc'> 0 & "`trap'"=="" { error `exitrc' } end /* End of subroutine chk_legend */ prog define orig2newsize, rclass * Subroutine to allow option -lmsize- to accept all size specifications in -help size- * Added in version 2.25, 10Oct2023 // Size specifications for the marker symbols that appear in legends accept any of the size types // listed in -help size-. (i.e. #pt, #in, #cm, #rs, #, *#), but also the size designations: // vtiny, tiny, vsmall, small, medsmall, medium, medlarge, large, vlarge, huge, vhuge, ehuge. syntax , [lmsize(string) origsize(real -99) debug] local lmsize = subinstr("`lmsize'"," ","",.) if "`lmsize'"=="" { local lmsize *1 } cap confirm number `lmsize' // If user specifies a positive numeric value, it is returned if _rc==0 { local newsize = real("`lmsize'") if `newsize' > 0 { return scalar newsize = real("`lmsize'") } else { di as err "User has specified option -lmsize- as: -`lmsize'-" exit 198 } exit } // Assure that -lmsize- contains one and only one of the defined // alphanumeric character strings listed in -help size- local Nalpha = 0 foreach alpha in /// * /// pt in cm rs /// vtiny tiny vsmall small medsmall medium medlarge large vlarge huge vhuge ehuge { if "`debug'" ~= "" di as txt "-alpha- is: " as res "`alpha'" if strpos("`lmsize'","`alpha'") > 0 { // Get the rest of -lmsize- after extracting -alpha- local notalpha = subinstr("`lmsize'","`alpha'","",.) cap confirm number `notalpha' // sizetype is one of pt, in, cm, rs or * if _rc== 0 { local sizetype "`alpha'" local numpart `notalpha' local Nalpha = `Nalpha' + 1 } // sizetype is one of vtiny, tiny, ... , ehuge else if "`notalpha'"=="" { if inlist("`alpha'", "pt", "in", "cm", "rs", "*") { di as err "An -lmsize- specification containing any of pt, in, cm, rs or * must include a number" di as err "Here, user has specified option -lmsize- as: -`lmsize'-" exit 198 } local sizetype "`alpha'" local numpart local Nalpha = `Nalpha' + 1 } } } if `Nalpha'~=1 { di as err "Invalid -lmsize- option: -`lmsize'-" exit 198 } if "`sizetype'"=="*" { cap assert "`lmsize'"== "`sizetype'`numpart'" } else { cap assert "`lmsize'"== "`numpart'`sizetype'" } if _rc > 0 { di as err "Invalid -lmsize- option: -`lmsize'-" exit 198 } if "`sizetype'"=="*" { return local newsize = `origsize' * real("`numpart'") } else { return local newsize = "`lmsize'" } return local lmsize `lmsize' return local sizetype `sizetype' return scalar numpart = real("`numpart'") return scalar origsize = real("`origsize'") end /* End of program -orig2newsize- */ exit * Version 1.0.5 (21feb2015): renamed for packaging with AIDSCost (no other changes) * Version 1.1.0 (30mar2016): add the -xtob1title- and -xtitlefrom()- options * Version 1.1.1 (1apr2016): make -xtitlefrom()- imply the -xtob1title- option * Version 1.1.2 (8apr2016): Attempt to add a size option to the legend * The value of the option -lsize- appears in the graph editor under * legend/properties/labels/size, but has no effect on the actual size of the labels * Version 1.1.3 (11apr2016): Incorporates Derek Wagner's suggestion for how * to add a size option to the legend (Subsequently deprecated) * Version 1.1.4 (12apr2016): Fixes bug in xtitlefrom() option * Version 1.2 (11nov2019): Implement options -ytol1title- and -maintotoptitle- * Version 1.3 (23Jan2021): Fix the option -lsize- and rename it -LABSize- * Add the legend options: SYMXsize, SYMYsize, LCOLS, LROWS, LHoles, * LTItle, LTSize, LSUBTItle, LSUBTSize, LXOffset, LYOffset, LOFF, * Version 1.31 (29Jan2021): Add options XTSize, YTSize, MTSize * Version 1.32 (29Jan2021): Add error trap when -legendfrom- graph has no legend (lines 61, 72) * Version 1.33 (12Mar2021): Add options -y2tor1title- & -y2titlefrom(name)- and -y2tsize- to move and re-size titles on the right y2-axis * Version 1.40 (24Mar2021): Enable legend relocation from a -gr combine- or a -gr,by()- graph * Version 1.41 (26Mar2021): Fix bug in options -lcols()- and -lrows()- * Version 1.42 (29Mar2021): Add the -hidelegendfrom- option * Version 1.50 (4Apr2021): Again attempt to fix the bug in options -lcols()- and -lrows()- * Version 1.60 (15Jun2021): Accommodate the graph display options in response to the issue raised here: * https://www.statalist.org/forums/forum/general-stata-discussion/general/1610172-grc1leg-ignoring-aspect-ratio * Version 2.0 (3Mar2022): Revamp to allow scaling of all legend elements with new -legscale()- * Set default value of -legscale()- as a function of the number of panels in the combined graph (lines 576-594) * Allow user to override the default scaling of all legend elements. * Fix bug in -saving()- option in ver. 1.60 where saved .gph file did not incorporate -grc1leg2- edits. * When executing option -saving()-, display a clickable message enabling user to view and validate the saved .gph file * Add debug options -debug- and -notrap- (undocumented) and -noautosize-. Change dots option to optionally on. * Version 2.01 (4Mar2022): Made program recursive by adding the modifer "else" at the beginning of lines 274, 285. * Version 2.02 (4Mar2022): Improve error trapping with -badlegend- subroutine. Subroutine -badlegend- sets graph on before exiting. * Version 2.10 (12Mar2022): Add several error traps to attempt to detect and then to avoid or politely exit on encountering a "bad" legend. * Use subroutine -chk_legend- to check existence of a legend and pull several legend attributes from -classutil describe-. * Version 2.11 (13Mar2022): Incomplete legend only disables marker resizing (line 557), not resizing of labels or symbols. * Alter warning and error messages accordingly. Add link to "known issues" when badlegend exits with error. * Version 2.12 (22Apr2022): Add double compound quotes around `"`legendfrom'"' wherever it appears. * Replace = word("`anything'",1) with -gettoken- in line 96 * Version 2.13 (30May2022): Remove error-generating -holes()- option on -gr display- command in line 139. * Version 2.20 (15Jun2022): Fix option -mtsize()-. For backward compatibility, keep option -maintitlefrom()-. * Add options -mainfrom()-, -subtosubtitle-, -subfrom()-, -stsize()- & -notetonote-, -notefrom()-, -ntsize()- * Version 2.21 (15Nov2022): Remove the trap requiring -legscale()- options to be absolute numbers * or multiplicative expressions. (Commented out lines 561-583) Allows Stata's -graph- engine * to trap errors in the -size()- option and allows the full range of sizing options specified in -help size-. * Version 2.22 (1Dec2022): Fabio Tufano found that -grc1leg2- would crash when attempting to rescale marker symbols, * if the component graphs have no markers. For example -graph pie- and -graph bar- have no markers. * So in line 623 , we only trap an error if _rc ~= 4018. See help r(4018). * Also add column names to the debug matrix -keystyledex- in line 868. * Version 2.23 (10Dec2022): Add code so that option -hidelegendfrom- is more likely to suppress the display of a blank panel * in place of the plot named by -legendfrom()-. Rarely helps. * Unnecessary when the hidden panel is that for the last named graph, and user configures the panel layout with -rows()- &/or -cols()-. * When all panels are in one row (i.e. -rows(1)-) or the panel to be hidden is one of only three graphs, * the -hidelegendfrom- option successfully suppresses the display of the blank panel regardless of its sequence in the list of graphs. * Best if the user always places the name of the hidden panel last in the list of graphs to be combined. * Version 2.24 (14May2023): NminofKeysLabels substituted for Nkeys in line 675. * Add _gm_edit ... fill_if_undrawn.set_false in line 254 * Version 2.25 (10Oct2023): Revise legend re-sizing. Add the subroutine -orig2newsize-. * -grc1leg2- no longer fails when the -order()- suboption has been used * in the -legendfrom()- graph to suppress one or more legend keys. * Version 2.26 (4Nov2023): Identical to -grc1leg2.ado- ver. 2.25. Only help and associated files have changed. * TODO: Explore whether titles acceptable by -gr combine- * (e.g. main, sub and note) can be combined with, replaced or appended to * titles transferred from a component graph??? * Can we exploit the -merged explicit- functionality? See "help repeated options", * especially note the section on -prefix- and -suffix- options. * Options outside the legend are of two kinds (all seem to work in mem and gph graphs): * 1. Options passed to -gr combine- * xcommon, ycommon, holes() * xsize(), ysize(), scheme() * 2. Options implemented in -grc1leg2- (but are outside the legend): * ring(), pos() * legendfrom(), hidelegendfrom * lxoffset, lyoffset, xtob1title, ytol1title, y2tor1title * Options inside the legend are of two kinds: * 3. Options that work in both memory and saved files: * labsize() for all labels * lmsize() for all markers * symxsize() and symysize() for all symbols * ltsize(), lsubtsize() * legscale() to set default for all of above * lholes() * * 4. Options that work for memory files BUT ARE LOST IN SAVED FILES * lrows(), lcols() * a. Best work-around is to apply these options in component graph, * so -grc1leg2- need never rearrange the rows and columns of a legend * b. Alternative is to save with the option -asis- which preserves the edits, * but prevents future editing. * Sources on Stata class programming for graphics: * help class * help classman * viewsource grc1leg.ado * viewsource legend_g.class * viewsource legendstyle.class * viewsource loggraph_g.class * viewsource graph_g.class * viewsource global_g.class * viewsource graphsize.class * viewsource gsize.class * viewsource numstyle.class * viewsource relsize.class * viewsource sizetype.class * viewsource symbolsize.class * viewsource codestyle.class * viewsource style.class * viewsource _gm_log.ado * viewsource _fr_legend_parse_and_log.ado * viewsource gr_current.ado