1 | #pragma rtGlobals=1 // Use modern global access method. |
---|
2 | #pragma version=5.0 |
---|
3 | #pragma IgorVersion=4.0 |
---|
4 | |
---|
5 | //***************************** |
---|
6 | // Vers. 1.2 092101 |
---|
7 | // |
---|
8 | // hook function and associated procedures that interact with the user |
---|
9 | // and the SANS_Data window |
---|
10 | // -displays pixel counts |
---|
11 | // - displays Q, qx, qy values |
---|
12 | // - displays q axes and pixel axes |
---|
13 | // |
---|
14 | // - of course, displays the detector image, w/ nice colors, legend, sliders to adjust color mapping |
---|
15 | // and a control bar to let the user adjust scaling, do averaging... |
---|
16 | // |
---|
17 | // allows the display default to be set to log scaling |
---|
18 | //***************************** |
---|
19 | |
---|
20 | |
---|
21 | //main procedure for display of SANS data files |
---|
22 | //uses "hook" functions to interact witht the user to get live cursor readout |
---|
23 | //based on the IGOR Pro Demo experiment- "SimpleDemoHook" - see the original |
---|
24 | //demo for more details of implementation |
---|
25 | // |
---|
26 | Function fRawWindowHook() |
---|
27 | //globals for the main data display window are kept in root:myGlobals |
---|
28 | Variable/G root:myGlobals:gXPos=0 |
---|
29 | Variable/G root:myGlobals:gYPos=0 |
---|
30 | Variable/G root:myGlobals:gQX=0 |
---|
31 | Variable/G root:myGlobals:gQY=0 |
---|
32 | Variable/G root:myGlobals:gQQ=0 |
---|
33 | Variable/G root:myGlobals:gNCounts=0 |
---|
34 | String/G root:myGlobals:gCurDispFile = "default string" |
---|
35 | String/G root:myGlobals:gCurTitle = "" |
---|
36 | Make/O/N=2 root:myGlobals:q_x_axis,root:myGlobals:q_y_axis |
---|
37 | |
---|
38 | NVAR pixelsX = root:myGlobals:gNPixelsX |
---|
39 | NVAR pixelsY = root:myGlobals:gNPixelsY |
---|
40 | |
---|
41 | //get the current displayed data (so the correct folder is used) |
---|
42 | SVAR cur_folder=root:myGlobals:gDataDisplayType |
---|
43 | SVAR cur_title = root:myGlobals:gCurTitle |
---|
44 | String curPath = "root:"+cur_folder |
---|
45 | Wave/T tw=$(curPath+":TextRead") |
---|
46 | cur_title = tw[6] //always update the title string |
---|
47 | |
---|
48 | DoWindow/F SANS_Data |
---|
49 | if( V_Flag==0 ) |
---|
50 | //no SANS_Data window - make one |
---|
51 | |
---|
52 | //Create NIH colors if needed |
---|
53 | if(!WaveExists($"root:myGlobals:NIHColors")) |
---|
54 | NIHColorIndex() |
---|
55 | Endif |
---|
56 | |
---|
57 | //window creation stuff |
---|
58 | Display /W=(10,50,400,490) /K=1 //K=1 flag suppresses saveMacro dialog |
---|
59 | DoWindow/C SANS_Data |
---|
60 | DoWindow/T SANS_Data,cur_folder |
---|
61 | SetWindow SANS_Data,hook=RawWindowHook,hookevents=2 |
---|
62 | ControlBar 100 |
---|
63 | |
---|
64 | SetVariable xpos,pos={7,5},size={50,17},title="X" |
---|
65 | SetVariable xpos,limits={-Inf,Inf,0},value= root:myGlobals:gXPos |
---|
66 | SetVariable xpos,help={"x-position on the detector"},frame=0,noedit=1 |
---|
67 | SetVariable ypos,pos={7,29},size={50,17},title="Y" |
---|
68 | SetVariable ypos,limits={-Inf,Inf,0},value= root:myGlobals:gYPos |
---|
69 | SetVariable ypos,help={"y-position on the detector"},frame=0,noedit=1 |
---|
70 | SetVariable counts,pos={7,59},size={150,17},title="Counts" |
---|
71 | SetVariable counts,limits={-Inf,Inf,0},value= root:myGlobals:gNCounts |
---|
72 | SetVariable counts,help={"Neutron counts"},frame=0,noedit=1 |
---|
73 | Button bisLin,pos={230,23},size={50,20},proc=Log_Lin,title="isLin" |
---|
74 | Button bisLin,help={"\"isLin\" means the counts displayed are on linear scale. \"isLog\" means the counts displayed are on log(base10) scale."} |
---|
75 | SetVariable qxval,pos={68,2},size={85,17},title="qX" |
---|
76 | SetVariable qxval,help={"q value in the x-direction on the detector"},frame=0,noedit=1 |
---|
77 | SetVariable qxval,format="%+7.5f",limits={-Inf,Inf,0},value= root:myGlobals:gQX |
---|
78 | SetVariable qyval,pos={68,21},size={85,17},title="qY" |
---|
79 | SetVariable qyval,help={"q value in the y-direction on the detector"},frame=0,noedit=1 |
---|
80 | SetVariable qyval,format="%+7.5f",limits={-Inf,Inf,0},value= root:myGlobals:gQY |
---|
81 | SetVariable q_pos,pos={68,40},size={85,17},title="q " |
---|
82 | SetVariable q_pos,help={"q-value on the detector at (x,y)"},format="%+7.5f" |
---|
83 | SetVariable q_pos,limits={-Inf,Inf,0},value= root:myGlobals:gQQ,frame=0,noedit=1 |
---|
84 | SetVariable CurFile,pos={170,4},size={210,17},title="File" |
---|
85 | SetVariable CurFile,help={"Currently displayed file"},frame=0,noedit=1 |
---|
86 | SetVariable CurFile,limits={-Inf,Inf,0},value= root:myGlobals:gCurDispFile |
---|
87 | |
---|
88 | SetVariable CurTitle,pos={4,81},size={260,17},title=" "//,title="LABEL:" |
---|
89 | SetVariable CurTitle,help={"Title string for currently displayed file"},frame=0,noedit=1 |
---|
90 | SetVariable CurTitle,fstyle=1,limits={-Inf,Inf,0},value= root:myGlobals:gCurTitle |
---|
91 | Button Print_status,pos={170,23},size={50,20},proc=StatusButton,title="Status" |
---|
92 | Button Print_status,help={"Print out information about the currently displayed file into the history window"} |
---|
93 | Button maskButton size={84,20}, pos={170,53}, proc=maskButtonProc,title="Show Mask" |
---|
94 | Button maskButton help={"If a mask has been loaded this will overlay it on the current plot"} |
---|
95 | |
---|
96 | GroupBox slideGrp,pos={268,46},size={124,48},title="Color Map" |
---|
97 | //draw after the group box so these are on "top" of the group box |
---|
98 | Button doAve,pos={290,23},size={50,20},proc=ShowAvgPanel_SANSData,title="I vs. Q" |
---|
99 | Button doAve,help={"This will circularly average the data to I vs. Q"} |
---|
100 | Slider loSlide,pos={280,77},size={100,16},proc=MapSliderProc |
---|
101 | Slider loSlide,limits={0,1,0.01},value= 0,vert= 0,ticks= 0 |
---|
102 | Slider loSlide,help={"Adjust the low threshold of the color map"} |
---|
103 | Slider hiSlide,pos={280,60},size={100,16},proc=MapSliderProc |
---|
104 | Slider hiSlide,limits={0,1,0.01},value= 1,vert= 0,ticks= 0 |
---|
105 | Slider hiSlide,help={"Adjust the high threshold of the color map"} |
---|
106 | |
---|
107 | endif |
---|
108 | |
---|
109 | //window was already open, or has just been created, add (or remove) |
---|
110 | //controls specific for RAW data (specified by the current folder) |
---|
111 | if(cmpstr(cur_folder,"RAW")==0) |
---|
112 | //show the "next" buttons |
---|
113 | //these buttons should only be available in RAW data type |
---|
114 | Button backOne size={20,20},pos={350,23},proc=BackOneFileButtonProc,title="<" |
---|
115 | Button backOne help={"Display the previous RAW data file run number"} |
---|
116 | Button forwardOne size={20,20},pos={375,23},proc=ForwardOneFileButtonProc,title=">" |
---|
117 | Button forwardOne help={"Display the next RAW data file run number"} |
---|
118 | // |
---|
119 | else |
---|
120 | //kill them |
---|
121 | KillControl backOne |
---|
122 | KillControl forwardOne |
---|
123 | Endif |
---|
124 | |
---|
125 | //reset the slider values to 0,1 |
---|
126 | Slider loSlide,value=0 |
---|
127 | Slider hiSlide,value=1 |
---|
128 | |
---|
129 | //remove old data and add new data to it |
---|
130 | //data display/modification stuff |
---|
131 | RemoveImage/Z data |
---|
132 | WAVE data = $(curPath + ":data") |
---|
133 | WAVE NIHColors = $"root:myGlobals:NIHColors" |
---|
134 | AppendImage data |
---|
135 | WaveStats/Q $(curPath + ":data") |
---|
136 | if(cmpstr(cur_folder,"MSK")==0) |
---|
137 | ModifyImage data ctab={0,1,BlueRedGreen,0} |
---|
138 | else |
---|
139 | //Call the procedure that would normally be called if the sliders were moved |
---|
140 | // MapSliderProc("both", 0, 1) |
---|
141 | MapSliderProc("reset", 0, 1) |
---|
142 | // ScaleColorsToData(V_min, V_max, NIHColors) |
---|
143 | // ModifyImage data cindex=NIHColors |
---|
144 | endif |
---|
145 | //make the pixels square, color the backgrounds |
---|
146 | ModifyGraph width={plan,1,bottom,left},mirror=0 |
---|
147 | ModifyGraph axisenab(bottom)={0,0.7} |
---|
148 | ModifyGraph axOffset(left)=-3 |
---|
149 | ModifyGraph standoff=0 |
---|
150 | ModifyGraph wbRGB=(65535,54611,49151),gbRGB=(65535,54611,49151),cbRGB=(1,52428,52428) |
---|
151 | |
---|
152 | //add the qx and qy axes |
---|
153 | Wave q_x_axis=$"root:myGlobals:q_x_axis" |
---|
154 | Wave q_y_axis=$"root:myGlobals:q_y_axis" |
---|
155 | Set_Q_Axes(q_x_axis,q_y_axis,curPath) |
---|
156 | RemoveFromGraph/Z q_x_axis,q_y_axis |
---|
157 | AppendToGraph/T q_x_axis |
---|
158 | AppendToGraph/R=Right_Q q_y_axis //plot on a free axis, crossing at x=127 (pixelsX) |
---|
159 | ModifyGraph freePos(Right_q)={pixelsX-1,bottom} |
---|
160 | ModifyGraph minor(top)=1,minor(Right_Q)=1,lowTrip(top)=1e-05,lowTrip(Right_Q)=1e-05 |
---|
161 | ModifyGraph mode(q_x_axis)=2,mode(q_y_axis)=2 //dots |
---|
162 | ModifyGraph axisEnab(top)={0,0.7} |
---|
163 | |
---|
164 | //add the color bar |
---|
165 | ColorScale/N=colBar/A=RT/X=-3/Y=-1.5/Z=1 image=data, heightPct=100, widthPct=4,notation=1 |
---|
166 | ColorScale/C/N=colBar/B=(65535,60076,49151) |
---|
167 | |
---|
168 | //update the displayed filename, using FileList in the current data folder |
---|
169 | SVAR FileList = $(curPath + ":FileList") |
---|
170 | String/G root:myGlobals:gCurDispFile = FileList |
---|
171 | |
---|
172 | //update the window title |
---|
173 | DoWindow/T SANS_Data,cur_folder |
---|
174 | |
---|
175 | // reset the initial state of the "isLin" button if it is reading "isLog", since the initial data state is |
---|
176 | //always set to linear |
---|
177 | //re-draw the data on the graph to make sure "data" from the current folder is being used |
---|
178 | ControlInfo bisLog |
---|
179 | if(V_flag ==1) //if bisLog exists, this will return true |
---|
180 | Button bisLog,title="isLin",rename=bisLin |
---|
181 | endif |
---|
182 | //now that button state and data are sure to match (both are linear) |
---|
183 | // set the display to log scale, if the global has been set |
---|
184 | NVAR gLogScalingAsDefault=root:myGlobals:gLogScalingAsDefault |
---|
185 | if(gLogScalingAsDefault) |
---|
186 | Log_lin("bisLin") |
---|
187 | endif |
---|
188 | |
---|
189 | //force an update of everything in the window |
---|
190 | DoUpdate |
---|
191 | |
---|
192 | //return data folder to root before exiting (redundant) |
---|
193 | SetDataFolder root: |
---|
194 | End |
---|
195 | |
---|
196 | //this is the hook function that is associated with the SANS_Data graph window |
---|
197 | //only mouse moved events are processed, although much more could be done |
---|
198 | //for more elaborate interaction with the user. |
---|
199 | //- sets globals (that are displayed in the control bar of the graph) for the |
---|
200 | //x and y positions (in Detector coordinates (1,128)) |
---|
201 | //qx, qy, and q (in Angstroms) |
---|
202 | //and the actual neutron counts (if raw) |
---|
203 | //or the data array value |
---|
204 | // |
---|
205 | Function RawWindowHook(s) |
---|
206 | String s |
---|
207 | |
---|
208 | //get the current displayed data (so the correct folder is used) |
---|
209 | SVAR cur_folder=root:myGlobals:gDataDisplayType |
---|
210 | SetDataFolder "root:"+cur_folder //use the full path, so it will always work |
---|
211 | String curPath = "root:" + cur_folder |
---|
212 | NVAR dataIsLog=$(curPath + ":gIsLogScale") //now a global variable in the current folder, not the globals folder |
---|
213 | if (dataIsLog) |
---|
214 | wave w=$(curPath + ":linear_data") |
---|
215 | else |
---|
216 | wave w=$(curPath + ":data") |
---|
217 | endif |
---|
218 | wave reals=$(curPath + ":realsread") |
---|
219 | |
---|
220 | String/G root:myGlobals:gHookStr= s |
---|
221 | Variable xpix,ypix,xaxval,yaxval,xint,yint,rawval |
---|
222 | String msg |
---|
223 | |
---|
224 | NVAR pixelsX = root:myGlobals:gNPixelsX |
---|
225 | NVAR pixelsY = root:myGlobals:gNPixelsY |
---|
226 | |
---|
227 | //only do something for mousemoved events |
---|
228 | if( StrSearch(s,"EVENT:mousemoved;",0) > 0 ) |
---|
229 | xpix= NumberByKey("MOUSEX",s) |
---|
230 | ypix= NumberByKey("MOUSEY",s) |
---|
231 | xaxval= AxisValFromPixel("","bottom",xpix) |
---|
232 | yaxval= AxisValFromPixel("","left",ypix) |
---|
233 | xint = round(xaxval) |
---|
234 | yint = round(yaxval) |
---|
235 | |
---|
236 | if((xint<0) || (xint>pixelsX-1) || (yint<0) || (yint>pixelsY-1)) //make sure cursor is on the image |
---|
237 | rawval = 0 |
---|
238 | else |
---|
239 | rawval = w[xint][yint] |
---|
240 | //update q, qX, and qY |
---|
241 | if(cmpstr(cur_folder,"MSK")!=0) |
---|
242 | Variable xctr=reals[16],yctr=reals[17],sdd=reals[18],lam=reals[26] |
---|
243 | Variable/G root:myGlobals:gQQ = CalcQval(xaxval+1,yaxval+1,xctr,yctr,sdd,lam) |
---|
244 | Variable/G root:myGlobals:gQX = CalcQX(xaxval+1,xctr,sdd,lam) |
---|
245 | Variable/G root:myGlobals:gQY = CalcQY(yaxval+1,yctr,sdd,lam) |
---|
246 | else |
---|
247 | Variable/G root:myGlobals:gQQ = 0 |
---|
248 | Variable/G root:myGlobals:gQX = 0 |
---|
249 | Variable/G root:myGlobals:gQY = 0 |
---|
250 | endif |
---|
251 | //add one to the x and y values to get from IGOR array indexing 0->127 to 1->128 detector |
---|
252 | Variable/G root:myGlobals:gXPos=xint+1 |
---|
253 | Variable/G root:myGlobals:gYPos=yint+1 |
---|
254 | Variable/G root:myGlobals:gNCounts=rawval |
---|
255 | endif |
---|
256 | endif |
---|
257 | |
---|
258 | //set data folder back to root |
---|
259 | SetDataFolder root: |
---|
260 | |
---|
261 | return 0 |
---|
262 | end |
---|
263 | |
---|
264 | //function to calculate the overall q-value, given all of the necesary trig inputs |
---|
265 | //NOTE: detector locations passed in are pixels = 0.5cm real space on the detector |
---|
266 | //and are in detector coordinates (1,128) rather than axis values |
---|
267 | //the pixel locations need not be integers, reals are ok inputs |
---|
268 | //sdd is in meters |
---|
269 | //wavelength is in Angstroms |
---|
270 | //returned q-value is in 1/Angstroms |
---|
271 | // |
---|
272 | // generalized to read the detector pixel dimension from the file header... |
---|
273 | // |
---|
274 | Function CalcQval(xaxval,yaxval,xctr,yctr,sdd,lam) |
---|
275 | Variable xaxval,yaxval,xctr,yctr,sdd,lam |
---|
276 | |
---|
277 | Variable dx,dy,thetax,thetay,qval,qx,qy |
---|
278 | |
---|
279 | Wave realW=$"root:raw:realsRead" |
---|
280 | Variable pixSizeX = realW[10]/10 //header is in mm, want cm |
---|
281 | Variable pixSizeY = realW[13]/10 //header is in mm, want cm |
---|
282 | |
---|
283 | sdd *=100 //convert to cm |
---|
284 | dx = (xaxval - xctr)*pixSizeX //delta x in cm |
---|
285 | dy = (yaxval - yctr)*pixSizeY //delta y in cm |
---|
286 | thetax = atan(dx/sdd) |
---|
287 | thetay = atan(dy/sdd) |
---|
288 | qx = 4*Pi/lam*sin(thetax/2) |
---|
289 | qy = 4*Pi/lam*sin(thetay/2) |
---|
290 | qval = sqrt(qx^2 + qy^2) |
---|
291 | |
---|
292 | return qval |
---|
293 | End |
---|
294 | |
---|
295 | //calculates just the q-value in the x-direction on the detector |
---|
296 | //input/output is the same as CalcQval() |
---|
297 | //ALL inputs are in detector coordinates |
---|
298 | // |
---|
299 | // generalized to read the detector pixel dimension from the file header... |
---|
300 | // |
---|
301 | Function CalcQX(xaxval,xctr,sdd,lam) |
---|
302 | Variable xaxval,xctr,sdd,lam |
---|
303 | //NOTE: detector locations passed in are pixel = 0.5cm real space on the Ordela detector |
---|
304 | //sdd is in meters |
---|
305 | //wavelength is in Angstroms |
---|
306 | |
---|
307 | Wave realW=$"root:raw:realsRead" |
---|
308 | Variable pixSize = realW[10]/10 //header is in mm, want cm |
---|
309 | |
---|
310 | Variable dx,thetax,qx |
---|
311 | |
---|
312 | sdd *=100 //convert to cm |
---|
313 | dx = (xaxval - xctr)*pixSize //delta x in cm |
---|
314 | thetax = atan(dx/sdd) |
---|
315 | qx = 4*Pi/lam*sin(thetax/2) |
---|
316 | |
---|
317 | return qx |
---|
318 | End |
---|
319 | |
---|
320 | //calculates just the q-value in the y-direction on the detector |
---|
321 | //input/output is the same as CalcQval() |
---|
322 | //ALL inputs are in detector coordinates |
---|
323 | // |
---|
324 | // generalized to read the detector pixel dimension from the file header... |
---|
325 | // |
---|
326 | Function CalcQY(yaxval,yctr,sdd,lam) |
---|
327 | Variable yaxval,yctr,sdd,lam |
---|
328 | //NOTE: detector locations passed in are pixel = 0.5cm real space on the Ordela detector |
---|
329 | //sdd is in meters |
---|
330 | //wavelength is in Angstroms |
---|
331 | |
---|
332 | Wave realW=$"root:raw:realsRead" |
---|
333 | Variable pixSize = realW[13]/10 //header is in mm, want cm |
---|
334 | |
---|
335 | Variable dy,thetay,qy |
---|
336 | |
---|
337 | sdd *=100 //convert to cm |
---|
338 | dy = (yaxval - yctr)*pixSize //delta y in cm |
---|
339 | thetay = atan(dy/sdd) |
---|
340 | qy = 4*Pi/lam*sin(thetay/2) |
---|
341 | |
---|
342 | return qy |
---|
343 | End |
---|
344 | |
---|
345 | //function to set the q-axis scaling after the data has been read in |
---|
346 | // - needs the location of the currently displayed data to get the header information |
---|
347 | // to be able to calculate q-values at the edges of the detector |
---|
348 | //** assumes a linear correspondence between pixel->q-values (which should bea a really |
---|
349 | // safe bet, since we're using the small -angle approximation...) |
---|
350 | // |
---|
351 | // actually re-scales the qy wave that is on the SANS_Data image |
---|
352 | // the qy dataset is 2 values, plotted as "dots", nearly invisible... |
---|
353 | // but does an adequate job of getting ticks on the right and top axes |
---|
354 | // |
---|
355 | Function Set_Q_Axes(qx,qy,curPath) |
---|
356 | Wave qx,qy |
---|
357 | String curPath |
---|
358 | |
---|
359 | NVAR pixelsX = root:myGlobals:gNPixelsX |
---|
360 | NVAR pixelsY = root:myGlobals:gNPixelsY |
---|
361 | |
---|
362 | WAVE reals=$(curPath + ":realsread") |
---|
363 | Variable xctr=reals[16],yctr=reals[17],sdd=reals[18],lam=reals[26] |
---|
364 | Variable maxX,minX,maxY,minY |
---|
365 | |
---|
366 | minX = CalcQX(1,xctr,sdd,lam) |
---|
367 | maxX = CalcQX(pixelsX,xctr,sdd,lam) |
---|
368 | SetScale/I x minX,maxX,"",qx |
---|
369 | |
---|
370 | minY = CalcQY(1,yctr,sdd,lam) |
---|
371 | maxY = CalcQY(pixelsY,yctr,sdd,lam) |
---|
372 | qy[0] = minY |
---|
373 | qy[1] = maxY |
---|
374 | |
---|
375 | return(0) |
---|
376 | End |
---|
377 | |
---|
378 | Function ToggleDefaultMapping() |
---|
379 | NVAR value = root:myGlobals:gLogScalingAsDefault |
---|
380 | value = !(value) |
---|
381 | End |
---|
382 | |
---|