Announcement

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

  • How to create a saving option within a program

    Hi,

    I am writing a program that creates some additional variables in the data set. I would like to provide an option in this program to save the data set with those additional variables.

    I would like to do several things:

    1. Provide an option to save the data set
    2. Allow the user to specify a name for the data set
    3. Allow the program to replace the data set (in case the user runs the program more than once).

    Ideally, the program would look something like:
    syntax varlist(min=3), [savedata(string)]


    A toy program could be:

    Code:
    program define test, rclass
    
    syntax , [savedata(string)]
    
    sysuse auto, clear
    
    gen mpg2 = mpg2
    gen turn2 = turn
    gen price2=price

    I would like to save the data set that also now contains these three newly generated variables.


    Any help is much appreciated.




  • #2
    Code:
    *! Version 1.0 May 20, 2022
    cap prog drop testsave
    program define testsave, rclass
    
        syntax , [savedata(string) REPLACE ]
    
        gen mpg2 = mpg
        gen turn2 = turn
        gen price2=price
    
        qui save "`savedata'", `replace'
    
    end
    
    * test
    sysuse auto, clear
    testsave, savedata(myfile)
    Regards
    --------------------------------------------------
    Attaullah Shah, PhD.
    Professor of Finance, Institute of Management Sciences Peshawar, Pakistan
    FinTechProfessor.com
    https://asdocx.com
    Check out my asdoc program, which sends outputs to MS Word.
    For more flexibility, consider using asdocx which can send Stata outputs to MS Word, Excel, LaTeX, or HTML.

    Comment


    • #3
      Hi Attaullah,

      Many thanks for your help.

      I have tried the code, it does save the data as 'myfile'. However, when I run the following code a second time:

      Code:
      sysuse auto, clear
      testsave, savedata(myfile)
      I receive an error that says 'myfile' already exists. I am not sure if the
      Code:
      replace
      option is working?

      Comment


      • #4
        since you did not use the "replace" option, there is no way to tell whether it is working, try adding
        Code:
        , replace
        after "myfile" within the parens

        Comment


        • #5
          Hi Rich,

          Thank you for your message.

          I tried with the "replace" option, however it creates a file called "myfile, replace.dta".

          So far, I have run:

          Code:
          cap prog drop testsave
          program define testsave, rclass
          
              syntax , [savedata(string) REPLACE ]
          
              gen mpg2 = mpg
              gen turn2 = turn
              gen price2=price
          
              qui save "`savedata'", `replace'
          
          end
              
          // Run the program the first time
          sysuse auto, clear
          testsave, savedata(myfile)
              
          // Run the program a second time
          sysuse auto, clear
          testsave, savedata(myfile, replace)
          The second time I run the 'testsave' program it creates a stata data set called "myfile, replace.dta".

          Any help is much appreciated =)

          Comment


          • #6
            You want

            Code:
            testsave, savedata(myfile) replace
            and you want to take your time to fully understand why you want the syntax that I have suggested and why your syntax did not produce the desired result.


            I would probably add a couple of lines of code to check for potential errors and prevent unintended results like the one you describe in #5. More generally, I would split the process into two steps:

            Code:
            create_new_variables
            save ...

            Edit: As an alternative, you can mimic Stata's standard saving() option:

            Code:
            program testsave
                version 17
                
                syntax [ , SAVING(string asis) ]
                
                ...
                
                if (`"`saving'"' != "") {
                    save `saving'
                }
            end
            This allows syntax as in #5. Actually, it allows all options that save allows. In my view, it is bad (or at least lazy) programming style to let save check for errors only at the very end; others might have a different opinion.
            Last edited by daniel klein; 20 May 2022, 03:31.

            Comment


            • #7
              Hi Daniel,

              Many thanks for your help. It certainly works! I have tried to do the same things but using two separate programs. The first program does the calculations then the second program does the saving of the data set. The problem is that the second program (i.e., 'testsave2') does not recognise the option called 'saving' (please see code below). The result is that a data set is saved in my working directory but it does not have a file name. In other words, it is not called "data.dta" (it is just called ".dta" without a name).

              It seems as though the second program (i.e., testsave2) is not able to find the option called 'saving' - is there a way to make these programs "communicate" the option called 'saving'?

              Code:
              cap prog drop testsave
              program testsave, rclass
                  version 17
                  
                  syntax [ , saving(string asis) ]
                  
                  gen mpg2 = mpg
                  gen turn2 = turn
                  gen price2 = price
                  
                  frames put mpg2 turn2 price2, into(otherframe)
                  frames otherframe {
                      if (`"`saving'"' != "") {
                          testsave2
                      }
                  }
                  frames drop otherframe
              end
                  
                  
              cap prog drop testsave2
              program testsave2, rclass
                  local pathdata = "`c(pwd)'" + "/"
                  save `pathdata'`saving'
              end
                  
                  
              sysuse auto, clear
              
              testsave, saving(data)

              As always, any help is much appreciated =)
              Last edited by Matthew Smith Stata; 20 May 2022, 09:18.

              Comment


              • #8
                I am having a hard time figuring out what you really want to do here and why. Why are you now introducing frames into your program? Why would you want to write a program that saves a dataset in the first place? That program already exists; it is called save.

                More generally, I think you should take a step back. You seem confused about a lot of the fundamentals. Read [U] 18 Programming Stata, recreate the examples and make sure you understand every step. Then come back and continue with whatever you are trying to achieve here.

                Comment


                • #9
                  Hi Daniel,

                  Thank you for the advice. I understand the fundamentals. This "problem" is a snippet of a much larger program that is being written and so has been isolated from the context. Nevertheless, the problem remains clear with this toy example.

                  What I wanted to do has been achieved (i.e., by using global macros).

                  Code:
                  cap prog drop testsave
                  program testsave, rclass
                      version 17
                      
                      syntax [ , saving(string asis) ]
                      
                      gen mpg2 = mpg
                      gen turn2 = turn
                      gen price2 = price
                      
                      global datapath "`c(pwd)'"
                      global pathdata "${datapath}/"
                      
                      global savename "`saving'"
                      
                      frames put mpg2 turn2 price2, into(otherframe)
                      frames otherframe {
                          if (`"`saving'"' != "") {
                              testsave2
                          }
                      }
                      frames drop otherframe
                  end
                      
                      
                  cap prog drop testsave2
                  program testsave2, rclass
                      save $pathdata$savename
                  end
                      
                      
                  sysuse auto, clear
                  
                  testsave, saving(data)

                  Thank you for your help.

                  Comment


                  • #10
                    No offense, but if you think you need global macros here, then you did not understand the fundamentals, such as local macros, passing arguments to programs, parsing arguments, and much more. If what you have works for you, great, but using this programming style in larger systems is going to get you into trouble sooner or later. I am not trying to be mean or show off; I am trying to help here but I think you would be better off with some written material. I am leaving it at this.

                    Comment

                    Working...
                    X