Data Folders

Hi,

I am wondering if it is possible to have the root:'s contents (waves and global variables) copied to a subfolder within root:, without copying other subfolders within root:.

For example, root: contains wave1, wave2, var1, var2, var3, and subfolder root:sub. Root:sub contains wave3, wave4, var4, and var5. Is it possible to create a new subfolder within root: called root:copyfolder which contains copies of wave1, wave2, var1, var2, and var3 so that the original wave1, wave2, var1, var2, and var3 are unaffected?

Also, is it a bad idea to create global variables of the same name, even if they are in separate datafolders?

Thank you.
for copying waves you can use something like this:

function CopyWaves()
   
    string TheWaves = Wavelist("*", ";", "")
    string CurrentWave
    NewDataFolder/O Copies
   
    variable i
    do
        CurrentWave = StringFromList(i, TheWaves)          
        if(strlen(CurrentWave)==0)  // no more waves
            break  
        endif
 
        wave w= $CurrentWave
        duplicate w root:copies:$CurrentWave
        i+=1
       
    while(1)
end


for the variables you'll need to implement e.g.

VariableList("*", ";", 4)


in the above code.

Ken wrote:
Also, is it a bad idea to create global variables of the same name, even if they are in separate datafolders?

That is really a question of style, and the use you want to make of the global variables. One of the reasons we created Data Folders is to allow you to segregate data that have the same names. We envision waves resulting from multiple experimental runs, where the wave names are all the same but put into data folders with names like Run1, Run2, etc.

I also frequently create a data folder with information about a control panel or graph that is the object of some code. I create a data folder named to refer to the graph, then I can have the same-named variables and waves but which refer to information in the various different graphs.

So that was a really long-winded way to say "No, it's fine".

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
Thank you. That was actually what I had in mind when I decided to introduce data folders into my code. I wanted to be able to duplicate all the current waves and global variables on the click of a button, so that before conducting new experimental runs, I would be able to save the current run for future use. Any changes to the current data and graph would not affect the state of the copied waves and global variables, which are stored in a separate data folder.

Below is my current code.

function DuplicateDF()
    string Folder_Name, Folder_BaseName = "Data_"
    string DFWavesList = Wavelist("*", ";", ""), DFVariablesList = VariableList("*", ";", 4), DFCurrentWave, DFCurrentVariable
    variable FolderCount = 1
    variable/G Temp
    do
        Folder_Name = Folder_BaseName + num2str(FolderCount)
        if(DataFolderExists(Folder_Name) != 1) // DF does not currently exist
            NewDataFolder/O/S $Folder_Name
            variable x
            // Duplicate waves
            do
                DFCurrentWave = StringFromList(x, DFWavesList,";") 
                if(strlen(DFCurrentWave)==0) // No more waves
                    break
                endif
                Duplicate/O root:$DFCurrentWave $DFCurrentWave
                x+=1
            while(1)
            // Duplicate variables
            x = 0
            do
                DFCurrentVariable = StringFromList(x, DFVariablesList,";") 
                if(strlen(DFCurrentVariable)==0) // No more variables
                    break
                endif
                NVAR Temp = root:$DFCurrentVariable
                variable/G $DFCurrentVariable = Temp
                x+=1
            while(1)
            break
        endif
        FolderCount += 1
    while(1)
    SetDataFolder root:
end


The code works as desired. However, this is my first time using the NVAR command, and I am wondering if this is the proper way to use it. If a global variable is already declared, is NVAR variableName the same as variable/G variableName? Also, how come in the above code, I cannot do variable/G $DFCurrentVariable = root:$DFCurrentVariable directly, but must create Temp to hold root:$DFCurrentVariable first?
I don't know if this is useful for you but I mention it anyway:
If you just want to quickly backup your stuff to a separate folder before doing something with it you can also do it without much programming:
Create a new folder then select the things you want to copy (including variables). Then drag and drop the selection over the new folder while holding 'alt'.
That's how I do it usually. I had a button for copying stuff before I discovered the convenience of 'alt' and 'ctrl+d'.
Variable/G and the related String/G commands create a new global variable (or string). They have the side-effect of creating a reference to the global variable also, so that's probably why you're confused about the role of these commands. NVAR and related SVAR and WAVE keywords create references to already-existing variables, strings or waves. A reference is just a temporary local variable that points to a global object. You use it in code that needs to have a name at a time when the object may not exist yet.

NVAR, SVAR and WAVE have dual roles. The first is at compile time: they provide a name to refer to an object that may not exist yet, so that the compiler can create the correct code. The second is is run-time: they actually look up the object by its real name and connect that object to the local name, so that you can use the local name as a surrogate for the real name.

You can read more about all this:

DisplayHelpTopic "Local Versus Global Variables"
DisplayHelpTopic "Converting a String into a Reference Using $"
DisplayHelpTopic "Accessing Global Variables And Waves"
Quote:
Also, how come in the above code, I cannot do variable/G $DFCurrentVariable = root:$DFCurrentVariable directly, but must create Temp to hold root:$DFCurrentVariable first?

The syntax Variable/G name=something is used to initialize the new global variable, so that syntax is already taken up for a different use.

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
I see. I suspected that that was the case, but wasn't sure (Igor complained when I used NVAR to call a global variable that was not yet declared at the time, or if I tried to set that global variable to a scalar value in the same line).

I am still confused why I cannot do variable/G $DFCurrentVariable = root:$DFCurrentVariable though. Through every iteration of the do loop, $DFCurrentVariable changes, so it's not like I am declaring the same variable twice. I have condensed the code into the necessary parts below. The commented out code is what works, while the non-commented out code gives the error, "can't use $ in this way in a function" when trying to compile the code.

function DuplicateVariablesIntoDF()
    string DFVariablesList = VariableList("*", ";", 4)
    string DFCurrentVariable
    //variable/G Temp

    NewDataFolder/O/S DataFolder
    variable x
    do
        DFCurrentVariable = StringFromList(x, DFVariablesList,";") 
        if(strlen(DFCurrentVariable)==0) // No more variables
            break
        endif
        variable/G $DFCurrentVariable = root:$DFCurrentVariable
        //NVAR Temp = root:$DFCurrentVariable
        //variable/G $DFCurrentVariable = Temp
        x+=1
    while(1)
end


By the way, I want to incorporate the duplication action into the code, but it was still interesting to learn that the same can be done using ctrl-d and alt-drag.
I have to confess that I'm confused about what you're trying to do with that code. Have you used DFCurrentVariable for two different things?

If you're trying to duplicate a datafolder, how about using the operation DuplicateDataFolder?

John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
I would like to duplicate root folder's contents into a new data folder within root. However, DuplicateDataFolder seems to only allow for duplicating all of a data folder's contents if that data folder's within root:, not if that data folder was the root: folder itself. If I had root: and root:DataToBeCopied, I can create a copy of the folder root:DataToBeCopied into root:NewFolder. I run into a problem with DuplicateDataFolder if the contents of DataToBeCopied is root: itself.

Entering DuplicateDataFolder root:,root:New into the command line, for instance, gives the message "cannot move a data folder into itself or into a child data folder."
Ken wrote:
variable/G $DFCurrentVariable = root:$DFCurrentVariable


Regardless of your intentions, this line is problematic in a number of different ways.

It appears that you may not yet fully understand the concept of global variables and references to global variables, and the subtle but important differences between them.

Remember that variable /G sets aside some storage somewhere. NVAR allows you to reference that storage. In order to keep these concepts straight in your mind I recommend that you stick to the following:

1) only use variable /G when you wish to create a global variable. Don't do any assignments in that line (i.e. don't mix variable /G and '=' in one line).

2) always use NVAR when you want to read or set the contents of a global variable.

Lastly, remember that an NVAR really is just a signpost - it is a pointer to something else. That is why it never makes sense to change the name of an NVAR (and Igor will prevent you from doing so). In plain terms: to get a signpost to point to something else, you just change the direction it points to, but you don't change its name (since that is irrelevant anyway - we don't give names to signposts in daily life).
Quote:
I am still confused why I cannot do Variable/G $DFCurrentVariable = root:$DFCurrentVariable


The reason is that it is illegal to reference a global variable from a user-defined function without a NVAR. You can CREATE a global variable (using Variable/G) but you cannot directly reference it, either on the lefthand side or the righthand side of an assignment statement. This is true whether you use $str in the path or not.

In your example, you are directly referencing the global variable on the righthand side.

Some illustrative examples:

Function Test1()
    SetDataFolder root:
    Variable/G globalVar = 987
   
    String name = "globalVar"
   
    // Try to directly reference on lefthand side
    root:globalVar = 123            // Illegal
    root:$name = 123            // Still illegal
   
    // Try to directly reference on righthand side
    Variable localVar
    localVar = root:globalVar       // Illegal
    localVar = root:$name           // Still illegal
       
    // Reference through an NVAR
    NVAR nv = root:globalVar
    nv = 123                // OK
    localVar = nv               // OK
    nv = 123
End


To add a twist, a statement like:
Variable/G globalVar

implicitly creates an NVAR so this is legal:
Variable/G globalVar
globalVar = 123     // Uses implicit NVAR


The implicit NVAR is created only when the Variable/G statement uses a simple name, not when it uses a path (Variable/G root:globalVar) or a $ constructions (Variable/G $name).

The same is true for String/G and Make. The create an implicit SVAR or WAVE reference only if a simple name is used.

To review these concepts, execute this:
DisplayHelpTopic "Accessing Global Variables And Waves"


hrodstein wrote:

root:globalVar = 123            // Illegal



Actually, that line seems to work fine for me.
741 wrote:
hrodstein wrote:

root:globalVar = 123            // Illegal



Actually, that line seems to work fine for me.


It also works for me which I find surprising. I'm not sure why. I think it is an anomaly:

Function Test3()
    SetDataFolder root:
    Variable/G globalVar1 = 987
    root:globalVar1 = 123       // This compiles and works though it seems that it should not compile
   
    NewDataFolder/O/S root:TestFolder
    Variable/G globalVar2 = 987
    root:TestFolder:globalVar2 = 123        // This does not compile
   
    SetDataFolder root:
End


I don't see any reason why the first assignment (root:globalVar=123) should compile while the second (root:TestFolder:globalVar2=123) does not. It seems like both should fail to compile. My understanding is that an NVAR should be required for both.

hrodstein wrote:

I don't see any reason why the first assignment (root:globalVar=123) should compile while the second (root:TestFolder:globalVar2=123) does not. It seems like both should fail to compile. My understanding is that an NVAR should be required for both.


Right, the second one fails with "no child data folder of that name exists". Whenever I see that error I sense trouble, because I still haven't figured out completely what that error is supposed to signal.

But especially baffling is this: how can this error ever appear at compile time?