Announcement

Collapse
No announcement yet.
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Trouble calling global containing two loop macros

    Dear Stata forum,

    I have a dataset compiled of experimental objectives (e.g. A00), analytes of interest, and experimental conditions to compare (sample_delay/sample_delay1). I have wrote a nested loop for analyte (NfL) of interest to run for every Objective (A00). I have generated global macros to store graph labelling options which will be dependent on the Objective and Analyte of interest (they contain `obj' and `analyte' within the name). The idea is that I would have these in an external do file that would run at the start of the do file. I have cut down the code to produce only a spaghetti plot (using xtline command) for one analyte and one objective.
    (search xtline to install package)

    Code:
    global A00NfLy="0 80" // NfL y-axis range
    global A00NfLx="0 80" // NfL x-axis range
    global A00NfLxlab="0(20)80" // NfL x-axis labels $`anaylte'xlab
    global A00xlab = "1 5 8 12" // x-axis labels for xtline spagetti plots
    
    
    foreach obj in A00  {
    
    
        foreach analyte of varlist NfL  {
    
            preserve
                    drop if Objective!="`obj'"
                    drop if Processingdelay==4
    
                xtline `analyte' , i(ID_visit) t(sample_delay1)  ///
                    overlay legend(off) aspectratio(1) ///
                    xlabel("$`obj'xlab", valuelabel) ///
                    ylabel("$`obj'`analyte'ylab") yscale(range("$`obj'`analyte'y"))    
                    name(spag_ALL, replace)
                        graph save "`analyte'_`obj'_ALL_Spag plot.gph" , replace
            
            restore
        }
    }
    The error I get is:

    Code:
    range() invalid -- invalid numlist
    r(121);
    I think my issue is when combining both loop macros to try and call the global A00NfLy and A00NfLylab. When I try and break it down each:

    Code:
    . local obj = "A00"
    
    . local analyte = "NfL"
    
    . di "$`obj'xlab"
    1 5 8 12
    
    . di "$`obj'`analyte'y"
    NfLy
    So calling global $A00xlab works but $A00NfLylab does not. Could someone help tell me if I have an issue with my use of quotes in this situation??? I need to be able to quickly format all the graphs consistently for each analyte/objective combo.

    Thanks,
    Lauren

    Code:
    * Example generated by -dataex-. For more info, type help dataex
    clear
    input str22 SampleID str7 ID_visit float disease_grp byte Processingdelay str5 Objective double NfL str7 sample_delay long sample_delay1
    "001-000.A.0.0.Ven_P"    "001-000" 0 0 "A00" 12.8232099637598 "Ven_P_0"  8
    "001-000.A.0.0.Ven_S"    "001-000" 0 0 "A00" 12.4721561722339 "Ven_S_0" 12
    "001-000.A.0.0.Cap_P"    "001-000" 0 0 "A00" 23.7322803122459 "Cap_P_0"  1
    "001-000.A.0.0.Cap_S"    "001-000" 0 0 "A00" 15.3790686393164 "Cap_S_0"  5
    "002-000.A.0.0.Ven_P"    "002-000" 1 0 "A00" 17.4525136837855 "Ven_P_0"  8
    "002-000.A.0.0.Ven_S"    "002-000" 1 0 "A00" 16.6536494463149 "Ven_S_0" 12
    "002-000.A.0.0.Cap_P"    "002-000" 1 0 "A00" 19.5717694531864 "Cap_P_0"  1
    "002-000.A.0.0.Cap_S"    "002-000" 1 0 "A00" 18.4071787272528 "Cap_S_0"  5
    "003-000.A.0.0.Ven_P"    "003-000" 0 0 "A00" 14.9352800760731 "Ven_P_0"  8
    "003-000.A.0.0.Ven_S"    "003-000" 0 0 "A00" 13.3980698197175 "Ven_S_0" 12
    "003-000.A.0.0.Cap_P"    "003-000" 0 0 "A00" 16.8338247887175 "Cap_P_0"  1
    "003-000.A.0.0.Cap_S"    "003-000" 0 0 "A00" 13.8783695698378 "Cap_S_0"  5
    "004-000.A.0.0.Ven_P"    "004-000" 1 0 "A00" 23.4103340003442 "Ven_P_0"  8
    "004-000.A.0.0.Ven_S"    "004-000" 1 0 "A00" 21.7338359178511 "Ven_S_0" 12
    "004-000.A.0.0.Cap_P"    "004-000" 1 0 "A00" 23.4523320833572 "Cap_P_0"  1
    "004-000.A.0.0.Cap_S"    "004-000" 1 0 "A00" 21.6395120711326 "Cap_S_0"  5
    "005-000.A.0.0.Ven_P"    "005-000" 0 0 "A00"  7.0198512335302 "Ven_P_0"  8
    "005-000.A.0.0.Ven_S"    "005-000" 0 0 "A00"  6.9046966821466 "Ven_S_0" 12
    "005-000.A.0.0.Cap_P"    "005-000" 0 0 "A00" 7.01208783823432 "Cap_P_0"  1
    "005-000.A.0.0.Cap_S"    "005-000" 0 0 "A00" 5.11242430205437 "Cap_S_0"  5
    "006-000.A.0.0.Ven_P"    "006-000" 2 0 "A00" 43.5597530377516 "Ven_P_0"  8
    "006-000.A.0.0.Ven_S"    "006-000" 2 0 "A00" 43.9181808077223 "Ven_S_0" 12
    "006-000.A.0.0.Cap_P"    "006-000" 2 0 "A00" 45.5521790956671 "Cap_P_0"  1
    "006-000.A.0.0.Cap_S"    "006-000" 2 0 "A00" 45.1104314938279 "Cap_S_0"  5
    "007-000.A.0.0.Ven_P"    "007-000" 1 0 "A00" 11.3301091332395 "Ven_P_0"  8
    "007-000.A.0.0.Ven_S"    "007-000" 1 0 "A00" 8.95780136200477 "Ven_S_0" 12
    "007-000.A.0.0.Cap_P"    "007-000" 1 0 "A00" 8.81102098195839 "Cap_P_0"  1
    "007-000.A.0.0.Cap_S"    "007-000" 1 0 "A00" 8.69714684579653 "Cap_S_0"  5
    "008-000.A.0.0.Ven_P"    "008-000" 0 0 "A00" 11.7017873220084 "Ven_P_0"  8
    "008-000.A.0.0.Ven_S"    "008-000" 0 0 "A00" 11.4152418460061 "Ven_S_0" 12
    "008-000.A.0.0.Cap_P"    "008-000" 0 0 "A00" 26.4188411190773 "Cap_P_0"  1
    "008-000.A.0.0.Cap_S"    "008-000" 0 0 "A00"  12.288604918731 "Cap_S_0"  5
    "009-000.A.0.0.Ven_P"    "009-000" 1 0 "A00" 32.4743054730123 "Ven_P_0"  8
    "009-000.A.0.0.Ven_S"    "009-000" 1 0 "A00"   33.86219920572 "Ven_S_0" 12
    "009-000.A.0.0.Cap_P"    "009-000" 1 0 "A00"  32.074160325192 "Cap_P_0"  1
    "009-000.A.0.0.Cap_S"    "009-000" 1 0 "A00" 30.8375761808333 "Cap_S_0"  5
    "010-000.A.0.0.Ven_P"    "010-000" 2 0 "A00" 30.0730098499468 "Ven_P_0"  8
    "010-000.A.0.0.Ven_S"    "010-000" 2 0 "A00" 27.4222733061866 "Ven_S_0" 12
    "010-000.A.0.0.Cap_P"    "010-000" 2 0 "A00" 32.5054229063763 "Cap_P_0"  1
    "010-000.A.0.0.Cap_S"    "010-000" 2 0 "A00" 28.5113568162498 "Cap_S_0"  5
    "011-000.A.0.0.Ven_P"    "011-000" 1 0 "A00"      27.86314247 "Ven_P_0"  8
    "011-000.A.0.0.Ven_S"    "011-000" 1 0 "A00"      24.45444406 "Ven_S_0" 12
    "011-000.A.0.0.Cap_P"    "011-000" 1 0 "A00"      28.97417553 "Cap_P_0"  1
    "012-000.A.0.0.Ven_P"    "012-000" 2 0 "A00"      40.33341793 "Ven_P_0"  8
    "012-000.A.0.0.Ven_S"    "012-000" 2 0 "A00"        39.057494 "Ven_S_0" 12
    "012-000.A.0.0.Cap_P"    "012-000" 2 0 "A00"      60.46692253 "Cap_P_0"  1
    "012-000.A.0.0.Cap_S"    "012-000" 2 0 "A00"      45.38509833 "Cap_S_0"  5
    "013-000.A.0.0.Ven_P"    "013-000" 0 0 "A00"      14.65149413 "Ven_P_0"  8
    "013-000.A.0.0.Ven_S"    "013-000" 0 0 "A00"      14.71016333 "Ven_S_0" 12
    "013-000.A.0.0.Cap_P"    "013-000" 0 0 "A00"       16.6604293 "Cap_P_0"  1
    "013-000.A.0.0.Cap_S"    "013-000" 0 0 "A00"      16.80206413 "Cap_S_0"  5
    "014-000.A.0.0.Ven_P"    "014-000" 1 0 "A00"      8.595706484 "Ven_P_0"  8
    "014-000.A.0.0.Ven_S"    "014-000" 1 0 "A00"      7.744093421 "Ven_S_0" 12
    "014-000.A.0.0.Cap_P"    "014-000" 1 0 "A00"      8.839780168 "Cap_P_0"  1
    "014-000.A.0.0.Cap_S"    "014-000" 1 0 "A00"      7.564593798 "Cap_S_0"  5
    "015-000.A.0.0.Ven_P"    "015-000" 2 0 "A00"      59.06629443 "Ven_P_0"  8
    "015-000.A.0.0.Ven_S"    "015-000" 2 0 "A00"      60.55670359 "Ven_S_0" 12
    "015-000.A.0.0.Cap_P"    "015-000" 2 0 "A00"      71.71274031 "Cap_P_0"  1
    "015-000.A.0.0.Cap_S"    "015-000" 2 0 "A00"      65.57058887 "Cap_S_0"  5
    "016-000.A.0.0.Ven_P"    "016-000" 2 0 "A00"      44.06225284 "Ven_P_0"  8
    "016-000.A.0.0.Ven_S"    "016-000" 2 0 "A00"      39.95055385 "Ven_S_0" 12
    "016-000.A.0.0.Cap_P"    "016-000" 2 0 "A00"      45.59128395 "Cap_P_0"  1
    "016-000.A.0.0.Cap_S"    "016-000" 2 0 "A00"      46.03946518 "Cap_S_0"  5
    "017-000.A.0.0.Ven_P"    "017-000" 2 0 "A00"      60.41304485 "Ven_P_0"  8
    "017-000.A.0.0.Ven_S"    "017-000" 2 0 "A00"      64.32861934 "Ven_S_0" 12
    "017-000.A.0.0.Cap_P"    "017-000" 2 0 "A00"      69.10275094 "Cap_P_0"  1
    "017-000.A.0.0.Cap_S"    "017-000" 2 0 "A00"      64.41109851 "Cap_S_0"  5
    "018-000.A.0.0.Ven_P"    "018-000" 0 0 "A00"      24.98245193 "Ven_P_0"  8
    "018-000.A.0.0.Ven_S"    "018-000" 0 0 "A00"      23.97155831 "Ven_S_0" 12
    "018-000.A.0.0.Cap_P"    "018-000" 0 0 "A00"        27.019583 "Cap_P_0"  1
    "018-000.A.0.0.Cap_S"    "018-000" 0 0 "A00"      23.88794076 "Cap_S_0"  5
    "019-000.A.0.0.Ven_P"    "019-000" 0 0 "A00"      5.670180033 "Ven_P_0"  8
    "019-000.A.0.0.Ven_S"    "019-000" 0 0 "A00"      5.960822594 "Ven_S_0" 12
    "019-000.A.0.0.Cap_P"    "019-000" 0 0 "A00"      8.095781335 "Cap_P_0"  1
    "019-000.A.0.0.Cap_S"    "019-000" 0 0 "A00"      7.457711532 "Cap_S_0"  5
    "020-000.A.0.0.Ven_P"    "020-000" 0 0 "A00"      5.689857002 "Ven_P_0"  8
    "020-000.A.0.0.Ven_S"    "020-000" 0 0 "A00"      5.737410508 "Ven_S_0" 12
    "020-000.A.0.0.Cap_P"    "020-000" 0 0 "A00"      5.739657212 "Cap_P_0"  1
    "020-000.A.0.0.Cap_S"    "020-000" 0 0 "A00"      5.882888073 "Cap_S_0"  5
    "021-000.A.0.0.Ven_P"    "021-000" 0 0 "A00"      4.762094851 "Ven_P_0"  8
    "021-000.A.0.0.Ven_S"    "021-000" 0 0 "A00"      4.828288344 "Ven_S_0" 12
    "021-000.A.0.0.Cap_P"    "021-000" 0 0 "A00"      5.421844346 "Cap_P_0"  1
    "021-000.A.0.0.Cap_S"    "021-000" 0 0 "A00"      5.927572933 "Cap_S_0"  5
    "022-000.A.0.0.Ven_P"    "022-000" 0 0 "A00"      7.046261148 "Ven_P_0"  8
    "022-000.A.0.0.Ven_S"    "022-000" 0 0 "A00"      6.870698082 "Ven_S_0" 12
    "022-000.A.0.0.Cap_P"    "022-000" 0 0 "A00"      7.295052204 "Cap_P_0"  1
    "024-000.A.0.0.Ven_P"    "024-000" 2 0 "A00"      19.86255374 "Ven_P_0"  8
    "024-000.A.0.0.Ven_S"    "024-000" 2 0 "A00"      19.54173634 "Ven_S_0" 12
    "024-000.A.0.0.Cap_P"    "024-000" 2 0 "A00"      17.36187772 "Cap_P_0"  1
    "024-000.A.0.0.Cap_S"    "024-000" 2 0 "A00"      17.60405891 "Cap_S_0"  5
    "025-000.A.0.0.Ven_P"    "025-000" 2 0 "A00"      45.06855239 "Ven_P_0"  8
    "025-000.A.0.0.Ven_S"    "025-000" 2 0 "A00"      46.57295806 "Ven_S_0" 12
    "025-000.A.0.0.Cap_P"    "025-000" 2 0 "A00"      48.43747505 "Cap_P_0"  1
    "025-000.A.0.0.Cap_S"    "025-000" 2 0 "A00"      45.12223331 "Cap_S_0"  5
    "019-001.B.1.a.Ven_P"    "019-001" 0 0 "B1a"      9.181497969 "Ven_P_0"  8
    "019-001.B.1.a.Ven_P 3d" "019-001" 0 3 "B1a"      8.638854088 "Ven_P_3"  9
    "019-001.B.1.a.Cap_P"    "019-001" 0 0 "B1a"      11.04319866 "Cap_P_0"  1
    "019-001.B.1.a.Cap_P 3d" "019-001" 0 3 "B1a"      8.747211213 "Cap_P_3"  2
    "026-000.B.1.a.Ven_P"    "026-000" 1 0 "B1a" 11.6308265770827 "Ven_P_0"  8
    "026-000.B.1.a.Ven_P 4d" "026-000" 1 4 "B1a" 9.43628599116204 "Ven_P_4" 10
    end
    label values disease_grp status
    label def status 0 "Controls", modify
    label def status 1 "PreHD", modify
    label def status 2 "Manifest HD", modify
    label values sample_delay1 sample_delay1
    label def sample_delay1 1 "Cap_P_0", modify
    label def sample_delay1 2 "Cap_P_3", modify
    label def sample_delay1 5 "Cap_S_0", modify
    label def sample_delay1 8 "Ven_P_0", modify
    label def sample_delay1 9 "Ven_P_3", modify
    label def sample_delay1 10 "Ven_P_4", modify
    label def sample_delay1 12 "Ven_S_0", modify

  • #2
    The error message is coming from the -xtline- command, and specifically with the -ylabel()- and -yscale()- options. Those options expect their (first) argument to be a numlist. When you have locals nested within globals, you need to use curly braces to guide Stata to know what the proper inclusion is. So you need:
    Code:
    ...
    ylabel("${`obj'`analyte'ylab}") yscale(range("${`obj'`analyte'y}"))  ///  
    ...
    Note that I have also added /// to the end of that part of the -xtline- command. Without that, once you fix the -ylabel()- and -yscale()- options, Stata will break when it sees the next line with -name(...)- and tell you that there is no command called name.

    Another problem is that, at least in the code you show, you never actually define global macro A00NfLylab. So you will need to include that as well.

    Finally, I will just remark that the use of global macros is an inherently unsafe coding practice that should be avoided except in the exceedingly rare circumstances where there is no available alternative. This is not such a case. There is no reason you cannot use local macros to hold this same information. You can even put those local macros in another do-file. To activate those locals in the current do-file, instead of -run-ning the other do-file, you -include- it. (See -help include-, Stata's most underrated command.) In this instance, an added benefit of doing this with local rather than global macros is that with local macros there is no ambiguity about what is nested within what and what is concatenated where, so you don't need to use, or think about, disambiguating with curly braces.
    Last edited by Clyde Schechter; 11 Apr 2023, 10:45.

    Comment


    • #3
      Originally posted by Clyde Schechter View Post
      The error message is coming from the -xtline- command, and specifically with the -ylabel()- and -yscale()- options. Those options expect their (first) argument to be a numlist. When you have locals nested within globals, you need to use curly braces to guide Stata to know what the proper inclusion is. So you need:
      Code:
      ...
      ylabel("${`obj'`analyte'ylab}") yscale(range("${`obj'`analyte'y}")) ///
      ...
      Note that I have also added /// to the end of that part of the -xtline- command. Without that, once you fix the -ylabel()- and -yscale()- options, Stata will break when it sees the next line with -name(...)- and tell you that there is no command called name.

      Another problem is that, at least in the code you show, you never actually define global macro A00NfLylab. So you will need to include that as well.

      Finally, I will just remark that the use of global macros is an inherently unsafe coding practice that should be avoided except in the exceedingly rare circumstances where there is no available alternative. This is not such a case. There is no reason you cannot use local macros to hold this same information. You can even put those local macros in another do-file. To activate those locals in the current do-file, instead of -run-ning the other do-file, you -include- it. (See -help include-, Stata's most underrated command.) In this instance, an added benefit of doing this with local rather than global macros is that with local macros there is no ambiguity about what is nested within what and what is concatenated where, so you don't need to use, or think about, disambiguating with curly braces.
      Thanks so much for this thoughtful response. The -include command and switching my globals to locals has worked perfectly! I am relatively new to coding so its very useful to understand better when to use local versus global. Well spotted on my /// typo from pasting incomplete code!

      Comment

      Working...
      X