#pragma TextEncoding = "UTF-8" #pragma rtGlobals=3 // Use modern global access method and strict wave access #pragma DefaultTab={3,20,4} // Set default tab width in Igor Pro 9 and later FUNCTION Make_DOY_Axis(VARIABLE vNum_Pnts, VARIABLE vAdd_Top_Axis) Make/O/D/N=(vNum_Pnts) TimeStamp=Date2Secs(2024,6,20)+30000*p //Make a test timestamp wave and some data Make/O/D/N=(vNum_Pnts) Data=enoise(1) SetScale d 0,0,"dat", TimeStamp Display Data vs Timestamp String strGraphName = S_name //You want to use a window hook instead of a free axis hook because the free axis hook gets called if you simply change the size of the graph window SetWindow $strGraphName, hook(DOY_WinHook)=DOY_Check_Resize_Hook ModifyGraph/W=$strGraphName grid(bottom)=1,gridHair(bottom)=0,gridRGB(bottom)=(0,0,0) //Add a grid to make sure the DOY math is correct SetWindow $strGraphName, userdata(Axis_Min)="" //These will hold the old values of the axis limits so we can check if they have changed SetWindow $strGraphName, userdata(Axis_Max)="" IF(vAdd_Top_Axis) //Top axis is linked to the bottom axis but uses a "normal" timestamp format for the tick labels NewFreeAxis/T/O/W=$strGraphName DateAndTime ModifyGraph/W=$strGraphName freePos(DateAndTime)={0,kwFraction} ModifyFreeAxis/W=$strGraphName DateAndTime, master=bottom Label DateAndTime " " ModifyGraph dateInfo(DateAndTime)={0,1,-1},dateFormat(DateAndTime)={Default,2,2,2,2,"Year-Month-DayOfMonth",12} ENDIF ModifyGraph fSize=14 //Do some formatting on the graph ModifyGraph tkLblRot(bottom)=45 Label bottom "ERT" ModifyGraph btLen=4 END //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //This hook only responds to "Graph Modified" events, and it then checks to see if the bottom axis limits have changed. //If they have, the tick waves get updated. Function DOY_Check_Resize_Hook(s) STRUCT WMWinHookStruct &s STRSWITCH(s.eventName) CASE "modified": GetAxis/W=$s.winName/Q bottom String strNew_Axis_Min, strNew_Axis_Max sprintf strNew_Axis_Min, "%.10f", V_Min sprintf strNew_Axis_Max, "%.10f", V_Max String strOld_Axis_Min=GetUserData(s.winName, "", "Axis_Min") String strOld_Axis_Max=GetUserData(s.winName, "", "Axis_Max") //I always get nervous using equals signs with floats, so compare the strings instead IF(cmpstr(strNew_Axis_Min, strOld_Axis_Min)!=0 || cmpstr(strNew_Axis_Max, strOld_Axis_Max)!=0) Variable vAxis_Min=str2num(strNew_Axis_Min) Variable vAxis_Max=str2num(strNew_Axis_Max) Variable vTime_Range=abs(vAxis_Max-vAxis_Min) //You'll want to customize this based on your preferences. IF(vTime_Range<(86400*2)) //If less than 2 days, use 6 hour intervals Variable vNum_Pnts=ceil(vTime_Range/(6*3600))+1 Make/O/D/N=(vNum_Pnts) Tick_Values=floor(vAxis_Min/(6*3600))*6*3600+6*3600*p Make/O/T/N=(vNum_Pnts) Tick_Labels=Make_DOY_Tag(Tick_Values[p]) ELSEIF(vTime_Range<(86400*7)) //If less than a week, use day intervals vNum_Pnts=ceil(vTime_Range/86400)+1 Make/O/D/N=(vNum_Pnts) Tick_Values=floor(vAxis_Min/86400)*86400+86400*p Make/O/T/N=(vNum_Pnts) Tick_Labels=Make_DOY_Tag(Tick_Values[p]) ELSE //Otherwise use 2 day intervals vNum_Pnts=ceil(vTime_Range/86400)/2+1 Make/O/D/N=(vNum_Pnts) Tick_Values=floor(vAxis_Min/86400)*86400+86400*p*2 Make/O/T/N=(vNum_Pnts) Tick_Labels=Make_DOY_Tag(Tick_Values[p]) ENDIF ModifyGraph/W=$s.winName userticks(bottom)={Tick_Values,Tick_Labels} SetWindow $s.winName, userdata(Axis_Min)=strNew_Axis_Min SetWindow $s.winName, userdata(Axis_Max)=strNew_Axis_Max ENDIF Return 1 BREAK ENDSWITCH END //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// FUNCTION/S Make_DOY_Tag(VARIABLE vTime) Variable vYear=str2num(StringFromList(0, Secs2Date(vTime, -2), "-")) String strDOY=num2str(floor((vTime-Date2Secs(vYear-1, 12, 31))/86400), "%03d") //Requires Igor 9 and above String strYear=(num2str(vYear))[2,3] String strDOY_Tag=strYear+"-"+strDOY+"T"+Secs2Time(vTime, 2) Return strDOY_Tag END //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //Benchmark function to check two waves of calculating the DOY FUNCTION Benchmark_DOY_Creation(VARIABLE vNum_Pnts) Make/O/D/N=(vNum_Pnts) TimeStamp=Date2Secs(2024,6,20)+p, Data=enoise(1) SetScale d 0,0,"dat", TimeStamp Variable iDex, vTimer, vTime vTimer=StartMSTimer FOR(iDex=0;iDex<100;iDex+=1) //This is about 50% faster than using DateToJulian Make/O/D/FREE/N=(vNum_Pnts) Year_Floor=str2num(StringFromList(0, Secs2Date(TimeStamp[p], -2), "-")) Make/O/D/FREE/N=(vNum_Pnts) DOY_Floor=floor((TimeStamp-Date2Secs(Year_Floor-1, 12, 31))/86400) ENDFOR vTime=StopMSTimer(vTimer) Print vTime/1e6/100 Sleep/S 2 vTimer=StartMSTimer FOR(iDex=0;iDex<100;iDex+=1) Make/O/T/FREE/N=(vNum_Pnts) DateW=Secs2Date(TimeStamp[p], -2) Make/O/D/FREE/N=(vNum_Pnts) Year_Julian=str2num(StringFromList(0, DateW, "-")) Make/O/D/FREE/N=(vNum_Pnts) Month_Julian=str2num(StringFromList(1, DateW, "-")) Make/O/D/FREE/N=(vNum_Pnts) Day_Julian=str2num(StringFromList(2, DateW, "-")) Make/O/D/FREE/N=(vNum_Pnts) DOY_Julian=dateToJulian(Year_Julian, Month_Julian, Day_Julian) - dateToJulian(Year_Julian, 1, 1) + 1 ENDFOR vTime=StopMSTimer(vTimer) Print vTime/1e6/100 END