Пример #1
0
    def __init__(self, wxparent=None, window=1, _larch=None, size=None, **kws):
        PlotFrame.__init__(self,
                           parent=None,
                           size=size,
                           output_title='plot2d',
                           exit_callback=self.onExit,
                           **kws)

        self.Show()
        self.Raise()
        self.panel.cursor_callback = self.onCursor
        self.panel.cursor_mode = 'zoom'
        self.window = int(window)
        self._larch = _larch
        self._xylims = {}
        self.cursor_hist = []
        self.symname = '%s.plot%i' % (MODNAME, self.window)
        symtable = ensuremod(self._larch, MODNAME)
        self.panel.canvas.figure.set_facecolor('#FDFDFB')

        if symtable is not None:
            symtable.set_symbol(self.symname, self)
            if not hasattr(symtable, '%s.cursor_maxhistory' % MODNAME):
                symtable.set_symbol('%s.cursor_maxhistory' % MODNAME,
                                    MAX_CURSHIST)

        if window not in PLOT_DISPLAYS:
            PLOT_DISPLAYS[window] = self
Пример #2
0
    def OnClick(self, event):
        p = self.dos_panel.GetParams()
        if p.step == 1234:
            awx.tetris_game()

        try:
            edos = self.bands.get_dos(step=p.step, width=p.width)
        except:
            awx.showErrorMessage(self)
            return

        tot_dos, tot_idos = edos.dos_idos()
        label = "$\sigma = %s, step = %s$" % (p.width, p.step)

        plotframe = None
        if self.replot_checkbox.GetValue() and len(self._pframes):
            plotframe = self._pframes[-1]

        if plotframe is None:
            plotframe = PlotFrame(parent=self)
            plotframe.plot(tot_dos.mesh, tot_dos.values, label=label, draw_legend=True)
            plotframe.Show()
            self._pframes.append(plotframe)
        else:
            plotframe.oplot(tot_dos.mesh, tot_dos.values, label=label, draw_legend=True)
Пример #3
0
    def onProject(self, event=None, mode='y'):

        wid = event.GetId()
        if mode=='x':
            x = self.tomo_frame[0].panel.ydata
            y = self.tomo_frame[0].panel.conf.data.sum(axis=1)
            x = self.tomo_frame[1].panel.ydata
            y = self.tomo_frame[1].panel.conf.data.sum(axis=1)
            axname = 'horizontal'
            if x is None:
                x = np.arange(y.shape[0])

        else:
            x = self.tomo_frame[0].panel.xdata
            y = self.tomo_frame[0].panel.conf.data.sum(axis=0)
            x = self.tomo_frame[1].panel.xdata
            y = self.tomo_frame[1].panel.conf.data.sum(axis=0)
            if x is None:
                x = np.arange(y.shape[0])

            axname = 'vertical'
        title = '%s: sum along %s axis' % (self.GetTitle(), axname)

        pf = PlotFrame(title=title, parent=self, size=(500, 250))
        colors = RGB_COLORS
        if len(y.shape) == 2 and y.shape[1] == 3:
            pf.plot(x, y[:,0], color=colors[0])
            pf.oplot(x, y[:,1], color=colors[1])
            pf.oplot(x, y[:,2], color=colors[2])
        else:
            pf.plot(x, y)
        pf.Raise()
        pf.Show()
Пример #4
0
 def raise_plotframe(self):
     if self.plotframe is not None:
         try:
             self.plotframe.Show()
         except:
             self.plotframe = None
     if self.plotframe is None:
         self.plotframe = PlotFrame(None, size=(650, 400))
         self.plotframe.Show()
Пример #5
0
    def onStartProjections(self, event=None):
        try:
            self.xplot.Raise()
        except:
            self.xplot = PlotFrame(parent=self)
        try:
            self.yplot.Raise()
        except:
            self.yplot = PlotFrame(parent=self)

        self.proj_start = True
        self.proj_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onShowProjections, self.proj_timer)
        self.proj_timer.Start(500)
Пример #6
0
    def onStartProjections(self, event=None):
        try:
            self.xplot.Raise()
        except:
            self.xplot = PlotFrame(parent=self)
        try:
            self.yplot.Raise()
        except:
            self.yplot = PlotFrame(parent=self)

        self.proj_start = True
        self.proj_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onShowProjections, self.proj_timer)
        self.proj_timer.Start(500)
Пример #7
0
    def OnCompare(self, event):
        """
        Callback triggered by the `compare` option in the popup menu of the panels
        Plote the netcdf variable/dimension as function of the file index.
        """
        # Get the name of the variable.
        name, obj = event.name, event.obj

        # Define the function to use the get the value of the dimension/variable.
        if isinstance(obj, netCDF4.Variable):
            def extract(dataset, name):
                return dataset.variables[name][:]

        elif isinstance(obj, netCDF4.Dimension):
            def extract(dataset, name):
                return np.array(len(dataset.dimensions[name]))

        else:
            raise ValueError("Don't know how to handle %s" % repr(obj))

        # Extract data. Make sure all the shapes are equal.
        data, shape = [], None
        for dataset in self.datasets:
            v = extract(dataset, name)
            data.append(v)
            if shape is None:
                shape = v.shape
            else:
                assert shape == v.shape

        # Plot data. Two Branches for scalars and arrays.
        opts = self.GetPlotOptions()

        is_scalar = not shape or (len(shape) == 1 and shape[0] == 1)
        #print(shape)

        from wxmplot import PlotFrame
        if is_scalar:
            frame = PlotFrame(parent=self)
            xx = range(len(self.datasets))

            if opts.plot_mode == "line":
                frame.plot(xx, data)
            else:
                frame.scatterplot(xx, data)

            frame.set_xlabel("File index")
            frame.set_ylabel(name)

            frame.Show()

        else:
            # Open new frame to allow the user to specify how to handle the array.
            ArrayComparisonFrame(self, name, data).Show()
Пример #8
0
    def show_PlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self, title='XRF Spectra')
        try:
            self.plotframe.Show()
        except wx.PyDeadObjectError:
            self.plotframe = PlotFrame(self, title='XRF Spectra')
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()
Пример #9
0
    def __init__(self, wxparent=None, window=1, _larch=None, **kws):
        PlotFrame.__init__(self, parent=wxparent,
                                 exit_callback=self.onExit, **kws)
        self.Show()
        self.Raise()
        self.cursor_pos = None
        self.panel.cursor_callback = self.onCursor
        self.window = int(window)
        self._larch = _larch
        self.symname = '%s.plot%i' % (MODNAME, self.window)
        symtable = ensuremod(self._larch)

        if symtable is not None:
            symtable.set_symbol(self.symname, self)
        if window not in PLOT_DISPLAYS:
            PLOT_DISPLAYS[window] = self
Пример #10
0
    def OnClick(self, event):
        method = self.method_choice.GetStringSelection()

        try:
            from wxmplot import PlotFrame
        except ImportError:
            #warnings.warn("Error while importing wxmplot. Some features won't be available")
            raise

        plotframe = None
        if self.replot_checkbox.GetValue() and len(self._pframes):
            plotframe = self._pframes[-1]

        try:
            if method == "None":
                g = self.func1d
            else:
                g = getattr(self.func1d, method)()

            if plotframe is None:
                plotframe = PlotFrame(self)
                self._pframes.append(plotframe)
                plotframe.plot(g.mesh, g.values, label=method, draw_legend=True)
                plotframe.Show()
            else:
                plotframe.oplot(g.mesh, g.values, label=method, draw_legend=True)

        except:
            showErrorMessage(self)
Пример #11
0
    def OnClick(self, event):
        method = self.method_choice.GetStringSelection()

        plotframe = None
        if self.replot_checkbox.GetValue() and len(self._pframes):
            plotframe = self._pframes[-1]

        try:
            if method == "None":
                g = self.func1d
            else:
                g = getattr(self.func1d, method)()

            if plotframe is None:
                plotframe = PlotFrame(self)
                self._pframes.append(plotframe)
                plotframe.plot(g.mesh,
                               g.values,
                               label=method,
                               draw_legend=True)
                plotframe.Show()
            else:
                plotframe.oplot(g.mesh,
                                g.values,
                                label=method,
                                draw_legend=True)

        except:
            showErrorMessage(self)
Пример #12
0
    def OnClick(self, event):
        p = self.dos_panel.GetParams()
        if p.step == 1234:
            awx.tetris_game()

        try:
            edos = self.bands.get_edos(step=p.step, width=p.width)
        except:
            awx.showErrorMessage(self)
            return

        tot_dos, tot_idos = edos.dos_idos()
        label = "$\sigma = %s, step = %s$" % (p.width, p.step)

        plotframe = None
        if self.replot_checkbox.GetValue() and len(self._pframes):
            plotframe = self._pframes[-1]

        if plotframe is None:
            plotframe = PlotFrame(parent=self)
            plotframe.plot(tot_dos.mesh,
                           tot_dos.values,
                           label=label,
                           draw_legend=True)
            plotframe.Show()
            self._pframes.append(plotframe)
        else:
            plotframe.oplot(tot_dos.mesh,
                            tot_dos.values,
                            label=label,
                            draw_legend=True)
Пример #13
0
    def __init__(self, wxparent=None, window=1, _larch=None, **kws):
        PlotFrame.__init__(self,
                           parent=wxparent,
                           exit_callback=self.onExit,
                           **kws)
        self.Show()
        self.Raise()
        self.cursor_pos = None
        self.panel.cursor_callback = self.onCursor
        self.window = int(window)
        self._larch = _larch
        self.symname = '%s.plot%i' % (MODNAME, self.window)
        symtable = ensuremod(self._larch)

        if symtable is not None:
            symtable.set_symbol(self.symname, self)
        if window not in PLOT_DISPLAYS:
            PLOT_DISPLAYS[window] = self
Пример #14
0
    def __init__(self, wxparent=None, window=1, _larch=None, size=None, **kws):
        PlotFrame.__init__(self, parent=None, size=size,
                           output_title='plot2d',
                           exit_callback=self.onExit, **kws)

        self.Show()
        self.Raise()
        self.panel.cursor_callback = self.onCursor
        self.panel.cursor_mode = 'zoom'
        self.window = int(window)
        self._larch = _larch
        self._xylims = {}
        self.symname = '%s.plot%i' % (MODNAME, self.window)
        symtable = ensuremod(self._larch, MODNAME)

        if symtable is not None:
            symtable.set_symbol(self.symname, self)
        if window not in PLOT_DISPLAYS:
            PLOT_DISPLAYS[window] = self
Пример #15
0
    def __init__(self, wxparent=None, window=1, _larch=None, size=None, **kws):
        PlotFrame.__init__(self,
                           parent=None,
                           size=size,
                           output_title='plot2d',
                           exit_callback=self.onExit,
                           **kws)

        self.Show()
        self.Raise()
        self.panel.cursor_callback = self.onCursor
        self.panel.cursor_mode = 'zoom'
        self.window = int(window)
        self._larch = _larch
        self._xylims = {}
        self.symname = '%s.plot%i' % (MODNAME, self.window)
        symtable = ensuremod(self._larch, MODNAME)

        if symtable is not None:
            symtable.set_symbol(self.symname, self)
        if window not in PLOT_DISPLAYS:
            PLOT_DISPLAYS[window] = self
Пример #16
0
    def get_plotwindow(self, new=False, **kws):
        pframe = None
        if not new:
            while pframe is None:
                try:
                    pframe = self.plotters.pop()
                    pframe.Show()
                    pframe.Raise()
                except IndexError:
                    pframe = None
                    break
                except PyDeadObjectError:
                    pframe = None

        if pframe is None:
            pframe = PlotFrame()
            pframe.Show()
            pframe.Raise()

        self.plotters.append(pframe)

        return pframe
Пример #17
0
    def OnClick(self, event):
        method = self.method_choice.GetStringSelection()

        plotframe = None
        if self.replot_checkbox.GetValue() and len(self._pframes):
            plotframe = self._pframes[-1]

        try:
            if method == "None":
                g = self.func1d
            else:
                g = getattr(self.func1d, method)()

            if plotframe is None:
                plotframe = PlotFrame(self)
                self._pframes.append(plotframe)
                plotframe.plot(g.mesh, g.values, label=method, draw_legend=True)
                plotframe.Show()
            else:
                plotframe.oplot(g.mesh, g.values, label=method, draw_legend=True)

        except:
            showErrorMessage(self)
Пример #18
0
    def __init__(self, wxparent=None, window=1, _larch=None, size=None, **kws):
        PlotFrame.__init__(self, parent=None, size=size,
                           output_title='plot2d',
                           exit_callback=self.onExit, **kws)

        self.Show()
        self.Raise()
        self.panel.cursor_callback = self.onCursor
        self.panel.cursor_mode = 'zoom'
        self.window = int(window)
        self._larch = _larch
        self._xylims = {}
        self.cursor_hist = []
        self.symname = '%s.plot%i' % (_larch_name, self.window)
        symtable = ensuremod(self._larch, _larch_name)
        self.panel.canvas.figure.set_facecolor('#FDFDFB')

        if symtable is not None:
            symtable.set_symbol(self.symname, self)
            if not hasattr(symtable, '%s.cursor_maxhistory' % _larch_name):
                symtable.set_symbol('%s.cursor_maxhistory' % _larch_name, MAX_CURSHIST)

        if window not in PLOT_DISPLAYS:
            PLOT_DISPLAYS[window] = self
Пример #19
0
    def onPlotData(self, event):
        operators = self.panel.GetSelectedOperators()

        from wxmplot import PlotFrame
        frame = PlotFrame(parent=self)

        xx = range(len(self.data))

        for oname, op in operators.items():
            #print(oname)
            values = [op(arr) for arr in self.data]

            frame.oplot(xx, values, label=oname)
            #if opts.plot_mode == "line":
            #    frame.oplot(xx, values)
            #else:
            #    frame.scatterplot(xx, values)

        frame.set_xlabel("File index")
        frame.set_ylabel(self.name)

        frame.Show()
Пример #20
0
 def onPlotData(self, event):
     operators = self.panel.GetSelectedOperators()
                                                     
     frame = PlotFrame(parent=self)
                                                     
     xx = range(len(self.data))
                                                     
     for oname, op in operators.items():
         #print(oname)
         values = [op(arr) for arr in self.data]
                                                     
         frame.oplot(xx, values, label=oname)
         #if opts.plot_mode == "line":
         #    frame.oplot(xx, values)
         #else:
         #    frame.scatterplot(xx, values)
                                       
     frame.set_xlabel("File index")
     frame.set_ylabel(self.name)
                                       
     frame.Show()
Пример #21
0
    def plot_variable(self, var_name, var, dataset):
        """
        Use `wxmplot` to plot the selected variables.

        Args:
            var_name:
                Name of the variable
            var:
                Netcdf4 `Variable`.
            dataset:
                Netcdf4 `Dataset`.
        """
        # Remove fake dimensions.
        shape, dimensions = [], []
        for num, name in zip(var.shape, var.dimensions):
            if num > 1:
                shape.append(num)
                dimensions.append(name)

        # Get data to plot.
        data = np.reshape(var[:], shape)
        opts = self.GetPlotOptions()

        cplx_mode = opts.cplx_mode
        if cplx_mode != "None":
            if shape[-1] != 2:
                err_msg = "cplx_mode: %s. Expecting 2 as last dimensions but got %d" % (
                    cplx_mode, shape[-1])
                raise ValueError(err_msg)
            # Convert to complex then change shape and dimensions
            data = data[..., 0] + 1j*data[..., 1]
            shape = shape[:-1]
            dimensions = dimensions[:-1]
            if cplx_mode == "Abs":
                data = np.abs(data)
            elif cplx_mode == "Real":
                data = data.real
            elif cplx_mode == "Imag":
                data = data.imag
            else:
                raise ValueError("Wrong value for cplx_mode %s" % cplx_mode)

        # Plotting a scalar?
        if not shape: return
        ndim = len(shape)

        if ndim == 1:
            # Vector
            dim_name = dimensions[0]
            xx = range(len(dataset.dimensions[dim_name]))

            frame = PlotFrame(parent=self)
            if opts.plot_mode == "line":
                frame.plot(xx, data)
            else:
                frame.scatterplot(xx, data)

            frame.set_xlabel(dim_name)
            frame.set_ylabel(var_name)

            frame.Show()

        elif ndim == 2:
            # Two dimensional array.
            dim_namex, dim_namey = dimensions
            xx, yy = range(len(dataset.dimensions[dim_namex])), range(len(dataset.dimensions[dim_namey]))

            mode = opts.image_mode

            if False:
                # 3d plot
                import matplotlib.pyplot as plt
                from mpl_toolkits.mplot3d import Axes3D
                fig = plt.figure()
                ax = Axes3D(fig)
                X, Y = np.meshgrid(xx, yy, sparse=False, indexing='ij')
                print(X.shape, Y.shape, data.shape)
                ax.plot_surface(X, Y, data) # rstride=8, cstride=8, alpha=0.3)
                plt.show()

            frame = ImageFrame(parent=self)
            frame.display(data, title=var_name, style=mode, x=xx, y=yy, xlabel=dim_namex, ylabel=dim_namey)
            frame.Show()

        else:
            raise NotImplementedError()
Пример #22
0
class MapImageFrame(ImageFrame):
    """
    MatPlotlib Image Display on a wx.Frame, using ImagePanel
    """

    def __init__(self, parent=None, size=None, mode='intensity',
                 lasso_callback=None, move_callback=None, save_callback=None,
                 show_xsections=False, cursor_labels=None,
                 output_title='Image',   **kws):

        # instdb=None,  inst_name=None,

        self.det = None
        self.xrmfile = None
        self.map = None
        self.move_callback = move_callback
        self.save_callback = save_callback

        ImageFrame.__init__(self, parent=parent, size=size,
                            lasso_callback=lasso_callback,
                            cursor_labels=cursor_labels, mode=mode,
                            output_title=output_title, **kws)

        self.panel.add_cursor_mode('prof', motion = self.prof_motion,
                                   leftdown = self.prof_leftdown,
                                   leftup   = self.prof_leftup)
        self.panel.report_leftdown = self.report_leftdown
        self.panel.report_motion   = self.report_motion


        self.prof_plotter = None
        self.zoom_ini =  None
        self.lastpoint = [None, None]
        self.this_point = None
        self.rbbox = None

    def display(self, map, det=None, xrmfile=None, xoff=0, yoff=0, **kws):
        self.xoff = xoff
        self.yoff = yoff
        self.det = det
        self.xrmfile = xrmfile
        self.map = map
        self.title = ''
        if 'title' in kws:
            self.title = kws['title']
        ImageFrame.display(self, map, **kws)
        if 'x' in kws:
            self.panel.xdata = kws['x']
        if 'y' in kws:
            self.panel.ydata = kws['y']
        if self.panel.conf.auto_contrast:
            self.set_contrast_levels()


    def prof_motion(self, event=None):
        if not event.inaxes or self.zoom_ini is None:
            return
        try:
            xmax, ymax  = event.x, event.y
        except:
            return

        xmin, ymin, xd, yd = self.zoom_ini
        if event.xdata is not None:
            self.lastpoint[0] = event.xdata
        if event.ydata is not None:
            self.lastpoint[1] = event.ydata

        yoff = self.panel.canvas.figure.bbox.height
        ymin, ymax = yoff - ymin, yoff - ymax

        zdc = wx.ClientDC(self.panel.canvas)
        zdc.SetLogicalFunction(wx.XOR)
        zdc.SetBrush(wx.TRANSPARENT_BRUSH)
        zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
        zdc.ResetBoundingBox()
        if not is_wxPhoenix:
            zdc.BeginDrawing()


        # erase previous box
        if self.rbbox is not None:
            zdc.DrawLine(*self.rbbox)
        self.rbbox = (xmin, ymin, xmax, ymax)
        zdc.DrawLine(*self.rbbox)
        if not is_wxPhoenix:
            zdc.EndDrawing()

    def prof_leftdown(self, event=None):
        self.report_leftdown(event=event)
        if event.inaxes and len(self.map.shape) == 2:
            self.lastpoint = [None, None]
            self.zoom_ini = [event.x, event.y, event.xdata, event.ydata]

    def prof_leftup(self, event=None):
        if len(self.map.shape) != 2:
            return
        if self.rbbox is not None:
            zdc = wx.ClientDC(self.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()

            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []

        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []
        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(self.panel.conf.data[iy,ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear() # reset_config()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)
        self.prof_plotter.plot(x, z, title=self.title, color='blue',
                               zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                               ylabel='counts', label='counts', **opts)

        self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                              zorder=3, side='right', color='#771111', **opts)

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'

    def prof_report_coords(self, event=None):
        """override report leftdown for profile plotter"""
        if event is None:
            return
        ex, ey = event.x, event.y
        msg = ''
        plotpanel = self.prof_plotter.panel
        axes  = plotpanel.fig.get_axes()[0]
        write = plotpanel.write_message
        try:
            x, y = axes.transData.inverted().transform((ex, ey))
        except:
            x, y = event.xdata, event.ydata

        if x is None or y is None:
            return

        _point = 0, 0, 0, 0, 0
        for ix, iy in self.prof_dat[1]:
            if (int(x) == ix and not self.prof_dat[0] or
                int(x) == iy and self.prof_dat[0]):
                _point = (ix, iy,
                              self.panel.xdata[ix],
                              self.panel.ydata[iy],
                              self.panel.conf.data[iy, ix])

        msg = "Pixel [%i, %i], X, Y = [%.4f, %.4f], Intensity= %g" % _point
        write(msg,  panel=0)

    def onCursorMode(self, event=None, mode='zoom'):
        self.panel.cursor_mode = mode
        if event is not None:
            if 1 == event.GetInt():
                self.panel.cursor_mode = 'lasso'
            elif 2 == event.GetInt():
                self.panel.cursor_mode = 'prof'


    def report_leftdown(self, event=None):
        if event is None:
            return
        if event.xdata is None or event.ydata is None:
            return

        ix, iy = round(event.xdata), round(event.ydata)
        conf = self.panel.conf
        if conf.flip_ud:  iy = conf.data.shape[0] - iy
        if conf.flip_lr:  ix = conf.data.shape[1] - ix

        self.this_point = None
        msg = ''
        if (ix >= 0 and ix < conf.data.shape[1] and
            iy >= 0 and iy < conf.data.shape[0]):
            pos = ''
            pan = self.panel
            # print( 'has xdata? ', pan.xdata is not None, pan.ydata is not None)
            labs, vals = [], []
            if pan.xdata is not None:
                labs.append(pan.xlab)
                vals.append(pan.xdata[ix])
            if pan.ydata is not None:
                labs.append(pan.ylab)
                vals.append(pan.ydata[iy])
            pos = ', '.join(labs)
            vals =', '.join(['%.4g' % v for v in vals])
            pos = '%s = [%s]' % (pos, vals)
            dval = conf.data[iy, ix]
            if len(pan.data_shape) == 3:
                dval = "%.4g, %.4g, %.4g" % tuple(dval)
            else:
                dval = "%.4g" % dval
            if pan.xdata is not None and pan.ydata is not None:
                self.this_point = (ix, iy)

            msg = "Pixel [%i, %i], %s, Intensity=%s " % (ix, iy, pos, dval)
        self.panel.write_message(msg, panel=0)

    def report_motion(self, event=None):
        return

    def onLasso(self, data=None, selected=None, mask=None, **kws):
        if hasattr(self.lasso_callback , '__call__'):

            self.lasso_callback(data=data, selected=selected, mask=mask,
                                xoff=self.xoff, yoff=self.yoff,
                                det=self.det, xrmfile=self.xrmfile, **kws)

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'

    def CustomConfig(self, panel, sizer, irow):
        """config panel for left-hand-side of frame"""
        conf = self.panel.conf
        lpanel = panel
        lsizer = sizer
        labstyle = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND

        self.zoom_mode = wx.RadioBox(panel, -1, "Cursor Mode:",
                                     wx.DefaultPosition, wx.DefaultSize,
                                     ('Zoom to Rectangle',
                                      'Pick Area for XRF Spectrum',
                                      'Show Line Profile'),
                                     1, wx.RA_SPECIFY_COLS)
        self.zoom_mode.Bind(wx.EVT_RADIOBOX, self.onCursorMode)
        sizer.Add(self.zoom_mode,  (irow, 0), (1, 4), labstyle, 3)
        if self.save_callback is not None:
            self.pos_name = wx.TextCtrl(panel, -1, '',  size=(175, -1),
                                        style=wx.TE_PROCESS_ENTER)
            self.pos_name.Bind(wx.EVT_TEXT_ENTER, self.onSavePixel)
            label   = SimpleText(panel, label='Save Position:',
                                 size=(-1, -1))
            # sbutton = Button(panel, 'Save Position', size=(100, -1),
            #                  action=self.onSavePixel)
            sizer.Add(label,         (irow+1, 0), (1, 2), labstyle, 3)
            sizer.Add(self.pos_name, (irow+1, 2), (1, 2), labstyle, 3)
            # sizer.Add(sbutton,       (irow+2, 0), (1, 2), labstyle, 3)

        if self.move_callback is not None:
            mbutton = Button(panel, 'Move to Position', size=(100, -1),
                                 action=self.onMoveToPixel)
            irow  = irow + 2
            sizer.Add(mbutton,       (irow+1, 0), (1, 2), labstyle, 3)

    def onMoveToPixel(self, event=None):
        if self.this_point is not None and self.move_callback is not None:
            p1 = float(self.panel.xdata[self.this_point[0]])
            p2 = float(self.panel.ydata[self.this_point[1]])
            self.move_callback(p1, p2)

    def onSavePixel(self, event=None):
        if self.this_point is not None and self.save_callback is not None:
            name  = str(event.GetString().strip())
            # name  = str(self.pos_name.GetValue().strip())
            ix, iy = self.this_point
            x = float(self.panel.xdata[ix])
            y = float(self.panel.ydata[iy])
            self.save_callback(name, ix, iy, x=x, y=y,
                               title=self.title, datafile=self.xrmfile)
Пример #23
0
    def prof_leftup(self, event=None):
        if len(self.map.shape) != 2:
            return
        if self.rbbox is not None:
            zdc = wx.ClientDC(self.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()

            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []

        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []
        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(self.panel.conf.data[iy,ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear() # reset_config()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)
        self.prof_plotter.plot(x, z, title=self.title, color='blue',
                               zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                               ylabel='counts', label='counts', **opts)

        self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                              zorder=3, side='right', color='#771111', **opts)

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'
Пример #24
0
class XRD2D_DisplayFrame(ImageFrame):
    """
    MatPlotlib Image Display on a wx.Frame, using ImagePanel
    """

    def __init__(self, _larch=None, parent=None, size=None, mode='intensity',
                 move_callback=None, save_callback=None,
                 show_xsections=False, cursor_labels=None,
                 output_title='Image',   **kws):

        self.xrmfile = None
        self.map = None
        self.move_callback = move_callback
        self.save_callback = save_callback

        self.larch = _larch
        if self.larch is None:
            self.init_larch()

        ImageFrame.__init__(self, parent=parent, size=size,
                            cursor_labels=cursor_labels, mode=mode,
                            output_title=output_title, **kws)

        self.panel.cursor_mode = 'zoom'
        self.panel.xaxis = 'q'
        self.panel.report_leftdown = self.report_leftdown
        self.panel.report_motion   = self.report_motion


        self.prof_plotter = None
        self.zoom_ini =  None
        self.lastpoint = [None, None]
        self.this_point = None
        self.rbbox = None

    def display(self, map, xrmfile=None, ai=None, mask=None, **kws):
        self.xrmfile = xrmfile
        self.map = map
        self.title = ''
        if 'title' in kws:
            self.title = kws['title']
        ImageFrame.display(self, map, **kws)

        if self.panel.conf.auto_contrast:
            self.set_contrast_levels()
        self.ai = ai
        self.mask = mask
        if np.shape(self.mask) == np.shape(map):
            self.masked_map = map * (np.ones(np.shape(self.mask))-mask.value)

        self.panel.xdata = np.arange(map.shape[0])
        self.panel.ydata = np.arange(map.shape[0])

    def init_larch(self):
        if self.larch is None:
            self.larch = Interpreter()

    def prof_motion(self, event=None):
        if not event.inaxes or self.zoom_ini is None:
            return
        try:
            xmax, ymax  = event.x, event.y
        except:
            return

        xmin, ymin, xd, yd = self.zoom_ini
        if event.xdata is not None:
            self.lastpoint[0] = event.xdata
        if event.ydata is not None:
            self.lastpoint[1] = event.ydata

        yoff = self.panel.canvas.figure.bbox.height
        ymin, ymax = yoff - ymin, yoff - ymax

        zdc = wx.ClientDC(self.panel.canvas)
        zdc.SetLogicalFunction(wx.XOR)
        zdc.SetBrush(wx.TRANSPARENT_BRUSH)
        zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
        zdc.ResetBoundingBox()
        if not is_wxPhoenix:
            zdc.BeginDrawing()


        # erase previous box
        if self.rbbox is not None:
            zdc.DrawLine(*self.rbbox)
        self.rbbox = (xmin, ymin, xmax, ymax)
        zdc.DrawLine(*self.rbbox)
        if not is_wxPhoenix:
            zdc.EndDrawing()

    def prof_leftdown(self, event=None):
        self.report_leftdown(event=event)
        if event.inaxes and len(self.map.shape) == 2:
            self.lastpoint = [None, None]
            self.zoom_ini = [event.x, event.y, event.xdata, event.ydata]

    def prof_leftup(self, event=None):
        if len(self.map.shape) != 2:
            return
        if self.rbbox is not None:
            zdc = wx.ClientDC(self.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()

            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []

        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []

        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(self.panel.conf.data[iy,ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear() # reset_config()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)
        self.prof_plotter.plot(x, z, title=self.title, color='blue',
                               zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                               ylabel='counts', label='counts', **opts)

        self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                              zorder=3, side='right', color='#771111', **opts)

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.panel.cursor_mode = 'zoom'

    def prof_report_coords(self, event=None):
        """override report leftdown for profile plotter"""
        if event is None:
            return
        ex, ey = event.x, event.y
        msg = ''
        plotpanel = self.prof_plotter.panel
        axes  = plotpanel.fig.get_axes()[0]
        write = plotpanel.write_message
        try:
            x, y = axes.transData.inverted().transform((ex, ey))
        except:
            x, y = event.xdata, event.ydata

        if x is None or y is None:
            return


        if self.ai is None:
            _point = 0, 0, 0
            for ix, iy in self.prof_dat[1]:
                if (int(x) == ix and not self.prof_dat[0] or
                    int(x) == iy and self.prof_dat[0]):
                    _point = (ix, iy,
                                  self.panel.conf.data[iy, ix])
                msg = "Pixel [%i, %i], Intensity= %g" % _point
        else:
            ai = self.ai
            xcenter = ai._poni2/ai.detector.pixel2        ## units pixels
            ycenter = ai._poni1/ai.detector.pixel1        ## units pixels
            _point = 0, 0, 0, 0, 0
            for ix, iy in self.prof_dat[1]:
                if (int(x) == ix and not self.prof_dat[0] or
                    int(x) == iy and self.prof_dat[0]):
                    x_pix = ix - xcenter                      ## units pixels
                    y_pix = iy - ycenter                      ## units pixels
                    x_m = x_pix * ai.detector.pixel2          ## units m
                    y_m = y_pix * ai.detector.pixel1          ## units m
                    twth = np.arctan2(math.sqrt(x_m**2 + y_m**2),ai._dist)  ## radians
                    twth = np.degrees(twth)                                 ## units degrees
                    eta  = np.arctan2(y_m,x_m)                              ## units radians
                    eta  = np.degrees(eta)                                  ## units degrees
                    _point = (ix, iy, twth, eta, self.panel.conf.data[iy, ix])
            msg = 'Pixel [%i, %i], 2TH=%.2f, ETA=%.1f, Intensity= %g' % _point
        write(msg,  panel=0)

    def report_leftdown(self, event=None):
        if event is None:
            return
        if event.xdata is None or event.ydata is None:
            return

        ix, iy = int(round(event.xdata)), int(round(event.ydata))
        conf = self.panel.conf
        if conf.flip_ud:  iy = conf.data.shape[0] - iy
        if conf.flip_lr:  ix = conf.data.shape[1] - ix

        self.this_point = None
        msg = ''
        if (ix >= 0 and ix < conf.data.shape[1] and
            iy >= 0 and iy < conf.data.shape[0]):
            pos = ''
            pan = self.panel
            labs, vals = [], []
            if pan.xdata is not None:
                labs.append(pan.xlab)
                vals.append(pan.xdata[ix])
            if pan.ydata is not None:
                labs.append(pan.ylab)
                vals.append(pan.ydata[iy])
            dval = conf.data[iy, ix]
            if len(pan.data_shape) == 3:
                dval = "%.4g, %.4g, %.4g" % tuple(dval)
            else:
                dval = "%.4g" % dval
            if pan.xdata is not None and pan.ydata is not None:
                self.this_point = (ix, iy)

            if self.ai is None:
                msg = "Pixel [%i, %i], Intensity=%s " % (ix, iy, dval)
            else:
                ai = self.ai
                xcenter = ai._poni2/ai.detector.pixel2        ## units pixels
                ycenter = ai._poni1/ai.detector.pixel1        ## units pixels
                x_pix = ix - xcenter                          ## units pixels
                y_pix = iy - ycenter                          ## units pixels
                x_m = x_pix * ai.detector.pixel2                        ## units m
                y_m = y_pix * ai.detector.pixel1                        ## units m
                twth = np.arctan2(math.sqrt(x_m**2 + y_m**2),ai._dist)  ## radians
                twth = np.degrees(twth)                                 ## units degrees
                eta  = np.arctan2(y_m,x_m)                              ## units radians
                eta  = np.degrees(eta)                                  ## units degrees
                msg = 'Pixel [%i, %i], 2TH=%.2f deg., ETA=%.1f deg., Intensity= %s' % (ix,
                                      iy, twth, eta, dval)
        self.panel.write_message(msg, panel=0)

    def report_motion(self, event=None):
        return

    def CustomConfig(self, panel, sizer, irow):
        """config panel for left-hand-side of frame"""
        conf = self.panel.conf
        lpanel = panel
        lsizer = sizer
        labstyle = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND

        self.MskCkBx = wx.CheckBox(panel, label='Apply mask?')
        self.MskCkBx.Bind(wx.EVT_CHECKBOX, self.onApplyMask)
        sizer.Add(self.MskCkBx, (irow+1,0), (1,4), labstyle, 3)

        self.LoadBtn = wx.Button(panel, label='Load New Mask')
        self.LoadBtn.Bind(wx.EVT_BUTTON, self.onLoadMask)
        sizer.Add(self.LoadBtn, (irow+2,0), (1,4), labstyle, 3)

        self.ReCalc1D = wx.Button(panel, label='Replot 1DXRD')
        self.ReCalc1D.Bind(wx.EVT_BUTTON, self.onReplot1DXRD)
        sizer.Add(self.ReCalc1D, (irow+3,0), (1,4), labstyle, 3)

    def onApplyMask(self, event):
        '''
        Applies mask to 2DXRD map
        mkak 2016.09.29
        '''
        if event.GetEventObject().GetValue():
            if self.masked_map is None:
                print('Mask file not defined.')

                question = 'No mask found in map file. Would you like to load a new file now?'
                caption = 'Load mask file?'
                dlg = wx.MessageDialog(self, question, caption, wx.YES_NO | wx.ICON_QUESTION)
                print( 'answer:', dlg.ShowModal()) # == wx.ID_YES
                read = dlg.ShowModal()
                dlg.Destroy()
                if read == wx.ID_YES:
                    self.onLoadMask()

                self.MskCkBx.SetValue(False)
            else:
                ImageFrame.display(self, self.masked_map)

        else:
            ImageFrame.display(self, self.map)

    def onLoadMask(self, evt=None):

        wildcards = 'pyFAI mask (*.edf)|*.edf|All files (*.*)|*.*'
        dlg = wx.FileDialog(self, message='Choose XRD mask file',
                           defaultDir=os.getcwd(),
                           wildcard=wildcards, style=wx.FD_OPEN)

        edffile, read = None, False
        if dlg.ShowModal() == wx.ID_OK:
            read = True
            edffile = dlg.GetPath().replace('\\', '/')
        dlg.Destroy()

        if read:

            print('Reading mask file: %s' % edffile)
            try:
                import fabio
                self.mask = fabio.open(edffile).data
                self.masked_map = self.map * (np.ones(np.shape(self.mask))-self.mask)
                self.MskCkBx.SetValue(True)
                ImageFrame.display(self, self.masked_map)
            except:
                print('File must be .edf format; user must have fabio installed.')

            ## Can this be called here?
            #readEDFfile(self,name='mask',keyword='maskfile')
            #add_calibration()

    def onReplot1DXRD(self, evt=None):

        print('Not yet implemented.')
Пример #25
0
class StageFrame(wx.Frame):
    htmllog  = 'SampleStage.html'
    html_header = """<html><head><title>Sample Stage Log</title></head>
<meta http-equiv='Pragma'  content='no-cache'>
<meta http-equiv='Refresh' content='300'>
<body>
    """

    def __init__(self, inifile='SampleStage.ini', size=(1600, 800),
                 ask_workdir=True, orientation='landscape'):
        super(StageFrame, self).__init__(None, wx.ID_ANY,
                                         style=wx.DEFAULT_FRAME_STYLE,
                                         size=size)

        self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
        self.read_config(configfile=inifile, get_dir=ask_workdir)
        self.overlay_frame = None
        self.last_pixel = None
        self.xhair_pixel = None
        self.create_frame(size=size, orientation=orientation)
        self.xplot = None
        self.yplot = None
        self.imgpanel.Start()

    def create_frame(self, size=(1600, 800), orientation='landscape'):
        "build main frame"
        self.statusbar = self.CreateStatusBar(2, wx.CAPTION)
        self.statusbar.SetStatusWidths([-4, -1])
        for index in range(2):
            self.statusbar.SetStatusText('', index)
        config = self.config

        opts = dict(writer=self.write_framerate,
                    leftdown_cb=self.onSelectPixel,
                    motion_cb=self.onPixelMotion,
                    xhair_cb=self.onShowCrosshair,
                    center_cb=self.onMoveToCenter,
                    autosave_file=self.autosave_file)
        if self.cam_type.startswith('fly2'):
            opts['camera_id'] = int(self.cam_fly2id)
            opts['output_pv'] = config['camera'].get('output_pv', None)
            ImagePanel, ConfPanel = ImagePanel_Fly2, ConfPanel_Fly2
        elif self.cam_type.startswith('area'):
            opts['prefix'] = self.cam_adpref
            ImagePanel, ConfPanel = ImagePanel_EpicsAD, ConfPanel_EpicsAD
        elif self.cam_type.startswith('webcam'):
            opts['url'] = self.cam_weburl
            ImagePanel, ConfPanel = ImagePanel_URL, ConfPanel_URL

        self.imgpanel  = ImagePanel(self, **opts)
        self.imgpanel.SetMinSize((285, 250))

        if orientation.lower().startswith('land'):
            size = (1600, 800)
            self.cpanel = wx.CollapsiblePane(self, label='Show Controls',
                                             style=wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE)

            self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged, self.cpanel)

            ppanel = wx.Panel(self.cpanel.GetPane())

            self.pospanel  = PositionPanel(ppanel, self, config=config['scandb'])
            self.pospanel.SetMinSize((250, 700))

            self.ctrlpanel = ControlPanel(ppanel,
                                          groups=config['stage_groups'],
                                          config=config['stages'],
                                          autofocus=self.onAutoFocus)

            self.confpanel = ConfPanel(ppanel,
                                       image_panel=self.imgpanel, **opts)

            msizer = wx.GridBagSizer(2, 2)
            msizer.Add(self.ctrlpanel, (0, 0), (1, 1), ALL_EXP|LEFT_TOP, 1)
            msizer.Add(self.confpanel, (1, 0), (1, 1), ALL_EXP|LEFT_TOP, 1)
            msizer.Add(self.pospanel,  (0, 1), (2, 1), ALL_EXP|LEFT_TOP, 2)

            pack(ppanel, msizer)

            sizer = wx.BoxSizer(wx.HORIZONTAL)
            sizer.AddMany([(self.imgpanel,  5, ALL_EXP|LEFT_CEN, 0),
                           (self.cpanel,    1, ALL_EXP|LEFT_CEN|wx.GROW, 1)])

            pack(self, sizer)
            self.cpanel.Collapse(False)
            self.cpanel.SetLabel('Hide Controls')

        else: # portrait mode
            size = (900, 1500)
            ppanel = wx.Panel(self)
            self.pospanel  = PositionPanel(ppanel, self, config=config['scandb'])
            self.pospanel.SetMinSize((250, 450))
            self.ctrlpanel = ControlPanel(ppanel,
                                          groups=config['stage_groups'],
                                          config=config['stages'],
                                          autofocus=self.onAutoFocus)

            self.confpanel = ConfPanel(ppanel,
                                       image_panel=self.imgpanel, **opts)

            msizer = wx.GridBagSizer(3, 3)
            msizer.Add(self.ctrlpanel, (0, 0), (1, 1), ALL_EXP|LEFT_TOP, 1)
            msizer.Add(self.pospanel,  (0, 1), (2, 1), ALL_EXP|LEFT_TOP, 2)
            msizer.Add(self.confpanel, (0, 2), (1, 1), ALL_EXP|LEFT_TOP, 1)

            pack(ppanel, msizer)

            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.AddMany([(self.imgpanel,  5, ALL_EXP|LEFT_CEN, 0),
                           (ppanel,    1, ALL_EXP|LEFT_CEN|wx.GROW, 1)])

            pack(self, sizer)

        self.imgpanel.confpanel = self.confpanel
        self.SetSize(size)
        if len(self.iconfile) > 0:
            self.SetIcon(wx.Icon(self.iconfile, wx.BITMAP_TYPE_ICO))

        ex  = [{'shape':'circle', 'color': (255, 0, 0),
                'width': 1.5, 'args': (0.5, 0.5, 0.007)},
               {'shape':'line', 'color': (200, 100, 0),
                'width': 2.0, 'args': (0.7, 0.97, 0.97, 0.97)}]

        self.create_menus()
        self.Bind(wx.EVT_CLOSE, self.onClose)
        self.init_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onInitTimer, self.init_timer)
        self.init_timer.Start(1000)

    def OnPaneChanged(self, evt=None):
        self.Layout()
        if self.cpanel.IsExpanded():
            self.cpanel.SetLabel('Hide Controls')
        else:
            self.cpanel.SetLabel('Show Controls')
        self.imgpanel.Refresh()


    def onInitTimer(self, event=None, **kws):
        if self.imgpanel.full_size is not None:
            if 'overlays' in self.config:
                olays = self.config['overlays']
                sbar = [float(x) for x in olays['scalebar'].split()]
                circ = [float(x) for x in olays['circle'].split()]

                img_x, img_y = self.imgpanel.full_size
                pix_x = float(self.config['camera']['calib_x'])
                iscale = 0.5/abs(pix_x * img_x)

                ssiz, sx, sy, swid, scolr, scolg, scolb = sbar
                csiz, cx, cy, cwid, ccolr, ccolg, ccolb = circ

                cargs = [cx, cy, csiz*iscale]
                sargs = [sx - ssiz*iscale, sy, sx + ssiz*iscale, sy]

                scol = wx.Colour(int(scolr), int(scolg), int(scolb))
                ccol = wx.Colour(int(ccolr), int(ccolg), int(ccolb))

                dobjs = [dict(shape='Line', width=swid,
                              style=wx.SOLID, color=scol, args=sargs),
                         dict(shape='Circle', width=cwid,
                              style=wx.SOLID, color=ccol, args=cargs)]

                if self.xhair_pixel is not None:
                    xwid, xcolr, xcolg, xcolb = swid, scolr, scolg, scolb
                    xcol = wx.Colour(int(xcolr), int(xcolg), int(xcolb))
                    xcol = wx.Colour(int(20), int(300), int(250))
                    hx = self.xhair_pixel['x']
                    hy = self.xhair_pixel['y']
                    xargs = [hx - ssiz*iscale, hy - ssiz*iscale, hx + ssiz*iscale, hy + ssiz*iscale]

                    dobjs.append(dict(shape='Line', width=2,
                                      style=wx.SOLID, color=xcol, args=xargs))
                    #print "Showing xhair: ", xargs
                # print 'Draw Objects ', dobjs
                self.imgpanel.draw_objects = dobjs
            self.init_timer.Stop()


    def onChangeCamera(self, evt=None):
        if not self.cam_type.startswith('area'):
            print 'How did that happen?'
            return

        name = self.cam_adpref
        prefix = None
        dlg = wx.TextEntryDialog(self, 'Enter PV for Area Detector',
                                 caption='Enter PV for Area Detector',
                                 defaultValue=name)
        dlg.Raise()
        if dlg.ShowModal() == wx.ID_OK:
            prefix = dlg.GetValue()
        dlg.Destroy()
        if prefix is not None:
            self.imgpanel.set_prefix(prefix)
            self.confpanel.set_prefix(prefix)
            self.cam_adpref = prefix


    def create_menus(self):
        "Create the menubar"
        mbar  = wx.MenuBar()
        fmenu = wx.Menu()
        pmenu = wx.Menu()
        omenu = wx.Menu()
        add_menu(self, fmenu, label="&Read Config", text="Read Configuration",
                 action = self.onReadConfig)

        add_menu(self, fmenu, label="&Save Config", text="Save Configuration",
                 action = self.onSaveConfig)

        add_menu(self, fmenu, label="Show Projections\tCtrl+G",
                 text="Start Projection Plots",
                 action = self.onStartProjections)

        add_menu(self, fmenu, label="Print Blurriness\tCtrl+B",
                 text="print blurriness",
                 action = self.onReportBlurry)

        add_menu(self, fmenu, label="Stop Projection\tCtrl+C",
                 text="Stop Projection Plots",
                 action = self.onStopProjections)

        add_menu(self, fmenu, label="Select &Working Directory\tCtrl+W",
                 text="change Working Folder",
                 action = self.onChangeWorkdir)

        if self.cam_type.startswith('area'):
            add_menu(self, fmenu, label="Change AreaDetector",
                     text="Change Camera to different AreaDetector",
                     action = self.onChangeCamera)

        fmenu.AppendSeparator()
        add_menu(self, fmenu, label="E&xit\tCtrl+x",  text="Quit Program",
                 action = self.onClose)

        add_menu(self, pmenu, label="Export Positions", text="Export Positions",
                 action = self.onExportPositions)
        add_menu(self, pmenu, label="Import Positions", text="Import Positions",
                 action = self.onImportPositions)
        add_menu(self, pmenu, label="Erase Many Positions\tCtrl+E",
                 text="Select Multiple Positions to Erase",
                 action = self.onEraseMany)


        add_menu(self, omenu, label="Image Overlays",
                 text="Setup Image Overlays",
                 action = self.onConfigOverlays)


        vmove  = wx.NewId()
        verase = wx.NewId()
        vreplace = wx.NewId()
        cenfine = wx.NewId()
        self.menu_opts = {vmove: 'v_move', verase: 'v_erase',
                          vreplace: 'v_replace',
                          cenfine: 'center_with_fine_stages'}

        mitem = omenu.Append(vmove, "Verify Go To ",
                             "Prompt to Verify Moving with 'Go To'",
                             wx.ITEM_CHECK)
        mitem.Check()
        self.Bind(wx.EVT_MENU, self.onMenuOption, mitem)

        mitem = omenu.Append(verase, "Verify Erase",
                     "Prompt to Verify Erasing Positions", wx.ITEM_CHECK)
        mitem.Check()
        self.Bind(wx.EVT_MENU, self.onMenuOption, mitem)

        mitem = omenu.Append(vreplace, "Verify Overwrite",
                     "Prompt to Verify Overwriting Positions",  wx.ITEM_CHECK)
        mitem.Check()
        self.Bind(wx.EVT_MENU, self.onMenuOption, mitem)

        mitem = omenu.Append(cenfine, "Center With Fine Stages",
                     "Bring to Center will move the Fine Stages", wx.ITEM_CHECK)
        mitem.Check(0)
        self.Bind(wx.EVT_MENU, self.onMenuOption, mitem)

        omenu.AppendSeparator()

        # print 'Create Menus ',      self.ctrlpanel.subpanels
        # for key, val in self.config['stages'].items():
        #     print key, val

        for name, panel in self.ctrlpanel.subpanels.items():
            show = 0
            label = 'Enable %s' % name
            mid = wx.NewId()
            self.menu_opts[mid] = label
            for mname, data in self.config['stages'].items():
                if data['group'] == name:
                    show = show + data['show']
            mitem = omenu.Append(mid, label, label, wx.ITEM_CHECK)
            if show > 0 :
                mitem.Check()
            self.Bind(wx.EVT_MENU, Closure(self.onShowHide, name=name, panel=panel), mitem)

        mbar.Append(fmenu, '&File')
        mbar.Append(omenu, '&Options')
        mbar.Append(pmenu, 'Positions')

        if len(self.config['scandb'].get('offline', '')):
            cmenu = wx.Menu()
            # add_menu(self, cmenu, label="Calibrate Microscope",
            #          text="Calibrate to Offline Microscope",
            #          action = self.pospanel.onMicroscopeCalibrate)
            add_menu(self, cmenu, label="Copy Positions from Offline Microscope",
                     text="Copy Positions from Offline Microscope",
                     action = self.pospanel.onMicroscopeTransfer)

            mbar.Append(cmenu, 'Offline Microscope')

        self.SetMenuBar(mbar)

    def onShowHide(self, event=None, panel=None, name='---'):
        showval = {True:1, False:0}[event.Checked()]
        if showval:
            panel.Enable()
        else:
            panel.Disable()

        for mname, data in self.config['stages'].items():
            if data['group'] == name:
                data['show'] = showval

    def onEraseMany(self, evt=None, **kws):
        self.pospanel.onEraseMany(event=evt)
        evt.Skip()

    def onConfigOverlays(self, evt=None, **kws):
        shown = False
        if self.overlay_frame is not None:
            try:
                self.overlay_frame.Raise()
                shown = True
            except:
                del self.overlay_frame
        if not shown:
            self.overlayframe = OverlayFrame(image_panel=self.imgpanel,
                                             config=self.config)

    def onMenuOption(self, evt=None):
        """events for options menu: move, erase, overwrite """
        setattr(self, self.menu_opts[evt.GetId()], evt.Checked())

    def read_config(self, configfile=None, get_dir=False):
        "open/read ini config file"
        if get_dir:
            ret = SelectWorkdir(self)
            if ret is None:
                self.Destroy()
            os.chdir(ret)
        self.cnf = StageConfig(configfile)
        self.config = self.cnf.config
        gui = self.config['gui']
        self.workdir_file  = gui.get('workdir_file', 'sampleviewer_workdir.txt')
        self.iconfile      = gui.get('icon_file', '')
        self.autosave_file = gui.get('autosave_file', 'SampleStage_autosave.ini')
        self.v_move    = gui.get('verify_move', True)
        self.v_erase   = gui.get('verify_erase', True)
        self.v_replace = gui.get('verify_overwrite', True)
        self.center_with_fine_stages = gui.get('center_with_fine_stages', False)
        self.SetTitle(gui.get('title', 'Microscope'))

        cam = self.config['camera']
        self.imgdir     = cam.get('image_folder', 'Sample_Images')
        self.cam_type   = cam.get('type', 'fly2').lower()
        self.cam_fly2id = cam.get('fly2_id', 0)
        self.cam_adpref = cam.get('ad_prefix', '')
        self.cam_adform = cam.get('ad_format', 'JPEG')
        self.cam_weburl = cam.get('web_url', 'http://164.54.160.115/jpg/2/image.jpg')
        self.get_cam_calib()
        try:
            pref = self.imgdir.split('_')[0]
        except:
            pref = 'Sample'
        self.htmllog = '%sStage.html' % pref
        if not os.path.exists(self.imgdir):
            os.makedirs(self.imgdir)
        if not os.path.exists(self.htmllog):
            self.begin_htmllog()

        self.config = self.cnf.config
        self.stages = OrderedDict()
        for mname, data in self.config.get('stages', {}).items():
            mot = Motor(name=mname)
            if data['prec'] is None:
                data['prec'] = mot.precision
            if data['desc'] is None:
                data['desc'] = mot.description
            if data['maxstep'] is None:
                data['maxstep'] = (mot.high_limit - mot.low_limit)/2.10
            self.stages[mname] = data

    def get_cam_calib(self):
        cam = self.config['camera']
        cx = self.cam_calibx = float(cam.get('calib_x', 0.001))
        cy = self.cam_caliby = float(cam.get('calib_y', 0.001))
        return cx, cy

    def begin_htmllog(self):
        "initialize log file"
        fout = open(self.htmllog, 'w')
        fout.write(self.html_header)
        fout.close()

    def save_image(self, fname):
        "save image to file"
        imgdata = self.imgpanel.SaveImage(fname)
        if imgdata is None:
            self.write_message('could not save image to %s' % fname)
        else:
            self.write_message('saved image to %s' % fname)
        return imgdata

    def autosave(self, positions=None):
        self.cnf.Save(self.autosave_file, positions=positions)

    def write_htmllog(self, name, thispos):
        stages  = self.config['stages']
        img_folder = self.config['camera']['image_folder']
        junk, img_file = os.path.split(thispos['image'])
        imgfile = os.path.join(img_folder, img_file)

        txt = []
        html_fmt ="""<hr>
    <table><tr><td><a href='%s'> <img src='%s' width=350></a></td>
    <td><table><tr><td>Position:</td><td>%s</td><td>%s</td></tr>
    <tr><td>Motor Name</td><td>PV Name</td><td>Value</td></tr>
    %s
    </table></td></tr></table>"""
        pos_fmt ="    <tr><td> %s </td><td> %s </td><td>   %f</td></tr>"
        for pvname, value in thispos['position'].items():
            txt.append(pos_fmt % (stages[pvname]['desc'], pvname, value))

        fout = open(self.htmllog, 'a')
        fout.write(html_fmt % (imgfile, imgfile, name,
                               thispos['timestamp'],  '\n'.join(txt)))
        fout.close()

    def write_message(self, msg='', index=0):
        "write to status bar"
        self.statusbar.SetStatusText(msg, index)

    def write_framerate(self, msg):
        "write to status bar"
        self.statusbar.SetStatusText(msg, 1)

    def onShowCrosshair(self, event=None, show=True, **kws):
        self.xhair_pixel = None
        if show:
            self.xhair_pixel = self.last_pixel
            print "Set XHAIR ", self.xhair_pixel

    def onAFTimer(self, event=None, **kws):
        if self.af_done:
            self.af_thread.join()
            self.af_timer.Stop()
            if self.ctrlpanel.af_message is not None:
                self.ctrlpanel.af_message.SetLabel('')
            self.ctrlpanel.af_button.Enable()

    def onAutoFocus(self, event=None, **kws):
        self.af_done = False
        self.ctrlpanel.af_button.Disable()
        self.af_thread = Thread(target=self.do_autofocus)
        self.af_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onAFTimer, self.af_timer)
        self.af_timer.Start(2000)
        self.af_thread.start()

    def do_autofocus(self):
        report = None
        if self.ctrlpanel.af_message is not None:
            report = self.ctrlpanel.af_message.SetLabel
        if report is not None:
            report('Auto-setting exposure')
        self.imgpanel.AutoSetExposureTime()
        report('Auto-focussing start')

        zstage = self.ctrlpanel.motors['z']._pvs['VAL']

        start_pos = zstage.get()
        min_pos = start_pos - 2.50
        max_pos = start_pos + 2.50

        step, min_step = 0.004*(81), 0.002
        # start trying both directions:

        score_start = image_blurriness(self.imgpanel)
        zstage.put(start_pos+step/2.0, wait=True)
        time.sleep(0.15)
        score_plus = image_blurriness(self.imgpanel)
        direction = 1
        if score_start < score_plus:
            direction = -1
        print("Start Scores: ", score_start, score_plus, direction)

        best_score = score_start
        best_pos = start_pos
        zstage.put(start_pos, wait=True)

        count = 0
        report('Auto-focussing finding focus')
        posvals = []
        scores  = []
        while step >= min_step and count < 32:
            self.imgpanel.Refresh()
            count += 1
            pos = zstage.get() + step * direction
            if pos < min_pos or pos > max_pos:
                break
            zstage.put(pos, wait=True, timeout=3.0)
            time.sleep(0.15)
            score = image_blurriness(self.imgpanel)
            # print(" step : ", step, direction, score_plus)
            report('Auto-focussing step=%.3f' % step)
            # print 'Focus %i: %.3f %.3f %.3f %.3f %.3f %.1f' % (
            #     count, pos, score, best_pos, best_score, step, direction)
            posvals.append(pos)
            scores.append(score)
            if score < best_score:
                best_score = score
                best_pos = pos
            else:
                # best_score = score
                step = step / 3.0
                if step < min_step:
                    break
                direction = -direction
                zstage.put(best_pos, wait=True, timeout=3.0)
                time.sleep(0.15)
            last_score = score
        zstage.put(best_pos)
        self.af_done = True
        report('Auto-focussing done.')



    def onMoveToCenter(self, event=None, **kws):
        "bring last pixel to image center"
        p = self.last_pixel
        if p is None:
            return

        cal_x, cal_y = self.get_cam_calib()
        dx = 0.001*cal_x*(p['x']-p['xmax']/2.0)
        dy = 0.001*cal_y*(p['y']-p['ymax']/2.0)

        mots = self.ctrlpanel.motors

        xmotor, ymotor = 'x', 'y'
        if self.center_with_fine_stages and 'finex' in mots:
            xmotor, ymotor = 'finex', 'finey'

        xscale, yscale = 1.0, 1.0
        for stage_info in self.stages.values():
            if stage_info['desc'].lower() == xmotor:
                xscale = stage_info['scale']
            if stage_info['desc'].lower() == ymotor:
                yscale = stage_info['scale']

        mots[xmotor].VAL += dx*xscale
        mots[ymotor].VAL += dy*yscale
        self.onSelectPixel(p['xmax']/2.0, p['ymax']/2.0,
                           xmax=p['xmax'], ymax=p['ymax'])

    def onSelectPixel(self, x, y, xmax=100, ymax=100):
        " select a pixel from image "
        self.last_pixel = dict(x=x, y=y, xmax=xmax, ymax=ymax)
        cal_x, cal_y = self.get_cam_calib()
        self.confpanel.on_selected_pixel(x, y, xmax, ymax,
                                         cam_calibx=cal_x,
                                         cam_caliby=cal_y)

    def onPixelMotion(self, x, y, xmax=100, ymax=100):
        " select a pixel from image "
        fmt  = """Pixel=(%i, %i) (%.1f, %.1f)um from center, (%.1f, %.1f)um from selected"""
        if x > 0 and x < xmax and y > 0 and y < ymax:
            dx = abs(self.cam_calibx*(x-xmax/2.0))
            dy = abs(self.cam_caliby*(y-ymax/2.0))
            ux, uy = 0, 0
            if self.last_pixel is not None:
                lastx = self.last_pixel['x']
                lasty = self.last_pixel['y']
                ux = abs(self.cam_calibx*(x-lastx))
                uy = abs(self.cam_caliby*(y-lasty))

            pix_msg = fmt % (x, y, dx, dy, ux, uy)
            self.write_message(pix_msg)

            if not self.confpanel.img_size_shown:
                self.confpanel.img_size.SetLabel("(%i, %i)" % (xmax, ymax))
                self.confpanel.img_size_shown = True

    def onClose(self, event=None):
        if wx.ID_YES == popup(self, "Really Quit?", "Exit Sample Stage?",
                              style=wx.YES_NO|wx.NO_DEFAULT|wx.ICON_QUESTION):

            fout = open(self.workdir_file, 'w')
            fout.write("%s\n" % os.path.abspath(os.curdir))
            fout.close()
            self.imgpanel.Stop()
            try:
                self.overlay_frame.Destroy()
            except:
                pass
            self.Destroy()

    def onExportPositions(self, event=None):
        fname = FileSave(self, 'Export Positions File',
                         wildcard='Position Files (*.pos)|*.pos|All files (*.*)|*.*',
                         default_file='Save.pos')
        if fname is not None:
            self.pospanel.SavePositions(fname)

        self.write_message('Saved Positions File %s' % fname)

    def onImportPositions(self, event=None):
        fname = FileOpen(self, 'Import Positions File',
                         wildcard='Position Files (*.pos)|*.pos|All files (*.*)|*.*',
                         default_file='Save.pos')
        if fname is not None:
            self.pospanel.LoadPositions(fname)

        self.write_message('Loaded Positions from File %s' % fname)


    def onChangeWorkdir(self, event=None):
        ret = SelectWorkdir(self)
        if ret is None:
            return
        os.chdir(ret)
        cam = self.config['camera']
        self.imgdir     = cam.get('image_folder', 'Sample_Images')
        if not os.path.exists(self.imgdir):
            os.makedirs(self.imgdir)
        if not os.path.exists(self.htmllog):
            self.begin_htmllog()


    def onReportBlurry(self, event=None):
        score = image_blurriness(self.imgpanel, full=True)
        tscore = -(5*score[0] - score[1])
        print(" blurriness: %.3f  %.3f -> %.3f " % (score[0], score[1], tscore))

    def onStartProjections(self, event=None):
        try:
            self.xplot.Raise()
        except:
            self.xplot = PlotFrame(parent=self)
        try:
            self.yplot.Raise()
        except:
            self.yplot = PlotFrame(parent=self)

        self.proj_start = True
        self.proj_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onShowProjections, self.proj_timer)
        self.proj_timer.Start(500)


    def onStopProjections(self, event=None):
        self.proj_timer.Stop()


    def onShowProjections(self, event=None):
        dat = self.imgpanel.grab_data()
        shape = dat.shape
        if len(shape) == 3:
            dat = dat.sum(axis=2)
        cx, cy = self.get_cam_calib()
        kws = dict(ylabel='intensity',
                   xlabel='distance ($\mu\mathrm{m}$)',
                   marker='+', markersize=4)

        _y = (np.arange(shape[0]) - shape[0]/2.0) *abs(cx)
        _x = (np.arange(shape[1]) - shape[1]/2.0) *abs(cy)
        _xi = dat.sum(axis=0)
        _yi = dat.sum(axis=1)
        ymin = min((min(_xi), min(_yi)))
        ymax = max((max(_xi), max(_yi)))

        if self.proj_start:
            self.xplot.plot(_x, _xi, title='X projection', **kws)
            self.yplot.plot(_y, _yi, title='Y projection', **kws)
            self.xplot.Show()
            self.yplot.Show()
            self.proj_start = False
        else:
            self.xplot.panel.update_line(0, _x, _xi, draw=True, update_limits=True)
            self.yplot.panel.update_line(0, _y, _yi, draw=True, update_limits=True)

            self.xplot.panel.axes.set_ylim((ymin, ymax), emit=True)
            self.yplot.panel.axes.set_ylim((ymin, ymax), emit=True)

            # print 'X lims: ', self.xplot.panel.conf.zoom_lims, xlims
            # self.xplot.panel.set_xylims(xlims)
            # self.yplot.panel.set_xylims(ylims)

    def onSaveConfig(self, event=None):
        fname = FileSave(self, 'Save Configuration File',
                         wildcard='INI (*.ini)|*.ini|All files (*.*)|*.*',
                         default_file='SampleStage.ini')
        if fname is not None:
            self.cnf.Save(fname)
        self.write_message('Saved Configuration File %s' % fname)


    def onReadConfig(self, event=None):
        fname = FileOpen(self, 'Read Configuration File',
                         wildcard='INI (*.ini)|*.ini|All files (*.*)|*.*',
                         default_file='SampleStage.ini')
        if fname is not None:
            self.read_config(fname)
            self.connect_motors()
            self.pospanel.set_positions(self.config['positions'])
        self.write_message('Read Configuration File %s' % fname)
Пример #26
0
    def prof_leftup(self, event=None):
        if len(self.map.shape) != 2:
            return
        if self.rbbox is not None:
            zdc = wx.ClientDC(self.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()

            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []

        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []
        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(self.panel.conf.data[iy,ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear() # reset_config()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)
        self.prof_plotter.plot(x, z, title=self.title, color='blue',
                               zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                               ylabel='counts', label='counts', **opts)

        self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                              zorder=3, side='right', color='#771111', **opts)

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'
Пример #27
0
    def OnCompare(self, event):
        """
        Callback triggered by the `compare` option in the popup menu of the panels
        Plote the netcdf variable/dimension as function of the file index.
        """
        # Get the name of the variable.
        name, obj = event.name, event.obj

        # Define the function to use the get the value of the dimension/variable.
        if isinstance(obj, netCDF4.Variable):

            def extract(dataset, name):
                return dataset.variables[name][:]

        elif isinstance(obj, netCDF4.Dimension):

            def extract(dataset, name):
                return np.array(len(dataset.dimensions[name]))

        else:
            raise ValueError("Don't know how to handle %s" % repr(obj))

        # Extract data. Make sure all the shapes are equal.
        data, shape = [], None
        for dataset in self.datasets:
            v = extract(dataset, name)
            data.append(v)
            if shape is None:
                shape = v.shape
            else:
                assert shape == v.shape

        # Plot data. Two Branches for scalars and arrays.
        opts = self.GetPlotOptions()

        is_scalar = not shape or (len(shape) == 1 and shape[0] == 1)
        #print(shape)

        from wxmplot import PlotFrame
        if is_scalar:
            frame = PlotFrame(parent=self)
            xx = range(len(self.datasets))

            if opts.plot_mode == "line":
                frame.plot(xx, data)
            else:
                frame.scatterplot(xx, data)

            frame.set_xlabel("File index")
            frame.set_ylabel(name)

            frame.Show()

        else:
            # Open new frame to allow the user to specify how to handle the array.
            ArrayComparisonFrame(self, name, data).Show()
Пример #28
0
    def plot_variable(self, var_name, var, dataset):
        """
        Use `wxmplot` to plot the selected variables.

        Args:
            var_name:
                Name of the variable
            var:
                Netcdf4 `Variable`.
            dataset:
                Netcdf4 `Dataset`.
        """
        # Remove fake dimensions.
        shape, dimensions = [], []
        for num, name in zip(var.shape, var.dimensions):
            if num > 1:
                shape.append(num)
                dimensions.append(name)

        # Get data to plot.
        data = np.reshape(var[:], shape)
        opts = self.GetPlotOptions()

        cplx_mode = opts.cplx_mode
        if cplx_mode != "None":
            if shape[-1] != 2:
                err_msg = "cplx_mode: %s. Expecting 2 as last dimensions but got %d" % (
                    cplx_mode, shape[-1])
                raise ValueError(err_msg)
            # Convert to complex then change shape and dimensions
            data = data[..., 0] + 1j * data[..., 1]
            shape = shape[:-1]
            dimensions = dimensions[:-1]
            if cplx_mode == "Abs":
                data = np.abs(data)
            elif cplx_mode == "Real":
                data = data.real
            elif cplx_mode == "Imag":
                data = data.imag
            else:
                raise ValueError("Wrong value for cplx_mode %s" % cplx_mode)

        # Plotting a scalar?
        if not shape: return
        ndim = len(shape)

        if ndim == 1:
            # Vector
            dim_name = dimensions[0]
            xx = range(len(dataset.dimensions[dim_name]))

            from wxmplot import PlotFrame
            frame = PlotFrame(parent=self)
            if opts.plot_mode == "line":
                frame.plot(xx, data)
            else:
                frame.scatterplot(xx, data)

            frame.set_xlabel(dim_name)
            frame.set_ylabel(var_name)

            frame.Show()

        elif ndim == 2:
            # Two dimensional array.
            dim_namex, dim_namey = dimensions
            xx, yy = range(len(dataset.dimensions[dim_namex])), range(
                len(dataset.dimensions[dim_namey]))

            mode = opts.image_mode

            if False:
                # 3d plot
                import matplotlib.pyplot as plt
                from mpl_toolkits.mplot3d import Axes3D
                fig = plt.figure()
                ax = Axes3D(fig)
                X, Y = np.meshgrid(xx, yy, sparse=False, indexing='ij')
                print(X.shape, Y.shape, data.shape)
                ax.plot_surface(X, Y, data)  # rstride=8, cstride=8, alpha=0.3)
                plt.show()

            from wxmplot import ImageFrame
            frame = ImageFrame(parent=self)
            frame.display(data,
                          title=var_name,
                          style=mode,
                          x=xx,
                          y=yy,
                          xlabel=dim_namex,
                          ylabel=dim_namey)
            frame.Show()

        else:
            raise NotImplementedError()
Пример #29
0
class StageFrame(wx.Frame):
    htmllog = 'SampleStage.html'
    html_header = """<html><head><title>Sample Stage Log</title></head>
<meta http-equiv='Pragma'  content='no-cache'>
<meta http-equiv='Refresh' content='300'>
<body>
    """

    def __init__(self,
                 inifile='SampleStage.ini',
                 size=(1600, 800),
                 ask_workdir=True,
                 orientation='landscape'):
        super(StageFrame, self).__init__(None,
                                         wx.ID_ANY,
                                         style=wx.DEFAULT_FRAME_STYLE,
                                         size=size)

        self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False))
        self.read_config(configfile=inifile, get_dir=ask_workdir)
        self.overlay_frame = None
        self.last_pixel = None
        self.xhair_pixel = None
        self.create_frame(size=size, orientation=orientation)
        self.xplot = None
        self.yplot = None
        self.imgpanel.Start()

    def create_frame(self, size=(1600, 800), orientation='landscape'):
        "build main frame"
        self.statusbar = self.CreateStatusBar(2, wx.CAPTION)
        self.statusbar.SetStatusWidths([-4, -1])
        for index in range(2):
            self.statusbar.SetStatusText('', index)
        config = self.config

        opts = dict(writer=self.write_framerate,
                    leftdown_cb=self.onSelectPixel,
                    motion_cb=self.onPixelMotion,
                    xhair_cb=self.onShowCrosshair,
                    center_cb=self.onMoveToCenter,
                    autosave_file=self.autosave_file)

        autofocus_cb = self.onAutoFocus

        if self.cam_type.startswith('fly2'):
            opts['camera_id'] = int(self.cam_fly2id)
            opts['output_pv'] = config['camera'].get('output_pv', None)
            ImagePanel, ConfPanel = ImagePanel_Fly2, ConfPanel_Fly2
        elif self.cam_type.startswith('adfly'):
            opts['prefix'] = self.cam_adpref
            ImagePanel, ConfPanel = ImagePanel_Fly2AD, ConfPanel_Fly2AD
            autofocus_cb = None
        elif self.cam_type.startswith('area'):
            opts['prefix'] = self.cam_adpref
            ImagePanel, ConfPanel = ImagePanel_EpicsAD, ConfPanel_EpicsAD
        elif self.cam_type.startswith('webcam'):
            opts['url'] = self.cam_weburl
            ImagePanel, ConfPanel = ImagePanel_URL, ConfPanel_URL

        self.imgpanel = ImagePanel(self, **opts)
        self.imgpanel.SetMinSize((285, 250))

        if orientation.lower().startswith('land'):
            size = (1600, 800)
            self.cpanel = wx.CollapsiblePane(self,
                                             label='Show Controls',
                                             style=wx.CP_DEFAULT_STYLE
                                             | wx.CP_NO_TLW_RESIZE)

            self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged,
                      self.cpanel)

            ppanel = wx.Panel(self.cpanel.GetPane())

            self.pospanel = PositionPanel(ppanel,
                                          self,
                                          config=config['scandb'])
            self.pospanel.SetMinSize((250, 700))

            self.ctrlpanel = ControlPanel(ppanel,
                                          groups=config['stage_groups'],
                                          config=config['stages'],
                                          autofocus=autofocus_cb)

            self.confpanel = ConfPanel(ppanel,
                                       image_panel=self.imgpanel,
                                       **opts)

            msizer = wx.GridBagSizer(2, 2)
            msizer.Add(self.ctrlpanel, (0, 0), (1, 1), ALL_EXP | LEFT_TOP, 1)
            msizer.Add(self.confpanel, (1, 0), (1, 1), ALL_EXP | LEFT_TOP, 1)
            msizer.Add(self.pospanel, (0, 1), (2, 1), ALL_EXP | LEFT_TOP, 2)

            pack(ppanel, msizer)

            sizer = wx.BoxSizer(wx.HORIZONTAL)
            sizer.AddMany([(self.imgpanel, 5, ALL_EXP | LEFT_CEN, 0),
                           (self.cpanel, 1, ALL_EXP | LEFT_CEN | wx.GROW, 1)])

            pack(self, sizer)
            self.cpanel.Collapse(False)
            self.cpanel.SetLabel('Hide Controls')

        else:  # portrait mode
            size = (900, 1500)
            ppanel = wx.Panel(self)
            self.pospanel = PositionPanel(ppanel,
                                          self,
                                          config=config['scandb'])
            self.pospanel.SetMinSize((250, 450))
            self.ctrlpanel = ControlPanel(ppanel,
                                          groups=config['stage_groups'],
                                          config=config['stages'],
                                          autofocus=autofocus_cb)

            self.confpanel = ConfPanel(ppanel,
                                       image_panel=self.imgpanel,
                                       **opts)

            msizer = wx.GridBagSizer(3, 3)
            msizer.Add(self.ctrlpanel, (0, 0), (1, 1), ALL_EXP | LEFT_TOP, 1)
            msizer.Add(self.pospanel, (0, 1), (2, 1), ALL_EXP | LEFT_TOP, 2)
            msizer.Add(self.confpanel, (0, 2), (1, 1), ALL_EXP | LEFT_TOP, 1)

            pack(ppanel, msizer)

            sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.AddMany([(self.imgpanel, 5, ALL_EXP | LEFT_CEN, 0),
                           (ppanel, 1, ALL_EXP | LEFT_CEN | wx.GROW, 1)])

            pack(self, sizer)

        self.imgpanel.confpanel = self.confpanel
        self.SetSize(size)
        if len(self.iconfile) > 0:
            self.SetIcon(wx.Icon(self.iconfile, wx.BITMAP_TYPE_ICO))

        ex = [{
            'shape': 'circle',
            'color': (255, 0, 0),
            'width': 1.5,
            'args': (0.5, 0.5, 0.007)
        }, {
            'shape': 'line',
            'color': (200, 100, 0),
            'width': 2.0,
            'args': (0.7, 0.97, 0.97, 0.97)
        }]

        self.create_menus()
        self.Bind(wx.EVT_CLOSE, self.onClose)
        self.init_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onInitTimer, self.init_timer)
        self.init_timer.Start(1000)

    def OnPaneChanged(self, evt=None):
        self.Layout()
        if self.cpanel.IsExpanded():
            self.cpanel.SetLabel('Hide Controls')
        else:
            self.cpanel.SetLabel('Show Controls')
        self.imgpanel.Refresh()

    def onInitTimer(self, event=None, **kws):
        if self.imgpanel.full_size is not None:
            if 'overlays' in self.config:
                olays = self.config['overlays']
                sbar = [float(x) for x in olays['scalebar'].split()]
                circ = [float(x) for x in olays['circle'].split()]

                img_x, img_y = self.imgpanel.full_size
                pix_x = float(self.config['camera']['calib_x'])
                iscale = 0.5 / abs(pix_x * img_x)

                ssiz, sx, sy, swid, scolr, scolg, scolb = sbar
                csiz, cx, cy, cwid, ccolr, ccolg, ccolb = circ

                cargs = [cx, cy, csiz * iscale]
                sargs = [sx - ssiz * iscale, sy, sx + ssiz * iscale, sy]

                scol = wx.Colour(int(scolr), int(scolg), int(scolb))
                ccol = wx.Colour(int(ccolr), int(ccolg), int(ccolb))

                dobjs = [
                    dict(shape='Line',
                         width=swid,
                         style=wx.SOLID,
                         color=scol,
                         args=sargs),
                    dict(shape='Circle',
                         width=cwid,
                         style=wx.SOLID,
                         color=ccol,
                         args=cargs)
                ]

                if self.xhair_pixel is not None:
                    xwid, xcolr, xcolg, xcolb = swid, scolr, scolg, scolb
                    xcol = wx.Colour(int(xcolr), int(xcolg), int(xcolb))
                    xcol = wx.Colour(int(20), int(300), int(250))
                    hx = self.xhair_pixel['x']
                    hy = self.xhair_pixel['y']
                    xargs = [
                        hx - ssiz * iscale, hy - ssiz * iscale,
                        hx + ssiz * iscale, hy + ssiz * iscale
                    ]

                    dobjs.append(
                        dict(shape='Line',
                             width=2,
                             style=wx.SOLID,
                             color=xcol,
                             args=xargs))
                    #print( "Showing xhair: ", xargs)
                # print('Draw Objects ', dobjs)
                self.imgpanel.draw_objects = dobjs
            self.init_timer.Stop()

    def onChangeCamera(self, evt=None):
        if not self.cam_type.startswith('area'):
            print('How did that happen?')
            return

        name = self.cam_adpref
        prefix = None
        dlg = wx.TextEntryDialog(self,
                                 'Enter PV for Area Detector',
                                 caption='Enter PV for Area Detector',
                                 defaultValue=name)
        dlg.Raise()
        if dlg.ShowModal() == wx.ID_OK:
            prefix = dlg.GetValue()
        dlg.Destroy()
        if prefix is not None:
            self.imgpanel.set_prefix(prefix)
            self.confpanel.set_prefix(prefix)
            self.cam_adpref = prefix

    def create_menus(self):
        "Create the menubar"
        mbar = wx.MenuBar()
        fmenu = wx.Menu()
        pmenu = wx.Menu()
        omenu = wx.Menu()
        add_menu(self,
                 fmenu,
                 label="&Read Config",
                 text="Read Configuration",
                 action=self.onReadConfig)

        add_menu(self,
                 fmenu,
                 label="&Save Config",
                 text="Save Configuration",
                 action=self.onSaveConfig)

        add_menu(self,
                 fmenu,
                 label="Show Projections\tCtrl+G",
                 text="Start Projection Plots",
                 action=self.onStartProjections)

        add_menu(self,
                 fmenu,
                 label="Print Blurriness\tCtrl+B",
                 text="print blurriness",
                 action=self.onReportBlurry)

        add_menu(self,
                 fmenu,
                 label="Stop Projection\tCtrl+C",
                 text="Stop Projection Plots",
                 action=self.onStopProjections)

        add_menu(self,
                 fmenu,
                 label="Select &Working Directory\tCtrl+W",
                 text="change Working Folder",
                 action=self.onChangeWorkdir)

        if self.cam_type.startswith('area'):
            add_menu(self,
                     fmenu,
                     label="Change AreaDetector",
                     text="Change Camera to different AreaDetector",
                     action=self.onChangeCamera)

        fmenu.AppendSeparator()
        add_menu(self,
                 fmenu,
                 label="E&xit\tCtrl+x",
                 text="Quit Program",
                 action=self.onClose)

        add_menu(self,
                 pmenu,
                 label="Export Positions",
                 text="Export Positions",
                 action=self.onExportPositions)
        add_menu(self,
                 pmenu,
                 label="Import Positions",
                 text="Import Positions",
                 action=self.onImportPositions)
        add_menu(self,
                 pmenu,
                 label="Erase Many Positions\tCtrl+E",
                 text="Select Multiple Positions to Erase",
                 action=self.onEraseMany)

        add_menu(self,
                 omenu,
                 label="Image Overlays",
                 text="Setup Image Overlays",
                 action=self.onConfigOverlays)

        vmove = wx.NewId()
        verase = wx.NewId()
        vreplace = wx.NewId()
        cenfine = wx.NewId()
        self.menu_opts = {
            vmove: 'v_move',
            verase: 'v_erase',
            vreplace: 'v_replace',
            cenfine: 'center_with_fine_stages'
        }

        mitem = omenu.Append(vmove, "Verify Go To ",
                             "Prompt to Verify Moving with 'Go To'",
                             wx.ITEM_CHECK)
        mitem.Check()
        self.Bind(wx.EVT_MENU, self.onMenuOption, mitem)

        mitem = omenu.Append(verase, "Verify Erase",
                             "Prompt to Verify Erasing Positions",
                             wx.ITEM_CHECK)
        mitem.Check()
        self.Bind(wx.EVT_MENU, self.onMenuOption, mitem)

        mitem = omenu.Append(vreplace, "Verify Overwrite",
                             "Prompt to Verify Overwriting Positions",
                             wx.ITEM_CHECK)
        mitem.Check()
        self.Bind(wx.EVT_MENU, self.onMenuOption, mitem)

        mitem = omenu.Append(cenfine, "Center With Fine Stages",
                             "Bring to Center will move the Fine Stages",
                             wx.ITEM_CHECK)
        mitem.Check(0)
        self.Bind(wx.EVT_MENU, self.onMenuOption, mitem)

        omenu.AppendSeparator()

        # print( 'Create Menus ',      self.ctrlpanel.subpanels)
        # for key, val in self.config['stages'].items():
        #     print( key, val)

        for name, panel in self.ctrlpanel.subpanels.items():
            show = 0
            label = 'Enable %s' % name
            mid = wx.NewId()
            self.menu_opts[mid] = label
            for mname, data in self.config['stages'].items():
                if data['group'] == name:
                    show = show + data['show']
            mitem = omenu.Append(mid, label, label, wx.ITEM_CHECK)
            if show > 0:
                mitem.Check()
            self.Bind(wx.EVT_MENU,
                      Closure(self.onShowHide, name=name, panel=panel), mitem)

        mbar.Append(fmenu, '&File')
        mbar.Append(omenu, '&Options')
        mbar.Append(pmenu, 'Positions')

        if len(self.config['scandb'].get('offline', '')):
            cmenu = wx.Menu()
            # add_menu(self, cmenu, label="Calibrate Microscope",
            #          text="Calibrate to Offline Microscope",
            #          action = self.pospanel.onMicroscopeCalibrate)
            add_menu(self,
                     cmenu,
                     label="Copy Positions from Offline Microscope",
                     text="Copy Positions from Offline Microscope",
                     action=self.pospanel.onMicroscopeTransfer)

            mbar.Append(cmenu, 'Offline Microscope')

        self.SetMenuBar(mbar)

    def onShowHide(self, event=None, panel=None, name='---'):
        showval = {True: 1, False: 0}[event.IsChecked()]
        if showval:
            panel.Enable()
        else:
            panel.Disable()

        for mname, data in self.config['stages'].items():
            if data['group'] == name:
                data['show'] = showval

    def onEraseMany(self, evt=None, **kws):
        self.pospanel.onEraseMany(event=evt)
        evt.Skip()

    def onConfigOverlays(self, evt=None, **kws):
        shown = False
        if self.overlay_frame is not None:
            try:
                self.overlay_frame.Raise()
                shown = True
            except:
                del self.overlay_frame
        if not shown:
            self.overlayframe = OverlayFrame(image_panel=self.imgpanel,
                                             config=self.config)

    def onMenuOption(self, evt=None):
        """events for options menu: move, erase, overwrite """
        setattr(self, self.menu_opts[evt.GetId()], evt.IsChecked())

    def read_config(self, configfile=None, get_dir=False):
        "open/read ini config file"
        if get_dir:
            ret = SelectWorkdir(self)
            if ret is None:
                self.Destroy()
            os.chdir(ret)
        self.cnf = StageConfig(configfile)
        self.config = self.cnf.config
        gui = self.config['gui']
        self.workdir_file = gui.get('workdir_file', 'sampleviewer_workdir.txt')
        self.iconfile = gui.get('icon_file', '')
        self.autosave_file = gui.get('autosave_file',
                                     'SampleStage_autosave.ini')
        self.v_move = gui.get('verify_move', True)
        self.v_erase = gui.get('verify_erase', True)
        self.v_replace = gui.get('verify_overwrite', True)
        self.center_with_fine_stages = gui.get('center_with_fine_stages',
                                               False)
        self.SetTitle(gui.get('title', 'Microscope'))

        cam = self.config['camera']
        self.imgdir = cam.get('image_folder', 'Sample_Images')
        self.cam_type = cam.get('type', 'fly2').lower()
        self.cam_fly2id = cam.get('fly2_id', 0)
        self.cam_adpref = cam.get('ad_prefix', '')
        self.cam_adform = cam.get('ad_format', 'JPEG')
        self.cam_weburl = cam.get('web_url',
                                  'http://164.54.160.115/jpg/2/image.jpg')
        self.get_cam_calib()
        try:
            pref = self.imgdir.split('_')[0]
        except:
            pref = 'Sample'
        self.htmllog = '%sStage.html' % pref
        if not os.path.exists(self.imgdir):
            os.makedirs(self.imgdir)
        if not os.path.exists(self.htmllog):
            self.begin_htmllog()

        self.config = self.cnf.config
        self.stages = OrderedDict()
        for mname, data in self.config.get('stages', {}).items():
            mot = Motor(name=mname)
            if data['prec'] is None:
                data['prec'] = mot.precision
            if data['desc'] is None:
                data['desc'] = mot.description
            if data['maxstep'] is None:
                data['maxstep'] = (mot.high_limit - mot.low_limit) / 2.10
            self.stages[mname] = data

    def get_cam_calib(self):
        cam = self.config['camera']
        cx = self.cam_calibx = float(cam.get('calib_x', 0.001))
        cy = self.cam_caliby = float(cam.get('calib_y', 0.001))
        return cx, cy

    def begin_htmllog(self):
        "initialize log file"
        fout = open(self.htmllog, 'w')
        fout.write(self.html_header)
        fout.close()

    def save_image(self, fname):
        "save image to file"
        imgdata = self.imgpanel.SaveImage(fname)
        if imgdata is None:
            self.write_message('could not save image to %s' % fname)
        else:
            self.write_message('saved image to %s' % fname)
        return imgdata

    def autosave(self, positions=None):
        self.cnf.Save(self.autosave_file, positions=positions)

    def write_htmllog(self, name, thispos):
        stages = self.config['stages']
        img_folder = self.config['camera']['image_folder']
        junk, img_file = os.path.split(thispos['image'])
        imgfile = os.path.join(img_folder, img_file)

        txt = []
        html_fmt = """<hr>
    <table><tr><td><a href='%s'> <img src='%s' width=350></a></td>
    <td><table><tr><td>Position:</td><td>%s</td><td>%s</td></tr>
    <tr><td>Motor Name</td><td>PV Name</td><td>Value</td></tr>
    %s
    </table></td></tr></table>"""
        pos_fmt = "    <tr><td> %s </td><td> %s </td><td>   %f</td></tr>"
        for pvname, value in thispos['position'].items():
            txt.append(pos_fmt % (stages[pvname]['desc'], pvname, value))

        fout = open(self.htmllog, 'a')
        fout.write(
            html_fmt %
            (imgfile, imgfile, name, thispos['timestamp'], '\n'.join(txt)))
        fout.close()

    def write_message(self, msg='', index=0):
        "write to status bar"
        self.statusbar.SetStatusText(msg, index)

    def write_framerate(self, msg):
        "write to status bar"
        self.statusbar.SetStatusText(msg, 1)

    def onShowCrosshair(self, event=None, show=True, **kws):
        self.xhair_pixel = None
        if show:
            self.xhair_pixel = self.last_pixel

    def onAFTimer(self, event=None, **kws):
        if self.af_done:
            self.af_thread.join()
            self.af_timer.Stop()
            if self.ctrlpanel.af_message is not None:
                self.ctrlpanel.af_message.SetLabel('')
            self.ctrlpanel.af_button.Enable()

    def onAutoFocus(self, event=None, **kws):
        self.af_done = False
        self.ctrlpanel.af_button.Disable()
        self.af_thread = Thread(target=self.do_autofocus)
        self.af_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onAFTimer, self.af_timer)
        self.af_timer.Start(2000)
        self.af_thread.start()

    def do_autofocus(self):
        report = None
        if self.ctrlpanel.af_message is not None:
            report = self.ctrlpanel.af_message.SetLabel
        if report is not None:
            report('Auto-setting exposure')
        self.imgpanel.AutoSetExposureTime()
        report('Auto-focussing start')

        def make_fibs(max=3000):
            f = [1., 1.]
            i = 0
            while True:
                val = f[i] + f[i + 1]
                if val > max:
                    break
                f.append(val)
                i += 1
            return f

        zstage = self.ctrlpanel.motors['z']._pvs['VAL']

        start_pos = zstage.get()
        focus_data = []

        def get_score(pos):
            zpos = start_pos + pos * 0.001
            zstage.put(zpos, wait=True)
            time.sleep(0.2)
            score = image_blurriness(self.imgpanel)
            dat = (pos, zstage.get(), score)
            focus_data.append(dat)
            return score

        # step 1: take up to 15 steps of 250 microns
        # while score is still improving
        report('Auto-focussing finding rough focus')
        scores = []
        NMAX = 15
        step = 250.0
        score0 = get_score(0)
        scorep = get_score(step)
        scorem = get_score(-step)
        sign = None
        best = 0.0
        if scorem < score0:
            score0 = scorem
            sign = -1.0
        elif scorep < score0:
            score0 = scorep
            sign = 1.0

        if sign is not None:
            i = 1
            while i < NMAX:
                i = i + 1
                tmp = sign * step * (i + 1)
                score = get_score(tmp)
                if score > score0:
                    break
                score0, best = score, tmp
        zstage.put(start_pos + best * 0.001, wait=True)

        # now refine
        start_pos = zstage.get()
        report('Auto-focussing refining focus')
        start, stop = -300, 300
        fibs = make_fibs(max=abs(stop - start))
        nfibs = len(fibs)
        step = fibs[nfibs - 3] / fibs[nfibs - 1]
        best = (start + stop) / 2
        z1, z2 = int(start + step * (stop - start)), int(stop - step *
                                                         (stop - start))
        score1, score2 = get_score(z1), get_score(z2)
        for i in range(nfibs - 2):
            step = fibs[nfibs - i - 3] / fibs[nfibs - i - 1]
            report("Auto-focussing refining focus %i " % (i + 1))
            if score1 > score2:
                start = z1
                best = int(stop - step * (stop - start))
                z1, z2 = z2, best
                score1, score2 = score2, get_score(best)
            else:
                stop = z2
                best = int(start + step * (stop - start))
                z1, z2 = best, z1
                score1, score2 = get_score(best), score1
            if abs(z1 - z2) < 2:
                break

        get_score(best)
        report('Auto-focussing done. ')
        self.ctrlpanel.af_button.Enable()

    def onMoveToCenter(self, event=None, **kws):
        "bring last pixel to image center"
        p = self.last_pixel
        if p is None:
            return

        cal_x, cal_y = self.get_cam_calib()
        dx = 0.001 * cal_x * (p['x'] - p['xmax'] / 2.0)
        dy = 0.001 * cal_y * (p['y'] - p['ymax'] / 2.0)

        mots = self.ctrlpanel.motors

        xmotor, ymotor = 'x', 'y'
        if self.center_with_fine_stages and 'finex' in mots:
            xmotor, ymotor = 'finex', 'finey'

        xscale, yscale = 1.0, 1.0
        for stage_info in self.stages.values():
            if stage_info['desc'].lower() == xmotor:
                xscale = stage_info['scale']
            if stage_info['desc'].lower() == ymotor:
                yscale = stage_info['scale']

        mots[xmotor].VAL += dx * xscale
        mots[ymotor].VAL += dy * yscale
        self.onSelectPixel(p['xmax'] / 2.0,
                           p['ymax'] / 2.0,
                           xmax=p['xmax'],
                           ymax=p['ymax'])

    def onSelectPixel(self, x, y, xmax=100, ymax=100):
        " select a pixel from image "
        self.last_pixel = dict(x=x, y=y, xmax=xmax, ymax=ymax)
        cal_x, cal_y = self.get_cam_calib()
        self.confpanel.on_selected_pixel(x,
                                         y,
                                         xmax,
                                         ymax,
                                         cam_calibx=cal_x,
                                         cam_caliby=cal_y)

    def onPixelMotion(self, x, y, xmax=100, ymax=100):
        " select a pixel from image "
        fmt = """Pixel=(%i, %i) (%.1f, %.1f)um from center, (%.1f, %.1f)um from selected"""
        if x > 0 and x < xmax and y > 0 and y < ymax:
            dx = abs(self.cam_calibx * (x - xmax / 2.0))
            dy = abs(self.cam_caliby * (y - ymax / 2.0))
            ux, uy = 0, 0
            if self.last_pixel is not None:
                lastx = self.last_pixel['x']
                lasty = self.last_pixel['y']
                ux = abs(self.cam_calibx * (x - lastx))
                uy = abs(self.cam_caliby * (y - lasty))

            pix_msg = fmt % (x, y, dx, dy, ux, uy)
            self.write_message(pix_msg)

            if not self.confpanel.img_size_shown:
                self.confpanel.img_size.SetLabel("(%i, %i)" % (xmax, ymax))
                self.confpanel.img_size_shown = True

    def onClose(self, event=None):
        if wx.ID_YES == popup(self,
                              "Really Quit?",
                              "Exit Sample Stage?",
                              style=wx.YES_NO | wx.NO_DEFAULT
                              | wx.ICON_QUESTION):

            fout = open(self.workdir_file, 'w')
            fout.write("%s\n" % os.path.abspath(os.curdir))
            fout.close()
            self.imgpanel.Stop()
            try:
                self.overlay_frame.Destroy()
            except:
                pass
            self.Destroy()

    def onExportPositions(self, event=None):
        curpath = os.getcwd()
        fname = FileSave(
            self,
            'Export Positions File',
            wildcard='Position Files (*.pos)|*.pos|All files (*.*)|*.*',
            default_file='Save.pos')
        if fname is not None:
            self.pospanel.SavePositions(fname)

        self.write_message('Saved Positions File %s' % fname)
        os.chdir(curpath)

    def onImportPositions(self, event=None):
        curpath = os.getcwd()
        fname = FileOpen(
            self,
            'Import Positions File',
            wildcard='Position Files (*.pos)|*.pos|All files (*.*)|*.*',
            default_file='Save.pos')
        if fname is not None:
            self.pospanel.LoadPositions(fname)

        self.write_message('Loaded Positions from File %s' % fname)
        os.chdir(curpath)

    def onChangeWorkdir(self, event=None):
        ret = SelectWorkdir(self)
        if ret is None:
            return
        os.chdir(ret)
        cam = self.config['camera']
        self.imgdir = cam.get('image_folder', 'Sample_Images')
        if not os.path.exists(self.imgdir):
            os.makedirs(self.imgdir)
        if not os.path.exists(self.htmllog):
            self.begin_htmllog()

    def onReportBlurry(self, event=None):
        score = image_blurriness(self.imgpanel)
        print(" blurriness = %.3f" % (score))

    def onStartProjections(self, event=None):
        try:
            self.xplot.Raise()
        except:
            self.xplot = PlotFrame(parent=self)
        try:
            self.yplot.Raise()
        except:
            self.yplot = PlotFrame(parent=self)

        self.proj_start = True
        self.proj_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.onShowProjections, self.proj_timer)
        self.proj_timer.Start(500)

    def onStopProjections(self, event=None):
        self.proj_timer.Stop()

    def onShowProjections(self, event=None):
        dat = self.imgpanel.grab_data()
        shape = dat.shape
        if len(shape) == 3:
            dat = dat.sum(axis=2)
        cx, cy = self.get_cam_calib()
        kws = dict(ylabel='intensity',
                   xlabel='distance ($\mu\mathrm{m}$)',
                   marker='+',
                   markersize=4)

        _y = (np.arange(shape[0]) - shape[0] / 2.0) * abs(cx)
        _x = (np.arange(shape[1]) - shape[1] / 2.0) * abs(cy)
        _xi = dat.sum(axis=0)
        _yi = dat.sum(axis=1)
        ymin = min((min(_xi), min(_yi)))
        ymax = max((max(_xi), max(_yi)))

        if self.proj_start:
            self.xplot.plot(_x, _xi, title='X projection', **kws)
            self.yplot.plot(_y, _yi, title='Y projection', **kws)
            self.xplot.Show()
            self.yplot.Show()
            self.proj_start = False
        else:
            self.xplot.panel.update_line(0,
                                         _x,
                                         _xi,
                                         draw=True,
                                         update_limits=True)
            self.yplot.panel.update_line(0,
                                         _y,
                                         _yi,
                                         draw=True,
                                         update_limits=True)

            self.xplot.panel.axes.set_ylim((ymin, ymax), emit=True)
            self.yplot.panel.axes.set_ylim((ymin, ymax), emit=True)

            # print('X lims: ', self.xplot.panel.conf.zoom_lims, xlims)
            # self.xplot.panel.set_xylims(xlims)
            # self.yplot.panel.set_xylims(ylims)

    def onSaveConfig(self, event=None):
        fname = FileSave(self,
                         'Save Configuration File',
                         wildcard='INI (*.ini)|*.ini|All files (*.*)|*.*',
                         default_file='SampleStage.ini')
        if fname is not None:
            self.cnf.Save(fname)
        self.write_message('Saved Configuration File %s' % fname)

    def onReadConfig(self, event=None):
        curpath = os.getcwd()
        fname = FileOpen(self,
                         'Read Configuration File',
                         wildcard='INI (*.ini)|*.ini|All files (*.*)|*.*',
                         default_file='SampleStage.ini')
        if fname is not None:
            self.read_config(fname)
            self.connect_motors()
            self.pospanel.set_positions(self.config['positions'])
        self.write_message('Read Configuration File %s' % fname)
        os.chdir(curpath)
Пример #30
0
class XRD2D_DisplayFrame(ImageFrame):
    """
    MatPlotlib Image Display on a wx.Frame, using ImagePanel
    """

    def __init__(self, _larch=None, parent=None, size=None, mode='intensity',
                 move_callback=None, save_callback=None,
                 show_xsections=False, cursor_labels=None,
                 output_title='Image',   **kws):

        self.xrmfile = None
        self.map = None
        self.move_callback = move_callback
        self.save_callback = save_callback

        self.larch = _larch
        if self.larch is None:
            self.init_larch()
            
        ImageFrame.__init__(self, parent=parent, size=size,
                            cursor_labels=cursor_labels, mode=mode,
                            output_title=output_title, **kws)

        self.panel.cursor_mode = 'zoom'
        self.panel.xaxis = 'q'
        self.panel.report_leftdown = self.report_leftdown
        self.panel.report_motion   = self.report_motion


        self.prof_plotter = None
        self.zoom_ini =  None
        self.lastpoint = [None, None]
        self.this_point = None
        self.rbbox = None

    def display(self, map, xrmfile=None, ai=None, mask=None, **kws):
        self.xrmfile = xrmfile
        self.map = map
        self.title = ''
        if 'title' in kws:
            self.title = kws['title']
        ImageFrame.display(self, map, **kws)

        if self.panel.conf.auto_contrast:
            self.set_contrast_levels()
        self.ai = ai
        self.mask = mask
        if np.shape(self.mask) == np.shape(map):
            self.masked_map = map * (np.ones(np.shape(self.mask))-mask.value)
        
        self.panel.xdata = np.arange(map.shape[0])
        self.panel.ydata = np.arange(map.shape[0])

    def init_larch(self):
        if self.larch is None:
            self.larch = Interpreter()

    def prof_motion(self, event=None):
        if not event.inaxes or self.zoom_ini is None:
            return
        try:
            xmax, ymax  = event.x, event.y
        except:
            return

        xmin, ymin, xd, yd = self.zoom_ini
        if event.xdata is not None:
            self.lastpoint[0] = event.xdata
        if event.ydata is not None:
            self.lastpoint[1] = event.ydata

        yoff = self.panel.canvas.figure.bbox.height
        ymin, ymax = yoff - ymin, yoff - ymax

        zdc = wx.ClientDC(self.panel.canvas)
        zdc.SetLogicalFunction(wx.XOR)
        zdc.SetBrush(wx.TRANSPARENT_BRUSH)
        zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
        zdc.ResetBoundingBox()
        if not is_wxPhoenix:
            zdc.BeginDrawing()


        # erase previous box
        if self.rbbox is not None:
            zdc.DrawLine(*self.rbbox)
        self.rbbox = (xmin, ymin, xmax, ymax)
        zdc.DrawLine(*self.rbbox)
        if not is_wxPhoenix:
            zdc.EndDrawing()

    def prof_leftdown(self, event=None):
        self.report_leftdown(event=event)
        if event.inaxes and len(self.map.shape) == 2:
            self.lastpoint = [None, None]
            self.zoom_ini = [event.x, event.y, event.xdata, event.ydata]

    def prof_leftup(self, event=None):
        if len(self.map.shape) != 2:
            return
        if self.rbbox is not None:
            zdc = wx.ClientDC(self.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()

            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []

        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []

        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(self.panel.conf.data[iy,ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear() # reset_config()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)
        self.prof_plotter.plot(x, z, title=self.title, color='blue',
                               zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                               ylabel='counts', label='counts', **opts)

        self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                              zorder=3, side='right', color='#771111', **opts)

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.panel.cursor_mode = 'zoom'

    def prof_report_coords(self, event=None):
        """override report leftdown for profile plotter"""
        if event is None:
            return
        ex, ey = event.x, event.y
        msg = ''
        plotpanel = self.prof_plotter.panel
        axes  = plotpanel.fig.get_axes()[0]
        write = plotpanel.write_message
        try:
            x, y = axes.transData.inverted().transform((ex, ey))
        except:
            x, y = event.xdata, event.ydata

        if x is None or y is None:
            return

        
        if self.ai is None:
            _point = 0, 0, 0
            for ix, iy in self.prof_dat[1]:
                if (int(x) == ix and not self.prof_dat[0] or
                    int(x) == iy and self.prof_dat[0]):
                    _point = (ix, iy,
                                  self.panel.conf.data[iy, ix])
                msg = "Pixel [%i, %i], Intensity= %g" % _point
        else:
            ai = self.ai
            xcenter = ai._poni2/ai.detector.pixel2        ## units pixels
            ycenter = ai._poni1/ai.detector.pixel1        ## units pixels
            _point = 0, 0, 0, 0, 0
            for ix, iy in self.prof_dat[1]:
                if (int(x) == ix and not self.prof_dat[0] or
                    int(x) == iy and self.prof_dat[0]):
                    x_pix = ix - xcenter                      ## units pixels
                    y_pix = iy - ycenter                      ## units pixels
                    x_m = x_pix * ai.detector.pixel2          ## units m
                    y_m = y_pix * ai.detector.pixel1          ## units m
                    twth = np.arctan2(math.sqrt(x_m**2 + y_m**2),ai._dist)  ## radians
                    twth = np.degrees(twth)                                 ## units degrees
                    eta  = np.arctan2(y_m,x_m)                              ## units radians
                    eta  = np.degrees(eta)                                  ## units degrees
                    _point = (ix, iy, twth, eta, self.panel.conf.data[iy, ix])
            msg = 'Pixel [%i, %i], 2TH=%.2f, ETA=%.1f, Intensity= %g' % _point
        write(msg,  panel=0)

    def report_leftdown(self, event=None):
        if event is None:
            return
        if event.xdata is None or event.ydata is None:
            return

        ix, iy = int(round(event.xdata)), int(round(event.ydata))
        conf = self.panel.conf
        if conf.flip_ud:  iy = conf.data.shape[0] - iy
        if conf.flip_lr:  ix = conf.data.shape[1] - ix

        self.this_point = None
        msg = ''
        if (ix >= 0 and ix < conf.data.shape[1] and
            iy >= 0 and iy < conf.data.shape[0]):
            pos = ''
            pan = self.panel
            labs, vals = [], []
            if pan.xdata is not None:
                labs.append(pan.xlab)
                vals.append(pan.xdata[ix])
            if pan.ydata is not None:
                labs.append(pan.ylab)
                vals.append(pan.ydata[iy])
            dval = conf.data[iy, ix]
            if len(pan.data_shape) == 3:
                dval = "%.4g, %.4g, %.4g" % tuple(dval)
            else:
                dval = "%.4g" % dval
            if pan.xdata is not None and pan.ydata is not None:
                self.this_point = (ix, iy)

            if self.ai is None:
                msg = "Pixel [%i, %i], Intensity=%s " % (ix, iy, dval)
            else:
                ai = self.ai
                xcenter = ai._poni2/ai.detector.pixel2        ## units pixels
                ycenter = ai._poni1/ai.detector.pixel1        ## units pixels
                x_pix = ix - xcenter                          ## units pixels
                y_pix = iy - ycenter                          ## units pixels
                x_m = x_pix * ai.detector.pixel2                        ## units m
                y_m = y_pix * ai.detector.pixel1                        ## units m
                twth = np.arctan2(math.sqrt(x_m**2 + y_m**2),ai._dist)  ## radians
                twth = np.degrees(twth)                                 ## units degrees
                eta  = np.arctan2(y_m,x_m)                              ## units radians
                eta  = np.degrees(eta)                                  ## units degrees
                msg = 'Pixel [%i, %i], 2TH=%.2f deg., ETA=%.1f deg., Intensity= %s' % (ix, 
                                      iy, twth, eta, dval)
        self.panel.write_message(msg, panel=0)

    def report_motion(self, event=None):
        return

    def CustomConfig(self, panel, sizer, irow):
        """config panel for left-hand-side of frame"""
        conf = self.panel.conf
        lpanel = panel
        lsizer = sizer
        labstyle = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND

        self.MskCkBx = wx.CheckBox(panel, label='Apply mask?')
        self.MskCkBx.Bind(wx.EVT_CHECKBOX, self.onApplyMask)
        sizer.Add(self.MskCkBx, (irow+1,0), (1,4), labstyle, 3)

        self.LoadBtn = wx.Button(panel, label='Load New Mask')
        self.LoadBtn.Bind(wx.EVT_BUTTON, self.onLoadMask)
        sizer.Add(self.LoadBtn, (irow+2,0), (1,4), labstyle, 3)

        self.ReCalc1D = wx.Button(panel, label='Replot 1DXRD')
        self.ReCalc1D.Bind(wx.EVT_BUTTON, self.onReplot1DXRD)
        sizer.Add(self.ReCalc1D, (irow+3,0), (1,4), labstyle, 3)

    def onApplyMask(self, event):
        '''
        Applies mask to 2DXRD map
        mkak 2016.09.29
        '''
        if event.GetEventObject().GetValue():
            if self.masked_map is None:
                print('Mask file not defined.')
                
                question = 'No mask found in map file. Would you like to load a new file now?'
                caption = 'Load mask file?'
                dlg = wx.MessageDialog(self, question, caption, wx.YES_NO | wx.ICON_QUESTION)
                print 'answer:', dlg.ShowModal() # == wx.ID_YES
                read = dlg.ShowModal()
                dlg.Destroy()
                if read == wx.ID_YES:
                    self.onLoadMask()

                self.MskCkBx.SetValue(False)
            else:
                ImageFrame.display(self, self.masked_map)

        else:
            ImageFrame.display(self, self.map)        
       
    def onLoadMask(self, evt=None):

        wildcards = 'pyFAI mask (*.edf)|*.edf|All files (*.*)|*.*'
        dlg = wx.FileDialog(self, message='Choose XRD mask file',
                           defaultDir=os.getcwd(),
                           wildcard=wildcards, style=wx.FD_OPEN)

        edffile, read = None, False
        if dlg.ShowModal() == wx.ID_OK:
            read = True
            edffile = dlg.GetPath().replace('\\', '/')
        dlg.Destroy()
        
        if read:

            print('Reading mask file: %s' % edffile)
            try:
                import fabio
                self.mask = fabio.open(edffile).data
                self.masked_map = self.map * (np.ones(np.shape(self.mask))-self.mask)
                self.MskCkBx.SetValue(True)
                ImageFrame.display(self, self.masked_map)
            except:
                print('File must be .edf format; user must have fabio installed.')
            
            ## Can this be called here?
            #readEDFfile(self,name='mask',keyword='maskfile')
            #add_calibration()

    def onReplot1DXRD(self, evt=None):

        print('Not yet implemented.')
Пример #31
0
class EditColumnFrame(wx.Frame):
    """Set Column Labels for a file"""
    def __init__(self,
                 parent,
                 group=None,
                 last_array_sel=None,
                 read_ok_cb=None,
                 edit_groupname=True):
        self.parent = parent
        self.dgroup = group
        if not hasattr(self.dgroup, 'is_xas'):
            try:
                self.dgroup.is_xas = 'energ' in self.dgroup.array_labels[
                    0].lower()
            except:
                self.dgroup.is_xas = False
        self.read_ok_cb = read_ok_cb

        self.array_sel = {
            'xpop': '',
            'xarr': None,
            'ypop': '',
            'yop': '/',
            'yarr1': None,
            'yarr2': None,
            'use_deriv': False
        }
        if last_array_sel is not None:
            self.array_sel.update(last_array_sel)

        if self.array_sel['yarr2'] is None and 'i0' in self.dgroup.array_labels:
            self.array_sel['yarr2'] = 'i0'

        if self.array_sel['yarr1'] is None:
            if 'itrans' in self.dgroup.array_labels:
                self.array_sel['yarr1'] = 'itrans'
            elif 'i1' in self.dgroup.array_labels:
                self.array_sel['yarr1'] = 'i1'
        message = "Build Arrys from Data Columns for %s" % self.dgroup.filename
        wx.Frame.__init__(self,
                          None,
                          -1,
                          'Build Arrays from Data Columns for %s' %
                          self.dgroup.filename,
                          style=FRAMESTYLE)

        self.SetFont(Font(10))
        panel = scrolled.ScrolledPanel(self)
        self.SetMinSize((600, 600))
        self.colors = GUIColors()
        self.plotframe = None

        # title row
        title = SimpleText(panel,
                           message,
                           font=Font(13),
                           colour=self.colors.title,
                           style=LCEN)

        opts = dict(action=self.onColumnChoice, size=(120, -1))

        arr_labels = self.dgroup.array_labels
        yarr_labels = arr_labels + ['1.0', '0.0', '']
        xarr_labels = arr_labels + ['<index>']

        self.xarr = Choice(panel, choices=xarr_labels, **opts)
        self.yarr1 = Choice(panel, choices=arr_labels, **opts)
        self.yarr2 = Choice(panel, choices=yarr_labels, **opts)

        opts['size'] = (90, -1)

        self.xpop = Choice(panel, choices=XPRE_OPS, **opts)
        self.ypop = Choice(panel, choices=YPRE_OPS, **opts)
        opts['size'] = (50, -1)
        self.yop = Choice(panel, choices=ARR_OPS, **opts)

        ylab = SimpleText(panel, 'Y = ')
        xlab = SimpleText(panel, 'X = ')
        self.xsuf = SimpleText(panel, '')
        self.ysuf = SimpleText(panel, '')

        self.xpop.SetStringSelection(self.array_sel['xpop'])
        self.ypop.SetStringSelection(self.array_sel['ypop'])
        self.yop.SetStringSelection(self.array_sel['yop'])
        if '(' in self.array_sel['ypop']:
            self.ysuf.SetLabel(')')

        ixsel, iysel, iy2sel = 0, 1, len(yarr_labels) - 1
        if self.array_sel['xarr'] in xarr_labels:
            ixsel = xarr_labels.index(self.array_sel['xarr'])
        if self.array_sel['yarr1'] in arr_labels:
            iysel = arr_labels.index(self.array_sel['yarr1'])
        if self.array_sel['yarr2'] in yarr_labels:
            iy2sel = yarr_labels.index(self.array_sel['yarr2'])
        self.xarr.SetSelection(ixsel)
        self.yarr1.SetSelection(iysel)
        self.yarr2.SetSelection(iy2sel)

        opts['size'] = (150, -1)
        self.use_deriv = Check(panel,
                               label='use derivative',
                               default=self.array_sel['use_deriv'],
                               **opts)

        self.is_xas = Check(panel,
                            label='use as XAS data',
                            default=self.dgroup.is_xas,
                            **opts)

        bpanel = wx.Panel(panel)
        bsizer = wx.BoxSizer(wx.HORIZONTAL)
        bsizer.Add(Button(bpanel, 'Preview', action=self.onColumnChoice), 4)
        bsizer.Add(Button(bpanel, 'OK', action=self.onOK), 4)
        bsizer.Add(Button(bpanel, 'Cancel', action=self.onCancel), 4)
        pack(bpanel, bsizer)

        sizer = wx.GridBagSizer(4, 8)
        sizer.Add(title, (0, 0), (1, 7), LCEN, 5)

        ir = 1
        sizer.Add(xlab, (ir, 0), (1, 1), CEN, 0)
        sizer.Add(self.xpop, (ir, 1), (1, 1), CEN, 0)
        sizer.Add(self.xarr, (ir, 2), (1, 1), CEN, 0)
        sizer.Add(self.xsuf, (ir, 3), (1, 1), CEN, 0)

        ir += 1
        sizer.Add(ylab, (ir, 0), (1, 1), CEN, 0)
        sizer.Add(self.ypop, (ir, 1), (1, 1), CEN, 0)
        sizer.Add(self.yarr1, (ir, 2), (1, 1), CEN, 0)
        sizer.Add(self.yop, (ir, 3), (1, 1), CEN, 0)
        sizer.Add(self.yarr2, (ir, 4), (1, 1), CEN, 0)
        sizer.Add(self.ysuf, (ir, 5), (1, 1), CEN, 0)

        ir += 1
        sizer.Add(self.use_deriv, (ir, 0), (1, 3), LCEN, 0)
        ir += 1
        sizer.Add(self.is_xas, (ir, 0), (1, 3), LCEN, 0)

        self.wid_groupname = None
        if edit_groupname:
            wid_grouplab = SimpleText(panel, 'Use Group Name: ')
            self.wid_groupname = wx.TextCtrl(panel,
                                             value=self.dgroup._groupname,
                                             size=(100, -1))
            ir += 1
            sizer.Add(wid_grouplab, (ir, 0), (1, 2), LCEN, 3)
            sizer.Add(self.wid_groupname, (ir, 2), (1, 3), LCEN, 3)

        ir += 1
        sizer.Add(bpanel, (ir, 0), (1, 5), LCEN, 3)

        pack(panel, sizer)

        ftext = wx.TextCtrl(self,
                            style=wx.TE_MULTILINE | wx.TE_READONLY,
                            size=(-1, 150))
        try:
            m = open(self.dgroup.filename, 'r')
            text = m.read()
            m.close()
        except:
            text = "The file '%s'\n was not found" % self.dgroup.filename
        ftext.SetValue(text)
        ftext.SetFont(Font(9))

        mainsizer = wx.BoxSizer(wx.VERTICAL)
        mainsizer.Add(panel, 0, wx.GROW | wx.ALL, 2)
        mainsizer.Add(ftext, 1, LCEN | wx.GROW, 2)
        pack(self, mainsizer)

        self.Show()
        self.Raise()

    def onOK(self, event=None):
        """ build arrays according to selection """

        if not hasattr(self.dgroup, '_xdat'):
            self.onColumnChoice()

        if self.wid_groupname is not None:
            self.dgroup._groupname = fix_varname(self.wid_groupname.GetValue())
        if self.plotframe is not None:
            try:
                self.plotframe.Destroy()
            except:
                pass
        if self.read_ok_cb is not None:
            self.read_ok_cb(self.dgroup, self.array_sel)
        self.Destroy()

    def onCancel(self, event=None):
        self.dgroup.import_ok = False
        if self.plotframe is not None:
            self.plotframe.Destroy()
        self.Destroy()

    def onColumnChoice(self, evt=None):
        """column selections changed calc _xdat and _ydat"""
        # dtcorr = self.dtcorr.IsChecked()
        dtcorr = False
        use_deriv = self.use_deriv.IsChecked()
        dgroup = self.dgroup

        ix = self.xarr.GetSelection()
        xname = self.xarr.GetStringSelection()
        if xname == '<index>':
            xname = self.dgroup.array_labels[0]
            dgroup._index = 1.0 * np.arange(len(getattr(dgroup, xname)))
            xname = '_index'

        dgroup.is_xas = self.is_xas.IsChecked()
        dgroup._xdat = getattr(dgroup, xname)

        def do_preop(opwid, arr):
            opstr = opwid.GetStringSelection().strip()
            suf = ''
            if opstr in ('-log(', 'log('):
                suf = ')'
                if opstr == 'log(':
                    arr = np.log(arr)
                elif opstr == '-log(':
                    arr = -np.log(arr)
            return suf, opstr, arr

        xsuf, xpop, dgroup._xdat = do_preop(self.xpop, dgroup._xdat)
        self.xsuf.SetLabel(xsuf)

        try:
            xunits = dgroup.array_units[ix].strip()
            xlabel = '%s (%s)' % (xname, xunits)
        except:
            xlabel = xname

        def get_data(group, arrayname, correct=False):
            if hasattr(group, 'get_data'):
                return group.get_data(arrayname, correct=correct)
            return getattr(group, arrayname, None)

        yname1 = self.yarr1.GetStringSelection().strip()
        yname2 = self.yarr2.GetStringSelection().strip()
        yop = self.yop.GetStringSelection().strip()

        ylabel = yname1
        if len(yname2) == 0:
            yname2, yop = '1.0', '*'
        else:
            ylabel = "%s%s%s" % (ylabel, yop, yname2)

        yarr1 = get_data(dgroup, yname1, correct=dtcorr)

        if yname2 in ('0.0', '1.0'):
            yarr2 = float(yname2)
            if yop == '/': yarr2 = 1.0
        else:
            yarr2 = get_data(dgroup, yname2, correct=dtcorr)

        dgroup._ydat = yarr1
        if yop == '+':
            dgroup._ydat = yarr1.__add__(yarr2)
        elif yop == '-':
            dgroup._ydat = yarr1.__sub__(yarr2)
        elif yop == '*':
            dgroup._ydat = yarr1.__mul__(yarr2)
        elif yop == '/':
            dgroup._ydat = yarr1.__truediv__(yarr2)

        ysuf, ypop, dgroup._ydat = do_preop(self.ypop, dgroup._ydat)
        self.ysuf.SetLabel(ysuf)

        if use_deriv:
            try:
                dgroup._ydat = np.gradient(dgroup._ydat) / np.gradient(
                    dgroup._xdat)
            except:
                pass

        self.array_sel = {
            'xpop': xpop,
            'xarr': xname,
            'ypop': ypop,
            'yop': yop,
            'yarr1': yname1,
            'yarr2': yname2,
            'use_deriv': use_deriv
        }

        try:
            npts = min(len(dgroup._xdat), len(dgroup._ydat))
        except AttributeError:
            print('Error calculating arrays (npts not correct)')
            return

        dgroup._npts = npts
        dgroup.plot_xlabel = xlabel
        dgroup.plot_ylabel = ylabel
        dgroup._xdat = np.array(dgroup._xdat[:npts])
        dgroup._ydat = np.array(dgroup._ydat[:npts])
        if dgroup.is_xas:
            dgroup.energy = dgroup._xdat
            dgroup.mu = dgroup._ydat

        self.raise_plotframe()

        ppanel = self.plotframe.panel

        popts = {}
        path, fname = os.path.split(dgroup.filename)

        popts['label'] = "%s: %s" % (fname, dgroup.plot_ylabel)
        popts['title'] = fname
        popts['ylabel'] = dgroup.plot_ylabel
        popts['xlabel'] = dgroup.plot_xlabel

        ppanel.plot(dgroup._xdat, dgroup._ydat, **popts)

    def raise_plotframe(self):
        if self.plotframe is not None:
            try:
                self.plotframe.Show()
            except:
                self.plotframe = None
        if self.plotframe is None:
            self.plotframe = PlotFrame(None, size=(650, 400))
            self.plotframe.Show()
Пример #32
0
class MapImageFrame(ImageFrame):
    """
    MatPlotlib Image Display on a wx.Frame, using ImagePanel
    """

    def __init__(self, parent=None, size=(650, 650), mode='intensity',
                 lasso_callback=None, move_callback=None, save_callback=None,
                 show_xsections=False, cursor_labels=None,
                 with_savepos=True,output_title='Image', **kws):

        # instdb=None,  inst_name=None,

        self.det = None
        self.xrmfile = None
        self.map = None
        self.move_callback = move_callback
        self.save_callback = save_callback
        self.with_savepos = with_savepos

        ImageFrame.__init__(self, parent=parent, size=size,
                            lasso_callback=lasso_callback,
                            cursor_labels=cursor_labels, mode=mode,
                            output_title=output_title, **kws)

        self.panel.add_cursor_mode('prof', motion = self.prof_motion,
                                   leftdown = self.prof_leftdown,
                                   leftup   = self.prof_leftup)
        self.panel.report_leftdown = self.report_leftdown
        self.panel.report_motion   = self.report_motion

        w0, h0 = self.GetSize()
        w1, h1 = self.GetBestSize()

        self.SetSize((max(w0, w1)+5, max(h0, h1)+5))
        self.SetMinSize((500, 500))

        self.prof_plotter = None
        self.zoom_ini =  None
        self.lastpoint = [None, None]
        self.this_point = None
        self.rbbox = None

    def display(self, map, det=None, xrmfile=None, xoff=0, yoff=0,
                with_savepos=True, **kws):
        self.xoff = xoff
        self.yoff = yoff
        self.det = det
        self.xrmfile = xrmfile
        self.map = map
        self.title = ''
        if 'title' in kws:
            self.title = kws['title']
        ImageFrame.display(self, map, **kws)
        if 'x' in kws:
            self.panel.xdata = kws['x']
        if 'y' in kws:
            self.panel.ydata = kws['y']
        self.set_contrast_levels()

        if self.save_callback is not None and hasattr(self, 'pos_name'):
            self.pos_name.Enable(with_savepos)

        sd = kws.get('subtitles', None)
        if sd is not None:
            for i, name in enumerate(('red', 'green', 'blue')):
                sub = sd.get(name, None)
                if sub is not None:
                    self.cmap_panels[i].title.SetLabel(sub)

    def prof_motion(self, event=None):
        if not event.inaxes or self.zoom_ini is None:
            return
        try:
            xmax, ymax  = event.x, event.y
        except:
            return
        xmin, ymin, xd, yd = self.zoom_ini
        if event.xdata is not None:
            self.lastpoint[0] = event.xdata
        if event.ydata is not None:
            self.lastpoint[1] = event.ydata

        yoff = self.panel.canvas.figure.bbox.height
        ymin, ymax = yoff - ymin, yoff - ymax

        zdc = wx.ClientDC(self.panel.canvas)
        zdc.SetLogicalFunction(wx.XOR)
        zdc.SetBrush(wx.TRANSPARENT_BRUSH)
        zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
        zdc.ResetBoundingBox()
        if not is_wxPhoenix:
            zdc.BeginDrawing()

        # erase previous box
        if self.rbbox is not None:
            zdc.DrawLine(*self.rbbox)
        self.rbbox = (xmin, ymin, xmax, ymax)
        zdc.DrawLine(*self.rbbox)
        if not is_wxPhoenix:
            zdc.EndDrawing()

    def prof_leftdown(self, event=None):
        self.report_leftdown(event=event)
        if event.inaxes: #  and len(self.map.shape) == 2:
            self.lastpoint = [None, None]
            self.zoom_ini = [event.x, event.y, event.xdata, event.ydata]

    def prof_leftup(self, event=None):
        # print("Profile Left up ", self.map.shape, self.rbbox)
        if self.rbbox is not None:
            zdc = wx.ClientDC(self.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()
            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []
        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []
        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(self.panel.conf.data[iy, ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        x = np.array(x)
        y = np.array(y)
        z = np.array(z)
        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)

        if isinstance(z[0], np.ndarray) and len(z[0]) == 3: # color plot
            rlab = self.subtitles['red']
            glab = self.subtitles['green']
            blab = self.subtitles['blue']
            self.prof_plotter.plot(x, z[:, 0], title=self.title, color='red',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=rlab, **opts)
            self.prof_plotter.oplot(x, z[:, 1], title=self.title, color='darkgreen',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=glab, **opts)
            self.prof_plotter.oplot(x, z[:, 2], title=self.title, color='blue',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=blab, **opts)

        else:

            self.prof_plotter.plot(x, z, title=self.title, color='blue',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label='counts', **opts)

        self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                              zorder=3, side='right', color='black', **opts)

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'

    def prof_report_coords(self, event=None):
        """override report leftdown for profile plotter"""
        if event is None:
            return
        ex, ey = event.x, event.y
        msg = ''
        plotpanel = self.prof_plotter.panel
        axes  = plotpanel.fig.properties()['axes'][0]
        write = plotpanel.write_message
        try:
            x, y = axes.transData.inverted().transform((ex, ey))
        except:
            x, y = event.xdata, event.ydata

        if x is None or y is None:
            return

        _point = 0, 0, 0, 0, 0
        for ix, iy in self.prof_dat[1]:
            if (int(x) == ix and not self.prof_dat[0] or
                int(x) == iy and self.prof_dat[0]):
                _point = (ix, iy,
                              self.panel.xdata[ix],
                              self.panel.ydata[iy],
                              self.panel.conf.data[iy, ix])

        msg = "Pixel [%i, %i], X, OME = [%.4f mm, %.4f deg], Intensity= %g" % _point
        write(msg,  panel=0)

    def onCursorMode(self, event=None, mode='zoom'):
        self.panel.cursor_mode = mode
        choice = self.zoom_mode.GetString(self.zoom_mode.GetSelection())
        if event is not None:
            if choice.startswith('Pick Area'):
            #if 1 == event.GetInt():
                self.panel.cursor_mode = 'lasso'
            elif choice.startswith('Show Line'):
            #elif 2 == event.GetInt():
                self.panel.cursor_mode = 'prof'

    def report_leftdown(self, event=None):
        if event is None:
            return
        if event.xdata is None or event.ydata is None:
            return

        ix, iy = int(round(event.xdata)), int(round(event.ydata))
        conf = self.panel.conf
        if conf.flip_ud:  iy = conf.data.shape[0] - iy
        if conf.flip_lr:  ix = conf.data.shape[1] - ix

        self.this_point = None
        msg = ''
        if (ix >= 0 and ix < conf.data.shape[1] and
            iy >= 0 and iy < conf.data.shape[0]):
            pos = ''
            pan = self.panel
            labs, vals = [], []
            if pan.xdata is not None:
                labs.append(pan.xlab)
                vals.append(pan.xdata[ix])
            if pan.ydata is not None:
                labs.append(pan.ylab)
                vals.append(pan.ydata[iy])
            pos = ', '.join(labs)
            vals =', '.join(['%.4g' % v for v in vals])
            pos = '%s = [%s]' % (pos, vals)
            dval = conf.data[iy, ix]
            if len(pan.data_shape) == 3:
                dval = "%.4g, %.4g, %.4g" % tuple(dval)
            else:
                dval = "%.4g" % dval
            if pan.xdata is not None and pan.ydata is not None:
                self.this_point = (ix, iy)

            msg = "Pixel [%i, %i], %s, Intensity=%s " % (ix, iy, pos, dval)
        self.panel.write_message(msg, panel=0)

    def report_motion(self, event=None):
        return

    def onLasso(self, data=None, selected=None, mask=None, **kws):
        if hasattr(self.lasso_callback , '__call__'):

            self.lasso_callback(data=data, selected=selected, mask=mask,
                                xoff=self.xoff, yoff=self.yoff, det=self.det,
                                xrmfile=self.xrmfile, **kws)

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'

    def CustomConfig(self, panel, sizer=None, irow=0):
        """config panel for left-hand-side of frame"""

        labstyle = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND

        if self.lasso_callback is None:
            zoom_opts = ('Zoom to Rectangle',
                         'Show Line Profile')
        else:
            zoom_opts = ('Zoom to Rectangle',
                         'Pick Area for XRF Spectrum',
                         'Show Line Profile')

        cpanel = wx.Panel(panel)
        if sizer is None:
            sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(SimpleText(cpanel, label='Cursor Modes', style=labstyle),
                  0, labstyle, 3)
        self.zoom_mode = wx.RadioBox(cpanel, -1, "",
                                     wx.DefaultPosition, wx.DefaultSize,
                                     zoom_opts, 1, wx.RA_SPECIFY_COLS)
        self.zoom_mode.Bind(wx.EVT_RADIOBOX, self.onCursorMode)

        sizer.Add(self.zoom_mode, 1, labstyle, 4)

        if self.save_callback is not None:
            sizer.Add(SimpleText(cpanel, label='Save Position:', style=labstyle),
                      0, labstyle, 3)
            self.pos_name = wx.TextCtrl(cpanel, -1, '',  size=(155, -1),
                                        style=wx.TE_PROCESS_ENTER)
            self.pos_name.Bind(wx.EVT_TEXT_ENTER, self.onSavePixel)
            sizer.Add(self.pos_name, 0, labstyle, 3)

        pack(cpanel, sizer)
        return cpanel

    def onMoveToPixel(self, event=None):
        pass

    def onSavePixel(self, event=None):
        if self.this_point is not None and self.save_callback is not None:
            name  = str(event.GetString().strip())
            # name  = str(self.pos_name.GetValue().strip())
            ix, iy = self.this_point
            x = float(self.panel.xdata[int(ix)])
            y = float(self.panel.ydata[int(iy)])
            self.save_callback(name, ix, iy, x=x, y=y,
                               title=self.title, xrmfile=self.xrmfile)
Пример #33
0
class TomographyFrame(BaseFrame):
### COPY OF ImageFrame(BaseFrame) with portions of ImageMatrixFrame(BaseFrame)
    '''
    MatPlotlib Image Display ons a wx.Frame, using ImagePanel
    '''

    help_msg =  '''Quick help:

Left-Click:   to display X,Y coordinates and Intensity
Left-Drag:    to zoom in on region
Right-Click:  display popup menu with choices:
               Zoom out 1 level
               Zoom all the way out
               --------------------
               Rotate Image
               Save Image

Keyboard Shortcuts:   (For Mac OSX, replace 'Ctrl' with 'Apple')
  Saving Images:
     Ctrl-S:     Save image to file
     Ctrl-C:     Copy image to clipboard
     Ctrl-P:     Print Image

  Zooming:
     Ctrl-Z:     Zoom all the way out

  Rotating/Flipping:
     Ctrl-R:     Rotate Clockwise
     Ctrl-T:     Flip Top/Bottom
     Ctrl-F:     Flip Left/Right

  Image Enhancement:
     Ctrl-L:     Log-Scale Intensity
     Ctrl-E:     Enhance Contrast


'''


    def __init__(self, parent=None, size=None, mode='intensity',
                 lasso_callback=None, 
                 output_title='Tomography Display Frame', subtitles=None,
                 user_menus=None, **kws):

        if size is None: size = (1500, 600)
        self.lasso_callback = lasso_callback
        self.user_menus = user_menus
        self.cursor_menulabels =  {}
        self.cursor_menulabels.update(CURSOR_MENULABELS)

        self.title = output_title

        self.det = None
        self.xrmfile = None
        self.wxmplot_version = get_wxmplot_version()

        BaseFrame.__init__(self, parent=parent,
                           title  = output_title,
                           output_title=output_title,
                           size=size, **kws)

        self.cmap_panels = {}

        self.subtitles = {}
        self.config_mode = None
        if subtitles is not None:
            self.subtitles = subtitles
        sbar_widths = [-2, -1, -1]
        sbar = self.CreateStatusBar(len(sbar_widths), wx.CAPTION)
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(10)
        sbar.SetFont(sfont)
        self.SetStatusWidths(sbar_widths)

        self.optional_menus = []

        self.bgcol = rgb2hex(self.GetBackgroundColour()[:3])

        splitter  = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        splitter.SetMinimumPaneSize(225)

        self.config_panel = wx.Panel(splitter)
        self.main_panel   = wx.Panel(splitter)
        
        img_opts = dict(size = (700, 525),
                        dpi  = 100,
                        data_callback  = self.onDataChange,
                        lasso_callback = self.onLasso,
                        output_title   = self.output_title)
        
        self.tomo_frame = [TomoFrameClass(panel=ImagePanel(self.main_panel, **img_opts),
                                          label='Sinogram'),
                           TomoFrameClass(panel=ImagePanel(self.main_panel, **img_opts),
                                          label='Tomograph')]

        for iframe in self.tomo_frame:
            iframe.panel.nstatusbar = sbar.GetFieldsCount()

        self.BuildMenu()

        self.SetBackgroundColour('#F8F8F4')

        self.imin_val = {}
        self.imax_val = {}
        self.islider_range = {}

        self.config_mode = 'int'
        if mode.lower().startswith('rgb'):
            self.config_mode = 'rgb'

        self.Build_ConfigPanel()

        for iframe in self.tomo_frame:
            kwargs = {'frame':iframe}
            iframe.panel.add_cursor_mode('prof', 
                                         motion   = partial(self.prof_motion,   **kwargs),
                                         leftdown = partial(self.prof_leftdown, **kwargs),
                                         leftup   = partial(self.prof_leftup,   **kwargs))
            iframe.panel.report_leftdown = partial(self.report_leftdown, **kwargs)
            iframe.panel.messenger = self.write_message


        self.prof_plotter = None
        self.zoom_ini =  None
        self.lastpoint = [None, None]
        self.this_point = None
        self.rbbox = None


        lsty = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND
        gsizer = wx.GridSizer(1, 2, 2, 2)
        lsty |= wx.GROW|wx.ALL|wx.EXPAND|wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL
        gsizer.Add(self.tomo_frame[0].panel, 1, lsty, 2)
        gsizer.Add(self.tomo_frame[1].panel, 1, lsty, 2)

        pack(self.main_panel, gsizer)
        splitter.SplitVertically(self.config_panel, self.main_panel, 1)

        mainsizer = wx.BoxSizer(wx.VERTICAL)
        mainsizer.Add(splitter, 1, wx.GROW|wx.ALL, 5)
        pack(self, mainsizer)


    def display(self, map1, map2, title=None, colormap=None, style='image',
                subtitles=None, name1='Sinogram', name2='Tomograph',
                xlabel='x', ylabel='y', rotlabel='theta',
                x=None, y=None, rot=None,
                **kws):

        '''plot after clearing current plot
        '''
        
        map1 = np.array(map1)
        map2 = np.array(map2)
        
        if len(map1.shape) != len(map2.shape):
            return

        self.tomo_frame[0].label, self.tomo_frame[1].label = name1, name2
        self.xdata,  self.ydata,  self.rotdata  = x,      y,      rot
        self.xlabel, self.ylabel, self.rotlabel = xlabel, ylabel, rotlabel

        if title is not None:
            self.SetTitle(title)
        if subtitles is not None:
            self.subtitles = subtitles
        cmode = self.config_mode.lower()[:3]



        # make sure 3d image is shaped (NY, NX, 3)
        if len(map1.shape) == 3:
            ishape = map1.shape
            if ishape[2] != 3:
                if ishape[0] == 3:
                    map1 = map1.swapaxes(0, 1).swapaxes(1, 2)
                elif ishape[1] == 3:
                    map1 = map1.swapaxes(1, 2)
        if len(map2.shape) == 3:
            ishape = map2.shape
            if ishape[2] != 3:
                if ishape[0] == 3:
                    map2 = map2.swapaxes(0, 1).swapaxes(1, 2)
                elif ishape[1] == 3:
                    map2 = map2.swapaxes(1, 2)

        self.xzoom = self.yzoom = slice(0, map1.shape[1]+1)
        self.rotzoom  = slice(0, map1.shape[0]+1)

        ## sets config_mode to single or tri color and builds panel accordingly
        if len(map1.shape) == 3 and len(map2.shape) == 3:
            if cmode != 'rgb':
                for comp in self.config_panel.Children:
                    comp.Destroy()
                self.config_mode = 'rgb'
                self.tomo_frame[0].panel.conf.tricolor_mode = 'rgb'
                self.Build_ConfigPanel()
        else: ##if len(map1.shape) == 2 and len(map2.shape) == 2:
            if cmode != 'int':
                for comp in self.config_panel.Children:
                    comp.Destroy()
                self.config_mode = 'int'
                self.Build_ConfigPanel()

        for map,iframe in zip([map1,map2],self.tomo_frame):
            iframe.map = map
            iframe.panel.display(iframe.map, style=style, **kws)
            iframe.panel.conf.title = iframe.label

        if colormap is not None and self.config_mode == 'int':
            self.cmap_panels[0].set_colormap(name=colormap)

        if subtitles is not None:
            if isinstance(subtitles, dict):
                self.set_subtitles(**subtitles)
            elif self.config_mode == 'int':
                self.set_subtitles(red=subtitles)

        contour_value = 0
        if style == 'contour':
            contour_value = 1
        self.set_contrast_levels()

        for iframe in self.tomo_frame:
            iframe.panel.redraw()

        self.config_panel.Refresh()
        self.SendSizeEvent()
        wx.CallAfter(self.EnableMenus)

    def prof_motion(self, event=None, frame=None):
        if not event.inaxes or self.zoom_ini is None:
            return
        try:
            xmax, ymax  = event.x, event.y
        except:
            return
        if frame is None:
            frame = self.tomo_frame[0]

        xmin, ymin, xd, yd = self.zoom_ini
        if event.xdata is not None:
            self.lastpoint[0] = event.xdata
        if event.ydata is not None:
            self.lastpoint[1] = event.ydata

        yoff = frame.panel.canvas.figure.bbox.height
        ymin, ymax = yoff - ymin, yoff - ymax

        zdc = wx.ClientDC(frame.panel.canvas)
        zdc.SetLogicalFunction(wx.XOR)
        zdc.SetBrush(wx.TRANSPARENT_BRUSH)
        zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
        zdc.ResetBoundingBox()
        if not is_wxPhoenix:
            zdc.BeginDrawing()

        # erase previous box
        if self.rbbox is not None:
            zdc.DrawLine(*self.rbbox)
        self.rbbox = (xmin, ymin, xmax, ymax)
        zdc.DrawLine(*self.rbbox)
        if not is_wxPhoenix:
            zdc.EndDrawing()

    def prof_leftdown(self, event=None, frame=None):
        if frame is None:
            frame = self.tomo_frame[0]
        self.report_leftdown(event=event,frame=frame)
        if event.inaxes: #  and len(self.map.shape) == 2:
            self.lastpoint = [None, None]
            self.zoom_ini = [event.x, event.y, event.xdata, event.ydata]

    def prof_leftup(self, event=None, frame=None):
        # print("Profile Left up ", self.map.shape, self.rbbox)
        if frame is None:
            frame = self.tomo_frame[0]

        if self.rbbox is not None:
            zdc = wx.ClientDC(frame.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()
            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []
        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []
        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(frame.panel.conf.data[iy, ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        x = np.array(x)
        y = np.array(y)
        z = np.array(z)
        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)

        if isinstance(z[0], np.ndarray) and len(z[0]) == 3: # color plot
            rlab = self.subtitles['red']
            glab = self.subtitles['green']
            blab = self.subtitles['blue']
            self.prof_plotter.plot(x, z[:, 0], title=self.title, color='red',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=rlab, **opts)
            self.prof_plotter.oplot(x, z[:, 1], title=self.title, color='darkgreen',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=glab, **opts)
            self.prof_plotter.oplot(x, z[:, 2], title=self.title, color='blue',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=blab, **opts)

        else:

            self.prof_plotter.plot(x, z, color='blue', title=self.title.split(':')[-1], #title=self.title, 
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label='counts', **opts)

        try:
            self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                                  zorder=3, side='right', color='black', **opts)
        except:
            pass

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.zoom_mode.SetSelection(0)
        frame.panel.cursor_mode = 'zoom'

    def prof_report_coords(self, event=None, frame=None):
        """override report leftdown for profile plotter"""
        if event is None:
            return
        ex, ey = event.x, event.y
        msg = ''
        if frame is None:
            frame = self.tomo_frame[0]

        plotpanel = self.prof_plotter.panel
        axes  = plotpanel.fig.properties()['axes'][0]
        write = plotpanel.write_message
        try:
            x, y = axes.transData.inverted().transform((ex, ey))
        except:
            x, y = event.xdata, event.ydata

        if x is None or y is None:
            return

        _point = 0, 0, 0, 0, 0
        for ix, iy in self.prof_dat[1]:
            if (int(x) == ix and not self.prof_dat[0] or
                int(x) == iy and self.prof_dat[0]):
                _point = (ix, iy,
                              frame.panel.xdata[ix],
                              frame.panel.ydata[iy],
                              frame.panel.conf.data[iy, ix])

        msg = "Pixel [%i, %i], X, OME = [%.4f mm, %.4f deg], Intensity= %g" % _point
        write(msg,  panel=0)

    def report_leftdown(self,event=None, frame=None):
        if event is None:
            return
        if event.xdata is None or event.ydata is None:
            return
        if frame is None:
            frame = self.tomo_frame[0]
        
        ix, iy = int(round(event.xdata)), int(round(event.ydata))

        if (ix >= 0 and ix < frame.map.shape[1] and
            iy >= 0 and iy < frame.map.shape[0]):
            pos = ''
            if self.xdata is not None:
                pos = ' %s=%.4g,' % (self.xlabel, self.xdata[ix])
            if self.ydata is not None:
                pos = '%s %s=%.4g,' % (pos, self.ylabel, self.ydata[iy])

            if len(frame.map.shape) > 2:
                msg = 'Pixel [%i, %i],%s %s=(%.4g, %.4g, %.4g)' % (ix, iy, pos,
                                                  frame.label,        frame.map[iy,ix,0],
                                                  frame.map[iy,ix,1], frame.map[iy,ix,2])
            else:
                msg = 'Pixel [%i, %i],%s %s=%.4g' % (ix, iy, pos,
                                                     frame.label, frame.map[iy, ix])
            self.write_message(msg, panel=0)

            #if callable(self.cursor_callback):
            #    self.cursor_callback(x=event.xdata, y=event.ydata)

    def set_subtitles(self, red=None, green=None, blue=None, **kws):
        if self.config_mode.startswith('int') and red is not None:
            self.cmap_panels[0].title.SetLabel(red)

        if self.config_mode.startswith('rgb') and red is not None:
            self.cmap_panels[0].title.SetLabel(red)

        if self.config_mode.startswith('rgb') and green is not None:
            self.cmap_panels[1].title.SetLabel(green)

        if self.config_mode.startswith('rgb') and blue is not None:
            self.cmap_panels[2].title.SetLabel(blue)


    def EnableMenus(self, evt=None):
        is_3color = len(self.tomo_frame[0].panel.conf.data.shape) > 2
        for menu, on_3color in self.optional_menus:
            menu.Enable(is_3color==on_3color)

    def unzoom_all(self):
        self.tomo_frame[0].panel.unzoom()
        self.tomo_frame[1].panel.unzoom()
    
    def BuildMenu(self):
        # file menu
        mfile = self.Build_FileMenu(extras=(('Save Image of Colormap',
                                     'Save Image of Colormap',
                                      self.onCMapSave),))

        # options menu
        mview = self.view_menu = wx.Menu()
        MenuItem(self, mview, 'Zoom Out\tCtrl+Z',
                 'Zoom out to full data range',
                 self.unzoom_all)

        m = MenuItem(self, mview, 'Toggle Background Color (Black/White)\tCtrl+W',
                     'Toggle background color for 3-color images',
                     self.onTriColorBG, kind=wx.ITEM_CHECK)

        self.optional_menus.append((m, True))

        mview.AppendSeparator()
        MenuItem(self, mview, 'Rotate clockwise\tCtrl+R', '',
                 partial(self.onFlip, mode='rot_cw'))
        MenuItem(self, mview,  'Flip Top/Bottom\tCtrl+T', '',
                 partial(self.onFlip, mode='flip_ud'))
        MenuItem(self, mview,  'Flip Left/Right\tCtrl+F', '',
                 partial(self.onFlip, mode='flip_lr'))

        mview.AppendSeparator()
        MenuItem(self, mview, 'Projet Horizontally\tCtrl+X', '',
                 partial(self.onProject, mode='x'))
        MenuItem(self, mview, 'Projet Vertically\tCtrl+Y', '',
                 partial(self.onProject, mode='y'))

        mview.AppendSeparator()
        m = MenuItem(self, mview, 'As Contour', 'Shown as contour map',
                     self.onContourToggle, kind=wx.ITEM_CHECK)
        m.Check(False)
        self.optional_menus.append((m, False))

        m = MenuItem(self, mview, 'Configure Contours', 'Configure Contours',
                     self.onContourConfig)
        self.optional_menus.append((m, False))

        # intensity contrast
        mint =self.intensity_menu = wx.Menu()
#         MenuItem(self, mint,  'Log Scale Intensity\tCtrl+L',
#                  'use logarithm to set intensity scale',
#                  self.onLogScale, kind=wx.ITEM_CHECK)

        MenuItem(self, mint, 'Toggle Contrast Enhancement\tCtrl+E',
                 'Toggle contrast between auto-scale and full-scale',
                 self.onEnhanceContrast, kind=wx.ITEM_CHECK)


        MenuItem(self, mint, 'Set Auto-Contrast Level',
                 'Set auto-contrast scale',
                 self.onContrastConfig)

        # smoothing
        msmoo = wx.Menu()
        for itype in Interp_List:
            wid = wx.NewId()
            msmoo.AppendRadioItem(wid, itype, itype)
            self.Bind(wx.EVT_MENU, partial(self.onInterp, name=itype), id=wid)

        # help
        mhelp = wx.Menu()
        MenuItem(self, mhelp, 'Quick Reference',
                 'Quick Reference for WXMPlot', self.onHelp)
        MenuItem(self, mhelp, 'About', 'About WXMPlot', self.onAbout)

        # add all sub-menus, including user-added
        submenus = [('File', mfile),
                    ('Image', mview),
                    ('Contrast', mint),
                    ('Smoothing', msmoo)]
        if self.user_menus is not None:
            submenus.extend(self.user_menus)
        submenus.append(('&Help', mhelp))

        mbar = wx.MenuBar()
        for title, menu in submenus:
            mbar.Append(menu, title)

        self.SetMenuBar(mbar)
        self.Bind(wx.EVT_CLOSE,self.onExit)

    def onInterp(self, evt=None, name=None):

        if name not in Interp_List:
            name = Interp_List[0]
        for iframe in self.tomo_frame:
            iframe.panel.conf.interp = name
            iframe.panel.redraw()

    def onCursorMode(self, event=None, mode='zoom'):

        choice = self.zoom_mode.GetString(self.zoom_mode.GetSelection())
        for iframe in self.tomo_frame:
            iframe.panel.cursor_mode = mode
            if event is not None:
                if choice.startswith('Pick Area'):
                    iframe.panel.cursor_mode = 'lasso'
                elif choice.startswith('Show Line'):
                    iframe.panel.cursor_mode = 'prof'

    def onProject(self, event=None, mode='y'):

        wid = event.GetId()
        if mode=='x':
            x = self.tomo_frame[0].panel.ydata
            y = self.tomo_frame[0].panel.conf.data.sum(axis=1)
            x = self.tomo_frame[1].panel.ydata
            y = self.tomo_frame[1].panel.conf.data.sum(axis=1)
            axname = 'horizontal'
            if x is None:
                x = np.arange(y.shape[0])

        else:
            x = self.tomo_frame[0].panel.xdata
            y = self.tomo_frame[0].panel.conf.data.sum(axis=0)
            x = self.tomo_frame[1].panel.xdata
            y = self.tomo_frame[1].panel.conf.data.sum(axis=0)
            if x is None:
                x = np.arange(y.shape[0])

            axname = 'vertical'
        title = '%s: sum along %s axis' % (self.GetTitle(), axname)

        pf = PlotFrame(title=title, parent=self, size=(500, 250))
        colors = RGB_COLORS
        if len(y.shape) == 2 and y.shape[1] == 3:
            pf.plot(x, y[:,0], color=colors[0])
            pf.oplot(x, y[:,1], color=colors[1])
            pf.oplot(x, y[:,2], color=colors[2])
        else:
            pf.plot(x, y)
        pf.Raise()
        pf.Show()

    def onFlip(self, event=None, mode=None):

        for iframe in self.tomo_frame:
            conf = iframe.panel.conf
            if mode == 'flip_lr':
                conf.flip_lr = not conf.flip_lr
            elif mode == 'flip_ud':
                conf.flip_ud = not conf.flip_ud
            elif mode == 'flip_orig':
                conf.flip_lr, conf.flip_ud = False, False
            elif mode == 'rot_cw':
                conf.rot = True
            iframe.panel.unzoom_all()

    def Build_ConfigPanel(self):
        '''config panel for left-hand-side of frame: RGB Maps'''
        
        csizer = wx.BoxSizer(wx.VERTICAL)
        lsty = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND

        icol = 0
        if self.config_mode == 'rgb':
            for iframe in self.tomo_frame:
                for ic,col in enumerate(RGB_COLORS):
                    self.cmap_panels[icol] =  ColorMapPanel(self.config_panel,
                                                            iframe.panel,
                                                            title='%s - %s: ' % (iframe.label,col.title()),
                                                            color=ic,
                                                            default=col,
                                                            colormap_list=None)

                    csizer.Add(self.cmap_panels[icol], 0, lsty, 2)
                    csizer.Add(wx.StaticLine(self.config_panel, size=(100, 2),
                                            style=wx.LI_HORIZONTAL), 0, lsty, 2)
                    icol += 1


        else:
            for iframe in self.tomo_frame:
                self.cmap_panels[icol] =  ColorMapPanel(self.config_panel,
                                                        iframe.panel,
                                                        title='%s: ' % iframe.label,
                                                        default='gray',
                                                        colormap_list=ColorMap_List)

                csizer.Add(self.cmap_panels[icol],  0, lsty, 1)
                csizer.Add(wx.StaticLine(self.config_panel, size=(100, 2),
                                        style=wx.LI_HORIZONTAL), 0, lsty, 2)
                icol += 1

        cust = self.CustomConfig(self.config_panel, None, 0)
        if cust is not None:
            csizer.Add(cust, 0, lsty, 1)
        pack(self.config_panel, csizer)

    def clear_highlight_area(self):
    
        for iframe in self.tomo_frame:
            for area in iframe.panel.conf.highlight_areas:
                for w in area.collections + area.labelTexts:
                    w.remove()

            iframe.panel.conf.highlight_areas = []
            iframe.panel.redraw()


    def add_highlight_area(self, mask0, label=None, col=0):
        """add a highlighted area -- outline an arbitrarily shape --
        as if drawn from a Lasso event.

        This takes a mask, which should be a boolean array of the
        same shape as the image.
        """
        
        panel = None

        for iframe in self.tomo_frame:
            imap_size = iframe.map.shape[:2]
            for imask in (mask0,np.swapaxes(mask0,0,1)):
               if imap_size == imask.shape:
                  panel = iframe.panel
                  mask = imask

        if panel is not None:
            patch = mask * np.ones(mask.shape) * 0.9
            cmap = panel.conf.cmap[col]
            area = panel.axes.contour(patch, cmap=cmap, levels=[0, 1])
            panel.conf.highlight_areas.append(area)
            col = None
            if hasattr(cmap, '_lut'):
                rgb  = [int(i*240)^255 for i in cmap._lut[0][:3]]
                col  = '#%02x%02x%02x' % (rgb[0], rgb[1], rgb[2])

            if label is not None:
                def fmt(*args, **kws): return label
                panel.axes.clabel(area, fontsize=9, fmt=fmt,
                                 colors=col, rightside_up=True)

            if col is not None:
                for l in area.collections:
                    l.set_color(col)

            panel.canvas.draw()

    def CustomConfig(self, panel, sizer=None, irow=0):
        '''
        override to add custom config panel items
        to bottom of config panel
        '''

        labstyle = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND
        
        if self.lasso_callback is None:
            zoom_opts = ('Zoom to Rectangle',
                         'Show Line Profile')
        else:
            zoom_opts = ('Zoom to Rectangle',
                         'Pick Area for XRM Spectra',
                         'Show Line Profile')
                         
        if self.wxmplot_version > 0.921:
            cpanel = wx.Panel(panel)
            if sizer is None:
                sizer = wx.BoxSizer(wx.VERTICAL)
            sizer.Add(SimpleText(cpanel, label='Cursor Modes', style=labstyle), 0, labstyle, 3)
            self.zoom_mode = wx.RadioBox(cpanel, -1, '',
                                         wx.DefaultPosition, wx.DefaultSize,
                                         zoom_opts, 1, wx.RA_SPECIFY_COLS)
            self.zoom_mode.Bind(wx.EVT_RADIOBOX, self.onCursorMode)

            sizer.Add(self.zoom_mode, 1, labstyle, 4)

            pack(cpanel, sizer)
            return cpanel
        else:  # support older versions of wxmplot, will be able to deprecate
            conf = self.tomo_frame[0].panel.conf # self.panel.conf
            lpanel = panel
            lsizer = sizer
            self.zoom_mode = wx.RadioBox(panel, -1, 'Cursor Mode:',
                                         wx.DefaultPosition, wx.DefaultSize,
                                         zoom_opts, 1, wx.RA_SPECIFY_COLS)
            self.zoom_mode.Bind(wx.EVT_RADIOBOX, self.onCursorMode)
            sizer.Add(self.zoom_mode,  (irow, 0), (1, 4), labstyle, 3)

    def onContrastConfig(self, event=None):
        
        for iframe in self.tomo_frame:
            dlg = AutoContrastDialog(parent=self, conf=iframe.panel.conf)
            dlg.CenterOnScreen()
            val = dlg.ShowModal()
            if val == wx.ID_OK:
                pass
            dlg.Destroy()


    def onContourConfig(self, event=None):

        for icol,iframe in enumerate(self.tomo_frame):
            conf = iframe.panel.conf
            dlg = ContourDialog(parent=self, conf=conf)
            dlg.CenterOnScreen()
            val = dlg.ShowModal()
            if val == wx.ID_OK:
                pass
            dlg.Destroy()
            if conf.style != 'contour':
                return

            if self.config_mode == 'int':
                self.cmap_panels[icol].set_colormap()

            iframe.panel.axes.cla()
            iframe.panel.display(conf.data, x=iframe.panel.xdata, y = iframe.panel.ydata,
                          xlabel=iframe.panel.xlab, ylabel=iframe.panel.ylab,
                          contour_labels=conf.contour_labels,
                          nlevels=conf.ncontour_levels, style='contour')
            iframe.panel.redraw()

    def onContourToggle(self, event=None):

        for icol,iframe in enumerate(self.tomo_frame):
            if len(iframe.panel.conf.data.shape) > 2:
                return
            conf  = iframe.panel.conf
            conf.style = 'image'
            if event.IsChecked():
                conf.style = 'contour'
            nlevels = int(conf.ncontour_levels)
            if self.config_mode == 'int':
                self.cmap_panels[0].set_colormap()
            iframe.panel.axes.cla()
            iframe.panel.display(conf.data, x=iframe.panel.xdata, y = iframe.panel.ydata,
                          nlevels=nlevels, contour_labels=conf.contour_labels,
                          xlabel=iframe.panel.xlab, ylabel=iframe.panel.ylab,
                          style=conf.style)
            iframe.panel.redraw()

    def onTriColorBG(self, event=None):
        bgcol = {True:'white', False:'black'}[event.IsChecked()]

        icol = 0
        for iframe in self.tomo_frame:
            conf = iframe.panel.conf
            if bgcol == conf.tricolor_bg:
                return

            conf.tricolor_bg = bgcol
            cmaps = colors = RGB_COLORS
            if bgcol.startswith('wh'):
                cmaps = ('Reds', 'Greens', 'Blues')

            for i in range(3):
                self.cmap_panels[icol].set_colormap(name=cmaps[i])
                icol += 1

            iframe.panel.redraw()

    def onLasso(self, data=None, selected=None, mask=None, **kws):

        ## orients mask correctly to match with raw data shape
        ## mkak 2018.01.24
        mask = np.swapaxes(mask,0,1)
        
        if hasattr(self.lasso_callback , '__call__'):
            self.lasso_callback(data=data, selected=selected, mask=mask, **kws)

    def onDataChange(self, data, x=None, y=None, col='int', **kw):

        icol = 0
        for iframe in self.tomo_frame:
            conf = iframe.panel.conf
            if len(data.shape) == 2: # intensity map
                imin, imax = data.min(), data.max()
                conf.int_lo[0] = imin
                conf.int_hi[0] = imax
                cpan = self.cmap_panels[0]

                cpan.cmap_lo.SetValue(imin)
                cpan.cmap_hi.SetValue(imax)

                cpan.imin_val.SetValue('%.4g' % imin)
                cpan.imax_val.SetValue('%.4g' % imax)
                cpan.imin_val.Enable()
                cpan.imax_val.Enable()
            else:
                for ix in range(3):
                    imin, imax = data[:,:,ix].min(), data[:,:,ix].max()
                    conf.int_lo[ix] = imin
                    conf.int_hi[ix] = imax
                    self.cmap_panels[icol].imin_val.SetValue('%.4g' % imin)
                    self.cmap_panels[icol].imax_val.SetValue('%.4g' % imax)
                    self.cmap_panels[icol].imin_val.Enable()
                    self.cmap_panels[icol].imax_val.Enable()
                    icol += 1

    def onEnhanceContrast(self, event=None):
        '''change image contrast, using scikit-image exposure routines'''
        
        for iframe in self.tomo_frame:
            iframe.panel.conf.auto_contrast = event.IsChecked()
        self.set_contrast_levels()
        for iframe in self.tomo_frame:
            iframe.panel.redraw()

    def set_contrast_levels(self):
        '''enhance contrast levels, or use full data range
        according to value of iframe.panel.conf.auto_contrast
        '''

        def set_panel_contrast(icol,conf,ix=-1):

            if ix < 0:
                ix = icol
                img  = conf.data
            else:
                img = conf.data[:,:,ix]

            jmin = imin = img.min()
            jmax = imax = img.max()

            self.cmap_panels[icol].imin_val.SetValue('%.4g' % imin)
            self.cmap_panels[icol].imax_val.SetValue('%.4g' % imax)
            conf.int_lo[ix] = imin
            conf.int_hi[ix] = imax

            if conf.auto_contrast:
                jmin, jmax = np.percentile(img, [      conf.auto_contrast_level,
                                                 100.0-conf.auto_contrast_level])
            if imax == imin:
                imax = imin + 0.5
            conf.cmap_lo[ix] = xlo = (jmin-imin)*conf.cmap_range/(imax-imin)
            conf.cmap_hi[ix] = xhi = (jmax-imin)*conf.cmap_range/(imax-imin)
            self.cmap_panels[icol].cmap_hi.SetValue(xhi)
            self.cmap_panels[icol].cmap_lo.SetValue(xlo)
            
            str = 'Shown: [ %.4g :  %.4g ]' % (jmin, jmax)
            self.cmap_panels[icol].islider_range.SetLabel(str)
            self.cmap_panels[icol].redraw_cmap()

        icol = 0
        for iframe in self.tomo_frame:
            conf = iframe.panel.conf
            if len(conf.data.shape) == 2: # intensity map
                set_panel_contrast(icol,conf)
                icol += 1
            elif len(conf.data.shape) == 3: # rgb map
                for ix in range(3):
                    set_panel_contrast(icol,conf,ix=ix)
                    icol += 1
            iframe.panel.redraw()

    def onLogScale(self, event=None):
        
        for iframe in self.tomo_frame:
            iframe.panel.conf.log_scale = not iframe.panel.conf.log_scale
            iframe.panel.redraw()

    def onCMapSave(self, event=None, col='int'):
        '''save color table image'''
        file_choices = 'PNG (*.png)|*.png'
        ofile = 'Colormap.png'

        dlg = wx.FileDialog(self, message='Save Colormap as...',
                            defaultDir=os.getcwd(),
                            defaultFile=ofile,
                            wildcard=file_choices,
                            style=wx.FD_SAVE|wx.FD_CHANGE_DIR)

        if dlg.ShowModal() == wx.ID_OK:
            self.cmap_panels[0].cmap_canvas.print_figure(dlg.GetPath(), dpi=600)

    def save_figure(self,event=None, transparent=True, dpi=600):
        ''' save figure image to file'''
        for iframe in self.tomo_frame:
            if iframe.panel is not None:
                iframe.panel.save_figure(event=event, transparent=transparent, dpi=dpi)
Пример #34
0
class with_profile_mode:
    def prof_motion(self, event=None):
        if not event.inaxes or self.zoom_ini is None:
            return
        try:
            xmax, ymax  = event.x, event.y
        except:
            return
        xmin, ymin, xd, yd = self.zoom_ini
        if event.xdata is not None:
            self.lastpoint[0] = event.xdata
        if event.ydata is not None:
            self.lastpoint[1] = event.ydata

        yoff = self.panel.canvas.figure.bbox.height
        ymin, ymax = yoff - ymin, yoff - ymax

        zdc = wx.ClientDC(self.panel.canvas)
        zdc.SetLogicalFunction(wx.XOR)
        zdc.SetBrush(wx.TRANSPARENT_BRUSH)
        zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
        zdc.ResetBoundingBox()
        if not is_wxPhoenix:
            zdc.BeginDrawing()

        # erase previous box
        if self.rbbox is not None:
            zdc.DrawLine(*self.rbbox)
        self.rbbox = (xmin, ymin, xmax, ymax)
        zdc.DrawLine(*self.rbbox)
        if not is_wxPhoenix:
            zdc.EndDrawing()

    def prof_leftdown(self, event=None):
        self.report_leftdown(event=event)
        if event.inaxes: #  and len(self.map.shape) == 2:
            self.lastpoint = [None, None]
            self.zoom_ini = [event.x, event.y, event.xdata, event.ydata]

    def prof_leftup(self, event=None):
        # print("Profile Left up ", self.map.shape, self.rbbox)
        if self.rbbox is not None:
            zdc = wx.ClientDC(self.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()
            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []
        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []
        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(self.panel.conf.data[iy, ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        x = np.array(x)
        y = np.array(y)
        z = np.array(z)
        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)

        if isinstance(z[0], np.ndarray) and len(z[0]) == 3: # color plot
            rlab = self.subtitles['red']
            glab = self.subtitles['green']
            blab = self.subtitles['blue']
            self.prof_plotter.plot(x, z[:, 0], title=self.title, color='red',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=rlab, **opts)
            self.prof_plotter.oplot(x, z[:, 1], title=self.title, color='darkgreen',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=glab, **opts)
            self.prof_plotter.oplot(x, z[:, 2], title=self.title, color='blue',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label=blab, **opts)

        else:

            self.prof_plotter.plot(x, z, title=self.title, color='blue',
                                   zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                                   ylabel='counts', label='counts', **opts)

        self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                              zorder=3, side='right', color='black', **opts)

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'

    def prof_report_coords(self, event=None):
        """override report leftdown for profile plotter"""
        if event is None:
            return
        ex, ey = event.x, event.y
        msg = ''
        plotpanel = self.prof_plotter.panel
        axes  = plotpanel.fig.properties()['axes'][0]
        write = plotpanel.write_message
        try:
            x, y = axes.transData.inverted().transform((ex, ey))
        except:
            x, y = event.xdata, event.ydata

        if x is None or y is None:
            return

        _point = 0, 0, 0, 0, 0
        for ix, iy in self.prof_dat[1]:
            if (int(x) == ix and not self.prof_dat[0] or
                int(x) == iy and self.prof_dat[0]):
                _point = (ix, iy,
                              self.panel.xdata[ix],
                              self.panel.ydata[iy],
                              self.panel.conf.data[iy, ix])

        msg = "Pixel [%i, %i], X, OME = [%.4f mm, %.4f deg], Intensity= %g" % _point
        write(msg,  panel=0)
Пример #35
0
class MapImageFrame(ImageFrame):
    """
    MatPlotlib Image Display on a wx.Frame, using ImagePanel
    """

    def __init__(self, parent=None, size=None, mode='intensity',
                 lasso_callback=None, move_callback=None, save_callback=None,
                 show_xsections=False, cursor_labels=None,
                 output_title='Image',   **kws):

        # instdb=None,  inst_name=None,

        self.det = None
        self.xrmfile = None
        self.map = None
        self.move_callback = move_callback
        self.save_callback = save_callback

        ImageFrame.__init__(self, parent=parent, size=size,
                            lasso_callback=lasso_callback,
                            cursor_labels=cursor_labels, mode=mode,
                            output_title=output_title, **kws)

        self.panel.add_cursor_mode('prof', motion = self.prof_motion,
                                   leftdown = self.prof_leftdown,
                                   leftup   = self.prof_leftup)
        self.panel.report_leftdown = self.report_leftdown
        self.panel.report_motion   = self.report_motion


        self.prof_plotter = None
        self.zoom_ini =  None
        self.lastpoint = [None, None]
        self.this_point = None
        self.rbbox = None

    def display(self, map, det=None, xrmfile=None, xoff=0, yoff=0, **kws):
        self.xoff = xoff
        self.yoff = yoff
        self.det = det
        self.xrmfile = xrmfile
        self.map = map
        self.title = ''
        if 'title' in kws:
            self.title = kws['title']
        ImageFrame.display(self, map, **kws)
        if 'x' in kws:
            self.panel.xdata = kws['x']
        if 'y' in kws:
            self.panel.ydata = kws['y']
        if self.panel.conf.auto_contrast:
            self.set_contrast_levels()


    def prof_motion(self, event=None):
        if not event.inaxes or self.zoom_ini is None:
            return
        try:
            xmax, ymax  = event.x, event.y
        except:
            return

        xmin, ymin, xd, yd = self.zoom_ini
        if event.xdata is not None:
            self.lastpoint[0] = event.xdata
        if event.ydata is not None:
            self.lastpoint[1] = event.ydata

        yoff = self.panel.canvas.figure.bbox.height
        ymin, ymax = yoff - ymin, yoff - ymax

        zdc = wx.ClientDC(self.panel.canvas)
        zdc.SetLogicalFunction(wx.XOR)
        zdc.SetBrush(wx.TRANSPARENT_BRUSH)
        zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
        zdc.ResetBoundingBox()
        if not is_wxPhoenix:
            zdc.BeginDrawing()


        # erase previous box
        if self.rbbox is not None:
            zdc.DrawLine(*self.rbbox)
        self.rbbox = (xmin, ymin, xmax, ymax)
        zdc.DrawLine(*self.rbbox)
        if not is_wxPhoenix:
            zdc.EndDrawing()

    def prof_leftdown(self, event=None):
        self.report_leftdown(event=event)
        if event.inaxes and len(self.map.shape) == 2:
            self.lastpoint = [None, None]
            self.zoom_ini = [event.x, event.y, event.xdata, event.ydata]

    def prof_leftup(self, event=None):
        if len(self.map.shape) != 2:
            return
        if self.rbbox is not None:
            zdc = wx.ClientDC(self.panel.canvas)
            zdc.SetLogicalFunction(wx.XOR)
            zdc.SetBrush(wx.TRANSPARENT_BRUSH)
            zdc.SetPen(wx.Pen('White', 2, wx.SOLID))
            zdc.ResetBoundingBox()
            if not is_wxPhoenix:
                zdc.BeginDrawing()
            zdc.DrawLine(*self.rbbox)
            if not is_wxPhoenix:
                zdc.EndDrawing()

            self.rbbox = None

        if self.zoom_ini is None or self.lastpoint[0] is None:
            return

        x0 = int(self.zoom_ini[2])
        x1 = int(self.lastpoint[0])
        y0 = int(self.zoom_ini[3])
        y1 = int(self.lastpoint[1])
        dx, dy = abs(x1-x0), abs(y1-y0)

        self.lastpoint, self.zoom_ini = [None, None], None
        if dx < 2 and dy < 2:
            self.zoom_ini = None
            return

        outdat = []

        if dy > dx:
            _y0 = min(int(y0), int(y1+0.5))
            _y1 = max(int(y0), int(y1+0.5))

            for iy in range(_y0, _y1):
                ix = int(x0 + (iy-int(y0))*(x1-x0)/(y1-y0))
                outdat.append((ix, iy))
        else:
            _x0 = min(int(x0), int(x1+0.5))
            _x1 = max(int(x0), int(x1+0.5))
            for ix in range(_x0, _x1):
                iy = int(y0 + (ix-int(x0))*(y1-y0)/(x1-x0))
                outdat.append((ix, iy))
        x, y, z = [], [], []
        for ix, iy in outdat:
            x.append(ix)
            y.append(iy)
            z.append(self.panel.conf.data[iy,ix])
        self.prof_dat = dy>dx, outdat

        if self.prof_plotter is not None:
            try:
                self.prof_plotter.Raise()
                self.prof_plotter.clear()

            except (AttributeError, PyDeadObjectError):
                self.prof_plotter = None

        if self.prof_plotter is None:
            self.prof_plotter = PlotFrame(self, title='Profile')
            self.prof_plotter.panel.report_leftdown = self.prof_report_coords

        xlabel, y2label = 'Pixel (x)',  'Pixel (y)'

        if dy > dx:
            x, y = y, x
            xlabel, y2label = y2label, xlabel
        self.prof_plotter.panel.clear() # reset_config()

        if len(self.title) < 1:
            self.title = os.path.split(self.xrmfile.filename)[1]

        opts = dict(linewidth=2, marker='+', markersize=3,
                    show_legend=True, xlabel=xlabel)
        self.prof_plotter.plot(x, z, title=self.title, color='blue',
                               zorder=20, xmin=min(x)-3, xmax=max(x)+3,
                               ylabel='counts', label='counts', **opts)

        self.prof_plotter.oplot(x, y, y2label=y2label, label=y2label,
                              zorder=3, side='right', color='#771111', **opts)

        self.prof_plotter.panel.unzoom_all()
        self.prof_plotter.Show()
        self.zoom_ini = None

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'

    def prof_report_coords(self, event=None):
        """override report leftdown for profile plotter"""
        if event is None:
            return
        ex, ey = event.x, event.y
        msg = ''
        plotpanel = self.prof_plotter.panel
        axes  = plotpanel.fig.get_axes()[0]
        write = plotpanel.write_message
        try:
            x, y = axes.transData.inverted().transform((ex, ey))
        except:
            x, y = event.xdata, event.ydata

        if x is None or y is None:
            return

        _point = 0, 0, 0, 0, 0
        for ix, iy in self.prof_dat[1]:
            if (int(x) == ix and not self.prof_dat[0] or
                int(x) == iy and self.prof_dat[0]):
                _point = (ix, iy,
                              self.panel.xdata[ix],
                              self.panel.ydata[iy],
                              self.panel.conf.data[iy, ix])

        msg = "Pixel [%i, %i], X, Y = [%.4f, %.4f], Intensity= %g" % _point
        write(msg,  panel=0)

    def onCursorMode(self, event=None, mode='zoom'):
        self.panel.cursor_mode = mode
        if event is not None:
            if 1 == event.GetInt():
                self.panel.cursor_mode = 'lasso'
            elif 2 == event.GetInt():
                self.panel.cursor_mode = 'prof'


    def report_leftdown(self, event=None):
        if event is None:
            return
        if event.xdata is None or event.ydata is None:
            return

        ix, iy = int(round(event.xdata)), int(round(event.ydata))
        conf = self.panel.conf
        if conf.flip_ud:  iy = conf.data.shape[0] - iy
        if conf.flip_lr:  ix = conf.data.shape[1] - ix

        self.this_point = None
        msg = ''
        if (ix >= 0 and ix < conf.data.shape[1] and
            iy >= 0 and iy < conf.data.shape[0]):
            pos = ''
            pan = self.panel
            # print( 'has xdata? ', pan.xdata is not None, pan.ydata is not None)
            labs, vals = [], []
            if pan.xdata is not None:
                labs.append(pan.xlab)
                vals.append(pan.xdata[ix])
            if pan.ydata is not None:
                labs.append(pan.ylab)
                vals.append(pan.ydata[iy])
            pos = ', '.join(labs)
            vals =', '.join(['%.4g' % v for v in vals])
            pos = '%s = [%s]' % (pos, vals)
            dval = conf.data[iy, ix]
            if len(pan.data_shape) == 3:
                dval = "%.4g, %.4g, %.4g" % tuple(dval)
            else:
                dval = "%.4g" % dval
            if pan.xdata is not None and pan.ydata is not None:
                self.this_point = (ix, iy)

            msg = "Pixel [%i, %i], %s, Intensity=%s " % (ix, iy, pos, dval)
        self.panel.write_message(msg, panel=0)

    def report_motion(self, event=None):
        return

    def onLasso(self, data=None, selected=None, mask=None, **kws):
        if hasattr(self.lasso_callback , '__call__'):

            self.lasso_callback(data=data, selected=selected, mask=mask,
                                xoff=self.xoff, yoff=self.yoff,
                                det=self.det, xrmfile=self.xrmfile, **kws)

        self.zoom_mode.SetSelection(0)
        self.panel.cursor_mode = 'zoom'

    def CustomConfig(self, panel, sizer, irow):
        """config panel for left-hand-side of frame"""
        conf = self.panel.conf
        lpanel = panel
        lsizer = sizer
        labstyle = wx.ALIGN_LEFT|wx.LEFT|wx.TOP|wx.EXPAND

        self.zoom_mode = wx.RadioBox(panel, -1, "Cursor Mode:",
                                     wx.DefaultPosition, wx.DefaultSize,
                                     ('Zoom to Rectangle',
                                      'Pick Area for XRF Spectrum',
                                      'Show Line Profile'),
                                     1, wx.RA_SPECIFY_COLS)
        self.zoom_mode.Bind(wx.EVT_RADIOBOX, self.onCursorMode)
        sizer.Add(self.zoom_mode,  (irow, 0), (1, 4), labstyle, 3)
        if self.save_callback is not None:
            self.pos_name = wx.TextCtrl(panel, -1, '',  size=(175, -1),
                                        style=wx.TE_PROCESS_ENTER)
            self.pos_name.Bind(wx.EVT_TEXT_ENTER, self.onSavePixel)
            label   = SimpleText(panel, label='Save Position:',
                                 size=(-1, -1))
            # sbutton = Button(panel, 'Save Position', size=(100, -1),
            #                  action=self.onSavePixel)
            sizer.Add(label,         (irow+1, 0), (1, 2), labstyle, 3)
            sizer.Add(self.pos_name, (irow+1, 2), (1, 2), labstyle, 3)
            # sizer.Add(sbutton,       (irow+2, 0), (1, 2), labstyle, 3)

        if self.move_callback is not None:
            mbutton = Button(panel, 'Move to Position', size=(100, -1),
                                 action=self.onMoveToPixel)
            irow  = irow + 2
            sizer.Add(mbutton,       (irow+1, 0), (1, 2), labstyle, 3)

    def onMoveToPixel(self, event=None):
        if self.this_point is not None and self.move_callback is not None:
            p1 = float(self.panel.xdata[self.this_point[0]])
            p2 = float(self.panel.ydata[self.this_point[1]])
            self.move_callback(p1, p2)

    def onSavePixel(self, event=None):
        if self.this_point is not None and self.save_callback is not None:
            name  = str(event.GetString().strip())
            # name  = str(self.pos_name.GetValue().strip())
            ix, iy = self.this_point
            x = float(self.panel.xdata[int(ix)])
            y = float(self.panel.ydata[int(iy)])
            self.save_callback(name, ix, iy, x=x, y=y,
                               title=self.title, datafile=self.xrmfile)
Пример #36
0
class ScanViewerFrame(wx.Frame):
    _about = """Scan 2D Plotter
  Matt Newville <newville @ cars.uchicago.edu>
  """

    def __init__(self, _larch=None, **kws):

        wx.Frame.__init__(self, None, -1, style=FRAMESTYLE)
        self.file_groups = {}
        self.file_paths = []
        title = "Column Data File Viewer"
        self.larch = _larch
        self.larch_buffer = None
        self.subframes = {}
        self.plotframe = None
        self.groupname = None
        self.SetTitle(title)
        self.SetSize((850, 650))
        self.SetFont(Font(10))

        self.config = {'chdir_on_fileopen': True}

        self.createMainPanel()
        self.createMenus()
        self.statusbar = self.CreateStatusBar(2, 0)
        self.statusbar.SetStatusWidths([-3, -1])
        statusbar_fields = ["Initializing....", " "]
        for i in range(len(statusbar_fields)):
            self.statusbar.SetStatusText(statusbar_fields[i], i)
        read_workdir('scanviewer.dat')

    def createMainPanel(self):
        splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        splitter.SetMinimumPaneSize(225)

        self.filelist = wx.ListBox(splitter)
        self.filelist.SetBackgroundColour(wx.Colour(255, 255, 255))
        self.filelist.Bind(wx.EVT_LISTBOX, self.ShowFile)

        self.detailspanel = self.createDetailsPanel(splitter)

        splitter.SplitVertically(self.filelist, self.detailspanel, 1)
        wx.CallAfter(self.init_larch)

    def createDetailsPanel(self, parent):
        mainpanel = wx.Panel(parent)
        mainsizer = wx.BoxSizer(wx.VERTICAL)
        panel = wx.Panel(mainpanel)
        sizer = wx.GridBagSizer(8, 7)

        self.title = SimpleText(panel, 'initializing...')
        ir = 0
        sizer.Add(self.title, (ir, 0), (1, 6), LCEN, 2)
        # x-axis

        self.xarr = Choice(panel,
                           choices=[],
                           action=self.onColumnChoices,
                           size=(120, -1))
        self.xop = Choice(panel,
                          choices=('', 'log'),
                          action=self.onColumnChoices,
                          size=(90, -1))

        ir += 1
        sizer.Add(SimpleText(panel, 'X = '), (ir, 0), (1, 1), CEN, 0)
        sizer.Add(self.xop, (ir, 1), (1, 1), CEN, 0)
        sizer.Add(SimpleText(panel, '('), (ir, 2), (1, 1), CEN, 0)
        sizer.Add(self.xarr, (ir, 3), (1, 1), RCEN, 0)
        sizer.Add(SimpleText(panel, ')'), (ir, 4), (1, 1), CEN, 0)

        self.yops = []
        self.yarr = []

        opts = {
            'choices': [],
            'size': (120, -1),
            'action': self.onColumnChoices
        }
        for i in range(3):
            self.yarr.append(Choice(panel, **opts))

        for opts, sel, siz in ((PRE_OPS, 0, 90), (ARR_OPS, 3, 50), (ARR_OPS, 3,
                                                                    50)):
            w1 = Choice(panel,
                        choices=opts,
                        action=self.onColumnChoices,
                        size=(siz, -1))
            w1.SetSelection(sel)
            self.yops.append(w1)

        ir += 1
        label = 'Y = '
        sizer.Add(SimpleText(panel, label), (ir, 0), (1, 1), CEN, 0)
        sizer.Add(self.yops[0], (ir, 1), (1, 1), CEN, 0)
        sizer.Add(SimpleText(panel, '[('), (ir, 2), (1, 1), CEN, 0)
        sizer.Add(self.yarr[0], (ir, 3), (1, 1), CEN, 0)
        sizer.Add(self.yops[1], (ir, 4), (1, 1), CEN, 0)
        sizer.Add(self.yarr[1], (ir, 5), (1, 1), CEN, 0)
        sizer.Add(SimpleText(panel, ')'), (ir, 6), (1, 1), LCEN, 0)
        ir += 1
        sizer.Add(self.yops[2], (ir, 4), (1, 1), CEN, 0)
        sizer.Add(self.yarr[2], (ir, 5), (1, 1), CEN, 0)
        sizer.Add(SimpleText(panel, ']'), (ir, 6), (1, 1), LCEN, 0)

        self.use_deriv = Check(panel,
                               default=False,
                               label='Use Derivative?',
                               action=self.onColumnChoices)
        self.dtcorr = Check(panel,
                            default=True,
                            label='correct deadtime?',
                            action=self.onColumnChoices)
        ir += 1
        sizer.Add(self.use_deriv, (ir, 0), (1, 3), LCEN, 0)
        sizer.Add(self.dtcorr, (ir, 3), (1, 3), LCEN, 0)

        pack(panel, sizer)

        self.nb = flat_nb.FlatNotebook(mainpanel, -1, agwStyle=FNB_STYLE)

        self.nb.SetTabAreaColour(wx.Colour(248, 248, 240))
        self.nb.SetActiveTabColour(wx.Colour(254, 254, 195))

        self.nb.SetNonActiveTabTextColour(wx.Colour(40, 40, 180))
        self.nb.SetActiveTabTextColour(wx.Colour(80, 0, 0))

        self.xas_panel = self.CreateXASPanel(self.nb)  # mainpanel)
        self.fit_panel = self.CreateFitPanel(self.nb)  # mainpanel)

        self.nb.AddPage(self.fit_panel, ' General Analysis ', True)
        self.nb.AddPage(self.xas_panel, ' XAS Processing ', True)
        mainsizer.Add(panel, 0, LCEN | wx.EXPAND, 2)

        btnbox = wx.Panel(mainpanel)
        btnsizer = wx.BoxSizer(wx.HORIZONTAL)
        for ttl, opt in (('New Plot', 'new'), ('Over Plot (left)', 'left'),
                         ('Over Plot (right)', 'right')):

            btnsizer.Add(
                Button(btnbox,
                       ttl,
                       size=(135, -1),
                       action=partial(self.onPlot, opt=opt)), LCEN, 1)

        pack(btnbox, btnsizer)
        mainsizer.Add(btnbox, 0, LCEN, 2)
        mainsizer.Add(self.nb, 1, LCEN | wx.EXPAND, 2)

        pack(mainpanel, mainsizer)

        return mainpanel

    def CreateFitPanel(self, parent):
        panel = wx.Panel(parent)
        tpan = wx.Panel(panel)
        self.fit_model = Choice(tpan,
                                size=(100, -1),
                                choices=('Gaussian', 'Lorentzian', 'Voigt',
                                         'Linear', 'Quadratic', 'Step',
                                         'Rectangle', 'Exponential'))
        self.fit_bkg = Choice(tpan,
                              size=(100, -1),
                              choices=('None', 'constant', 'linear',
                                       'quadratic'))
        self.fit_step = Choice(tpan,
                               size=(100, -1),
                               choices=('linear', 'error function', 'arctan'))

        tsizer = wx.GridBagSizer(10, 4)
        tsizer.Add(SimpleText(tpan, 'Fit Model: '), (0, 0), (1, 1), LCEN)
        tsizer.Add(self.fit_model, (0, 1), (1, 1), LCEN)

        tsizer.Add(SimpleText(tpan, 'Background: '), (0, 2), (1, 1), LCEN)
        tsizer.Add(self.fit_bkg, (0, 3), (1, 1), LCEN)

        tsizer.Add(
            Button(tpan, 'Show Fit', size=(100, -1), action=self.onFitPeak),
            (1, 1), (1, 1), LCEN)

        tsizer.Add(SimpleText(tpan, 'Step Form: '), (1, 2), (1, 1), LCEN)
        tsizer.Add(self.fit_step, (1, 3), (1, 1), LCEN)

        pack(tpan, tsizer)

        self.fit_report = RichTextCtrl(panel,
                                       size=(525, 250),
                                       style=wx.VSCROLL | wx.NO_BORDER)

        self.fit_report.SetEditable(False)
        self.fit_report.SetFont(Font(9))

        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(tpan, 0, wx.GROW | wx.ALL, 2)
        sizer.Add(self.fit_report, 1, LCEN | wx.GROW, 2)
        pack(panel, sizer)
        return panel

    def InitializeXASPanel(self):
        if self.groupname is None:
            lgroup = None
        lgroup = getattr(self.larch.symtable, self.groupname)
        self.xas_e0.SetValue(getattr(lgroup, 'e0', 0))
        self.xas_step.SetValue(getattr(lgroup, 'edge_step', 0))
        self.xas_pre1.SetValue(getattr(lgroup, 'pre1', -200))
        self.xas_pre2.SetValue(getattr(lgroup, 'pre2', -30))
        self.xas_nor1.SetValue(getattr(lgroup, 'norm1', 50))
        self.xas_nor2.SetValue(getattr(lgroup, 'norm2', -10))

        self.xas_vict.SetSelection(getattr(lgroup, 'nvict', 1))
        self.xas_nnor.SetSelection(getattr(lgroup, 'nnorm', 2))

    def CreateXASPanel(self, parent):
        p = panel = wx.Panel(parent)
        self.xas_autoe0 = Check(panel, default=True, label='auto?')
        self.xas_showe0 = Check(panel, default=True, label='show?')
        self.xas_autostep = Check(panel, default=True, label='auto?')
        self.xas_op = Choice(
            panel,
            size=(225, -1),
            choices=('Raw Data', 'Normalized', 'Derivative',
                     'Normalized + Derivative', 'Pre-edge subtracted',
                     'Raw Data With Pre-edge/Post-edge Curves'),
            action=self.onXASChoice)
        opts = {
            'size': (95, -1),
            'precision': 3
        }  # , 'action': self.onXASChoice}
        self.xas_e0 = FloatCtrl(panel, value=0, **opts)
        self.xas_step = FloatCtrl(panel, value=0, **opts)
        opts['precision'] = 1
        self.xas_pre1 = FloatCtrl(panel, value=-200, **opts)
        self.xas_pre2 = FloatCtrl(panel, value=-30, **opts)
        self.xas_nor1 = FloatCtrl(panel, value=50, **opts)
        self.xas_nor2 = FloatCtrl(panel, value=-50, **opts)
        opts = {
            'size': (50, -1),
            'choices': ('0', '1', '2', '3'),
            'action': self.onXASChoice
        }
        self.xas_vict = Choice(panel, **opts)
        self.xas_nnor = Choice(panel, **opts)
        self.xas_vict.SetSelection(1)
        self.xas_nnor.SetSelection(2)
        sizer = wx.GridBagSizer(10, 4)

        sizer.Add(SimpleText(p, 'Plot XAS as: '), (0, 0), (1, 1), LCEN)
        sizer.Add(SimpleText(p, 'E0 : '), (1, 0), (1, 1), LCEN)
        sizer.Add(SimpleText(p, 'Edge Step: '), (2, 0), (1, 1), LCEN)
        sizer.Add(SimpleText(p, 'Pre-edge range: '), (3, 0), (1, 1), LCEN)
        sizer.Add(SimpleText(p, 'Normalization range: '), (4, 0), (1, 1), LCEN)

        sizer.Add(self.xas_op, (0, 1), (1, 3), LCEN)
        sizer.Add(self.xas_e0, (1, 1), (1, 1), LCEN)
        sizer.Add(self.xas_step, (2, 1), (1, 1), LCEN)
        sizer.Add(self.xas_pre1, (3, 1), (1, 1), LCEN)
        sizer.Add(SimpleText(p, ':'), (3, 2), (1, 1), LCEN)
        sizer.Add(self.xas_pre2, (3, 3), (1, 1), LCEN)
        sizer.Add(self.xas_nor1, (4, 1), (1, 1), LCEN)
        sizer.Add(SimpleText(p, ':'), (4, 2), (1, 1), LCEN)
        sizer.Add(self.xas_nor2, (4, 3), (1, 1), LCEN)

        sizer.Add(self.xas_autoe0, (1, 2), (1, 2), LCEN)
        sizer.Add(self.xas_showe0, (1, 4), (1, 2), LCEN)
        sizer.Add(self.xas_autostep, (2, 2), (1, 2), LCEN)

        sizer.Add(SimpleText(p, 'Victoreen:'), (3, 4), (1, 1), LCEN)
        sizer.Add(self.xas_vict, (3, 5), (1, 1), LCEN)
        sizer.Add(SimpleText(p, 'PolyOrder:'), (4, 4), (1, 1), LCEN)
        sizer.Add(self.xas_nnor, (4, 5), (1, 1), LCEN)

        pack(panel, sizer)
        return panel

    def onFitPeak(self, evt=None):
        gname = self.groupname

        dtext = []
        model = self.fit_model.GetStringSelection().lower()
        dtext.append('Fit Model: %s' % model)
        bkg = self.fit_bkg.GetStringSelection()
        if bkg == 'None':
            bkg = None
        if bkg is None:
            dtext.append('No Background')
        else:
            dtext.append('Background: %s' % bkg)

        step = self.fit_step.GetStringSelection().lower()
        if model in ('step', 'rectangle'):
            dtext.append('Step form: %s' % step)

        try:
            lgroup = getattr(self.larch.symtable, gname)
            x = lgroup._xdat_
            y = lgroup._ydat_
        except AttributeError:
            self.write_message('need data to fit!')
            return
        if step.startswith('error'):
            step = 'erf'
        elif step.startswith('arctan'):
            step = 'atan'

        pgroup = fit_peak(x,
                          y,
                          model,
                          background=bkg,
                          step=step,
                          _larch=self.larch)

        dtext = '\n'.join(dtext)
        dtext = '%s\n%s\n' % (
            dtext, fit_report(
                pgroup.params, min_correl=0.25, _larch=self.larch))

        self.fit_report.SetEditable(True)
        self.fit_report.SetValue(dtext)
        self.fit_report.SetEditable(False)

        popts1 = dict(style='solid', linewidth=3, marker='None', markersize=4)
        popts2 = dict(style='short dashed',
                      linewidth=2,
                      marker='None',
                      markersize=4)

        lgroup.plot_yarrays = [(lgroup._ydat_, popts1, lgroup.plot_ylabel)]
        if bkg is None:
            lgroup._fit = pgroup.fit[:]
            lgroup.plot_yarrays.append((lgroup._fit, popts2, 'fit'))
        else:
            lgroup._fit = pgroup.fit[:]
            lgroup._fit_bgr = pgroup.bkg[:]
            lgroup.plot_yarrays.append((lgroup._fit, popts2, 'fit'))
            lgroup.plot_yarrays.append((lgroup._fit_bgr, popts2, 'background'))
        self.onPlot()

    def xas_process(self, gname, new_mu=False, **kws):
        """ process (pre-edge/normalize) XAS data from XAS form, overwriting
        larch group '_y1_' attribute to be plotted
        """

        out = self.xas_op.GetStringSelection().lower()  # raw, pre, norm, flat
        preopts = {'group': gname, 'e0': None}

        lgroup = getattr(self.larch.symtable, gname)
        dtcorr = self.dtcorr.IsChecked()
        if new_mu:
            try:
                del lgroup.e0, lgroup.edge_step
            except:
                pass

        if not self.xas_autoe0.IsChecked():
            e0 = self.xas_e0.GetValue()
            if e0 < max(lgroup._xdat_) and e0 > min(lgroup._xdat_):
                preopts['e0'] = e0

        if not self.xas_autostep.IsChecked():
            preopts['step'] = self.xas_step.GetValue()

        dt = debugtime()

        preopts['pre1'] = self.xas_pre1.GetValue()
        preopts['pre2'] = self.xas_pre2.GetValue()
        preopts['norm1'] = self.xas_nor1.GetValue()
        preopts['norm2'] = self.xas_nor2.GetValue()

        preopts['nvict'] = self.xas_vict.GetSelection()
        preopts['nvict'] = self.xas_vict.GetSelection()
        preopts['nnorm'] = self.xas_nnor.GetSelection()

        preopts['make_flat'] = 'False'
        preopts['group'] = gname
        preopts = ", ".join(["%s=%s" % (k, v) for k, v in preopts.items()])

        preedge_cmd = "pre_edge(%s._xdat_, %s._ydat_, %s)"
        self.larch(preedge_cmd % (gname, gname, preopts))
        if self.xas_autoe0.IsChecked():
            self.xas_e0.SetValue(lgroup.e0)
        if self.xas_autostep.IsChecked():
            self.xas_step.SetValue(lgroup.edge_step)

        details_group = lgroup
        try:
            details_group = lgroup.pre_edge_details
        except:
            pass

        self.xas_pre1.SetValue(details_group.pre1)
        self.xas_pre2.SetValue(details_group.pre2)
        self.xas_nor1.SetValue(details_group.norm1)
        self.xas_nor2.SetValue(details_group.norm2)

        popts1 = dict(style='solid', linewidth=3, marker='None', markersize=4)
        popts2 = dict(style='short dashed',
                      linewidth=2,
                      zorder=-5,
                      marker='None',
                      markersize=4)
        poptsd = dict(style='solid',
                      linewidth=2,
                      zorder=-5,
                      side='right',
                      y2label='derivative',
                      marker='None',
                      markersize=4)

        lgroup.plot_yarrays = [(lgroup._ydat_, popts1, lgroup.plot_ylabel)]
        y4e0 = lgroup._ydat_
        if out.startswith('raw data with'):
            lgroup.plot_yarrays = [(lgroup._ydat_, popts1, lgroup.plot_ylabel),
                                   (lgroup.pre_edge, popts2, 'pre edge'),
                                   (lgroup.post_edge, popts2, 'post edge')]
        elif out.startswith('pre'):
            self.larch('%s.pre_edge_sub = %s.norm * %s.edge_step' %
                       (gname, gname, gname))
            lgroup.plot_yarrays = [(lgroup.pre_edge_sub, popts1,
                                    'pre edge subtracted XAFS')]
            y4e0 = lgroup.pre_edge_sub
        elif 'norm' in out and 'deriv' in out:
            lgroup.plot_yarrays = [(lgroup.norm, popts1, 'normalized XAFS'),
                                   (lgroup.dmude, poptsd, 'derivative')]
            y4e0 = lgroup.norm

        elif out.startswith('norm'):
            lgroup.plot_yarrays = [(lgroup.norm, popts1, 'normalized XAFS')]
            y4e0 = lgroup.norm
        elif out.startswith('deriv'):
            lgroup.plot_yarrays = [(lgroup.dmude, popts1, 'derivative')]
            y4e0 = lgroup.dmude

        lgroup.plot_ymarkers = []
        if self.xas_showe0.IsChecked():
            ie0 = index_of(lgroup._xdat_, lgroup.e0)
            lgroup.plot_ymarkers = [(lgroup.e0, y4e0[ie0], {'label': 'e0'})]
        return

    def init_larch(self):
        t0 = time.time()
        if self.larch is None:
            self.larch = Interpreter()
        self.larch.symtable.set_symbol('_sys.wx.wxapp', wx.GetApp())
        self.larch.symtable.set_symbol('_sys.wx.parent', self)

        self.SetStatusText('ready')
        self.datagroups = self.larch.symtable
        self.title.SetLabel('')

    def write_message(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(s, panel)

    def get_data(self, group, arrayname, correct=False):
        if hasattr(group, 'get_data'):
            return group.get_data(arrayname, correct=correct)
        return getattr(group, arrayname, None)

    def onXASChoice(self, evt=None, **kws):
        if self.groupname is None:
            return
        self.xas_process(self.groupname, **kws)
        self.onPlot()

    def onColumnChoices(self, evt=None):
        """column selections changed ..
        recalculate _xdat_ and _ydat_
        arrays for this larch group"""
        dtcorr = self.dtcorr.IsChecked()
        use_deriv = self.use_deriv.IsChecked()
        ix = self.xarr.GetSelection()
        x = self.xarr.GetStringSelection()
        xop = self.xop.GetStringSelection()
        op1 = self.yops[0].GetStringSelection()
        op2 = self.yops[1].GetStringSelection()
        op3 = self.yops[2].GetStringSelection()
        y1 = self.yarr[0].GetStringSelection()
        y2 = self.yarr[1].GetStringSelection()
        y3 = self.yarr[2].GetStringSelection()

        array_sel = {
            'xop': xop,
            'xarr': x,
            'op1': op1,
            'op2': op2,
            'op3': op3,
            'y1': y1,
            'y2': y2,
            'y3': y3,
            'dtcorr': dtcorr,
            'use_deriv': use_deriv
        }
        try:
            gname = self.groupname
            lgroup = getattr(self.larch.symtable, gname)
        except:
            gname = SCANGROUP
            lgroup = getattr(self.larch.symtable, gname)

        xlabel = x
        try:
            xunits = lgroup.array_units[ix]
        except:
            xunits = ''
        if xop != '':
            xlabel = "%s(%s)" % (xop, xlabel)
        if xunits != '':
            xlabel = '%s (%s)' % (xlabel, xunits)

        ylabel = y1
        if y2 == '':
            y2, op2 = '1.0', '*'
        else:
            ylabel = "%s%s%s" % (ylabel, op2, y2)
        if y3 == '':
            y3, op3 = '1.0', '*'
        else:
            ylabel = "(%s)%s%s" % (ylabel, op3, y3)

        if op1 != '':
            ylabel = "%s(%s)" % (op1, ylabel)

        if y1 in ('0.0', '1.0'):
            y1 = float(yl1)
        else:
            y1 = self.get_data(lgroup, y1, correct=dtcorr)

        if y2 in ('0.0', '1.0'):
            y2 = float(y2)
            if op2 == '/': y2 = 1.0
        else:
            y2 = self.get_data(lgroup, y2, correct=dtcorr)
        if y3 in ('0.0', '1.0'):
            y3 = float(y3)
            if op3 == '/': y3 = 1.0
        else:
            y3 = self.get_data(lgroup, y3, correct=dtcorr)
        if x not in ('0', '1'):
            x = self.get_data(lgroup, x)
        lgroup._x = x
        lgroup._y1 = y1
        lgroup._y2 = y2
        lgroup._y3 = y3

        self.larch("%s._xdat_ = %s(%s._x)" % (gname, xop, gname))
        try:
            yexpr = "%s._ydat_ = %s((%s._y1 %s %s._y2) %s %s._y3)" % (
                gname, op1, gname, op2, gname, op3, gname)
            self.larch(yexpr)
        except RuntimeWarning:
            self.larch("%s._ydat_ = %s._y1")

        try:
            if use_deriv:
                d_calc = "%s._ydat_ = gradient(%s._ydat_)/gradient(%s._xdat_)"
                self.larch(d_calc % (gname, gname, gname))
        except:
            pass

        try:
            npts = min(len(lgroup._xdat_), len(lgroup._ydat_))
        except AttributeError:
            print('Error calculating arrays (npts not correct)')
            return

        del lgroup._x, lgroup._y1, lgroup._y2, lgroup._y3

        lgroup.array_sel = array_sel
        lgroup.plot_xlabel = xlabel
        lgroup.plot_ylabel = ylabel
        lgroup._xdat_ = np.array(lgroup._xdat_[:npts])
        lgroup._ydat_ = np.array(lgroup._ydat_[:npts])

        if (self.nb.GetCurrentPage() == self.xas_panel):
            self.xas_process(self.groupname, new_mu=True)
        else:
            lgroup.plot_yarrays = [(lgroup._ydat_, {}, None)]

    def onPlot(self, evt=None, opt='new', npts=None, reprocess=False):

        try:
            self.plotframe.Show()
        except:  #  wx.PyDeadObjectError
            self.plotframe = PlotFrame(None, size=(650, 400))
            self.plotframe.Show()
            self.plotpanel = self.plotframe.panel

        if reprocess:
            if (self.nb.GetCurrentPage() == self.xas_panel):
                self.xas_process(self.groupname, new_mu=True)

        side = 'left'
        update = False
        plotcmd = self.plotpanel.plot
        if opt in ('left', 'right'):
            side = opt
            plotcmd = self.plotpanel.oplot
        elif opt == 'update' and npts > 4:
            plotcmd = self.plotpanel.update_line
            update = True
        if 'new' in opt:
            self.plotpanel.clear()
        popts = {'side': side}

        try:
            gname = self.groupname
            lgroup = getattr(self.larch.symtable, gname)
        except:
            gname = SCANGROUP
            lgroup = getattr(self.larch.symtable, gname)
            return

        if not hasattr(lgroup, '_xdat_'):
            self.onColumnChoices()

        lgroup._xdat_ = np.array(lgroup._xdat_[:npts])
        plot_yarrays = [(lgroup._ydat_, {}, None)]
        if hasattr(lgroup, 'plot_yarrays'):
            plot_yarrays = lgroup.plot_yarrays
        #for yarr in plot_yarrays:
        #    yarr = np.array(yarr[:npts])

        path, fname = os.path.split(lgroup.filename)
        popts['label'] = "%s: %s" % (fname, lgroup.plot_ylabel)
        if side == 'right':
            popts['y2label'] = lgroup.plot_ylabel
        else:
            popts['ylabel'] = lgroup.plot_ylabel

        if plotcmd == self.plotpanel.plot:
            popts['title'] = fname

        if update:
            self.plotpanel.set_xlabel(lgroup.plot_xlabel)
            self.plotpanel.set_ylabel(lgroup.plot_ylabel)
            for itrace, yarr, label in enumerate(plot_yarrays):
                plotcmd(itrace,
                        lgroup._xdat_,
                        yarr[0],
                        draw=True,
                        update_limits=((npts < 5) or (npts % 5 == 0)),
                        **yarr[1])
                self.plotpanel.set_xylims(
                    (min(lgroup._xdat_), max(lgroup._xdat_), min(yarr),
                     max(yarr)))

        else:
            for yarr in plot_yarrays:
                popts.update(yarr[1])
                if yarr[2] is not None:
                    popts['label'] = yarr[2]
                plotcmd(lgroup._xdat_, yarr[0], **popts)
                plotcmd = self.plotpanel.oplot
            if hasattr(lgroup, 'plot_ymarkers'):
                for x, y, opts in lgroup.plot_ymarkers:
                    popts = {'marker': 'o', 'markersize': 4}
                    popts.update(opts)
                    self.plotpanel.oplot([x], [y], **popts)
            self.plotpanel.canvas.draw()

    def onShowLarchBuffer(self, evt=None):
        if self.larch_buffer is None:
            self.larch_buffer = larchframe.LarchFrame(_larch=self.larch)

        self.larch_buffer.Show()
        self.larch_buffer.Raise()

    def ShowFile(self, evt=None, groupname=None, **kws):
        if groupname is None and evt is not None:
            fpath = self.file_paths[evt.GetInt()]
            groupname = self.file_groups[fpath]

        if not hasattr(self.datagroups, groupname):
            print('Error reading file ', groupname)
            return

        self.groupname = groupname
        self.lgroup = getattr(self.datagroups, groupname, None)

        if groupname == SCANGROUP:
            self.lgroup.filename = filename
        elif self.lgroup is not None:
            if hasattr(self.lgroup, 'array_labels'):
                array_labels = self.lgroup.array_labels[:]
            elif hasattr(self.lgroup, 'column_labels'):
                array_labels = self.lgroup.column_labels[:]
            else:
                array_labels = []
                for attr in dir(self.lgroup):
                    if isinstance(getattr(self.lgroup, attr), np.ndarray):
                        array_labels.append(attr)
                self.lgroup.array_labels = array_labels
            self.set_array_labels()
            if hasattr(self.lgroup, 'array_sel'):
                sel = self.lgroup.array_sel
                try:
                    self.xarr.SetStringSelection(sel['xarr'])
                    self.xop.SetStringSelection(sel['xop'])
                    self.yops[0].SetStringSelection(sel['op1'])
                    self.yops[1].SetStringSelection(sel['op2'])
                    self.yops[2].SetStringSelection(sel['op3'])
                    self.yarr[0].SetStringSelection(sel['y1'])
                    self.yarr[1].SetStringSelection(sel['y2'])
                    self.yarr[2].SetStringSelection(sel['y3'])
                    self.dtcorr.SetValue({True: 1, False: 0}[sel['dtcorr']])
                    self.use_deriv.SetValue({
                        True: 1,
                        False: 0
                    }[sel['use_deriv']])
                except:
                    pass

    def set_array_labels(self, labels=None):
        """set choices for array dropdowns from array labels"""
        array_labels = self.lgroup.array_labels
        xcols = array_labels[:]
        ycols = array_labels[:]
        y2cols = array_labels[:] + ['1.0', '0.0', '']
        ncols = len(xcols)
        self.title.SetLabel(self.lgroup.filename)

        _xarr = self.xarr.GetStringSelection()
        if len(_xarr) < 1 or _xarr not in xcols:
            _xarr = xcols[0]

        _yarr = [[], [], []]
        for j in range(3):
            _yarr[j] = self.yarr[j].GetStringSelection()
            if _yarr[j] not in ycols:
                _yarr[j] = ''

        self.xarr.SetItems(xcols)
        self.xarr.SetStringSelection(_xarr)
        for j in range(3):
            if j == 0:
                self.yarr[j].SetItems(ycols)
                if _yarr[j] in ycols and len(_yarr[j]) > 0:
                    self.yarr[j].SetStringSelection(_yarr[j])
                elif ycols[0] == _xarr and len(ycols) > 1:
                    self.yarr[j].SetStringSelection(ycols[1])
            else:
                self.yarr[j].SetItems(y2cols)
                self.yarr[j].SetStringSelection(_yarr[j])

        inb = 0
        for colname in xcols:
            if 'energ' in colname.lower():
                inb = 1
        self.nb.SetSelection(inb)
        if inb == 1:
            self.InitializeXASPanel()

    def createMenus(self):
        # ppnl = self.plotpanel
        self.menubar = wx.MenuBar()
        #
        fmenu = wx.Menu()
        MenuItem(self, fmenu, "&Open Data File\tCtrl+O", "Read Scan File",
                 self.onReadScan)

        MenuItem(self, fmenu, "Show Larch Buffer",
                 "Show Larch Programming Buffer", self.onShowLarchBuffer)

        fmenu.AppendSeparator()

        MenuItem(self, fmenu, "&Quit\tCtrl+Q", "Quit program", self.onClose)

        self.menubar.Append(fmenu, "&File")

        omenu = wx.Menu()
        MenuItem(self, omenu, "Edit Column Labels\tCtrl+E",
                 "Edit Column Labels", self.onEditColumnLabels)

        self.menubar.Append(omenu, "Options")

        # fmenu.AppendSeparator()
        # MenuItem(self, fmenu, "&Copy\tCtrl+C",
        #          "Copy Figure to Clipboard", self.onClipboard)
        # MenuItem(self, fmenu, "&Save\tCtrl+S", "Save Figure", self.onSaveFig)
        # MenuItem(self, fmenu, "&Print\tCtrl+P", "Print Figure", self.onPrint)
        # MenuItem(self, fmenu, "Page Setup", "Print Page Setup", self.onPrintSetup)
        # MenuItem(self, fmenu, "Preview", "Print Preview", self.onPrintPreview)
        #

        #MenuItem(self, pmenu, "Unzoom\tCtrl+Z", "Unzoom Plot", self.onUnzoom)
        ##pmenu.AppendSeparator()
        #MenuItem(self, pmenu, "Toggle Legend\tCtrl+L",
        #         "Toggle Legend on Plot", self.onToggleLegend)
        #MenuItem(self, pmenu, "Toggle Grid\tCtrl+G",
        #         "Toggle Grid on Plot", self.onToggleGrid)
        # self.menubar.Append(pmenu, "Plot Options")
        self.SetMenuBar(self.menubar)
        self.Bind(wx.EVT_CLOSE, self.onClose)

    def onAbout(self, evt):
        dlg = wx.MessageDialog(self, self._about, "About Epics StepScan",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onClose(self, evt):
        save_workdir('scanviewer.dat')

        try:
            self.plotframe.Destroy()
        except:
            pass
        if self.larch_buffer is not None:
            try:
                self.larch_buffer.onClose()
            except:
                pass

        for nam in dir(self.larch.symtable._sys.wx):
            obj = getattr(self.larch.symtable._sys.wx, nam)
            del obj

        self.Destroy()

    def show_subframe(self, name, frameclass):
        shown = False
        if name in self.subframes:
            try:
                self.subframes[name].Raise()
                shown = True
            except:
                del self.subframes[name]
        if not shown:
            self.subframes[name] = frameclass(self)

    def onEditColumnLabels(self, evt=None):
        self.show_subframe('coledit', EditColumnFrame)

    def onReadScan(self, evt=None):
        dlg = wx.FileDialog(self,
                            message="Load Column Data File",
                            defaultDir=os.getcwd(),
                            wildcard=FILE_WILDCARDS,
                            style=wx.FD_OPEN)
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            path = path.replace('\\', '/')
            if path in self.file_groups:
                if wx.ID_YES != popup(self, "Re-read file '%s'?" % path,
                                      'Re-read file?'):
                    return

            gname = '_sview0001'
            count, maxcount = 1, 9999
            while hasattr(self.datagroups, gname) and count < maxcount:
                count += 1
                gname = '_sview%4.4i' % count

            if hasattr(self.datagroups, gname):
                gname = randname()

            parent, fname = os.path.split(path)
            if self.config['chdir_on_fileopen']:
                os.chdir(parent)

            fh = open(path, 'r')
            line1 = fh.readline().lower()
            fh.close()
            reader = 'read_ascii'
            if 'epics scan' in line1:
                reader = 'read_gsescan'
            elif 'xdi' in line1:
                reader = 'read_xdi'
                if 'epics stepscan file' in line1:
                    reader = 'read_gsexdi'

            self.larch("%s = %s('%s')" % (gname, reader, path))
            self.larch("%s.path  = '%s'" % (gname, path))
            self.filelist.Append(fname)
            self.file_paths.append(path)
            self.file_groups[path] = gname

            self.ShowFile(groupname=gname)

        dlg.Destroy()
Пример #37
0
    def onPlot(self, evt=None, opt='new', npts=None, reprocess=False):

        try:
            self.plotframe.Show()
        except:  #  wx.PyDeadObjectError
            self.plotframe = PlotFrame(None, size=(650, 400))
            self.plotframe.Show()
            self.plotpanel = self.plotframe.panel

        if reprocess:
            if (self.nb.GetCurrentPage() == self.xas_panel):
                self.xas_process(self.groupname, new_mu=True)

        side = 'left'
        update = False
        plotcmd = self.plotpanel.plot
        if opt in ('left', 'right'):
            side = opt
            plotcmd = self.plotpanel.oplot
        elif opt == 'update' and npts > 4:
            plotcmd = self.plotpanel.update_line
            update = True
        if 'new' in opt:
            self.plotpanel.clear()
        popts = {'side': side}

        try:
            gname = self.groupname
            lgroup = getattr(self.larch.symtable, gname)
        except:
            gname = SCANGROUP
            lgroup = getattr(self.larch.symtable, gname)
            return

        if not hasattr(lgroup, '_xdat_'):
            self.onColumnChoices()

        lgroup._xdat_ = np.array(lgroup._xdat_[:npts])
        plot_yarrays = [(lgroup._ydat_, {}, None)]
        if hasattr(lgroup, 'plot_yarrays'):
            plot_yarrays = lgroup.plot_yarrays
        #for yarr in plot_yarrays:
        #    yarr = np.array(yarr[:npts])

        path, fname = os.path.split(lgroup.filename)
        popts['label'] = "%s: %s" % (fname, lgroup.plot_ylabel)
        if side == 'right':
            popts['y2label'] = lgroup.plot_ylabel
        else:
            popts['ylabel'] = lgroup.plot_ylabel

        if plotcmd == self.plotpanel.plot:
            popts['title'] = fname

        if update:
            self.plotpanel.set_xlabel(lgroup.plot_xlabel)
            self.plotpanel.set_ylabel(lgroup.plot_ylabel)
            for itrace, yarr, label in enumerate(plot_yarrays):
                plotcmd(itrace,
                        lgroup._xdat_,
                        yarr[0],
                        draw=True,
                        update_limits=((npts < 5) or (npts % 5 == 0)),
                        **yarr[1])
                self.plotpanel.set_xylims(
                    (min(lgroup._xdat_), max(lgroup._xdat_), min(yarr),
                     max(yarr)))

        else:
            for yarr in plot_yarrays:
                popts.update(yarr[1])
                if yarr[2] is not None:
                    popts['label'] = yarr[2]
                plotcmd(lgroup._xdat_, yarr[0], **popts)
                plotcmd = self.plotpanel.oplot
            if hasattr(lgroup, 'plot_ymarkers'):
                for x, y, opts in lgroup.plot_ymarkers:
                    popts = {'marker': 'o', 'markersize': 4}
                    popts.update(opts)
                    self.plotpanel.oplot([x], [y], **popts)
            self.plotpanel.canvas.draw()
Пример #38
0
class MapViewerFrame(wx.Frame):
    _about = """XRF Map Viewer
  Matt Newville <newville @ cars.uchicago.edu>
  """
    def __init__(self, conffile=None,  **kwds):

        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, None, -1, size=(700, 400),  **kwds)

        self.data = None
        self.filemap = {}
        self.im_displays = []
        self.larch = None
        self.plotframe = None

        self.Font14=wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD, 0, "")
        self.Font12=wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, 0, "")
        self.Font11=wx.Font(11, wx.SWISS, wx.NORMAL, wx.BOLD, 0, "")
        self.Font10=wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, 0, "")
        self.Font9 =wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, 0, "")

        self.SetTitle("GSE XRM MapViewer")
        self.SetFont(self.Font9)

        self.createMainPanel()
        self.createMenus()
        self.statusbar = self.CreateStatusBar(2, 0)
        self.statusbar.SetStatusWidths([-3, -1])
        statusbar_fields = ["Initializing....", " "]
        for i in range(len(statusbar_fields)):
            self.statusbar.SetStatusText(statusbar_fields[i], i)

    def createMainPanel(self):
        sizer = wx.BoxSizer(wx.VERTICAL)
        splitter  = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE)
        splitter.SetMinimumPaneSize(175)

        self.filelist = EditableListBox(splitter, self.ShowFile)
        # self.detailspanel = self.createViewOptsPanel(splitter)

        dpanel = self.detailspanel = wx.Panel(splitter)
        dpanel.SetMinSize((575, 350))
        self.createNBPanels(dpanel)
        splitter.SplitVertically(self.filelist, self.detailspanel, 1)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(splitter, 1, wx.GROW|wx.ALL, 5)
        wx.CallAfter(self.init_larch)
        pack(self, sizer)

    def createNBPanels(self, parent):
        self.title = SimpleText(parent, 'initializing...')
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(self.title, 0, ALL_CEN)

        self.nb = flat_nb.FlatNotebook(parent, wx.ID_ANY, agwStyle=FNB_STYLE)
        self.nb.SetBackgroundColour('#FCFCFA')
        self.SetBackgroundColour('#F0F0E8')

        self.nbpanels = {}
        for name, key, creator in (('Simple ROI Map',  'roimap', SimpleMapPanel),
                                   ('3-Color ROI Map', '3color',  TriColorMapPanel)):
            #  ('2x2 Grid',         self.MapGridPanel)):
            # print 'panel ' , name, parent, creator
            p = creator(parent, owner=self)
            self.nb.AddPage(p, name, True)
            self.nbpanels[key] = p

        self.nb.SetSelection(0)
        sizer.Add(self.nb, 1, wx.ALL|wx.EXPAND)
        pack(parent, sizer)

    def lassoHandler(self, data=None, selected=None, det=None, mask=None, **kws):
        mask.shape = data.shape
        energy  = self.current_file.xrfmap['detsum/energy'].value
        spectra = self.current_file.xrfmap['detsum/data'].value
        spectra = spectra.swapaxes(0, 1)[mask].sum(axis=0)
        self.show_PlotFrame()
        spectra[np.where(spectra<1)] = 1
        self.plotframe.plot(energy, spectra, ylog_scale=True)

    def show_PlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self, title='XRF Spectra')
        try:
            self.plotframe.Show()
        except wx.PyDeadObjectError:
            self.plotframe = PlotFrame(self, title='XRF Spectra')
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()

    def add_imdisplay(self, title, det=None, config_on_frame=True):
        on_lasso = Closure(self.lassoHandler, det=det)
        self.im_displays.append(ImageFrame(output_title=title,
                                           lasso_callback=on_lasso,
                                           config_on_frame=config_on_frame))

    def display_map(self, map, title='', info='', x=None, y=None, det=None,
                    with_config=True):
        """display a map in an available image display"""
        displayed = False
        while not displayed:
            try:
                imd = self.im_displays.pop()
                imd.display(map, title=title, x=x, y=y)
                displayed = True
            except IndexError:
                on_lasso = Closure(self.lassoHandler, det=det)
                imd = ImageFrame(output_title=title,
                                 lasso_callback=on_lasso,
                                 config_on_frame=with_config)
                imd.display(map, title=title, x=x, y=y)
                displayed = True
            except PyDeadObjectError:
                displayed = False
        self.im_displays.append(imd)
        imd.SetStatusText(info, 1)

        imd.Show()
        imd.Raise()

    def init_larch(self):
        t0 = time.time()
        from larch import Interpreter
        from larch.wxlib import inputhook
        self.larch = Interpreter()
        self.larch.symtable.set_symbol('_sys.wx.wxapp', wx.GetApp())
        self.larch.symtable.set_symbol('_sys.wx.parent', self)
        self.SetStatusText('ready')
        self.datagroups = self.larch.symtable
        self.title.SetLabel('')

    def onPlot(self, evt):    self.do_plot(newplot=True)

    def onOPlot(self, evt):   self.do_plot(newplot=False)

    def do_plot(self, newplot=False):

        ix = self.x_choice.GetSelection()
        x  = self.x_choice.GetStringSelection()
        if self.data is None and ix > -1:
            self.SetStatusText( 'cannot plot - no valid data')
        xop = self.x_op.GetStringSelection()
        yop1 = self.y_op1.GetStringSelection()
        yop2 = self.y_op2.GetStringSelection()
        yop3 = self.y_op3.GetStringSelection()

        y1 = self.y1_choice.GetStringSelection()
        y2 = self.y2_choice.GetStringSelection()
        y3 = self.y3_choice.GetStringSelection()
        if y1 == '': y1 = '1'
        if y2 == '': y2 = '1'
        if y3 == '': y3 = '1'

        gname = self.groupname
        lgroup = getattr(self.larch.symtable, gname)

        xlabel_ = xlabel = x
        xunits = lgroup.column_units[ix]
        if xunits != '':
            xlabel = '%s (%s)' % (xlabel, xunits)

        x = "%s.get_data('%s')" % (gname, x)

        if xop == 'log': x = "log(%s)" % x

        ylabel = "[%s%s%s]%s%s" % (y1, yop2, y2, yop3, y3)
        if y2 == '1' and yop2 in ('*', '/') or y2 == '0' and yop2 in ('+', '-'):
            ylabel = "(%s%s%s" % (y1, yop3, y3)
            if y3 == '1' and yop3 in ('*', '/') or y3 == '0' and yop3 in ('+', '-'):
                ylabel = "%s" % (y1)
        elif y3 == '1' and yop3 in ('*', '/') or y3 == '0' and yop3 in ('+', '-'):
            ylabel = "%s%s%s" % (y1, yop2, y2)
        if yop1 != '':
            yoplab = yop1.replace('deriv', 'd')
            ylabel = '%s(%s)' % (yoplab, ylabel)
            if '(' in yop1: ylabel = "%s)" % ylabel

        y1 = y1 if y1 in ('0, 1') else "%s.get_data('%s')" % (gname, y1)
        y2 = y2 if y2 in ('0, 1') else "%s.get_data('%s')" % (gname, y2)
        y3 = y3 if y3 in ('0, 1') else "%s.get_data('%s')" % (gname, y3)

        y = "%s((%s %s %s) %s (%s))" % (yop1, y1, yop2, y2, yop3, y3)
        if '(' in yop1: y = "%s)" % y
        if 'deriv' in yop1:
            y = "%s/deriv(%s)" % (y, x)
            ylabel = '%s/d(%s)' % (ylabel, xlabel_)

        fmt = "plot(%s, %s, label='%s', xlabel='%s', ylabel='%s', new=%s)"
        cmd = fmt % (x, y, self.data.fname, xlabel, ylabel, repr(newplot))
        self.larch(cmd)

    def ShowFile(self, evt=None, filename=None, **kws):
        if filename is None and evt is not None:
            filename = evt.GetString()
        if self.check_ownership(filename):
            self.filemap[filename].process()
        self.current_file = self.filemap[filename]
        self.title.SetLabel("%s" % filename)

        rois = list(self.filemap[filename].xrfmap['roimap/sum_name'])
        rois_extra = [''] + rois

        set_choices(self.nbpanels['roimap'].roi1, rois)
        set_choices(self.nbpanels['roimap'].roi2, rois_extra)
        set_choices(self.nbpanels['3color'].rchoice, rois)
        set_choices(self.nbpanels['3color'].gchoice, rois)
        set_choices(self.nbpanels['3color'].bchoice, rois)

    def createMenus(self):
        self.menubar = wx.MenuBar()
        fmenu = wx.Menu()
        add_menu(self, fmenu, "&Open Map File\tCtrl+O",
                 "Read Map File",  self.onReadFile)
        add_menu(self, fmenu, "&Open Map Folder\tCtrl+F",
                 "Read Map Folder",  self.onReadFolder)

        fmenu.AppendSeparator()
        add_menu(self, fmenu, "&Quit\tCtrl+Q",
                  "Quit program", self.onClose)

        self.menubar.Append(fmenu, "&File")
        self.SetMenuBar(self.menubar)

    def onAbout(self,evt):
        dlg = wx.MessageDialog(self, self._about,"About GSEXRM MapViewer",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def onClose(self,evt):
        for xrmfile in self.filemap.values():
            xrmfile.close()

        for imd in self.im_displays:
            try:
                imd.Destroy()
            except:
                pass

        for nam in dir(self.larch.symtable._plotter):
            obj = getattr(self.larch.symtable._plotter, nam)
            try:
                obj.Destroy()
            except:
                pass
        for nam in dir(self.larch.symtable._sys.wx):
            obj = getattr(self.larch.symtable._sys.wx, nam)
            del obj
        self.Destroy()

    def onReadFolder(self, evt=None):
        dlg = wx.DirDialog(self, message="Read Map Folder",
                           defaultPath=os.getcwd(),
                           style=wx.OPEN)

        path, read = None, False
        if dlg.ShowModal() == wx.ID_OK:
            read = True
            path = dlg.GetPath().replace('\\', '/')
        dlg.Destroy()
        if read:
            try:
                xrmfile = GSEXRM_MapFile(folder=str(path))
            except:
                popup(self, NOT_GSEXRM_FOLDER % fname,
                      "Not a Map folder")
                return
            fname = xrmfile.filename
            if fname not in self.filemap:
                self.filemap[fname] = xrmfile
            if fname not in self.filelist.GetItems():
                self.filelist.Append(fname)
            if self.check_ownership(fname):
                self.process_file(fname)
            self.ShowFile(filename=fname)

    def onReadFile(self, evt=None):
        dlg = wx.FileDialog(self, message="Read Map File",
                            defaultDir=os.getcwd(),
                            wildcard=FILE_WILDCARDS,
                            style=wx.OPEN)
        path, read = None, False
        if dlg.ShowModal() == wx.ID_OK:
            read = True
            path = dlg.GetPath().replace('\\', '/')
            if path in self.filemap:
                read = popup(self, "Re-read file '%s'?" % path, 'Re-read file?',
                             style=wx.YES_NO)
        dlg.Destroy()

        if read:
            try:
                parent, fname = os.path.split(path)
                xrmfile = GSEXRM_MapFile(fname)
            except:
                popup(self, NOT_GSEXRM_FILE % fname,
                      "Not a Map file!")
                return
            if fname not in self.filemap:
                self.filemap[fname] = xrmfile
            if fname not in self.filelist.GetItems():
                self.filelist.Append(fname)
            if self.check_ownership(fname):
                self.process_file(fname)
            self.ShowFile(filename=fname)

    def onGSEXRM_Data(self,  **kws):
        print 'Saw GSEXRM_Data ', kws

    def process_file(self, filename):
        """Request processing of map file.
        This can take awhile, so is done in a separate thread,
        with updates displayed in message bar
        """
        xrm_map = self.filemap[filename]
        if xrm_map.status == GSEXRM_FileStatus.created:
            xrm_map.initialize_xrfmap()

        if xrm_map.dimension is None and isGSEXRM_MapFolder(self.folder):
            xrm_map.read_master()

        if self.filemap[filename].folder_has_newdata():

            print 'PROCESS ', filename, xrm_map.folder_has_newdata()
            dthread  = Thread(target=self.new_mapdata, args=(filename,))
            dthread.start()
            dthread.join()

    def new_mapdata(self, filename):
        xrm_map = self.filemap[filename]

        nrows = len(xrm_map.rowdata)
        if xrm_map.folder_has_newdata():
            irow = xrm_map.last_row + 1
            while irow < nrows:
                row = xrm_map.read_rowdata(irow)
                if row is not None:
                    xrm_map.add_rowdata(row)
                irow  = irow + 1
                time.sleep(.001)
                wx.Yield()

        xrm_map.resize_arrays(xrm_map.last_row+1)
        xrm_map.h5root.flush()

    def OLDprocess_file(self, filename):
        """Request processing of map file.
        This can take awhile, so is done in a separate thread,
        with updates displayed in message bar
        """
        xrm_map = self.filemap[filename]
        def on_process(row=0, maxrow=0, filename=None, status='unknown'):
            print 'on process ', row, maxrow, filename, status
            if maxrow < 1 or filename is None:
                return
            #self.SetStatusText('processing row=%i / %i for %s [%s]' %
            #                   (row, maxrow, fname, status))

        if xrm_map.folder_has_newdata():
            print 'PROCESS ', filename, xrm_map.folder_has_newdata()
            dthread  = Thread(target=self.filemap[filename].process,
                              kwargs={'callback': on_process},
                              name='process_thread')
            dthread.start()
            dthread.join()

    def check_ownership(self, fname):
        """
        check whether we're currently owner of the file.
        this is important!! HDF5 files can be corrupted.
        """
        if not self.filemap[fname].check_hostid():
            if popup(self, NOT_OWNER_MSG % fname,
                     'Not Owner of HDF5 File', style=wx.YES_NO):
                self.filemap[fname].claim_hostid()
        return self.filemap[fname].check_hostid()