
Create images of graphs and allow Igor to reopen the original image pxp when it opens the image

The following code must be compiled in Igor at the time that the image is opened by Igor. The image must have been saved with the included saveTopGraphs() function, which creates a text file in addition to the image file. The text file must be kept in the same folder as the image file. If these conditions are met, one can drag the image into Igor or double click on the image (if Igor is set as the default program) and the original pxp will open.
The ability to activate an existing pxp window that is already open requires that NirCmd.exe (download and documentation at http://nirsoft.net/utils/nircmd2.html) is available from command line (e.g., add it to your Windows folder).
#pragma TextEncoding = "UTF-8" #pragma rtGlobals=3 // Use modern global access method and strict wave access. //PART 1: save a graph with a text file containing "recovery" information (including waves in the graph,the pxp name,etc) function saveTopGraphs(numGraphs, pathName, [h, w, res, nStr,type,nt]) Variable numGraphs; String pathName Variable h, w //optionally set height. Uses inches by multiplying input value by 72 Variable res //see otions in switch statement below. 0 or 8 is 8x screen resolution, 1 is 1x, so on String nStr //when passed, this is used as start of output name. If more than one graph being saved, naming is [nStr]0, [nStr]1, ... Variable type //-2 for high res enhanced metafile, -5 for png, -7 for tiff, -8 pdf Variable nt //supress transparency Variable usedType if (ParamIsDefault(type)) //no type speficiation, use default usedType = -5 //-2 for high res enhanced metafile (good for illustrator), -5 for png (good for PPT or illustrator by ref), -7 for tiff else usedType = type endif make/o/t/free typeExtensions = {".emf",".png",".jpg",".tif",".pdf",".svg"} dl_assignLblsFromList(typeExtensions,0,0,"-2;-5;-6;-7;-8;-9;","",0) Variable spbt = (ParamIsDefault(nt) || !nt) ? 1 : 0 //Save PNG Background as Transparent (only affects PNGs) PathInfo $pathName if (!V_flag) Newpath/O $pathName if (V_flag) Print "saveTopGraphs(): path set canceled; aborting." endif endif PathInfo $pathName String picSavePath = S_path if (ParamIsDefault(res) || numtype(res) || (res <= 0)) res = 8 endif Variable resVal = res*72 //1 to 8 are options for res String graphWindows = WinList("*", ";", "WIN:1" ) Variable i, count,maxn=min(numGraphs,ItemsInList(graphWindows)); String picFileName,graphN,infoTxtFileName make/o/t/free/n=(1,15) picInfo //put info along one row for easy writing with save/J (delimited text from wave columns) for (i=0;i<maxn;i+=1) graphN = StringFromList(i, graphWindows) //check for height, width changes if (!ParamIsDefault(h) || !ParamIsDefault(w)) if (!ParamIsDefault(h)) ModifyGraph/W=$graphN height = h*72 ModifyGraph/W=$graphN height = 0 //makes height adjustable again endif if (!ParamIsDefault(w)) ModifyGraph/W=$graphN width = w*72 ModifyGraph/W=$graphN width = 0 //makes height adjustable again endif doupdate endif //check for a custom name if (ParamIsDefault(nStr)) //no custom name SavePICT/Z/O/P=$pathName/EF=2/Q=1/B=(resVal)/E=(usedType)/TRAN=(spbt)/WIN=$graphN picFileName = graphN + typeExtensions[%$num2str(usedType)] else //custom name if (numGraphs < 2) //just one input, don't append a number to give it a unique name picFileName = nStr else //multiple windows to save, append a number to make sure output name is unique for each one picFileName = nStr + num2str(count) endif picFileName += typeExtensions[%$num2str(usedType)] SavePICT/Z/O/P=$pathName/EF=2/E=(usedType)/Q=1/B=(resVal)/TRAN=(spbt)/WIN=$graphN as picFileName endif if (V_flag == 0) Print "Saved: " + graphN,"target save name =", picFileName //save text file with info about this file Pathinfo home String traces=tracenamelist(graphN,";",2^0+2^1+2^2+2^3+2^4+2^5),wavesForTraces="",xwavesForTraces="" Variable j,numTraces=itemsinlist(traces) for (j=0;j<numTraces;j+=1) wavesForTraces+=nameofwave(tracenametowaveref(graphN,stringfromlist(j,traces))) xWavesForTraces+=nameofwave(XWaveRefFromTrace(graphN,stringfromlist(j,traces))) endfor picInfo[0][0]="picFileName~"+picFileName picInfo[0][1]="graphName~"+graphN picInfo[0][2]="experimentName~"+igorinfo(1)+".pxp" picInfo[0][3]="experimentFullPath~"+S_path //from pathinfo home picInfo[0][4]="lastSaveDate~"+date() picInfo[0][5]="lastSaveTime~"+time() picInfo[0][6]="picSavePath~"+picSavePath picInfo[0][7]="OS_user~"+igorinfo(7) picInfo[0][8]="saveWidthInch~"+num2str(winDim(graphN,0)) picInfo[0][9]="saveHeightInch~"+num2str(winDim(graphN,1)) picInfo[0][10]="graphFullWaveList~"+wavelist("*",";","WIN:"+graphN) picInfo[0][11]="graphTraceList~"+traces picInfo[0][12]="wavesForTraces~"+wavesForTraces picInfo[0][13]="xWavesForTraces~"+xWavesForTraces picInfo[0][14]="winRecreation~"+winrecreation(graphN,0) infoTxtFileName = picFileName +".txt" save/J/P=$pathName/o/dlim="\r\n"/e=0 picInfo as infoTxtFileName count+=1 else Print "Error in saveTopGraphs() from SavePICT. Error code = " , num2str(V_flag) ," on graphN",graphN,"i=",i endif endfor Print "total num saved = " + num2str(count) + " of target num = " + num2str(numGraphs) end //PART 2: what to do if that graph is passed to Igor as a file to open //setup to call a function when any file open request is started function BeforeFileOpenHook(refNum, fileNameStr, pathNameStr, fileTypeStr, fileCreatorStr, fileKind ) Variable refNum //is the file reference number. You can use this number with file I/O operations to read from the file. Igor closes the file when the user-defined function returns, and refNum becomes invalid. The file is opened for read-only; if you want to write to the file, you must close and reopen it with write access. refNum will be -1 for experiment files and XOPs. In this case, Igor has not opened the file for you. String fileNameStr // contains the name of the file. String pathNameStr // contains the name of the symbolic path. pathNameStr is not the value of the path. Use the PathInfo operation to determine the path's value. String fileTypeStr // contains the Macintosh file type code, if applicable. File type codes are obsolete. Use the file name extension to determine if you want to handle the file. You can use ParseFilePath to obtain the extension from fileNameStr . String fileCreatorStr // contains the Macintosh creator code, if applicable. Creator codes are obsolete so ignore this parameter. Variable fileKind // is a number that identifies what kind of file Igor thinks it is. Values for fileKind are listed in the next section. return fio_reopenImgPxp(refNum,fileNameStr,pathNameStr) end //handle reopening static strconstant acceptedFileExtensions = "png;emf;" //don't include periods; semi-colon delimited list. Currently only png and emf will be handled. Others can be added function fio_reopenImgPxp(refNum,fileNameStr,pathNameStr) Variable refNum;string fileNameStr,pathNameStr String fileExtension = fio_getFileNameOrExtension(fileNameStr,1) Variable acceptedFileExtension = itemsinlist(ListMatch(acceptedFileExtensions,"*"+fileExtension)) > 0 if (!acceptedFileExtension) return 0 endif String txtFileName = fileNameStr + ".txt" STring txtFiles = indexedfile($pathNameStr,-1,".txt") Variable txtFileInd = whichlistitem(txtFileName,txtFiles) if (txtFileInd < 0) print "fio_reopenImgPxp() acceptable file type opened but no associated text file found, aborting" return 0 endif //make sure path to search for pxp files is set (once per experiment with drag) //this could be altered to search more of the available drives pathinfo fio_reopenImgPxpPath if (!V_flag) newpath/M="fio_reopenImgPxp() Choose a new path for retrieving PXP files on image drag"/o fio_reopenImgPxpPath//fio_reopenImgPxp if (V_flag) Print "fio_reopenImgPxp() failed to set path to retrieve pxp files on image drag, aborting. need to set symbolic path with name fio_reopenImgPxpPath" endif endif String pxpPath = S_path String info = fio_readTxtFile(pathNameStr,txtFileName) String experimentName = stringbykey("experimentName",info,"~","\r") String experimentName_noPrefix = removeending(experimentName,".pxp") if (stringmatch(experimentName,igorinfo(1))) print "fio_reopenImgPxp() This pxp created the image" return 1 endif WAVE/T openExpInfo = fio_getIgorExperiments("") Variable expIndex = finddimlabel(openExpInfo,0,experimentName_noPrefix) if (expIndex >= 0) Variable is64 = str2num(openExpInfo[expIndex][%is64]) String winTitle=openExpInfo[expIndex][%$"Window Title"] String activateCmd="nircmd win activate title \""+winTitle+"\"" String flashCmd="nircmd win flash title \""+winTitle+"\"" print "fio_reopenImgPxp() Pxp file that created this image,",experimentName," is already open in",selectstring(is64,"Igor32","Igor64"),"win="+winTitle,"attempting to activate that window (requires nircmd)" executescripttext/B/Z/w=1 activateCmd if (V_flag) print "fio_reopenImgPxp() could not activate pxp that contained image ("+experimentName+"), appears nircd is not installed. Add nircmd.exe (http://www.nirsoft.net/utils/nircmd.html) to C:/Windows" else executescripttext/B/Z/w=1 flashCmd endif //doesnt seem like there is any easily available error handling if window is not found return 1 endif String pxpFiles = indexedfile(fio_reopenImgPxpPath,-1,".pxp") Variable pxpFileInd = whichlistitem(experimentName,pxpFiles) if (pxpFileInd<0) print "fio_reopenImgPxp() pxp that generated image:",experimentName,". not found. need to set symbolic path with name fio_reopenImgPxpPath to proper path, or maybe it has been renamed since last image save" return 1 endif String sysPxpPath = parsefilepath(5,pxpPath,"*",0,100) String fullPath = sysPxpPath+stringfromlist(pxpFileInd,pxpFiles) print "fio_reopenImgPxp() pxp that generated image found at:",fullPath+". attempting open in new instance of Igor64" executeIgorScript_doCmd(fullPath,64,newInstance=1,noCommand=1) return 1 end //get a (textwave) list of open Igor experiment windows (via ExecuteScriptText) function/WAVE fio_getIgorExperiments(outRef) String outRef //pass "" for free wave String cmdExeKeys="Image Name;PID;Session Name;Session#;Mem Usage;Status;User Name;CPU Time;Window Title;" //output from the script below contains items with these keys. formatting is parsed by key in text_getCmdExeListInfo() ExecuteScriptText/B "tasklist /v /FO LIST /fi \"IMAGENAME eq Igor*\"" WAVE/T instanceInfo = listtotextwave(S_value,"\r\n\r\n") //format is /r delimited list with key:<\t>itemStr<\r> it seems duplicate/o/free/t instanceInfo,titleStrs,winTitles,imageNameStrs Variable numWins = dimsize(instanceInfo,0),i,itemsInWindowTitleStr Variable numCmdKeys=itemsinlist(cmdExeKeys),numParams=itemsinlist(cmdExeKeys)+3 if (strlen(outRef) == 0) make/o/free/n=(numWins,numParams)/t out else make/o/n=(numWins,numParams)/t $outref/wave=out endif String key for (i=0;i<numCmdKeys;i+=1) key=stringfromlist(i,cmdExeKeys) setdimlabel 1,i,$key,out endfor setdimlabel 1,numCmdKeys,is64,out setdimlabel 1,numCmdKeys+1,isDefault,out setdimlabel 1,numCmdKeys+2,winTitleNoIgorInfo,out //also stored in the dimension label out[][0,numCmdKeys]=text_getCmdExeListInfo(stringfromlist(q,cmdExeKeys),instanceInfo[p]) out[][%is64] = num2str(stringmatch(out[p][%$"Image Name"],"*Igor64.exe*")) out[][%isDefault] = num2str(itemsinlist(out[p][%$"Window Title"]," - ") < 2 )//for named windows, will be 2; for unnamed will be 1 --not a super safe test. Would be better to get Igor version and check a match to expected given 32-bit or 64-bit String experimentName for (i=0;i<numWins;i+=1) experimentName = stringfromlist(0,out[i][%$"Window Title"]," - ") experimentName = text_removeSurroundingSpaces(experimentName,2) out[i][%winTitleNoIgorInfo] = experimentName setdimlabel 0,i,$experimentName,out endfor return out end //parses output from ExecuteScriptText "tasklist..." as above function/S text_getCmdExeListInfo(key,list) String key,list String match = stringfromlist(0,listmatch(list,key+":*","\r\n"),"\r\n") match = replacestring(key+":",match,"",0,1) return text_removeSurroundingSpaces(match,2) end //wrapper function for calling Igor from script strconstant ksExecutable32="IgorBinaries_Win32\Igor.exe" strconstant ksExecutable64="IgorBinaries_x64\Igor64.exe" function executeIgorScript_doCmd(cmdStr,igorVers,[newInstance,noCommand]) String cmdStr //command to execute in other instance of igor Variable igorVers //version of Igor to command Variable newInstance //use the /I flag to start a new Igor instance. otherwise, a new instance should only be created if there are no instances of the version of Igor running Variable noCommand //suppress the /X command flag. This is required to open a pre-existing pxp file String windowsIgorPath = SpecialDirPath("Igor Application",0,1,0) Variable doNewInstance = !ParamIsDefault(newInstance) && newInstance Variable doCommand = ParamIsDefault(noCommand) || !noCommand String newInstanceOption = selectstring(doNewInstance,"","/I ") String commandOption = selectstring(doCommand,"","/X ") string execPath switch (igorVers) case 32: execPath = "\""+ windowsIgorPath + ksExecutable32 +"\"" break case 64: execPath = "\""+ windowsIgorPath + ksExecutable64 +"\"" break default: return 0 //not a valid igor version endswitch String scriptText = execPath + " " +commandOption + newInstanceOption + "\"" + cmdStr + "\"" ExecuteScriptText scriptText end //GENERALISH HELPER FUNCTIONS needed to run parts 1 and 2 function/S fio_getFileNameOrExtension(str,extensionNotName) String str Variable extensionNotName Variable items = itemsinlist(str,".") if (extensionNotName) return stringfromlist(items-1,str,".") endif String noExt = removelistitem(items-1,str,".") Variable len = strlen(noExt) return noExt[0,len-2] //remove last "." end function dl_assignLblsFromList(wv,dim,startIndex,list,appendStr,appendBeforeLblNotAfter[reuseLast]) WAVE wv Variable dim //dim to label Variable startIndex //index to start at in dim to label (end index is based on length of list) String list //list of labels to assign String appendStr Variable appendBeforeLblNotAfter Variable reuseLast //optionally pass to coninue using the last in the list until the end of the dimension variable i,num=itemsinlisT(list),maxIndex = dimsize(wv,dim),index,count=0 String lb=stringfromlist(0,list) for (i=0;(i+startIndex)<maxIndex;i+=1) //loop through from startIndex til end of dimension .. index = i+startIndex if (i >= num) if (ParamIsDefault(reuseLast) || !reuseLast) break endif SetDimLabel dim,index,$lb,wv;count+=1 endif if (appendBeforeLblNotAfter) lb=appendStr + stringfromlist(i,list) else lb=stringfromlist(i,list) + appendStr endif SetDimLabel dim,index,$lb,wv;count+=1 endfor return count end function winDim(winN,widthOrHeight) String winN Variable widthOrHeight //0 width 1 height, returns in inches if (strlen(winN) < 1) winN = winname(0,1) endif getwindow $winN,psize Variable minCoord,maxCoord if (widthOrHeight) //height minCoord = V_top maxCoord = v_bottom else minCoord = V_left maxCoord = v_right endif //getwindow $winN,expand return (maxCoord - minCoord) / 72// / v_value end Function/S fio_readTxtFile(pathNameStr,fileNameStr) String pathNameStr //symbolic path for file String fileNameStr //full name of file including extension Variable refNum Open/R/P=$pathNameStr refNum as fileNameStr if (refNum == 0) pathinfo $pathNameStr print "fio_readTxtFile() failed to find pathNameStr",fileNameStr,"in symbolic path",pathNameStr,"("+S_path+")" return "" // Failed endif Variable lineNumber, len String buffer,out="" lineNumber = 0 do FReadLine refNum, buffer len = strlen(buffer) if (len == 0) break // No more lines to be read endif out += buffer if (CmpStr(buffer[len-1],"\r") != 0) // Last line has no CR ? out+="\r" endif lineNumber += 1 while (1) close refnum return out End function/S text_removeSurroundingSpaces(str,beforeAfterOrBoth) String str; Variable beforeAfterOrBoth //0 just before, 1 after, 2 both Variable i,firstNonSpacePos,lastNonSpacePos,len=strlen(str) if ( (beforeAfterOrBoth==0) || (beforeAfterOrBoth==2) ) for (i=0;i<len;i+=1) if (!stringmatch(str[i], " ")) break endif endfor firstNonSpacePos = i if (firstNonSpacePos == len) //got through whole loop, string is empty or all blank return "" endif if (beforeAfterOrBoth==0) return str[firstNonSpacePos,inf] endif endif //beforeAfterOrBoth is 1 or 2 for (i=len-1;i>=0;i-=1) if (!stringmatch(str[i]," ")) break endif endfor lastNonSpacePos = i if (beforeAfterOrBoth==1) //just return without ending spaces if (lastNonSpacePos == 0) //got through whole loop, string is empty or all blank return "" endif return str[0,lastNonSpacePos] endif if (lastNonSpacePos == firstNonSpacePos) //got through whole loop, string is empty or all blank return "" endif //return without ending and preceding spaces return str[firstNonSpacePos,lastNonSpacePos] end

Forum

Support

Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More