#pragma TextEncoding = "UTF-8" #pragma rtGlobals=3 // Use modern global access method and strict wave access. #pragma rtFunctionErrors=1 #pragma ModuleName = TL //Transfer Layout (TL) //Ben Murphy-Baum //March, 2023 //******************* Transfer Layout ********************** //********************************************************** // This package provides users a way to extract the data included in a layout to // another Igor file for further work. //Access through the 'Data' menu or run manually as TL#SaveLayout(name=layoutNameStr) and TL#ImportLayout() // Save Layout : // Save all waves associated with every graph in a layout to a HDF5 file, // along with the window recreation code for each graph, and the layout itself. // Error waves, X scaling waves, contours, images, and normal traces are included. // Layouts are saved in User Procedures:NeuroTools+:Layouts // Import Layout : // Loads the waves from the saved layout HDF5 file, and runs the window recreation // code for the graphs and then the layout to rebuild the layout in the new Igor file. // If a wave being imported already exists, it is not overwritten and the original wave is maintained. //********************************************************** //********************************************************** Menu "Data",dynamic SubMenu "Transfer Layout" SubMenu "Save Layout" TL#GetLayoutList(),/Q, TL#SaveLayout() End "Import Layout",/Q, TL#ImportLayout() End End Static Function/S GetLayoutList() return WinList("*",";","WIN:4") End Static Function SaveLayout([name]) String name //With this optional parameter, users can run the function manually through the command line //instead of through the 'Data' menu If(ParamIsDefault(name)) GetLastUserMenuInfo If(!strlen(S_Value)) return 0 EndIf String layoutName = S_Value Else layoutName = name EndIf DFREF saveDF = GetDataFolderDFR() //This is important for getting the correct paths to waves with the recreation macro //ImportLayout() also bases itself from root: SetDataFolder root: Variable i,j,k,whichPage,groupRef,fileRef,objectRef String objectInfo = "" String graphName = "" //Close any open HDF5 files HDF5CloseFile/A 0 //Saves the HDF5 files to specific location right now. //Make the NeuroTools+ folder if it doesn't exist, and the layouts subfolder String pathStr = SpecialDirPath("Igor Pro User Files",0,0,0) + "User Procedures:NeuroTools+" NewPath/Q/Z/O/C layoutPath,pathStr pathStr += ":Layouts" NewPath/Q/Z/O/C layoutPath,pathStr If(V_flag) return 0 EndIf //Ask what to name the layout file String savedLayoutName = layoutName Prompt savedLayoutName,"Layout Name:" DoPrompt "Save Layout",savedLayoutName If(V_flag || !strlen(savedLayoutName)) return 0 EndIf //Ensure correct extension savedLayoutName = RemoveEnding(savedLayoutName,".h5") + ".h5" //Loop around until we get a unique file name or we agree to overwrite or cancel Do //Create the h5 file, overwrite if asked HDF5CreateFile/Z/P=layoutPath fileRef as SavedLayoutName If(V_flag) DoAlert/T="Overwrite file" 1,"Overwrite existing file?" If(V_flag == 1) //Delete the file entirely to reclaim the memory for the 'overwrite' DeleteFile/P=layoutPath/Z SavedLayoutName HDF5CreateFile/O/Z/P=layoutPath fileRef as SavedLayoutName break Else savedLayoutName = RemoveEnding(savedLayoutName,".h5") DoPrompt "Save Layout",savedLayoutName If(V_flag) return 0 EndIf savedLayoutName = RemoveEnding(savedLayoutName,".h5") + ".h5" EndIf Else break EndIf While(1) //This will hold the waves we need to dispose of after the program finishes String cleanupList = "" //Put the layout window recreation macro into a text wave //Each line of the macro goes into a different row of the text wave String winRec = WinRecreation(layoutName,0) Make/T/N=1000/O root:$(layoutName + "_Code")/Wave=LayoutCode cleanupList += GetWavesDataFolder(LayoutCode,2) + ";" Variable pos = 0 Variable startPos = 0 Variable count = 0 Do startPos = pos pos = strsearch(winRec,"\r",startPos) If(pos == -1 || count + 1 > DimSize(LayoutCode,0) - 1) break EndIf LayoutCode[count] = winRec[startPos,pos] count += 1 pos += 1 //move past the carriage return While(1) Redimension/N=(count) LayoutCode String info = LayoutInfo (layoutName,"Layout") Variable nPages = NumberByKey("NUMPAGES",info,":",";") //Saves the waves included in each page of the layout For(whichPage=1;whichPage < nPages + 1;whichPage ++) //Set the layout page LayoutPageAction/W=$layoutName page=whichPage info = LayoutInfo (layoutName,"Layout") Variable nObjects = NumberByKey("NUMOBJECTS",info,":",";") //Saves the window recreation macro into a text wave for each graph object For(i=0;i DimSize(Code,0) - 1) break EndIf Code[count] = winRec[startPos,pos] //Sketchy work around for violin plots. TraceNameList has a bug I think that will only detect //the first wave in the violin plot, if multiple have been appended. //This detects the line they are appended to the violin plot, so we can extract the full wave list from //the recreation macro later If(stringmatch(Code[count],"*AppendViolinPlot*")) isViolinPlot = count EndIf count += 1 pos += 1 //move past the carriage return While(1) Redimension/N=(count) Code //Get the data paths that go into the graph String traceType = "" String traceList = TraceNameList(graphName,";",2^0 + 2^1 + 2^3 + 2^4) //Violin plot fails to find all traces within it, so we need to manually find them all. If(isViolinPlot) String violinWaveList = Code[isViolinPlot] violinWaveList = violinWaveList[strlen("\tAppendViolinPlot "),strlen(violinWaveList)] traceList = RemoveListItem(ItemsInList(traceList,";")-1,traceList,";") For(k=0;k