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"
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).
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?