Coverage for /Users/Newville/Codes/xraylarch/larch/wxmap/mapimageframe.py: 15%
219 statements
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
« prev ^ index » next coverage.py v7.3.2, created at 2023-11-09 10:08 -0600
1#!/usr/bin/python
2"""
3subclass of wxmplot.ImageFrame specific for Map Viewer -- adds custom menus
4"""
6import os
7import time
8from threading import Thread
9import socket
11from functools import partial
12import wx
14import numpy as np
15from matplotlib.figure import Figure
16from matplotlib.backends.backend_wxagg import FigureCanvasWxAgg
18import wxmplot
19from wxmplot import ImageFrame, PlotFrame, PlotPanel
20from wxmplot.imagepanel import ImagePanel
22from wxmplot.imageconf import ColorMap_List, Interp_List
23from wxmplot.colors import rgb2hex, register_custom_colormaps
25from wxutils import (SimpleText, TextCtrl, Button, Popup, Choice, pack)
27def get_wxmplot_version():
28 return "this function is deprecated"
30class MapImageFrame(ImageFrame):
31 """
32 MatPlotlib Image Display on a wx.Frame, using ImagePanel
33 """
35 def __init__(self, parent=None, size=(900, 750), mode='intensity',
36 lasso_callback=None, move_callback=None, save_callback=None,
37 show_xsections=False, cursor_labels=None,
38 with_savepos=True,output_title='Image', **kws):
39 self.det = None
40 self.xrmfile = None
41 self.map = None
42 self.move_callback = move_callback
43 self.save_callback = save_callback
44 self.with_savepos = with_savepos
46 ImageFrame.__init__(self, parent=parent, size=size,
47 lasso_callback=lasso_callback,
48 cursor_labels=cursor_labels, mode=mode,
49 output_title=output_title, **kws)
51 w0, h0 = self.GetSize()
52 w1, h1 = self.GetBestSize()
53 self.SetSize((max(w0, w1)+25, max(h0, h1)+50))
54 self.SetMinSize((500, 500))
55 self.prof_plotter = None
56 self.zoom_ini = None
57 self.lastpoint = [None, None]
59 self.rbbox = None
61 def display(self, map, det=None, xrmfile=None, xoff=0, yoff=0,
62 with_savepos=True, **kws):
63 self.xoff = xoff
64 self.yoff = yoff
65 self.det = det
66 self.xrmfile = xrmfile
67 self.map = map
68 self.title = ''
69 if 'title' in kws:
70 self.title = kws['title']
71 if 'contrast_level' not in kws:
72 kws['contrast_level'] = 0.5
73 ImageFrame.display(self, map, **kws)
74 # self.set_contrast_levels()
76 if self.save_callback is not None and hasattr(self, 'pos_name'):
77 self.pos_name.Enable(with_savepos)
79 sd = kws.get('subtitles', None)
80 if sd is not None:
81 for i, name in enumerate(('red', 'green', 'blue')):
82 sub = sd.get(name, None)
83 if sub is not None:
84 self.cmap_panels[i].title.SetLabel(sub)
87 def onCursorMode(self, event=None, mode='zoom'):
88 self.panel.cursor_mode = mode
89 choice = self.zoom_mode.GetString(self.zoom_mode.GetSelection())
90 if event is not None:
91 if choice.startswith('Pick Area'):
92 self.panel.cursor_mode = 'lasso'
94 def onLasso(self, data=None, selected=None, mask=None, **kws):
95 if hasattr(self.lasso_callback , '__call__'):
97 self.lasso_callback(data=data, selected=selected, mask=mask,
98 xoff=self.xoff, yoff=self.yoff, det=self.det,
99 xrmfile=self.xrmfile, **kws)
101 self.zoom_mode.SetSelection(0)
102 self.panel.cursor_mode = 'zoom'
104 def CustomConfig(self, panel, sizer=None, irow=0):
105 """config panel for left-hand-side of frame"""
107 labstyle = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND
109 if self.lasso_callback is None:
110 zoom_opts = ('Zoom to Rectangle',)
111 else:
112 zoom_opts = ('Zoom to Rectangle',
113 'Pick Area for XRF Spectrum')
115 cpanel = wx.Panel(panel)
116 if sizer is None:
117 sizer = wx.BoxSizer(wx.VERTICAL)
118 sizer.Add(SimpleText(cpanel, label='Cursor Modes', style=labstyle),
119 0, labstyle, 3)
120 self.zoom_mode = wx.RadioBox(cpanel, -1, "",
121 wx.DefaultPosition, wx.DefaultSize,
122 zoom_opts, 1, wx.RA_SPECIFY_COLS)
123 self.zoom_mode.Bind(wx.EVT_RADIOBOX, self.onCursorMode)
125 sizer.Add(self.zoom_mode, 1, labstyle, 4)
127 if self.save_callback is not None:
128 sizer.Add(SimpleText(cpanel, label='Save Position:', style=labstyle),
129 0, labstyle, 3)
130 self.pos_name = wx.TextCtrl(cpanel, -1, '', size=(155, -1),
131 style=wx.TE_PROCESS_ENTER)
132 self.pos_name.Bind(wx.EVT_TEXT_ENTER, self.onSavePixel)
133 sizer.Add(self.pos_name, 0, labstyle, 3)
135 pack(cpanel, sizer)
136 return cpanel
138 def onSavePixel(self, event=None):
139 ix, iy = self.panel.conf.slice_xy
140 if ix > 0 and iy > 0 and self.save_callback is not None:
141 name = str(event.GetString().strip())
142 x = float(self.panel.xdata[int(ix)])
143 y = float(self.panel.ydata[int(iy)])
144 self.save_callback(name, ix, iy, x=x, y=y,
145 title=self.title, xrmfile=self.xrmfile)
148class CorrelatedMapFrame(wxmplot.ImageMatrixFrame):
149 """
150 wx.Frame, with 3 ImagePanels and correlation plot for 2 map arrays
151 """
152 def __init__(self, parent=None, xrmfile=None,
153 title='CorrelatedMaps', **kws):
155 self.xrmfile = xrmfile
156 wxmplot.ImageMatrixFrame.__init__(self, parent, size=(900, 625),
157 title=title, **kws)
159 def CustomConfig(self, parent):
160 pass
163class with_profile_mode:
164 def prof_motion(self, event=None):
165 if not event.inaxes or self.zoom_ini is None:
166 return
167 try:
168 xmax, ymax = event.x, event.y
169 except:
170 return
171 xmin, ymin, xd, yd = self.zoom_ini
172 if event.xdata is not None:
173 self.lastpoint[0] = event.xdata
174 if event.ydata is not None:
175 self.lastpoint[1] = event.ydata
177 yoff = self.panel.canvas.figure.bbox.height
178 ymin, ymax = yoff - ymin, yoff - ymax
180 zdc = wx.ClientDC(self.panel.canvas)
181 zdc.SetLogicalFunction(wx.XOR)
182 zdc.SetBrush(wx.TRANSPARENT_BRUSH)
183 zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
184 zdc.ResetBoundingBox()
186 # erase previous box
187 if self.rbbox is not None:
188 zdc.DrawLine(*self.rbbox)
189 self.rbbox = (xmin, ymin, xmax, ymax)
190 zdc.DrawLine(*self.rbbox)
192 def prof_leftdown(self, event=None):
193 self.report_leftdown(event=event)
194 if event.inaxes: # and len(self.map.shape) == 2:
195 self.lastpoint = [None, None]
196 self.zoom_ini = [event.x, event.y, event.xdata, event.ydata]
198 def prof_leftup(self, event=None):
199 # print("Profile Left up ", self.map.shape, self.rbbox)
200 if self.rbbox is not None:
201 zdc = wx.ClientDC(self.panel.canvas)
202 zdc.SetLogicalFunction(wx.XOR)
203 zdc.SetBrush(wx.TRANSPARENT_BRUSH)
204 zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
205 zdc.ResetBoundingBox()
206 zdc.DrawLine(*self.rbbox)
207 self.rbbox = None
209 if self.zoom_ini is None or self.lastpoint[0] is None:
210 return
212 x0 = int(self.zoom_ini[2])
213 x1 = int(self.lastpoint[0])
214 y0 = int(self.zoom_ini[3])
215 y1 = int(self.lastpoint[1])
216 dx, dy = abs(x1-x0), abs(y1-y0)
218 self.lastpoint, self.zoom_ini = [None, None], None
219 if dx < 2 and dy < 2:
220 self.zoom_ini = None
221 return
223 outdat = []
224 if dy > dx:
225 _y0 = min(int(y0), int(y1+0.5))
226 _y1 = max(int(y0), int(y1+0.5))
228 for iy in range(_y0, _y1):
229 ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
230 outdat.append((ix, iy))
231 else:
232 _x0 = min(int(x0), int(x1+0.5))
233 _x1 = max(int(x0), int(x1+0.5))
234 for ix in range(_x0, _x1):
235 iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
236 outdat.append((ix, iy))
237 x, y, z = [], [], []
238 for ix, iy in outdat:
239 x.append(ix)
240 y.append(iy)
241 z.append(self.panel.conf.data[iy, ix])
242 self.prof_dat = dy>dx, outdat
244 if self.prof_plotter is not None:
245 try:
246 self.prof_plotter.Raise()
247 self.prof_plotter.clear()
249 except (AttributeError, Exception):
250 self.prof_plotter = None
252 if self.prof_plotter is None:
253 self.prof_plotter = PlotFrame(self, title='Profile')
254 self.prof_plotter.panel.report_leftdown = self.prof_report_coords
256 xlabel, y2label = 'Pixel (x)', 'Pixel (y)'
258 x = np.array(x)
259 y = np.array(y)
260 z = np.array(z)
261 if dy > dx:
262 x, y = y, x
263 xlabel, y2label = y2label, xlabel
264 self.prof_plotter.panel.clear()
266 if len(self.title) < 1:
267 self.title = os.path.split(self.xrmfile.filename)[1]
269 opts = dict(linewidth=2, marker='+', markersize=3,
270 show_legend=True, xlabel=xlabel)
272 if isinstance(z[0], np.ndarray) and len(z[0]) == 3: # color plot
273 rlab = self.subtitles['red']
274 glab = self.subtitles['green']
275 blab = self.subtitles['blue']
276 self.prof_plotter.plot(x, z[:, 0], title=self.title, color='red',
277 zorder=20, xmin=min(x)-3, xmax=max(x)+3,
278 ylabel='counts', label=rlab, **opts)
279 self.prof_plotter.oplot(x, z[:, 1], title=self.title, color='darkgreen',
280 zorder=20, xmin=min(x)-3, xmax=max(x)+3,
281 ylabel='counts', label=glab, **opts)
282 self.prof_plotter.oplot(x, z[:, 2], title=self.title, color='blue',
283 zorder=20, xmin=min(x)-3, xmax=max(x)+3,
284 ylabel='counts', label=blab, **opts)
286 else:
288 self.prof_plotter.plot(x, z, title=self.title, color='blue',
289 zorder=20, xmin=min(x)-3, xmax=max(x)+3,
290 ylabel='counts', label='counts', **opts)
292 self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
293 zorder=3, side='right', color='black', **opts)
295 self.prof_plotter.panel.unzoom_all()
296 self.prof_plotter.Show()
297 self.zoom_ini = None
299 self.zoom_mode.SetSelection(0)
300 self.panel.cursor_mode = 'zoom'
302 def prof_report_coords(self, event=None):
303 """override report leftdown for profile plotter"""
304 if event is None:
305 return
306 ex, ey = event.x, event.y
307 msg = ''
308 plotpanel = self.prof_plotter.panel
309 axes = plotpanel.fig.properties()['axes'][0]
310 write = plotpanel.write_message
311 try:
312 x, y = axes.transData.inverted().transform((ex, ey))
313 except:
314 x, y = event.xdata, event.ydata
316 if x is None or y is None:
317 return
319 _point = 0, 0, 0, 0, 0
320 for ix, iy in self.prof_dat[1]:
321 if (int(x) == ix and not self.prof_dat[0] or
322 int(x) == iy and self.prof_dat[0]):
323 _point = (ix, iy,
324 self.panel.xdata[ix],
325 self.panel.ydata[iy],
326 self.panel.conf.data[iy, ix])
328 msg = "Pixel [%i, %i], X, OME = [%.4f mm, %.4f deg], Intensity= %g" % _point
329 write(msg, panel=0)