Example #1
0
    def onShowIntegration(self, event=None):

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()
    def ShowPlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self)
            self.has_plot = False
        try:
            self.plotframe.Show()
        except wx.PyDeadObjectError:
            self.plotframe = PlotFrame(self)
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()
Example #3
0
    def ShowPlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self)
            self.has_plot = False
        try:
            self.plotframe.Show()
        except PyDeadObjectError:
            self.plotframe = PlotFrame(self)
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()
Example #4
0
class TestFrame(wx.Frame):
    def __init__(self, parent=None, *args, **kwds):
        kwds[
            "style"] = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL
        wx.Frame.__init__(self, parent, wx.NewId(), '', wx.DefaultPosition,
                          wx.Size(-1, -1), **kwds)
        self.SetTitle(" WXMPlot Plotting Demo")
        self.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, False))
        self.plotframe = None
        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer = wx.Timer(self)
        self.Refresh()
        self.ShowPlotFrame(do_raise=False, clear=False)
        self.onStartTimer()

    def ShowPlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self)
            self.has_plot = False
        try:
            self.plotframe.Show()
        except PyDeadObjectError:
            self.plotframe = PlotFrame(self)
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()

    def onStartTimer(self, event=None):
        self.count = 0
        self.timer.Start(1)

    def onTimer(self, event):
        # print 'timer ', self.count, time.time()
        self.count += 1
        self.x = arange(0.0, 3, 0.01)
        self.y = sin(2 * pi * self.x + self.count)
        self.plotframe.plot(self.x, self.y)

    def OnExit(self, event):
        try:
            if self.plotframe != None: self.plotframe.onExit()
        except:
            pass
        self.Destroy()
Example #5
0
    def onAutoIntegration(self, event=None):
        if not event.IsChecked():
            self.int_timer.Stop()
            return

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()
        self.int_timer.Start(500)
Example #6
0
    def ShowPlotFrame(self, do_raise=True, clear=True):
        """make sure plot frame is enabled, and visible"""
        if self.plotframe is None:
            self.plotframe = PlotFrame(self, axissize=[0.08, 0.06, 0.91, 0.92])
            # self.has_plot = False
        try:
            self.plotframe.Show()
        except wx.PyDeadObjectError:
            self.plotframe = PlotFrame(self, axissize=[0.08, 0.06, 0.91, 0.92])
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()
            
            self.plotYdata = []
            self.plotXdata = []
Example #7
0
    def onShowIntegration(self, event=None):

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()
Example #8
0
    def onAutoIntegration(self, event=None):
        if not event.IsChecked():
            self.int_timer.Stop()
            return

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()
        self.int_timer.Start(500)
class TestFrame(wx.Frame):
    def __init__(self, parent=None, *args,**kwds):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL
        wx.Frame.__init__(self, parent, wx.NewId(), '',
                         wx.DefaultPosition, wx.Size(-1,-1), **kwds)
        self.SetTitle("signal test")
        self.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.BOLD,False))
        self.plotframe  = None
        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer = wx.Timer(self)

        #slider
        self.sld = wx.Slider(self, value = 973, minValue = 800, maxValue = 1100, style = wx.SL_HORIZONTAL)
        self.sld.Bind(wx.EVT_SLIDER, self.OnSliderScroll)

        self.Refresh()
        self.ShowPlotFrame(do_raise=False, clear=False)
        self.onStartTimer()

    def ShowPlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self)
            self.has_plot = False
        try:
            self.plotframe.Show()
        except PyDeadObjectError:
            self.plotframe = PlotFrame(self)
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()

    def onStartTimer(self,event=None):
        self.count = 0
        self.timer.Start(1)

    def onTimer(self, event):
        # print 'timer ', self.count, time.time()
        self.count += 1
        N_Samples = 256 * 1024
        samples = sdr.read_samples(N_Samples)

        interval = 2048
        N = N_Samples//interval * interval
        y = samples[:N]

        y = y[:len(y//interval*interval)]
        y = y.reshape(N//interval, interval)
        y_windowed = y*np.kaiser(interval, 6)
        Y = fftshift(fft(y_windowed,axis=1),axes=1)

        Pspect = np.mean(abs(Y)*abs(Y),axis=0);
        self.plotframe.plot(np.arange(0, len(Pspect), 1),Pspect)

    def OnExit(self, event):
        try:
            if self.plotframe != None:  self.plotframe.onExit()
        except:
            pass
        self.Destroy()

    def OnSliderScroll(self, e):
        obj = e.GetEventObject()
        val = obj.GetValue()
        sdr.center_freq = val * 1e5
        print("frequency: "+str(sdr.center_freq / 10e6)+"MHz")
Example #10
0
    def onProfile(self, x0, y0, x1, y1):
        width = self.ad_cam.SizeX
        height = self.ad_cam.SizeY

        x0, y0 = int(x0 * width), int(y0 * height)
        x1, y1 = int(x1 * width), int(y1 * height)
        dx, dy = abs(x1 - x0), abs(y1 - y0)

        if dx < 2 and dy < 2:
            return
        outdat = []
        if self.colormode == 2:
            self.data.shape = (self.im_size[1], self.im_size[0], 3)
        else:
            self.data.shape = self.im_size[1], self.im_size[0]

        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))

        if self.lineplotter is None:
            self.lineplotter = PlotFrame(self, title='Image Profile')
        else:
            try:
                self.lineplotter.Raise()
            except PyDeadObjectError:
                self.lineplotter = PlotFrame(self, title='Image Profile')

        if self.colormode == 2:
            x, y, r, g, b = [], [], [], [], []
            for ix, iy in outdat:
                x.append(ix)
                y.append(iy)
                r.append(self.data[iy, ix, 0])
                g.append(self.data[iy, ix, 1])
                b.append(self.data[iy, ix, 2])
            xlabel = 'Pixel (x)'
            if dy > dx:
                x = y
                xlabel = 'Pixel (y)'
            self.lineplotter.plot(x,
                                  r,
                                  color='red',
                                  label='red',
                                  xlabel=xlabel,
                                  ylabel='Intensity',
                                  title='Image %i' %
                                  self.ad_cam.ArrayCounter_RBV)
            self.lineplotter.oplot(x, g, color='green', label='green')
            self.lineplotter.oplot(x, b, color='blue', label='blue')

        else:
            x, y, z = [], [], []
            for ix, iy in outdat:
                x.append(ix)
                y.append(iy)
                z.append(self.data[iy, ix])
            xlabel = 'Pixel (x)'
            if dy > dx:
                x = y
            xlabel = 'Pixel (y)'
            self.lineplotter.plot(x,
                                  z,
                                  color='k',
                                  xlabel=xlabel,
                                  ylabel='Intensity',
                                  title='Image %i' %
                                  self.ad_cam.ArrayCounter_RBV)
        self.lineplotter.Show()
        self.lineplotter.Raise()
Example #11
0
class AD_Display(wx.Frame):
    """AreaDetector Display """
    img_attrs = ('ArrayData', 'UniqueId_RBV', 'NDimensions_RBV',
                 'ArraySize0_RBV', 'ArraySize1_RBV', 'ArraySize2_RBV',
                 'ColorMode_RBV')

    cam_attrs = ('Acquire', 'ArrayCounter', 'ArrayCounter_RBV',
                 'DetectorState_RBV', 'NumImages', 'ColorMode', 'DataType_RBV',
                 'Gain', 'AcquireTime', 'AcquirePeriod', 'ImageMode',
                 'MaxSizeX_RBV', 'MaxSizeY_RBV', 'TriggerMode', 'SizeX',
                 'SizeY', 'MinX', 'MinY')

    # plugins to enable
    enabled_plugins = ('image1', 'Over1', 'ROI1', 'JPEG1', 'TIFF1')

    stat_msg = 'Read %.1f%% of images: rate=%.1f frames/sec'

    def __init__(self,
                 prefix=None,
                 app=None,
                 scale=1.0,
                 approx_height=1200,
                 known_cameras=None):
        self.app = app
        self.ad_img = None
        self.ad_cam = None
        self.imgcount = 0
        self.prefix = prefix
        self.fname = 'AD_Image.tiff'
        self.scale = scale
        self.known_cameras = known_cameras
        self.arrsize = [0, 0, 0]
        self.imbuff = None
        self.d_size = None
        self.im_size = None
        self.colormode = 0
        self.last_update = 0.0
        self.n_img = 0
        self.imgcount_start = 0
        self.n_drawn = 0
        self.img_id = 0
        self.starttime = time.time()
        self.drawing = False
        self.lineplotter = None
        self.zoom_lims = []

        wx.Frame.__init__(self,
                          None,
                          -1,
                          "Epics Area Detector Display",
                          style=wx.DEFAULT_FRAME_STYLE)

        if known_cameras is not None:
            self.ConnectToCamera(name=self.prefix)
        else:
            self.ConnectToPV(name=self.prefix)

        self.img_w = 0
        self.img_h = 0
        self.wximage = wx.EmptyImage(
            1024, 1360)  # 1360, 1024) # approx_height, 1.5*approx_height)
        self.buildMenus()
        self.buildFrame()

    def OnLeftUp(self, event):
        if self.image is not None:
            self.image.OnLeftUp(event)

    def ConnectToCamera(self, name=None, event=None):
        if name is None:
            name = ''
        if self.known_cameras is None:
            return
        cam_names = self.known_cameras.keys()
        cam_names.sort()
        dlg = wx.SingleChoiceDialog(self,
                                    'Select Camera',
                                    caption='Select Camera',
                                    choices=cam_names)
        dlg.Raise()
        if dlg.ShowModal() == wx.ID_OK:
            cname = dlg.GetStringSelection()
            if cname in self.known_cameras:
                self.prefix = self.known_cameras[cname]
            wx.CallAfter(self.connect_pvs)
        dlg.Destroy()

    def ConnectToPV(self, event=None, name=None):
        print 'Connect To PV ', name, event
        if name is None:
            name = ''
        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:
            self.prefix = dlg.GetValue()
            wx.CallAfter(self.connect_pvs)
        dlg.Destroy()

    def onCopyImage(self, event=None):
        "copy bitmap of canvas to system clipboard"
        bmp = wx.BitmapDataObject()
        bmp.SetBitmap(wx.BitmapFromImage(self.wximage))
        wx.TheClipboard.Open()
        wx.TheClipboard.SetData(bmp)
        wx.TheClipboard.Close()
        wx.TheClipboard.Flush()

    @EpicsFunction
    def CameraOff(self):
        try:
            self.ad_cam.Acquire = 0
        except:
            pass

    @EpicsFunction
    def onSaveImage(self, event=None):
        "prompts for and save image to file"
        defdir = os.getcwd()
        self.fname = "Image_%i.tiff" % self.ad_cam.ArrayCounter_RBV
        dlg = wx.FileDialog(None,
                            message='Save Image as',
                            defaultDir=os.getcwd(),
                            defaultFile=self.fname,
                            style=wx.SAVE)
        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = os.path.abspath(dlg.GetPath())

        dlg.Destroy()
        if path is not None and self.data is not None:
            Image.frombuffer(self.im_mode, self.im_size, self.data.flatten(),
                             'raw', self.im_mode, 0, 1).save(path)

    def onExit(self, event=None):
        try:
            wx.Yield()
        except:
            pass
        self.CameraOff()
        self.Destroy()

    def onAbout(self, event=None):
        msg = """Epics Image Display version 0.2

http://pyepics.github.com/epicsapps/

Matt Newville <*****@*****.**>"""

        dlg = wx.MessageDialog(self, msg, "About Epics Image Display",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def buildMenus(self):
        fmenu = wx.Menu()
        add_menu(self, fmenu, "&Connect to Pre-defiend Camera",
                 "Connect to PV", self.ConnectToCamera)
        add_menu(self, fmenu, "&Connect to AreaDetector PV\tCtrl+O",
                 "Connect to PV", self.ConnectToPV)
        add_menu(self, fmenu, "&Save\tCtrl+S", "Save Image", self.onSaveImage)
        add_menu(self, fmenu, "&Copy\tCtrl+C", "Copy Image to Clipboard",
                 self.onCopyImage)
        fmenu.AppendSeparator()
        add_menu(self, fmenu, "E&xit\tCtrl+Q", "Exit Program", self.onExit)

        omenu = wx.Menu()
        add_menu(self, omenu, "&Zoom out\tCtrl+Z", "Zoom Out", self.unZoom)
        add_menu(self, omenu, "Reset Image Counter", "Set Image Counter to 0",
                 self.onResetImageCounter)
        omenu.AppendSeparator()
        add_menu(self, omenu, "&Rotate Clockwise\tCtrl+R", "Rotate Clockwise",
                 self.onRotCW)
        add_menu(self, omenu, "Rotate CounterClockwise",
                 "Rotate Counter Clockwise", self.onRotCCW)
        add_menu(self, omenu, "Flip Up/Down\tCtrl+T", "Flip Up/Down",
                 self.onFlipV)
        add_menu(self, omenu, "Flip Left/Right\tCtrl+F", "Flip Left/Right",
                 self.onFlipH)
        omenu.AppendSeparator()

        self.CM_ZOOM = wx.NewId()
        self.CM_SHOW = wx.NewId()
        self.CM_PROF = wx.NewId()
        omenu.Append(self.CM_ZOOM, "Cursor Mode: Zoom to Box\tCtrl+B",
                     "Zoom to box by clicking and dragging", wx.ITEM_RADIO)
        omenu.Append(self.CM_SHOW, "Cursor Mode: Show X,Y\tCtrl+X",
                     "Show X,Y, Intensity Values", wx.ITEM_RADIO)
        omenu.Append(self.CM_PROF, "Cursor Mode: Line Profile\tCtrl+L",
                     "Show Line Profile", wx.ITEM_RADIO)
        self.Bind(wx.EVT_MENU, self.onCursorMode, id=self.CM_ZOOM)
        self.Bind(wx.EVT_MENU, self.onCursorMode, id=self.CM_PROF)
        self.Bind(wx.EVT_MENU, self.onCursorMode, id=self.CM_SHOW)

        hmenu = wx.Menu()
        add_menu(self, hmenu, "About", "About Epics AreadDetector Display",
                 self.onAbout)

        mbar = wx.MenuBar()
        mbar.Append(fmenu, "File")
        mbar.Append(omenu, "Options")
        mbar.Append(hmenu, "&Help")
        self.SetMenuBar(mbar)

    def onCursorMode(self, event=None):
        if event.Id == self.CM_ZOOM:
            self.image.cursor_mode = 'zoom'
        elif event.Id == self.CM_PROF:
            self.image.cursor_mode = 'profile'
        elif event.Id == self.CM_SHOW:
            self.image.cursor_mode = 'show'

    @DelayedEpicsCallback
    def onResetImageCounter(self, event=None):
        self.ad_cam.ArrayCounter = 0

    def onRotCW(self, event):
        self.image.rot90 = (self.image.rot90 + 1) % 4
        self.image.Refresh()

    def onRotCCW(self, event):
        self.image.rot90 = (self.image.rot90 - 1) % 4
        self.image.Refresh()

    def onFlipV(self, event):
        self.image.flipv = not self.image.flipv
        self.image.Refresh()

    def onFlipH(self, event):
        self.image.fliph = not self.image.fliph
        self.image.Refresh()

    def buildFrame(self):
        sbar = self.CreateStatusBar(3, wx.CAPTION | wx.THICK_FRAME)
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(10)
        sbar.SetFont(sfont)

        self.SetStatusWidths([-3, -1, -1])
        self.SetStatusText('', 0)

        sizer = wx.GridBagSizer(10, 4)
        panel = wx.Panel(self)
        self.panel = panel
        labstyle = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM | wx.EXPAND
        ctrlstyle = wx.ALIGN_LEFT | wx.ALIGN_BOTTOM

        rlabstyle = wx.ALIGN_RIGHT | wx.RIGHT | wx.TOP | wx.EXPAND

        txtstyle = wx.ALIGN_LEFT | wx.ST_NO_AUTORESIZE | wx.TE_PROCESS_ENTER
        self.wids = {}
        self.wids['exptime'] = PVFloatCtrl(panel, pv=None, size=(100, -1))
        self.wids['period'] = PVFloatCtrl(panel, pv=None, size=(100, -1))
        self.wids['numimages'] = PVFloatCtrl(panel, pv=None, size=(100, -1))
        self.wids['gain'] = PVFloatCtrl(panel,
                                        pv=None,
                                        size=(100, -1),
                                        minval=0,
                                        maxval=20)

        self.wids['imagemode'] = PVEnumChoice(panel, pv=None, size=(100, -1))
        self.wids['triggermode'] = PVEnumChoice(panel, pv=None, size=(100, -1))
        self.wids['color'] = PVEnumChoice(panel, pv=None, size=(100, -1))
        self.wids['start'] = wx.Button(panel, -1, label='Start', size=(50, -1))
        self.wids['stop'] = wx.Button(panel, -1, label='Stop', size=(50, -1))

        if HAS_OVERLAY_DEVICE:
            self.wids['o1color'] = csel.ColourSelect(panel,
                                                     -1,
                                                     "",
                                                     '#FEFEFE',
                                                     size=(60, 25))
            self.wids['o1color'].Bind(csel.EVT_COLOURSELECT,
                                      Closure(self.onColor, item=1))
            self.wids['o1posx'] = PVFloatCtrl(panel,
                                              pv=None,
                                              size=(50, -1),
                                              minval=0)
            self.wids['o1posy'] = PVFloatCtrl(panel,
                                              pv=None,
                                              size=(50, -1),
                                              minval=0)
            self.wids['o1sizx'] = PVFloatCtrl(panel,
                                              pv=None,
                                              size=(50, -1),
                                              minval=0)
            self.wids['o1sizy'] = PVFloatCtrl(panel,
                                              pv=None,
                                              size=(50, -1),
                                              minval=0)
            self.wids['o1shape'] = PVEnumChoice(panel, pv=None, size=(100, -1))
            self.wids['o1use'] = PVEnumChoice(panel, pv=None, size=(50, -1))
            self.wids['o1name'] = PVTextCtrl(panel, pv=None, size=(100, -1))

            self.wids['o2color'] = csel.ColourSelect(panel,
                                                     -1,
                                                     "",
                                                     '#FEFEFE',
                                                     size=(60, 25))
            self.wids['o2color'].Bind(csel.EVT_COLOURSELECT,
                                      Closure(self.onColor, item=2))
            self.wids['o2posx'] = PVFloatCtrl(panel,
                                              pv=None,
                                              size=(50, -1),
                                              minval=0)
            self.wids['o2posy'] = PVFloatCtrl(panel,
                                              pv=None,
                                              size=(50, -1),
                                              minval=0)
            self.wids['o2sizx'] = PVFloatCtrl(panel,
                                              pv=None,
                                              size=(50, -1),
                                              minval=0)
            self.wids['o2sizy'] = PVFloatCtrl(panel,
                                              pv=None,
                                              size=(50, -1),
                                              minval=0)
            self.wids['o2shape'] = PVEnumChoice(panel, pv=None, size=(100, -1))
            self.wids['o2use'] = PVEnumChoice(panel, pv=None, size=(50, -1))
            self.wids['o2name'] = PVTextCtrl(panel, pv=None, size=(100, -1))

        for key in ('start', 'stop'):
            self.wids[key].Bind(wx.EVT_BUTTON, Closure(self.onEntry, key=key))

        self.wids['zoomsize'] = wx.StaticText(panel,
                                              -1,
                                              size=(250, -1),
                                              style=txtstyle)
        self.wids['fullsize'] = wx.StaticText(panel,
                                              -1,
                                              size=(250, -1),
                                              style=txtstyle)

        def txt(label, size=100):
            return wx.StaticText(panel,
                                 label=label,
                                 size=(size, -1),
                                 style=labstyle)

        def lin(len=30, wid=2, style=wx.LI_HORIZONTAL):
            return wx.StaticLine(panel, size=(len, wid), style=style)

        sizer.Add(txt(' '), (0, 0), (1, 1), labstyle)
        sizer.Add(txt('Image Mode '), (1, 0), (1, 1), labstyle)
        sizer.Add(self.wids['imagemode'], (1, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('# Images '), (2, 0), (1, 1), labstyle)
        sizer.Add(self.wids['numimages'], (2, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Trigger Mode '), (3, 0), (1, 1), labstyle)
        sizer.Add(self.wids['triggermode'], (3, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Period '), (4, 0), (1, 1), labstyle)
        sizer.Add(self.wids['period'], (4, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Exposure Time '), (5, 0), (1, 1), labstyle)
        sizer.Add(self.wids['exptime'], (5, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Gain '), (6, 0), (1, 1), labstyle)
        sizer.Add(self.wids['gain'], (6, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Color Mode'), (7, 0), (1, 1), labstyle)
        sizer.Add(self.wids['color'], (7, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Acquire '), (9, 0), (1, 1), labstyle)

        sizer.Add(self.wids['start'], (9, 1), (1, 1), ctrlstyle)
        sizer.Add(self.wids['stop'], (9, 2), (1, 1), ctrlstyle)

        sizer.Add(self.wids['fullsize'], (12, 0), (1, 3), labstyle)
        sizer.Add(self.wids['zoomsize'], (13, 0), (1, 3), labstyle)

        sizer.Add(lin(75), (15, 0), (1, 3), labstyle)

        if HAS_OVERLAY_DEVICE:
            ir = 16
            sizer.Add(txt('Overlay 1:'), (ir + 0, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1use'], (ir + 0, 1), (1, 2), ctrlstyle)
            sizer.Add(txt('Shape:'), (ir + 1, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1shape'], (ir + 1, 1), (1, 2), ctrlstyle)
            sizer.Add(txt('Name:'), (ir + 2, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1name'], (ir + 2, 1), (1, 2), ctrlstyle)

            sizer.Add(txt('Position '), (ir + 3, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1posx'], (ir + 3, 1), (1, 1), ctrlstyle)
            sizer.Add(self.wids['o1posy'], (ir + 3, 2), (1, 1), ctrlstyle)
            sizer.Add(txt('Size '), (ir + 4, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1sizx'], (ir + 4, 1), (1, 1), ctrlstyle)
            sizer.Add(self.wids['o1sizy'], (ir + 4, 2), (1, 1), ctrlstyle)
            sizer.Add(txt('Color '), (ir + 5, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1color'], (ir + 5, 1), (1, 2), ctrlstyle)
            sizer.Add(lin(75), (ir + 6, 0), (1, 3), labstyle)

            ir = ir + 7
            sizer.Add(txt('Overlay 1:'), (ir + 0, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2use'], (ir + 0, 1), (1, 2), ctrlstyle)
            sizer.Add(txt('Shape:'), (ir + 1, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2shape'], (ir + 1, 1), (1, 2), ctrlstyle)
            sizer.Add(txt('Name:'), (ir + 2, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2name'], (ir + 2, 1), (1, 2), ctrlstyle)

            sizer.Add(txt('Position '), (ir + 3, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2posx'], (ir + 3, 1), (1, 1), ctrlstyle)
            sizer.Add(self.wids['o2posy'], (ir + 3, 2), (1, 1), ctrlstyle)
            sizer.Add(txt('Size '), (ir + 4, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2sizx'], (ir + 4, 1), (1, 1), ctrlstyle)
            sizer.Add(self.wids['o2sizy'], (ir + 4, 2), (1, 1), ctrlstyle)
            sizer.Add(txt('Color '), (ir + 5, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2color'], (ir + 5, 1), (1, 2), ctrlstyle)
            sizer.Add(lin(75), (ir + 6, 0), (1, 3), labstyle)

        self.image = ImageView(self,
                               size=(1360, 1024),
                               onzoom=self.onZoom,
                               onprofile=self.onProfile,
                               onshow=self.onShowXY)

        panel.SetSizer(sizer)
        sizer.Fit(panel)

        mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        mainsizer.Add(panel, 0, wx.LEFT | wx.GROW | wx.ALL, 5)
        mainsizer.Add(self.image, 1, wx.CENTER | wx.GROW | wx.ALL, 5)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.SetAutoLayout(True)

        try:
            self.SetIcon(wx.Icon(ICON_FILE, wx.BITMAP_TYPE_ICO))
        except:
            pass

        self.RefreshImage()
        wx.CallAfter(self.connect_pvs)

    def messag(self, s, panel=0):
        """write a message to the Status Bar"""
        wx.CallAfter(Closure(self.SetStatusText, text=s, number=panel))
        # self.SetStatusText(s, panel)

    @EpicsFunction
    def unZoom(self, event=None, full=False):
        if self.zoom_lims is None or full:
            self.zoom_lims = []

        if len(self.zoom_lims) == 0:
            xmin, ymin = 0, 0
            width = self.ad_cam.MaxSizeX_RBV
            height = self.ad_cam.MaxSizeY_RBV
            self.zoom_lims = []
        else:
            xmin, ymin, width, height = self.zoom_lims.pop()
            if (self.ad_cam.MinX == xmin and self.ad_cam.MinY == ymin
                    and self.ad_cam.SizeX == width
                    and self.ad_cam.SizeY == height):
                try:
                    xmin, ymin, width, height = self.zoom_lims.pop()
                except:
                    xmin, ymin = 0, 0
                    width = self.ad_cam.MaxSizeX_RBV
                    height = self.ad_cam.MaxSizeY_RBV

        self.ad_cam.MinX = xmin
        self.ad_cam.MinY = ymin
        self.ad_cam.SizeX = width
        self.ad_cam.SizeY = height
        self.zoom_lims.append((xmin, ymin, width, height))
        time.sleep(0.05)
        self.showZoomsize()
        if self.ad_cam.Acquire == 0 and self.im_size is not None:
            self.img_w = width
            self.img_h = height
            try:
                if self.colormode == 2:
                    self.data.shape = [self.im_size[1], self.im_size[0], 3]
                    zdata = self.data[ymin:ymin + height, xmin:xmin + width, :]
                else:
                    self.data.shape = self.im_size[1], self.im_size[0]
                    zdata = self.data[ymin:ymin + height, xmin:xmin + width]
            except ValueError:
                pass
            self.data = zdata  #self.data.flatten()
            self.im_size = (width, height)
            # print zdata.shape, width, height, self.im_mode
            self.DatatoImage()  # zdata, (width, height), self.im_mode)

        self.RefreshImage()
        self.image.Refresh()

    @EpicsFunction
    def onColor(self, event=None, item=None):
        if HAS_OVERLAY_DEVICE:
            color = event.GetValue()
            over = self.ad_overlays[item - 1]
            over.Red = color[0]
            over.Green = color[1]
            over.Blue = color[2]

    @EpicsFunction
    def showZoomsize(self):
        try:
            msg = 'Showing:  %i x %i pixels' % (self.ad_cam.SizeX,
                                                self.ad_cam.SizeY)
            self.wids['zoomsize'].SetLabel(msg)
        except:
            pass

    @EpicsFunction
    def onZoom(self, x0, y0, x1, y1):
        width = self.ad_cam.SizeX
        height = self.ad_cam.SizeY
        xmin = max(0, int(self.ad_cam.MinX + x0 * width))
        ymin = max(0, int(self.ad_cam.MinY + y0 * height))

        width = int(x1 * width)
        height = int(y1 * height)
        if width < 2 or height < 2:
            return
        self.ad_cam.MinX = xmin
        self.ad_cam.MinY = ymin
        self.ad_cam.SizeX = width
        self.ad_cam.SizeY = height
        if self.zoom_lims is None:
            self.zoom_lims = []
        self.zoom_lims.append((xmin, ymin, width, height))

        time.sleep(0.05)
        self.showZoomsize()

        if self.ad_cam.Acquire == 0:
            self.img_w = width
            self.img_h = height
            if self.colormode == 2:
                self.data.shape = [self.im_size[1], self.im_size[0], 3]
                zdata = self.data[ymin:ymin + height, xmin:xmin + width, :]
            else:
                self.data.shape = self.im_size[1], self.im_size[0]
                zdata = self.data[ymin:ymin + height, xmin:xmin + width]
            self.data = zdata  #. flatten()
            self.im_size = (width, height)
            self.DatatoImage()
        self.image.Refresh()

    def DatatoImage(self):  #,  data, size, mode):
        """convert raw data to image"""
        #x = debugtime()

        width, height = self.im_size
        d_size = (int(width * self.scale), int(height * self.scale))
        data = self.data.flatten()
        #x.add('flatten')
        if self.imbuff is None or d_size != self.d_size or self.im_mode == 'L':
            try:
                self.imbuff = Image.frombuffer(self.im_mode, self.im_size,
                                               data, 'raw', self.im_mode, 0, 1)
                #x.add('made image')
            except:
                return
        self.d_size = d_size = (int(width * self.scale),
                                int(height * self.scale))
        if self.imbuff.size != d_size:
            self.imbuff = self.imbuff.resize(d_size)
            #x.add('resized imbuff')

        if self.wximage.GetSize() != self.imbuff.size:
            self.wximage = wx.EmptyImage(d_size[0], d_size[1])
        #x.add('created wximage %s  ' % (repr(self.wximage.GetSize())))
        if self.im_mode == 'L':
            self.wximage.SetData(self.imbuff.convert('RGB').tostring())
        elif self.im_mode == 'RGB':
            data.shape = (3, width, height)
            self.wximage = wx.ImageFromData(width, height, data)
        #x.add('set wx image wximage : %i, %i ' % d_size)
        self.image.SetValue(self.wximage)
        #x.add('set image value')
        #x.show()

    def onProfile(self, x0, y0, x1, y1):
        width = self.ad_cam.SizeX
        height = self.ad_cam.SizeY

        x0, y0 = int(x0 * width), int(y0 * height)
        x1, y1 = int(x1 * width), int(y1 * height)
        dx, dy = abs(x1 - x0), abs(y1 - y0)

        if dx < 2 and dy < 2:
            return
        outdat = []
        if self.colormode == 2:
            self.data.shape = (self.im_size[1], self.im_size[0], 3)
        else:
            self.data.shape = self.im_size[1], self.im_size[0]

        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))

        if self.lineplotter is None:
            self.lineplotter = PlotFrame(self, title='Image Profile')
        else:
            try:
                self.lineplotter.Raise()
            except PyDeadObjectError:
                self.lineplotter = PlotFrame(self, title='Image Profile')

        if self.colormode == 2:
            x, y, r, g, b = [], [], [], [], []
            for ix, iy in outdat:
                x.append(ix)
                y.append(iy)
                r.append(self.data[iy, ix, 0])
                g.append(self.data[iy, ix, 1])
                b.append(self.data[iy, ix, 2])
            xlabel = 'Pixel (x)'
            if dy > dx:
                x = y
                xlabel = 'Pixel (y)'
            self.lineplotter.plot(x,
                                  r,
                                  color='red',
                                  label='red',
                                  xlabel=xlabel,
                                  ylabel='Intensity',
                                  title='Image %i' %
                                  self.ad_cam.ArrayCounter_RBV)
            self.lineplotter.oplot(x, g, color='green', label='green')
            self.lineplotter.oplot(x, b, color='blue', label='blue')

        else:
            x, y, z = [], [], []
            for ix, iy in outdat:
                x.append(ix)
                y.append(iy)
                z.append(self.data[iy, ix])
            xlabel = 'Pixel (x)'
            if dy > dx:
                x = y
            xlabel = 'Pixel (y)'
            self.lineplotter.plot(x,
                                  z,
                                  color='k',
                                  xlabel=xlabel,
                                  ylabel='Intensity',
                                  title='Image %i' %
                                  self.ad_cam.ArrayCounter_RBV)
        self.lineplotter.Show()
        self.lineplotter.Raise()

    def onShowXY(self, xval, yval):
        ix = max(0, int(xval * self.ad_cam.SizeX))
        iy = max(0, int(yval * self.ad_cam.SizeY))

        if self.colormode == 2:
            self.data.shape = (self.im_size[1], self.im_size[0], 3)
            ival = tuple(self.data[iy, ix, :])
            smsg = 'Pixel %i, %i, (R, G, B) = %s' % (ix, iy, repr(ival))
        else:
            self.data.shape = self.im_size[1], self.im_size[0]
            ival = self.data[iy, ix]
            smsg = 'Pixel %i, %i, Intensity = %i' % (ix, iy, ival)

        self.messag(smsg, panel=1)

    def onName(self, evt=None, **kws):
        if evt is None:
            return
        s = evt.GetString()
        s = str(s).strip()
        if s.endswith(':image1:'): s = s[:-8]
        if s.endswith(':cam1:'): s = s[:-6]
        if s.endswith(':'): s = s[:-1]
        self.prefix = s
        self.connect_pvs()

    @EpicsFunction
    def onEntry(self, evt=None, key='name', **kw):
        if evt is None:
            return
        if key == 'start':
            self.n_img = 0
            self.n_drawn = 0
            self.starttime = time.time()
            self.imgcount_start = self.ad_cam.ArrayCounter_RBV
            self.ad_cam.Acquire = 1
        elif key == 'stop':
            self.ad_cam.Acquire = 0
        elif key == 'unzoom':
            self.unZoom()
        else:
            print 'unknown Entry ? ', key

    @EpicsFunction
    def connect_pvs(self, verbose=True):
        if self.prefix is None or len(self.prefix) < 2:
            return

        try:
            self.ad_cam.Acquire = 0
        except:
            pass

        if self.prefix.endswith(':'):
            self.prefix = self.prefix[:-1]
        if self.prefix.endswith(':image1'):
            self.prefix = self.prefix[:-7]
        if self.prefix.endswith(':cam1'):
            self.prefix = self.prefix[:-5]

        if verbose:
            self.messag('Connecting to AD %s' % self.prefix)
        self.ad_img = epics.Device(self.prefix + ':image1:',
                                   delim='',
                                   attrs=self.img_attrs)
        self.ad_cam = epics.Device(self.prefix + ':cam1:',
                                   delim='',
                                   attrs=self.cam_attrs)
        self.ad_overlays = []
        if HAS_OVERLAY_DEVICE:
            for ix in (1, 2):
                pvn = '%s:Over1:%i:' % (self.prefix, ix)
                self.ad_overlays.append(AD_OverlayPlugin(pvn))

        time.sleep(0.010)
        if not self.ad_img.PV('UniqueId_RBV').connected:
            epics.poll()
            if not self.ad_img.PV('UniqueId_RBV').connected:
                self.messag('Warning:  Camera seems to not be connected!')
                return
        if verbose:
            self.messag('Connected to AD %s' % self.prefix)

        self.SetTitle("Epics Image Display: %s" % self.prefix)

        self.wids['color'].SetPV(self.ad_cam.PV('ColorMode'))
        self.wids['exptime'].SetPV(self.ad_cam.PV('AcquireTime'))
        self.wids['period'].SetPV(self.ad_cam.PV('AcquirePeriod'))
        self.wids['gain'].SetPV(self.ad_cam.PV('Gain'))
        self.wids['numimages'].SetPV(self.ad_cam.PV('NumImages'))
        self.wids['imagemode'].SetPV(self.ad_cam.PV('ImageMode'))
        self.wids['triggermode'].SetPV(self.ad_cam.PV('TriggerMode'))

        sizex = self.ad_cam.MaxSizeX_RBV
        sizey = self.ad_cam.MaxSizeY_RBV

        if HAS_OVERLAY_DEVICE:
            over = self.ad_overlays[0]
            c1 = (over.Red, over.Green, over.Blue)
            self.wids['o1color'].SetColour(hexcolor(c1))
            self.wids['o1posx'].SetPV(over.PV('PositionX'))
            self.wids['o1posx'].SetMax(sizex)
            self.wids['o1posy'].SetPV(over.PV('PositionY'))
            self.wids['o1posy'].SetMax(sizey)
            self.wids['o1sizx'].SetPV(over.PV('SizeX'))
            self.wids['o1sizx'].SetMax(sizex)
            self.wids['o1sizy'].SetPV(over.PV('SizeY'))
            self.wids['o1sizy'].SetMax(sizey)
            self.wids['o1shape'].SetPV(over.PV('Shape'))
            self.wids['o1name'].SetPV(over.PV('Name'))
            self.wids['o1use'].SetPV(over.PV('Use'))

            over = self.ad_overlays[1]
            c1 = (over.Red, over.Green, over.Blue)
            self.wids['o2color'].SetColour(hexcolor(c1))
            self.wids['o2posx'].SetPV(over.PV('PositionX'))
            self.wids['o2posx'].SetMax(sizex)
            self.wids['o2posy'].SetPV(over.PV('PositionY'))
            self.wids['o2posy'].SetMax(sizey)
            self.wids['o2sizx'].SetPV(over.PV('SizeX'))
            self.wids['o2sizx'].SetMax(sizex)
            self.wids['o2sizy'].SetPV(over.PV('SizeY'))
            self.wids['o2sizy'].SetMax(sizey)
            self.wids['o2shape'].SetPV(over.PV('Shape'))
            self.wids['o2name'].SetPV(over.PV('Name'))
            self.wids['o2use'].SetPV(over.PV('Use'))

        sizelabel = 'Image Size: %i x %i pixels'
        try:
            sizelabel = sizelabel % (sizex, sizey)
        except:
            sizelabel = sizelabel % (0, 0)

        self.wids['fullsize'].SetLabel(sizelabel)
        self.showZoomsize()

        self.ad_img.add_callback('ArrayCounter_RBV', self.onNewImage)
        self.ad_img.add_callback('ArraySize0_RBV', self.onProperty, dim=0)
        self.ad_img.add_callback('ArraySize1_RBV', self.onProperty, dim=1)
        self.ad_img.add_callback('ArraySize2_RBV', self.onProperty, dim=2)
        self.ad_img.add_callback('ColorMode_RBV', self.onProperty, dim='color')
        self.ad_cam.add_callback('DetectorState_RBV', self.onDetState)

        epics.caput("%s:cam1:ArrayCallbacks" % self.prefix, 1)
        for p in self.enabled_plugins:
            epics.caput("%s:%s:EnableCallbacks" % (self.prefix, p), 1)
        epics.caput("%s:JPEG1:NDArrayPort" % self.prefix, "OVER1")
        epics.caput("%s:TIFF1:NDArrayPort" % self.prefix, "OVER1")
        epics.caput("%s:image1:NDArrayPort" % self.prefix, "OVER1")

        self.ad_cam.Acquire = 1
        self.GetImageSize()
        self.unZoom()

        epics.poll()
        self.RefreshImage()

    @EpicsFunction
    def GetImageSize(self):
        self.arrsize = [1, 1, 1]
        self.arrsize[0] = self.ad_img.ArraySize0_RBV
        self.arrsize[1] = self.ad_img.ArraySize1_RBV
        self.arrsize[2] = self.ad_img.ArraySize2_RBV
        self.colormode = self.ad_img.ColorMode_RBV

        self.img_w = self.arrsize[1]
        self.img_h = self.arrsize[0]
        if self.colormode == 2:
            self.img_w = self.arrsize[2]
            self.img_h = self.arrsize[1]

    @DelayedEpicsCallback
    def onDetState(self, pvname=None, value=None, char_value=None, **kw):
        self.messag(char_value, panel=1)

    @DelayedEpicsCallback
    def onProperty(self, pvname=None, value=None, dim=None, **kw):
        if dim == 'color':
            self.colormode = value
        else:
            self.arrsize[dim] = value

    @DelayedEpicsCallback
    def onNewImage(self, pvname=None, value=None, **kw):
        if value != self.img_id:
            self.img_id = value
            if not self.drawing:
                self.drawing = True
                self.RefreshImage()

    @EpicsFunction
    def RefreshImage(self, pvname=None, **kws):
        try:
            wx.Yield()
        except:
            pass
        d = debugtime()

        if self.ad_img is None or self.ad_cam is None:
            return
        imgdim = self.ad_img.NDimensions_RBV
        imgcount = self.ad_cam.ArrayCounter_RBV
        now = time.time()
        if (imgcount == self.imgcount or abs(now - self.last_update) < 0.025):
            self.drawing = False
            return
        d.add('refresh img start')
        self.imgcount = imgcount
        self.drawing = True
        self.n_drawn += 1
        self.n_img = imgcount - self.imgcount_start
        #print 'ImgCount, n_drawn: ', imgcount, self.n_img, self.n_drawn

        self.last_update = time.time()
        self.image.can_resize = False

        xmin = self.ad_cam.MinX
        ymin = self.ad_cam.MinY
        width = self.ad_cam.SizeX
        height = self.ad_cam.SizeY

        arraysize = self.arrsize[0] * self.arrsize[1]
        if imgdim == 3:
            arraysize = arraysize * self.arrsize[2]
        if not self.ad_img.PV('ArrayData').connected:
            self.drawing = False
            return

        d.add('refresh img before raw get %i' % arraysize)
        rawdata = self.ad_img.PV('ArrayData').get(count=arraysize)
        d.add('refresh img after raw get')
        im_mode = 'L'
        im_size = (self.arrsize[0], self.arrsize[1])

        if self.colormode == 2:
            im_mode = 'RGB'
            im_size = [self.arrsize[1], self.arrsize[2]]
        if (self.colormode == 0 and isinstance(rawdata, np.ndarray)
                and rawdata.dtype != np.uint8):
            im_mode = 'I'
            rawdata = rawdata.astype(np.uint32)

        d.add('refresh img before msg')
        self.messag(' Image # %i ' % self.ad_cam.ArrayCounter_RBV, panel=2)
        d.add('refresh img before get image size')
        self.GetImageSize()

        self.im_size = im_size
        self.im_mode = im_mode
        self.data = rawdata
        d.add('refresh img before data to image')
        self.DatatoImage()
        d.add('refresh img after data to image')
        self.image.can_resize = True
        nmissed = max(0, self.n_img - self.n_drawn)

        delt = time.time() - self.starttime
        percent_drawn = self.n_drawn * 100 / (self.n_drawn + nmissed)
        smsg = self.stat_msg % (percent_drawn, self.n_drawn / delt)
        self.messag(smsg, panel=0)

        self.drawing = False
        d.add('refresh img done')
Example #12
0
class TestFrame(wx.Frame):
    def __init__(self, parent=None, *args, **kwds):

        kwds["style"] = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL

        wx.Frame.__init__(self, parent, wx.NewId(), "", wx.DefaultPosition, wx.Size(-1, -1), **kwds)
        self.SetTitle(" WXMPlot Plotting Demo")

        self.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, False))
        menu = wx.Menu()
        ID_EXIT = wx.NewId()

        menu_exit = menu.Append(ID_EXIT, "E&xit", "Terminate the program")

        menuBar = wx.MenuBar()
        menuBar.Append(menu, "&File")
        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.OnExit, menu_exit)

        self.Bind(wx.EVT_CLOSE, self.OnExit)  # CloseEvent)

        self.plotframe = None

        self.create_data()
        framesizer = wx.BoxSizer(wx.VERTICAL)

        panel = wx.Panel(self, -1, size=(-1, -1))
        panelsizer = wx.BoxSizer(wx.VERTICAL)

        panelsizer.Add(
            wx.StaticText(panel, -1, "wxmplot 2D PlotPanel examples "),
            0,
            wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT | wx.EXPAND,
            10,
        )

        b10 = wx.Button(panel, -1, "Example #1", size=(-1, -1))
        b20 = wx.Button(panel, -1, "Example #2", size=(-1, -1))
        b22 = wx.Button(panel, -1, "Plot with 2 axes", size=(-1, -1))
        b31 = wx.Button(panel, -1, "Plot with Errorbars", size=(-1, -1))
        b32 = wx.Button(panel, -1, "SemiLog Plot", size=(-1, -1))
        b40 = wx.Button(panel, -1, "Start Timed Plot", size=(-1, -1))
        b50 = wx.Button(panel, -1, "Stop Timed Plot", size=(-1, -1))
        b60 = wx.Button(panel, -1, "Plot 500,000 points", size=(-1, -1))

        b10.Bind(wx.EVT_BUTTON, self.onPlot1)
        b20.Bind(wx.EVT_BUTTON, self.onPlot2)
        b22.Bind(wx.EVT_BUTTON, self.onPlot2Axes)
        b31.Bind(wx.EVT_BUTTON, self.onPlotErr)
        b32.Bind(wx.EVT_BUTTON, self.onPlotSLog)
        b40.Bind(wx.EVT_BUTTON, self.onStartTimer)
        b50.Bind(wx.EVT_BUTTON, self.onStopTimer)
        b60.Bind(wx.EVT_BUTTON, self.onPlotBig)

        panelsizer.Add(b10, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b20, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b22, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b31, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b32, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b40, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b50, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b60, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)

        panel.SetSizer(panelsizer)
        panelsizer.Fit(panel)

        framesizer.Add(panel, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.EXPAND, 2)
        self.SetSizer(framesizer)
        framesizer.Fit(self)

        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer = wx.Timer(self)
        self.Refresh()

    def create_data(self):
        self.count = 0
        self.x = x = arange(0.0, 25.0, 0.1)
        self.y1 = 4 * cos(2 * pi * (x - 1) / 5.7) / (6 + x) + 2 * sin(2 * pi * (x - 1) / 2.2) / (10)
        self.y2 = sin(2 * pi * x / 30.0)
        self.y3 = -pi + 2 * (x / 10.0 + exp(-(x - 3) / 5.0))
        self.y4 = exp(0.01 + 0.5 * x) / (x + 2)
        self.y5 = 3000 * self.y3
        self.npts = len(self.x)
        self.bigx = linspace(0, 2500, 500000)
        self.bigy = sin(pi * self.bigx / 140.0) + cos(pi * self.bigx / 277.0) + cos(pi * self.bigx / 820.0)

    def ShowPlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self)
            self.has_plot = False
        try:
            self.plotframe.Show()
        except PyDeadObjectError:
            self.plotframe = PlotFrame(self)
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()

    def onPlot1(self, event=None):
        self.ShowPlotFrame()
        self.plotframe.plot(self.x, self.y1)
        self.plotframe.oplot(self.x, self.y2)
        self.plotframe.write_message("Plot 1")

    def onPlot2(self, event=None):
        self.ShowPlotFrame()
        x = arange(100)
        y1 = cos(pi * x / 72)
        y2 = sin(pi * x / 23)
        self.plotframe.plot(x, y1, color="red")
        self.plotframe.oplot(x, y2, color="green3", marker="+")
        self.plotframe.write_message("Plot 2")

    def onPlotErr(self, event=None):
        self.ShowPlotFrame()
        npts = 81
        x = linspace(0, 40.0, npts)
        y = 0.4 * cos(x / 2.0) + random.normal(scale=0.03, size=npts)
        dy = 0.03 * (ones(npts) + random.normal(scale=0.2, size=npts))

        self.plotframe.plot(
            x, y, dy=dy, color="red", linewidth=0, xlabel="x", ylabel="y", marker="o", title="Plot with error bars"
        )
        self.plotframe.write_message("Errorbars!")

    def onPlot2Axes(self, event=None):
        self.ShowPlotFrame()

        self.plotframe.plot(self.x, self.y2, color="black", style="dashed")
        self.plotframe.oplot(self.x, self.y5, color="red", side="right")
        self.plotframe.write_message("Plot with 2 axes")

    def onPlotSLog(self, event=None):
        self.ShowPlotFrame()

        self.plotframe.plot(self.x, self.y4, ylog_scale=True, color="black", style="dashed")
        self.plotframe.write_message("Semi Log Plot")

    def onPlotBig(self, event=None):
        self.ShowPlotFrame()

        t0 = time.time()
        self.plotframe.plot(self.bigx, self.bigy, marker="+", linewidth=0)
        dt = time.time() - t0
        self.plotframe.write_message("Plot array with npts=%i, elapsed time=%8.3f s" % (len(self.bigx), dt))

    def report_memory(i):
        pid = os.getpid()
        if os.name == "posix":
            mem = os.popen("ps -o rss -p %i" % pid).readlines()[1].split()[0]
        else:
            mem = 0
        return int(mem)

    def onStartTimer(self, event=None):
        self.count = 0
        self.up_count = 0
        self.n_update = 1
        self.datrange = None
        self.time0 = time.time()
        self.start_mem = self.report_memory()
        self.timer.Start(10)

    def timer_results(self):
        if self.count < 2:
            return
        etime = time.time() - self.time0
        tpp = etime / max(1, self.count)
        s = "drew %i points in %8.3f s: time/point= %8.4f s" % (self.count, etime, tpp)
        self.plotframe.write_message(s)
        self.time0 = 0
        self.count = 0
        self.datrange = None

    def onStopTimer(self, event=None):
        self.timer.Stop()
        try:
            self.timer_results()
        except:
            pass

    def onTimer(self, event):
        # print 'timer ', self.count, time.time()
        self.count += 1
        self.ShowPlotFrame(do_raise=False, clear=False)
        n = self.count
        if n < 2:
            return
        if n >= self.npts:
            self.timer.Stop()
            self.timer_results()
        elif n <= 3:
            self.plotframe.plot(self.x[:n], self.y1[:n])  # , grid=False)

        else:
            self.plotframe.update_line(0, self.x[:n], self.y1[:n], update_limits=n < 10, draw=True)

            etime = time.time() - self.time0
            s = " %i / %i points in %8.4f s" % (n, self.npts, etime)
            self.plotframe.write_message(s)

        if self.datrange is None:
            self.datrange = [min(self.x[:n]), max(self.x[:n]), min(self.y1[:n]), max(self.y1[:n])]

        dr = [min(self.x[:n]), max(self.x[:n]), min(self.y1[:n]), max(self.y1[:n])]
        lims = self.plotframe.panel.get_viewlimits()
        if dr[0] < lims[0] or dr[1] > lims[1] or dr[2] < lims[2] or dr[3] > lims[3]:
            self.datrange = dr
            if n < len(self.x):
                nmax = min(int(n * 1.6), len(self.x) - 1)
                self.datrange[1] = self.x[nmax]
            self.plotframe.panel.set_xylims(self.datrange)

    #        if (n > self.n_update-1) or
    #             (xr[0] < xv[0]) or (xr[1] > xv[1]) or
    #             (yr[0] < yv[0]) or (yr[1] > yv[1])):
    #             nx = self.n_update = min(self.npts,3+int(self.n_update*2.0))
    #             if nx > int(0.92*self.npts):
    #                 nx = self.n_update = self.npts
    #                 xylims = (min(self.x),max(self.x),
    #                           min(self.y1),max(self.y1))
    #             else:
    #                 xylims = (min(self.x[0:nx]),max(self.x[0:nx]),
    #                           min(self.y1[0:nx]),max(self.y1[0:nx]))
    #             self.up_count = self.up_count + 1
    #             self.plotframe.panel.set_xylims(xylims)

    def OnAbout(self, event):
        dlg = wx.MessageDialog(
            self,
            "This sample program shows some\n" "examples of MPlot PlotFrame.\n" "message dialog.",
            "About MPlot test",
            wx.OK | wx.ICON_INFORMATION,
        )
        dlg.ShowModal()
        dlg.Destroy()

    def OnExit(self, event):
        try:
            if self.plotframe != None:
                self.plotframe.onExit()
        except:
            pass
        self.Destroy()
Example #13
0
class ADFrame(wx.Frame):
    """
    AreaDetector Display Frame
    """
    def __init__(self, configfile=None):
        wx.Frame.__init__(self,
                          None,
                          -1,
                          'AreaDetector Viewer',
                          style=wx.DEFAULT_FRAME_STYLE)

        if configfile is None:
            wcard = 'Detector Config Files (*.yaml)|*.yaml|All files (*.*)|*.*'
            configfile = FileOpen(self,
                                  "Read Detector Configuration File",
                                  default_file='det.yaml',
                                  wildcard=wcard)
        if configfile is None:
            sys.exit()

        self.config = read_adconfig(configfile)
        self.prefix = self.config['general']['prefix']
        self.fname = self.config['general']['name']
        self.colormode = self.config['general']['colormode'].lower()
        self.cam_attrs = self.config['cam_attributes']
        self.img_attrs = self.config['img_attributes']
        self.fsaver = self.config['general']['filesaver']

        self.SetTitle(self.config['general']['title'])
        self.scandb = None
        if ScanDB is not None:
            self.scandb = ScanDB()
            if self.scandb.engine is None:  # not connected to running scandb server
                self.scandb = None

        self.calib = None
        self.ad_img = None
        self.ad_cam = None
        self.lineplotter = None
        self.integrator = None
        self.int_panel = None
        self.int_lastid = None
        self.contrast_levels = None
        self.thumbnail = None

        self.buildMenus()
        self.buildFrame()

    def buildFrame(self):
        self.SetFont(Font(11))

        sbar = self.CreateStatusBar(3, wx.CAPTION)
        self.SetStatusWidths([-1, -1, -1])
        self.SetStatusText('', 0)

        sizer = wx.GridBagSizer(3, 3)
        panel = self.panel = wx.Panel(self)
        pvpanel = PVConfigPanel(panel, self.prefix, self.config['controls'])

        wsize = (100, -1)
        lsize = (250, -1)

        start_btn = wx.Button(panel, label='Start', size=wsize)
        stop_btn = wx.Button(panel, label='Stop', size=wsize)
        start_btn.Bind(wx.EVT_BUTTON, partial(self.onButton, key='start'))
        stop_btn.Bind(wx.EVT_BUTTON, partial(self.onButton, key='stop'))

        self.contrast = ContrastControl(panel,
                                        callback=self.set_contrast_level)
        self.imagesize = wx.StaticText(panel,
                                       label='? x ?',
                                       size=(150, 30),
                                       style=txtstyle)

        def lin(len=200, wid=2, style=wx.LI_HORIZONTAL):
            return wx.StaticLine(panel, size=(len, wid), style=style)

        irow = 0
        sizer.Add(pvpanel, (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(start_btn, (irow, 0), (1, 1), labstyle)
        sizer.Add(stop_btn, (irow, 1), (1, 1), labstyle)

        if self.config['general'].get('show_free_run', False):
            free_btn = wx.Button(panel, label='Free Run', size=wsize)
            free_btn.Bind(wx.EVT_BUTTON, partial(self.onButton, key='free'))
            irow += 1
            sizer.Add(free_btn, (irow, 0), (1, 2), labstyle)

        irow += 1
        sizer.Add(lin(200, wid=4), (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(self.imagesize, (irow, 0), (1, 3), labstyle)

        if self.colormode.startswith('mono'):
            self.cmap_choice = wx.Choice(panel,
                                         size=(80, -1),
                                         choices=self.config['colormaps'])
            self.cmap_choice.SetSelection(0)
            self.cmap_choice.Bind(wx.EVT_CHOICE, self.onColorMap)
            self.cmap_reverse = wx.CheckBox(panel,
                                            label='Reverse',
                                            size=(60, -1))
            self.cmap_reverse.Bind(wx.EVT_CHECKBOX, self.onColorMap)

            irow += 1
            sizer.Add(wx.StaticText(panel, label='Color Map: '), (irow, 0),
                      (1, 1), labstyle)

            sizer.Add(self.cmap_choice, (irow, 1), (1, 1), labstyle)
            sizer.Add(self.cmap_reverse, (irow, 2), (1, 1), labstyle)

        irow += 1
        sizer.Add(self.contrast.label, (irow, 0), (1, 1), labstyle)
        sizer.Add(self.contrast.choice, (irow, 1), (1, 1), labstyle)

        if self.config['general']['show_1dintegration']:
            self.show1d_btn = wx.Button(panel,
                                        label='Show 1D Integration',
                                        size=(200, -1))
            self.show1d_btn.Bind(wx.EVT_BUTTON, self.onShowIntegration)
            self.show1d_btn.Disable()
            irow += 1
            sizer.Add(self.show1d_btn, (irow, 0), (1, 2), labstyle)

        if self.config['general']['show_thumbnail']:
            t_size = self.config['general'].get('thumbnail_size', 100)

            self.thumbnail = ThumbNailImagePanel(panel,
                                                 imgsize=t_size,
                                                 size=(350, 350),
                                                 motion_writer=partial(
                                                     self.write, panel=0))

            label = wx.StaticText(panel,
                                  label='Thumbnail size (pixels): ',
                                  size=(200, -1),
                                  style=txtstyle)

            self.thumbsize = FloatSpin(panel,
                                       value=100,
                                       min_val=10,
                                       increment=5,
                                       action=self.onThumbSize,
                                       size=(150, -1),
                                       style=txtstyle)

            irow += 1
            sizer.Add(label, (irow, 0), (1, 1), labstyle)
            sizer.Add(self.thumbsize, (irow, 1), (1, 1), labstyle)
            irow += 1
            sizer.Add(self.thumbnail, (irow, 0), (1, 2), labstyle)

        panel.SetSizer(sizer)
        sizer.Fit(panel)

        # image panel
        self.image = ADMonoImagePanel(
            self,
            prefix=self.prefix,
            rot90=self.config['general']['default_rotation'],
            size=(750, 750),
            writer=partial(self.write, panel=1),
            thumbnail=self.thumbnail,
            motion_writer=partial(self.write, panel=2))

        mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        mainsizer.Add(panel, 0, wx.LEFT | wx.GROW | wx.ALL)
        mainsizer.Add(self.image, 1, wx.CENTER | wx.GROW | wx.ALL)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.SetAutoLayout(True)
        iconfile = self.config['general'].get('iconfile', None)
        if iconfile is None or not os.path.exists(iconfile):
            iconfile = DEFAULT_ICONFILE
        try:
            self.SetIcon(wx.Icon(iconfile, wx.BITMAP_TYPE_ICO))
        except:
            pass
        self.connect_pvs()

    def onThumbSize(self, event=None):
        self.thumbnail.imgsize = int(self.thumbsize.GetValue())

    def onColorMap(self, event=None):
        cmap_name = self.cmap_choice.GetStringSelection()
        if self.cmap_reverse.IsChecked():
            cmap_name = cmap_name + '_r'
        self.image.colormap = getattr(colormap, cmap_name)
        self.image.Refresh()

    def onCopyImage(self, event=None):
        "copy bitmap of canvas to system clipboard"
        bmp = wx.BitmapDataObject()
        bmp.SetBitmap(wx.Bitmap(self.image.GrabWxImage()))
        wx.TheClipboard.Open()
        wx.TheClipboard.SetData(bmp)
        wx.TheClipboard.Close()
        wx.TheClipboard.Flush()

    def onReadCalibFile(self, event=None):
        "read calibration file"
        wcards = "Poni Files(*.poni)|*.poni|All files (*.*)|*.*"
        dlg = wx.FileDialog(None,
                            message='Read Calibration File',
                            defaultDir=os.getcwd(),
                            wildcard=wcards,
                            style=wx.FD_OPEN)
        ppath = None
        if dlg.ShowModal() == wx.ID_OK:
            ppath = os.path.abspath(dlg.GetPath())

        if os.path.exists(ppath):
            self.setup_calibration(ppath)

    def setup_calibration(self, ponifile):
        """set up calibration from PONI file"""
        calib = read_poni(ponifile)
        # if self.image.rot90 in (1, 3):
        #     calib['rot3'] = np.pi/2.0
        self.calib = calib
        if HAS_PYFAI:
            self.integrator = AzimuthalIntegrator(**calib)
            self.show1d_btn.Enable()
        else:
            self.write('Warning: PyFAI is not installed')

        if self.scandb is not None:
            _, calname = os.path.split(ponifile)
            self.scandb.set_detectorconfig(calname, json.dumps(calib))
            self.scandb.set_info('xrd_calibration', calname)

    def onShowIntegration(self, event=None):

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()

    def onAutoIntegration(self, event=None):
        if not event.IsChecked():
            self.int_timer.Stop()
            return

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()
        self.int_timer.Start(500)

    def show_1dpattern(self, init=False):
        if self.calib is None or not HAS_PYFAI:
            return

        img = self.ad_img.PV('ArrayData').get()

        h, w = self.image.GetImageSize()
        img.shape = (w, h)

        # may need to trim outer pixels (int1d_trimx/int1d_trimy in config)
        xstride = 1
        if self.config['general'].get('int1d_flipx', False):
            xstride = -1

        xslice = slice(None, None, xstride)
        trimx = int(self.config['general'].get('int1d_trimx', 0))
        if trimx != 0:
            xslice = slice(trimx * xstride, -trimx * xstride, xstride)

        ystride = 1
        if self.config['general'].get('int1d_flipy', True):
            ystride = -1

        yslice = slice(None, None, ystride)
        trimy = int(self.config['general'].get('int1d_trimy', 0))
        if trimy > 0:
            yslice = slice(trimy * ystride, -trimy * ystride, ystride)

        img = img[yslice, xslice]

        img_id = self.ad_cam.ArrayCounter_RBV
        q, xi = self.integrator.integrate1d(img,
                                            2048,
                                            unit='q_A^-1',
                                            correctSolidAngle=True,
                                            polarization_factor=0.999)
        if init:
            self.int_panel.plot(q,
                                xi,
                                xlabel=r'$Q (\rm\AA^{-1})$',
                                marker='+',
                                title='Image %d' % img_id)
            self.int_panel.Raise()
            self.int_panel.Show()
        else:
            self.int_panel.update_line(0, q, xi, draw=True)
            self.int_panel.set_title('Image %d' % img_id)

    @EpicsFunction
    def onSaveImage(self, event=None):
        "prompts for and save image to file"
        defdir = os.getcwd()
        self.fname = "Image_%i.tiff" % self.ad_cam.ArrayCounter_RBV
        dlg = wx.FileDialog(None,
                            message='Save Image as',
                            defaultDir=os.getcwd(),
                            defaultFile=self.fname,
                            style=wx.FD_SAVE)
        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = os.path.abspath(dlg.GetPath())

        root, fname = os.path.split(path)
        epics.caput("%s%sFileName" % self.prefix, self.fsaver, fname)
        epics.caput("%s%sFileWriteMode" % self.prefix, self.fsaver, 0)
        time.sleep(0.05)
        epics.caput("%s%sWriteFile" % self.prefix, self.fsaver, 1)
        time.sleep(0.05)

        file_pv = "%s%sFullFileName_RBV" % (self.prefix, self.prefix)
        print("Saved image File ", epics.caget(file_pv, as_string=True))

    def onExit(self, event=None):
        try:
            wx.Yield()
        except:
            pass
        self.Destroy()

    def onAbout(self, event=None):
        msg = """areaDetector Display version 0.2
Matt Newville <*****@*****.**>"""

        dlg = wx.MessageDialog(self, msg, "About areaDetector Display",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def buildMenus(self):
        fmenu = wx.Menu()
        MenuItem(self, fmenu, "&Save\tCtrl+S", "Save Image", self.onSaveImage)
        MenuItem(self, fmenu, "&Copy\tCtrl+C", "Copy Image to Clipboard",
                 self.onCopyImage)
        MenuItem(self, fmenu, "Read Calibration File", "Read PONI Calibration",
                 self.onReadCalibFile)
        fmenu.AppendSeparator()
        MenuItem(self, fmenu, "E&xit\tCtrl+Q", "Exit Program", self.onExit)

        omenu = wx.Menu()
        MenuItem(self, omenu, "&Rotate CCW\tCtrl+R",
                 "Rotate Counter Clockwise", self.onRot90)
        MenuItem(self, omenu, "Flip Up/Down\tCtrl+T", "Flip Up/Down",
                 self.onFlipV)
        MenuItem(self, omenu, "Flip Left/Right\tCtrl+F", "Flip Left/Right",
                 self.onFlipH)
        MenuItem(self, omenu, "Reset Rotations and Flips", "Reset",
                 self.onResetRotFlips)
        omenu.AppendSeparator()

        hmenu = wx.Menu()
        MenuItem(self, hmenu, "About", "About areaDetector Display",
                 self.onAbout)

        mbar = wx.MenuBar()
        mbar.Append(fmenu, "File")
        mbar.Append(omenu, "Options")

        mbar.Append(hmenu, "&Help")
        self.SetMenuBar(mbar)

    def onResetRotFlips(self, event):
        self.image.rot90 = 0
        self.image.flipv = self.image.fliph = False

    def onRot90(self, event):
        self.image.rot90 = (self.image.rot90 - 1) % 4

    def onFlipV(self, event):
        self.image.flipv = not self.image.flipv

    def onFlipH(self, event):
        self.image.fliph = not self.image.fliph

    def set_contrast_level(self, contrast_level=0):
        self.image.contrast_levels = [contrast_level, 100.0 - contrast_level]
        self.image.Refresh()

    def write(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(text=s, number=panel)

    @EpicsFunction
    def onButton(self, event=None, key='free'):
        key = key.lower()
        if key.startswith('free'):
            ftime = self.config['general']['free_run_time']
            self.image.restart_fps_counter()
            self.ad_cam.AcquireTime = ftime
            self.ad_cam.AcquirePeriod = ftime
            self.ad_cam.NumImages = int((3 * 86400.) / ftime)
            self.ad_cam.Acquire = 1
        elif key.startswith('start'):
            self.image.restart_fps_counter()
            self.ad_cam.Acquire = 1
        elif key.startswith('stop'):
            self.ad_cam.Acquire = 0

    @EpicsFunction
    def connect_pvs(self, verbose=True):
        if self.prefix is None or len(self.prefix) < 2:
            return
        self.write('Connecting to areaDetector %s' % self.prefix)

        self.ad_img = epics.Device(self.prefix + 'image1:',
                                   delim='',
                                   attrs=self.img_attrs)
        self.ad_cam = epics.Device(self.prefix + 'cam1:',
                                   delim='',
                                   attrs=self.cam_attrs)

        if self.config['general']['use_filesaver']:
            epics.caput("%s%sEnableCallbacks" % (self.prefix, self.fsaver), 1)
            epics.caput("%s%sAutoSave" % (self.prefix, self.fsaver), 0)
            epics.caput("%s%sAutoIncrement" % (self.prefix, self.fsaver), 0)
            epics.caput("%s%sFileWriteMode" % (self.prefix, self.fsaver), 0)

        time.sleep(0.002)
        if not self.ad_img.PV('UniqueId_RBV').connected:
            epics.poll()
            if not self.ad_img.PV('UniqueId_RBV').connected:
                self.write('Warning: detector seems to not be connected!')
                return
        if verbose:
            self.write('Connected to detector %s' % self.prefix)

        self.SetTitle("Epics areaDetector Display: %s" % self.prefix)

        sizex = self.ad_cam.MaxSizeX_RBV
        sizey = self.ad_cam.MaxSizeY_RBV

        sizelabel = 'Image Size: %i x %i pixels'
        try:
            sizelabel = sizelabel % (sizex, sizey)
        except:
            sizelabel = sizelabel % (0, 0)

        self.imagesize.SetLabel(sizelabel)

        self.ad_cam.add_callback('DetectorState_RBV', self.onDetState)
        self.contrast.set_level_str('0.01')

    @DelayedEpicsCallback
    def onDetState(self, pvname=None, value=None, char_value=None, **kw):
        self.write(char_value, panel=0)
Example #14
0
class ADFrame(wx.Frame):
    """
    AreaDetector Display Frame
    """
    def __init__(self, configfile=None):
        wx.Frame.__init__(self, None, -1, 'AreaDetector Viewer',
                          style=wx.DEFAULT_FRAME_STYLE)

        if configfile is None:
            wcard = 'Detector Config Files (*.yaml)|*.yaml|All files (*.*)|*.*'
            configfile = FileOpen(self, "Read Detector Configuration File",
                                  default_file='det.yaml',
                                  wildcard=wcard)
        if configfile is None:
            sys.exit()

        self.config = read_adconfig(configfile)
        self.prefix = self.config['general']['prefix']
        self.fname = self.config['general']['name']
        self.colormode = self.config['general']['colormode'].lower()
        self.cam_attrs = self.config['cam_attributes']
        self.img_attrs = self.config['img_attributes']
        self.fsaver = self.config['general']['filesaver']

        self.SetTitle(self.config['general']['title'])
        self.scandb = None
        if ScanDB is not None:
            self.scandb = ScanDB()
            if self.scandb.engine is None: # not connected to running scandb server
                self.scandb = None

        self.calib = None
        self.ad_img = None
        self.ad_cam = None
        self.lineplotter = None
        self.integrator = None
        self.int_panel = None
        self.int_lastid = None
        self.contrast_levels = None
        self.thumbnail = None

        self.buildMenus()
        self.buildFrame()

    def buildFrame(self):
        self.SetFont(Font(11))

        sbar = self.CreateStatusBar(3, wx.CAPTION)
        self.SetStatusWidths([-1, -1, -1])
        self.SetStatusText('',0)

        sizer = wx.GridBagSizer(3, 3)
        panel = self.panel = wx.Panel(self)
        pvpanel = PVConfigPanel(panel, self.prefix, self.config['controls'])

        wsize = (100, -1)
        lsize = (250, -1)

        start_btn = wx.Button(panel, label='Start',    size=wsize)
        stop_btn  = wx.Button(panel, label='Stop',     size=wsize)
        start_btn.Bind(wx.EVT_BUTTON, partial(self.onButton, key='start'))
        stop_btn.Bind(wx.EVT_BUTTON,  partial(self.onButton, key='stop'))

        self.contrast = ContrastControl(panel, callback=self.set_contrast_level)
        self.imagesize = wx.StaticText(panel, label='? x ?',
                                       size=(150, 30), style=txtstyle)


        def lin(len=200, wid=2, style=wx.LI_HORIZONTAL):
            return wx.StaticLine(panel, size=(len, wid), style=style)

        irow = 0
        sizer.Add(pvpanel,  (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(start_btn, (irow, 0), (1, 1), labstyle)
        sizer.Add(stop_btn,  (irow, 1), (1, 1), labstyle)

        if self.config['general'].get('show_free_run', False):
            free_btn  = wx.Button(panel, label='Free Run', size=wsize)
            free_btn.Bind(wx.EVT_BUTTON,  partial(self.onButton, key='free'))
            irow += 1
            sizer.Add(free_btn,  (irow, 0), (1, 2), labstyle)

        irow += 1
        sizer.Add(lin(200, wid=4),  (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(self.imagesize, (irow, 0), (1, 3), labstyle)

        if self.colormode.startswith('mono'):
            self.cmap_choice = wx.Choice(panel, size=(80, -1),
                                         choices=self.config['colormaps'])
            self.cmap_choice.SetSelection(0)
            self.cmap_choice.Bind(wx.EVT_CHOICE,  self.onColorMap)
            self.cmap_reverse = wx.CheckBox(panel, label='Reverse', size=(60, -1))
            self.cmap_reverse.Bind(wx.EVT_CHECKBOX,  self.onColorMap)

            irow += 1
            sizer.Add(wx.StaticText(panel, label='Color Map: '),
                      (irow, 0), (1, 1), labstyle)

            sizer.Add(self.cmap_choice,  (irow, 1), (1, 1), labstyle)
            sizer.Add(self.cmap_reverse, (irow, 2), (1, 1), labstyle)

        irow += 1
        sizer.Add(self.contrast.label,  (irow, 0), (1, 1), labstyle)
        sizer.Add(self.contrast.choice, (irow, 1), (1, 1), labstyle)

        if self.config['general']['show_1dintegration']:
            self.show1d_btn = wx.Button(panel, label='Show 1D Integration',
                                         size=(200, -1))
            self.show1d_btn.Bind(wx.EVT_BUTTON, self.onShowIntegration)
            self.show1d_btn.Disable()
            irow += 1
            sizer.Add(self.show1d_btn, (irow, 0), (1, 2), labstyle)

        if self.config['general']['show_thumbnail']:
            t_size=self.config['general'].get('thumbnail_size', 100)

            self.thumbnail = ThumbNailImagePanel(panel, imgsize=t_size,
                                                 size=(350, 350),
                                                 motion_writer=partial(self.write, panel=0))

            label = wx.StaticText(panel, label='Thumbnail size (pixels): ',
                                       size=(200, -1), style=txtstyle)

            self.thumbsize = FloatSpin(panel, value=100, min_val=10, increment=5,
                                       action=self.onThumbSize,
                                       size=(150, -1), style=txtstyle)

            irow += 1
            sizer.Add(label,          (irow, 0), (1, 1), labstyle)
            sizer.Add(self.thumbsize, (irow, 1), (1, 1), labstyle)
            irow += 1
            sizer.Add(self.thumbnail, (irow, 0), (1, 2), labstyle)

        panel.SetSizer(sizer)
        sizer.Fit(panel)

        # image panel
        self.image = ADMonoImagePanel(self, prefix=self.prefix,
                                      rot90=self.config['general']['default_rotation'],
                                      size=(750, 750),
                                      writer=partial(self.write, panel=1),
                                      thumbnail=self.thumbnail,
                                      motion_writer=partial(self.write, panel=2))

        mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        mainsizer.Add(panel, 0, wx.LEFT|wx.GROW|wx.ALL)
        mainsizer.Add(self.image, 1, wx.CENTER|wx.GROW|wx.ALL)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.SetAutoLayout(True)
        iconfile = self.config['general'].get('iconfile', None)
        if iconfile is None or not os.path.exists(iconfile):
            iconfile = DEFAULT_ICONFILE
        try:
            self.SetIcon(wx.Icon(iconfile, wx.BITMAP_TYPE_ICO))
        except:
            pass
        self.connect_pvs()


    def onThumbSize(self, event=None):
        self.thumbnail.imgsize = int(self.thumbsize.GetValue())

    def onColorMap(self, event=None):
        cmap_name = self.cmap_choice.GetStringSelection()
        if self.cmap_reverse.IsChecked():
            cmap_name = cmap_name + '_r'
        self.image.colormap = getattr(colormap, cmap_name)
        self.image.Refresh()

    def onCopyImage(self, event=None):
        "copy bitmap of canvas to system clipboard"
        bmp = wx.BitmapDataObject()
        bmp.SetBitmap(wx.Bitmap(self.image.GrabWxImage()))
        wx.TheClipboard.Open()
        wx.TheClipboard.SetData(bmp)
        wx.TheClipboard.Close()
        wx.TheClipboard.Flush()

    def onReadCalibFile(self, event=None):
        "read calibration file"
        wcards = "Poni Files(*.poni)|*.poni|All files (*.*)|*.*"
        dlg = wx.FileDialog(None, message='Read Calibration File',
                            defaultDir=os.getcwd(),
                            wildcard=wcards,
                            style=wx.FD_OPEN)
        ppath = None
        if dlg.ShowModal() == wx.ID_OK:
            ppath = os.path.abspath(dlg.GetPath())

        if os.path.exists(ppath):
            self.setup_calibration(ppath)

    def setup_calibration(self, ponifile):
        """set up calibration from PONI file"""
        calib = read_poni(ponifile)
        # if self.image.rot90 in (1, 3):
        #     calib['rot3'] = np.pi/2.0
        self.calib = calib
        if HAS_PYFAI:
            self.integrator = AzimuthalIntegrator(**calib)
            self.show1d_btn.Enable()
        else:
            self.write('Warning: PyFAI is not installed')

        if self.scandb is not None:
            _, calname  = os.path.split(ponifile)
            self.scandb.set_detectorconfig(calname, json.dumps(calib))
            self.scandb.set_info('xrd_calibration', calname)

    def onShowIntegration(self, event=None):

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()

    def onAutoIntegration(self, event=None):
        if not event.IsChecked():
            self.int_timer.Stop()
            return

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()
        self.int_timer.Start(500)

    def show_1dpattern(self, init=False):
        if self.calib is None or not HAS_PYFAI:
            return

        img = self.ad_img.PV('ArrayData').get()

        h, w = self.image.GetImageSize()
        img.shape = (w, h)

        # may need to trim outer pixels (int1d_trimx/int1d_trimy in config)
        xstride = 1
        if self.config['general'].get('int1d_flipx', False):
            xstride = -1

        xslice = slice(None, None, xstride)
        trimx = int(self.config['general'].get('int1d_trimx', 0))
        if trimx != 0:
            xslice = slice(trimx*xstride, -trimx*xstride, xstride)

        ystride = 1
        if self.config['general'].get('int1d_flipy', True):
            ystride = -1

        yslice = slice(None, None, ystride)
        trimy = int(self.config['general'].get('int1d_trimy', 0))
        if trimy > 0:
            yslice = slice(trimy*ystride, -trimy*ystride, ystride)

        img = img[yslice, xslice]

        img_id = self.ad_cam.ArrayCounter_RBV
        q, xi = self.integrator.integrate1d(img, 2048, unit='q_A^-1',
                                            correctSolidAngle=True,
                                            polarization_factor=0.999)
        if init:
            self.int_panel.plot(q, xi, xlabel=r'$Q (\rm\AA^{-1})$', marker='+',
                                title='Image %d' % img_id)
            self.int_panel.Raise()
            self.int_panel.Show()
        else:
            self.int_panel.update_line(0, q, xi, draw=True)
            self.int_panel.set_title('Image %d' % img_id)

    @EpicsFunction
    def onSaveImage(self, event=None):
        "prompts for and save image to file"
        defdir = os.getcwd()
        self.fname = "Image_%i.tiff"  % self.ad_cam.ArrayCounter_RBV
        dlg = wx.FileDialog(None, message='Save Image as',
                            defaultDir=os.getcwd(),
                            defaultFile=self.fname,
                            style=wx.FD_SAVE)
        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = os.path.abspath(dlg.GetPath())


        root, fname = os.path.split(path)
        epics.caput("%s%sFileName" % self.prefix, self.fsaver, fname)
        epics.caput("%s%sFileWriteMode" % self.prefix, self.fsaver, 0)
        time.sleep(0.05)
        epics.caput("%s%sWriteFile" % self.prefix, self.fsaver, 1)
        time.sleep(0.05)

        file_pv = "%s%sFullFileName_RBV" % (self.prefix, self.prefix)
        print("Saved image File ", epics.caget(file_pv,  as_string=True))

    def onExit(self, event=None):
        try:
            wx.Yield()
        except:
            pass
        self.Destroy()

    def onAbout(self, event=None):
        msg =  """areaDetector Display version 0.2
Matt Newville <*****@*****.**>"""

        dlg = wx.MessageDialog(self, msg, "About areaDetector Display",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def buildMenus(self):
        fmenu = wx.Menu()
        MenuItem(self, fmenu, "&Save\tCtrl+S", "Save Image", self.onSaveImage)
        MenuItem(self, fmenu, "&Copy\tCtrl+C", "Copy Image to Clipboard",
                 self.onCopyImage)
        MenuItem(self, fmenu, "Read Calibration File", "Read PONI Calibration",
                 self.onReadCalibFile)
        fmenu.AppendSeparator()
        MenuItem(self, fmenu, "E&xit\tCtrl+Q",  "Exit Program", self.onExit)

        omenu = wx.Menu()
        MenuItem(self, omenu,  "&Rotate CCW\tCtrl+R", "Rotate Counter Clockwise", self.onRot90)
        MenuItem(self, omenu,  "Flip Up/Down\tCtrl+T", "Flip Up/Down", self.onFlipV)
        MenuItem(self, omenu,  "Flip Left/Right\tCtrl+F", "Flip Left/Right", self.onFlipH)
        MenuItem(self, omenu,  "Reset Rotations and Flips", "Reset", self.onResetRotFlips)
        omenu.AppendSeparator()

        hmenu = wx.Menu()
        MenuItem(self, hmenu, "About", "About areaDetector Display", self.onAbout)

        mbar = wx.MenuBar()
        mbar.Append(fmenu, "File")
        mbar.Append(omenu, "Options")

        mbar.Append(hmenu, "&Help")
        self.SetMenuBar(mbar)

    def onResetRotFlips(self, event):
        self.image.rot90 = 0
        self.image.flipv = self.image.fliph = False

    def onRot90(self, event):
        self.image.rot90 = (self.image.rot90 - 1) % 4

    def onFlipV(self, event):
        self.image.flipv= not self.image.flipv

    def onFlipH(self, event):
        self.image.fliph = not self.image.fliph

    def set_contrast_level(self, contrast_level=0):
        self.image.contrast_levels = [contrast_level, 100.0-contrast_level]
        self.image.Refresh()

    def write(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(text=s, number=panel)

    @EpicsFunction
    def onButton(self, event=None, key='free'):
        key = key.lower()
        if key.startswith('free'):
            ftime = self.config['general']['free_run_time']
            self.image.restart_fps_counter()
            self.ad_cam.AcquireTime   = ftime
            self.ad_cam.AcquirePeriod = ftime
            self.ad_cam.NumImages = int((3*86400.)/ftime)
            self.ad_cam.Acquire = 1
        elif key.startswith('start'):
            self.image.restart_fps_counter()
            self.ad_cam.Acquire = 1
        elif key.startswith('stop'):
            self.ad_cam.Acquire = 0

    @EpicsFunction
    def connect_pvs(self, verbose=True):
        if self.prefix is None or len(self.prefix) < 2:
            return
        self.write('Connecting to areaDetector %s' % self.prefix)

        self.ad_img = epics.Device(self.prefix + 'image1:', delim='',
                                   attrs=self.img_attrs)
        self.ad_cam = epics.Device(self.prefix + 'cam1:', delim='',
                                   attrs=self.cam_attrs)

        if self.config['general']['use_filesaver']:
            epics.caput("%s%sEnableCallbacks" % (self.prefix, self.fsaver), 1)
            epics.caput("%s%sAutoSave" % (self.prefix, self.fsaver), 0)
            epics.caput("%s%sAutoIncrement" % (self.prefix, self.fsaver), 0)
            epics.caput("%s%sFileWriteMode" % (self.prefix, self.fsaver), 0)

        time.sleep(0.002)
        if not self.ad_img.PV('UniqueId_RBV').connected:
            epics.poll()
            if not self.ad_img.PV('UniqueId_RBV').connected:
                self.write('Warning: detector seems to not be connected!')
                return
        if verbose:
            self.write('Connected to detector %s' % self.prefix)

        self.SetTitle("Epics areaDetector Display: %s" % self.prefix)

        sizex = self.ad_cam.MaxSizeX_RBV
        sizey = self.ad_cam.MaxSizeY_RBV

        sizelabel = 'Image Size: %i x %i pixels'
        try:
            sizelabel = sizelabel  % (sizex, sizey)
        except:
            sizelabel = sizelabel  % (0, 0)

        self.imagesize.SetLabel(sizelabel)

        self.ad_cam.add_callback('DetectorState_RBV',  self.onDetState)
        self.contrast.set_level_str('0.01')

    @DelayedEpicsCallback
    def onDetState(self, pvname=None, value=None, char_value=None, **kw):
        self.write(char_value, panel=0)
Example #15
0
    def onProfile(self, x0, y0, x1, y1):
        width  = self.ad_cam.SizeX
        height = self.ad_cam.SizeY

        x0, y0 = int(x0 * width), int(y0 * height)
        x1, y1 = int(x1 * width), int(y1 * height)
        dx, dy = abs(x1 - x0), abs(y1 - y0)

        if dx < 2 and dy < 2:
            return
        outdat = []
        if self.colormode == 2:
            self.data.shape = (self.im_size[1], self.im_size[0], 3)
        else:
            self.data.shape = self.im_size[1], self.im_size[0]

        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))

        if self.lineplotter is None:
            self.lineplotter = PlotFrame(self, title='Image Profile')
        else:
            try:
                self.lineplotter.Raise()
            except PyDeadObjectError:
                self.lineplotter = PlotFrame(self, title='Image Profile')

        if self.colormode == 2:
            x, y, r, g, b = [], [], [], [], []
            for ix, iy in outdat:
                x.append(ix)
                y.append(iy)
                r.append(self.data[iy,ix,0])
                g.append(self.data[iy,ix,1])
                b.append(self.data[iy,ix,2])
            xlabel = 'Pixel (x)'
            if dy > dx:
                x = y
                xlabel = 'Pixel (y)'
            self.lineplotter.plot(x,  r, color='red', label='red',
                                  xlabel=xlabel, ylabel='Intensity',
                                  title='Image %i' % self.ad_cam.ArrayCounter_RBV)
            self.lineplotter.oplot(x, g, color='green', label='green')
            self.lineplotter.oplot(x, b, color='blue', label='blue')

        else:
            x, y, z = [], [], []
            for ix, iy in outdat:
                x.append(ix)
                y.append(iy)
                z.append(self.data[iy,ix])
            xlabel = 'Pixel (x)'
            if dy > dx:
                x = y
            xlabel = 'Pixel (y)'
            self.lineplotter.plot(x, z, color='k',
                                  xlabel=xlabel, ylabel='Intensity',
                                  title='Image %i' % self.ad_cam.ArrayCounter_RBV)
        self.lineplotter.Show()
        self.lineplotter.Raise()
Example #16
0
class AD_Display(wx.Frame):
    """AreaDetector Display """
    img_attrs = ('ArrayData', 'UniqueId_RBV', 'NDimensions_RBV',
                 'ArraySize0_RBV', 'ArraySize1_RBV', 'ArraySize2_RBV',
                 'ColorMode_RBV')

    cam_attrs = ('Acquire', 'ArrayCounter', 'ArrayCounter_RBV',
                 'DetectorState_RBV',  'NumImages', 'ColorMode',
                 'DataType_RBV',  'Gain',
                 'AcquireTime', 'AcquirePeriod', 'ImageMode',
                 'MaxSizeX_RBV', 'MaxSizeY_RBV', 'TriggerMode',
                 'SizeX', 'SizeY', 'MinX', 'MinY')

    # plugins to enable
    enabled_plugins = ('image1', 'Over1', 'ROI1', 'JPEG1', 'TIFF1')

    stat_msg = 'Read %.1f%% of images: rate=%.1f frames/sec'

    def __init__(self, prefix=None, app=None, scale=1.0, approx_height=1200,
                 known_cameras=None):
        self.app = app
        self.ad_img = None
        self.ad_cam = None
        self.imgcount = 0
        self.prefix = prefix
        self.fname = 'AD_Image.tiff'
        self.scale  = scale
        self.known_cameras = known_cameras
        self.arrsize  = [0,0,0]
        self.imbuff = None
        self.d_size = None
        self.im_size = None
        self.colormode = 0
        self.last_update = 0.0
        self.n_img   = 0
        self.imgcount_start = 0
        self.n_drawn = 0
        self.img_id = 0
        self.starttime = time.time()
        self.drawing = False
        self.lineplotter = None
        self.zoom_lims = []

        wx.Frame.__init__(self, None, -1, "Epics Area Detector Display",
                          style=wx.DEFAULT_FRAME_STYLE)

        if known_cameras is not None:
            self.ConnectToCamera(name=self.prefix)
        else:
            self.ConnectToPV(name=self.prefix)

        self.img_w = 0
        self.img_h = 0
        self.wximage = wx.EmptyImage(1024, 1360) # 1360, 1024) # approx_height, 1.5*approx_height)
        self.buildMenus()
        self.buildFrame()

    def OnLeftUp(self, event):
        if self.image is not None:
            self.image.OnLeftUp(event)

    def ConnectToCamera(self, name=None, event=None):
        if name is None:
            name = ''
        if self.known_cameras is None:
            return
        cam_names = self.known_cameras.keys()
        cam_names.sort()
        dlg = wx.SingleChoiceDialog(self, 'Select Camera',
                                    caption='Select Camera',
                                    choices=cam_names)
        dlg.Raise()
        if dlg.ShowModal() == wx.ID_OK:
            cname = dlg.GetStringSelection()
            if cname in self.known_cameras:
                self.prefix = self.known_cameras[cname]
            wx.CallAfter(self.connect_pvs)
        dlg.Destroy()

    def ConnectToPV(self, event=None, name=None):
        print 'Connect To PV ', name , event
        if name is None:
            name = ''
        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:
            self.prefix = dlg.GetValue()
            wx.CallAfter(self.connect_pvs)
        dlg.Destroy()

    def onCopyImage(self, event=None):
        "copy bitmap of canvas to system clipboard"
        bmp = wx.BitmapDataObject()
        bmp.SetBitmap(wx.BitmapFromImage(self.wximage))
        wx.TheClipboard.Open()
        wx.TheClipboard.SetData(bmp)
        wx.TheClipboard.Close()
        wx.TheClipboard.Flush()

    @EpicsFunction
    def CameraOff(self):
        try:
            self.ad_cam.Acquire = 0
        except:
            pass


    @EpicsFunction
    def onSaveImage(self, event=None):
        "prompts for and save image to file"
        defdir = os.getcwd()
        self.fname = "Image_%i.tiff"  % self.ad_cam.ArrayCounter_RBV
        dlg = wx.FileDialog(None, message='Save Image as',
                            defaultDir=os.getcwd(),
                            defaultFile=self.fname,
                            style=wx.SAVE)
        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = os.path.abspath(dlg.GetPath())

        dlg.Destroy()
        if path is not None and self.data is not None:
            Image.frombuffer(self.im_mode, self.im_size, self.data.flatten(),
                             'raw', self.im_mode, 0, 1).save(path)

    def onExit(self, event=None):
        try:
            wx.Yield()
        except:
            pass
        self.CameraOff()
        self.Destroy()

    def onAbout(self, event=None):
        msg =  """Epics Image Display version 0.2

http://pyepics.github.com/epicsapps/

Matt Newville <*****@*****.**>"""

        dlg = wx.MessageDialog(self, msg, "About Epics Image Display",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def buildMenus(self):
        fmenu = wx.Menu()
        add_menu(self, fmenu, "&Connect to Pre-defiend Camera", "Connect to PV", self.ConnectToCamera)
        add_menu(self, fmenu, "&Connect to AreaDetector PV\tCtrl+O", "Connect to PV", self.ConnectToPV)
        add_menu(self, fmenu, "&Save\tCtrl+S", "Save Image", self.onSaveImage)
        add_menu(self, fmenu, "&Copy\tCtrl+C", "Copy Image to Clipboard", self.onCopyImage)
        fmenu.AppendSeparator()
        add_menu(self, fmenu, "E&xit\tCtrl+Q",  "Exit Program", self.onExit)

        omenu = wx.Menu()
        add_menu(self, omenu, "&Zoom out\tCtrl+Z", "Zoom Out", self.unZoom)
        add_menu(self, omenu, "Reset Image Counter", "Set Image Counter to 0", self.onResetImageCounter)
        omenu.AppendSeparator()
        add_menu(self, omenu,  "&Rotate Clockwise\tCtrl+R", "Rotate Clockwise", self.onRotCW)
        add_menu(self, omenu,  "Rotate CounterClockwise", "Rotate Counter Clockwise", self.onRotCCW)
        add_menu(self, omenu,  "Flip Up/Down\tCtrl+T", "Flip Up/Down", self.onFlipV)
        add_menu(self, omenu,  "Flip Left/Right\tCtrl+F", "Flip Left/Right", self.onFlipH)
        omenu.AppendSeparator()

        self.CM_ZOOM = wx.NewId()
        self.CM_SHOW = wx.NewId()
        self.CM_PROF = wx.NewId()
        omenu.Append(self.CM_ZOOM, "Cursor Mode: Zoom to Box\tCtrl+B" ,
                     "Zoom to box by clicking and dragging", wx.ITEM_RADIO)
        omenu.Append(self.CM_SHOW, "Cursor Mode: Show X,Y\tCtrl+X",
                     "Show X,Y, Intensity Values",  wx.ITEM_RADIO)
        omenu.Append(self.CM_PROF, "Cursor Mode: Line Profile\tCtrl+L",
                     "Show Line Profile",  wx.ITEM_RADIO)
        self.Bind(wx.EVT_MENU, self.onCursorMode,  id=self.CM_ZOOM)
        self.Bind(wx.EVT_MENU, self.onCursorMode,  id=self.CM_PROF)
        self.Bind(wx.EVT_MENU, self.onCursorMode,  id=self.CM_SHOW)

        hmenu = wx.Menu()
        add_menu(self, hmenu, "About", "About Epics AreadDetector Display", self.onAbout)

        mbar = wx.MenuBar()
        mbar.Append(fmenu, "File")
        mbar.Append(omenu, "Options")
        mbar.Append(hmenu, "&Help")
        self.SetMenuBar(mbar)

    def onCursorMode(self, event=None):
        if event.Id == self.CM_ZOOM:
            self.image.cursor_mode = 'zoom'
        elif event.Id == self.CM_PROF:
            self.image.cursor_mode = 'profile'
        elif event.Id == self.CM_SHOW:
            self.image.cursor_mode = 'show'

    @DelayedEpicsCallback
    def onResetImageCounter(self, event=None):
        self.ad_cam.ArrayCounter = 0

    def onRotCW(self, event):
        self.image.rot90 = (self.image.rot90 + 1) % 4
        self.image.Refresh()

    def onRotCCW(self, event):
        self.image.rot90 = (self.image.rot90 - 1) % 4
        self.image.Refresh()

    def onFlipV(self, event):
        self.image.flipv= not self.image.flipv
        self.image.Refresh()

    def onFlipH(self, event):
        self.image.fliph = not self.image.fliph
        self.image.Refresh()

    def buildFrame(self):
        sbar = self.CreateStatusBar(3, wx.CAPTION|wx.THICK_FRAME)
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(10)
        sbar.SetFont(sfont)

        self.SetStatusWidths([-3, -1, -1])
        self.SetStatusText('',0)

        sizer = wx.GridBagSizer(10, 4)
        panel = wx.Panel(self)
        self.panel = panel
        labstyle = wx.ALIGN_LEFT|wx.ALIGN_BOTTOM|wx.EXPAND
        ctrlstyle = wx.ALIGN_LEFT|wx.ALIGN_BOTTOM

        rlabstyle = wx.ALIGN_RIGHT|wx.RIGHT|wx.TOP|wx.EXPAND

        txtstyle=wx.ALIGN_LEFT|wx.ST_NO_AUTORESIZE|wx.TE_PROCESS_ENTER
        self.wids = {}
        self.wids['exptime']   = PVFloatCtrl(panel, pv=None, size=(100, -1))
        self.wids['period']    = PVFloatCtrl(panel, pv=None, size=(100, -1))
        self.wids['numimages'] = PVFloatCtrl(panel, pv=None, size=(100, -1))
        self.wids['gain']      = PVFloatCtrl(panel, pv=None, size=(100, -1),
                                             minval=0, maxval=20)

        self.wids['imagemode']   = PVEnumChoice(panel, pv=None, size=(100, -1))
        self.wids['triggermode'] = PVEnumChoice(panel, pv=None, size=(100, -1))
        self.wids['color']       = PVEnumChoice(panel, pv=None, size=(100, -1))
        self.wids['start']       = wx.Button(panel, -1, label='Start', size=(50, -1))
        self.wids['stop']        = wx.Button(panel, -1, label='Stop', size=(50,  -1))

        if HAS_OVERLAY_DEVICE:
            self.wids['o1color']  = csel.ColourSelect(panel,  -1, "", '#FEFEFE', size=(60, 25))
            self.wids['o1color'].Bind(csel.EVT_COLOURSELECT, Closure(self.onColor, item=1))
            self.wids['o1posx']  = PVFloatCtrl(panel, pv=None, size=(50, -1), minval=0)
            self.wids['o1posy']  = PVFloatCtrl(panel, pv=None, size=(50, -1), minval=0)
            self.wids['o1sizx']  = PVFloatCtrl(panel, pv=None, size=(50, -1), minval=0)
            self.wids['o1sizy']  = PVFloatCtrl(panel, pv=None, size=(50, -1), minval=0)
            self.wids['o1shape']  = PVEnumChoice(panel, pv=None, size=(100, -1))
            self.wids['o1use']    = PVEnumChoice(panel, pv=None, size=(50, -1))
            self.wids['o1name']  = PVTextCtrl(panel, pv=None, size=(100, -1))

            self.wids['o2color']  = csel.ColourSelect(panel,  -1, "", '#FEFEFE', size=(60, 25))
            self.wids['o2color'].Bind(csel.EVT_COLOURSELECT, Closure(self.onColor, item=2))
            self.wids['o2posx']  = PVFloatCtrl(panel, pv=None, size=(50, -1), minval=0)
            self.wids['o2posy']  = PVFloatCtrl(panel, pv=None, size=(50, -1), minval=0)
            self.wids['o2sizx']  = PVFloatCtrl(panel, pv=None, size=(50, -1), minval=0)
            self.wids['o2sizy']  = PVFloatCtrl(panel, pv=None, size=(50, -1), minval=0)
            self.wids['o2shape']  = PVEnumChoice(panel, pv=None, size=(100, -1))
            self.wids['o2use']    = PVEnumChoice(panel, pv=None, size=(50, -1))
            self.wids['o2name']  = PVTextCtrl(panel, pv=None, size=(100, -1))

        for key in ('start', 'stop'):
            self.wids[key].Bind(wx.EVT_BUTTON, Closure(self.onEntry, key=key))

        self.wids['zoomsize']= wx.StaticText(panel, -1,  size=(250,-1), style=txtstyle)
        self.wids['fullsize']= wx.StaticText(panel, -1,  size=(250,-1), style=txtstyle)

        def txt(label, size=100):
            return wx.StaticText(panel, label=label, size=(size, -1), style=labstyle)

        def lin(len=30, wid=2, style=wx.LI_HORIZONTAL):
            return wx.StaticLine(panel, size=(len, wid), style=style)

        sizer.Add(txt(' '),                 (0, 0), (1, 1), labstyle)
        sizer.Add(txt('Image Mode '),       (1, 0), (1, 1), labstyle)
        sizer.Add(self.wids['imagemode'],   (1, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('# Images '),         (2, 0), (1, 1), labstyle)
        sizer.Add(self.wids['numimages'],   (2, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Trigger Mode '),     (3, 0), (1, 1), labstyle)
        sizer.Add(self.wids['triggermode'], (3, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Period '),           (4, 0), (1, 1), labstyle)
        sizer.Add(self.wids['period'],      (4, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Exposure Time '),    (5, 0), (1, 1), labstyle)
        sizer.Add(self.wids['exptime'],     (5, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Gain '),             (6, 0), (1, 1), labstyle)
        sizer.Add(self.wids['gain'],        (6, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Color Mode'),        (7, 0), (1, 1), labstyle)
        sizer.Add(self.wids['color'],       (7, 1), (1, 2), ctrlstyle)

        sizer.Add(txt('Acquire '),          (9, 0), (1, 1), labstyle)

        sizer.Add(self.wids['start'],       (9, 1), (1, 1), ctrlstyle)
        sizer.Add(self.wids['stop'],        (9, 2), (1, 1), ctrlstyle)

        sizer.Add(self.wids['fullsize'],    (12, 0), (1, 3), labstyle)
        sizer.Add(self.wids['zoomsize'],    (13, 0), (1, 3), labstyle)

        sizer.Add(lin(75),                 (15, 0), (1, 3), labstyle)

        if HAS_OVERLAY_DEVICE:
            ir = 16
            sizer.Add(txt('Overlay 1:'),        (ir+0, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1use'],       (ir+0, 1), (1, 2), ctrlstyle)
            sizer.Add(txt('Shape:'),            (ir+1, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1shape'],     (ir+1, 1), (1, 2), ctrlstyle)
            sizer.Add(txt('Name:'),             (ir+2, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1name'],      (ir+2, 1), (1, 2), ctrlstyle)

            sizer.Add(txt('Position '),         (ir+3, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1posx'],      (ir+3, 1), (1, 1), ctrlstyle)
            sizer.Add(self.wids['o1posy'],      (ir+3, 2), (1, 1), ctrlstyle)
            sizer.Add(txt('Size '),             (ir+4, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1sizx'],      (ir+4, 1), (1, 1), ctrlstyle)
            sizer.Add(self.wids['o1sizy'],      (ir+4, 2), (1, 1), ctrlstyle)
            sizer.Add(txt('Color '),            (ir+5, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o1color'],     (ir+5, 1), (1, 2), ctrlstyle)
            sizer.Add(lin(75),                  (ir+6, 0), (1, 3), labstyle)

            ir = ir + 7
            sizer.Add(txt('Overlay 1:'),        (ir+0, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2use'],       (ir+0, 1), (1, 2), ctrlstyle)
            sizer.Add(txt('Shape:'),            (ir+1, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2shape'],     (ir+1, 1), (1, 2), ctrlstyle)
            sizer.Add(txt('Name:'),             (ir+2, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2name'],      (ir+2, 1), (1, 2), ctrlstyle)

            sizer.Add(txt('Position '),         (ir+3, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2posx'],      (ir+3, 1), (1, 1), ctrlstyle)
            sizer.Add(self.wids['o2posy'],      (ir+3, 2), (1, 1), ctrlstyle)
            sizer.Add(txt('Size '),             (ir+4, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2sizx'],      (ir+4, 1), (1, 1), ctrlstyle)
            sizer.Add(self.wids['o2sizy'],      (ir+4, 2), (1, 1), ctrlstyle)
            sizer.Add(txt('Color '),            (ir+5, 0), (1, 1), labstyle)
            sizer.Add(self.wids['o2color'],     (ir+5, 1), (1, 2), ctrlstyle)
            sizer.Add(lin(75),                  (ir+6, 0), (1, 3), labstyle)

        self.image = ImageView(self, size=(1360, 1024), onzoom=self.onZoom,
                               onprofile=self.onProfile, onshow=self.onShowXY)

        panel.SetSizer(sizer)
        sizer.Fit(panel)

        mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        mainsizer.Add(panel, 0, wx.LEFT|wx.GROW|wx.ALL, 5)
        mainsizer.Add(self.image, 1, wx.CENTER|wx.GROW|wx.ALL, 5)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.SetAutoLayout(True)

        try:
            self.SetIcon(wx.Icon(ICON_FILE, wx.BITMAP_TYPE_ICO))
        except:
            pass

        self.RefreshImage()
        wx.CallAfter(self.connect_pvs )

    def messag(self, s, panel=0):
        """write a message to the Status Bar"""
        wx.CallAfter(Closure(self.SetStatusText, text=s, number=panel))
        # self.SetStatusText(s, panel)

    @EpicsFunction
    def unZoom(self, event=None, full=False):
        if self.zoom_lims is None or full:
            self.zoom_lims = []

        if len(self.zoom_lims) == 0:
            xmin, ymin = 0, 0
            width  = self.ad_cam.MaxSizeX_RBV
            height = self.ad_cam.MaxSizeY_RBV
            self.zoom_lims = []
        else:
            xmin, ymin, width, height = self.zoom_lims.pop()
            if (self.ad_cam.MinX == xmin and
                self.ad_cam.MinY == ymin and
                self.ad_cam.SizeX == width and
                self.ad_cam.SizeY == height):
                try:
                    xmin, ymin, width, height = self.zoom_lims.pop()
                except:
                    xmin, ymin = 0, 0
                    width = self.ad_cam.MaxSizeX_RBV
                    height = self.ad_cam.MaxSizeY_RBV

        self.ad_cam.MinX  = xmin
        self.ad_cam.MinY  = ymin
        self.ad_cam.SizeX = width
        self.ad_cam.SizeY = height
        self.zoom_lims.append((xmin, ymin, width, height))
        time.sleep(0.05)
        self.showZoomsize()
        if self.ad_cam.Acquire == 0 and self.im_size is not None:
            self.img_w = width
            self.img_h = height
            try:
                if self.colormode == 2:
                    self.data.shape = [self.im_size[1], self.im_size[0], 3]
                    zdata = self.data[ymin:ymin+height, xmin:xmin+width,:]
                else:
                    self.data.shape = self.im_size[1], self.im_size[0]
                    zdata = self.data[ymin:ymin+height,xmin:xmin+width]
            except ValueError:
                pass
            self.data = zdata #self.data.flatten()
            self.im_size = (width, height)
            # print zdata.shape, width, height, self.im_mode
            self.DatatoImage()   # zdata, (width, height), self.im_mode)

        self.RefreshImage()
        self.image.Refresh()

    @EpicsFunction
    def onColor(self, event=None, item=None):
        if HAS_OVERLAY_DEVICE:
            color = event.GetValue()
            over = self.ad_overlays[item-1]
            over.Red = color[0]
            over.Green = color[1]
            over.Blue = color[2]

    @EpicsFunction
    def showZoomsize(self):
        try:
            msg  = 'Showing:  %i x %i pixels' % (self.ad_cam.SizeX, self.ad_cam.SizeY)
            self.wids['zoomsize'].SetLabel(msg)
        except:
            pass

    @EpicsFunction
    def onZoom(self, x0, y0, x1, y1):
        width  = self.ad_cam.SizeX
        height = self.ad_cam.SizeY
        xmin   = max(0, int(self.ad_cam.MinX  + x0 * width))
        ymin   = max(0, int(self.ad_cam.MinY  + y0 * height))

        width  = int(x1 * width)
        height = int(y1 * height)
        if width < 2 or height < 2:
            return
        self.ad_cam.MinX = xmin
        self.ad_cam.MinY = ymin
        self.ad_cam.SizeX = width
        self.ad_cam.SizeY = height
        if self.zoom_lims is None:
            self.zoom_lims = []
        self.zoom_lims.append((xmin, ymin, width, height))

        time.sleep(0.05)
        self.showZoomsize()

        if self.ad_cam.Acquire == 0:
            self.img_w = width
            self.img_h = height
            if self.colormode == 2:
                self.data.shape = [self.im_size[1], self.im_size[0], 3]
                zdata = self.data[ymin:ymin+height, xmin:xmin+width,:]
            else:
                self.data.shape = self.im_size[1], self.im_size[0]
                zdata = self.data[ymin:ymin+height,xmin:xmin+width]
            self.data = zdata #. flatten()
            self.im_size = (width, height)
            self.DatatoImage()
        self.image.Refresh()

    def DatatoImage(self):  #,  data, size, mode):
        """convert raw data to image"""
        #x = debugtime()

        width, height = self.im_size
        d_size = (int(width*self.scale), int(height*self.scale))
        data = self.data.flatten()
        #x.add('flatten')
        if self.imbuff is None or d_size != self.d_size or self.im_mode == 'L':
            try:
                self.imbuff =  Image.frombuffer(self.im_mode, self.im_size, data,
                                                'raw',  self.im_mode, 0, 1)
                #x.add('made image')
            except:
                return
        self.d_size = d_size = (int(width*self.scale), int(height*self.scale))
        if self.imbuff.size != d_size:
            self.imbuff = self.imbuff.resize(d_size)
            #x.add('resized imbuff')

        if self.wximage.GetSize() != self.imbuff.size:
            self.wximage = wx.EmptyImage(d_size[0], d_size[1])
        #x.add('created wximage %s  ' % (repr(self.wximage.GetSize())))
        if self.im_mode == 'L':
            self.wximage.SetData(self.imbuff.convert('RGB').tostring())
        elif self.im_mode == 'RGB':
            data.shape = (3, width, height)
            self.wximage = wx.ImageFromData(width, height, data)
        #x.add('set wx image wximage : %i, %i ' % d_size)
        self.image.SetValue(self.wximage)
        #x.add('set image value')
        #x.show()


    def onProfile(self, x0, y0, x1, y1):
        width  = self.ad_cam.SizeX
        height = self.ad_cam.SizeY

        x0, y0 = int(x0 * width), int(y0 * height)
        x1, y1 = int(x1 * width), int(y1 * height)
        dx, dy = abs(x1 - x0), abs(y1 - y0)

        if dx < 2 and dy < 2:
            return
        outdat = []
        if self.colormode == 2:
            self.data.shape = (self.im_size[1], self.im_size[0], 3)
        else:
            self.data.shape = self.im_size[1], self.im_size[0]

        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))

        if self.lineplotter is None:
            self.lineplotter = PlotFrame(self, title='Image Profile')
        else:
            try:
                self.lineplotter.Raise()
            except PyDeadObjectError:
                self.lineplotter = PlotFrame(self, title='Image Profile')

        if self.colormode == 2:
            x, y, r, g, b = [], [], [], [], []
            for ix, iy in outdat:
                x.append(ix)
                y.append(iy)
                r.append(self.data[iy,ix,0])
                g.append(self.data[iy,ix,1])
                b.append(self.data[iy,ix,2])
            xlabel = 'Pixel (x)'
            if dy > dx:
                x = y
                xlabel = 'Pixel (y)'
            self.lineplotter.plot(x,  r, color='red', label='red',
                                  xlabel=xlabel, ylabel='Intensity',
                                  title='Image %i' % self.ad_cam.ArrayCounter_RBV)
            self.lineplotter.oplot(x, g, color='green', label='green')
            self.lineplotter.oplot(x, b, color='blue', label='blue')

        else:
            x, y, z = [], [], []
            for ix, iy in outdat:
                x.append(ix)
                y.append(iy)
                z.append(self.data[iy,ix])
            xlabel = 'Pixel (x)'
            if dy > dx:
                x = y
            xlabel = 'Pixel (y)'
            self.lineplotter.plot(x, z, color='k',
                                  xlabel=xlabel, ylabel='Intensity',
                                  title='Image %i' % self.ad_cam.ArrayCounter_RBV)
        self.lineplotter.Show()
        self.lineplotter.Raise()

    def onShowXY(self, xval, yval):
        ix  = max(0, int( xval * self.ad_cam.SizeX))
        iy  = max(0, int( yval * self.ad_cam.SizeY))

        if self.colormode == 2:
            self.data.shape = (self.im_size[1], self.im_size[0], 3)
            ival = tuple(self.data[iy, ix, :])
            smsg  = 'Pixel %i, %i, (R, G, B) = %s' % (ix, iy, repr(ival))
        else:
            self.data.shape = self.im_size[1], self.im_size[0]
            ival = self.data[iy, ix]
            smsg  = 'Pixel %i, %i, Intensity = %i' % (ix, iy, ival)

        self.messag(smsg, panel=1)


    def onName(self, evt=None, **kws):
        if evt is None:
            return
        s = evt.GetString()
        s = str(s).strip()
        if s.endswith(':image1:'): s = s[:-8]
        if s.endswith(':cam1:'):   s = s[:-6]
        if s.endswith(':'):   s = s[:-1]
        self.prefix = s
        self.connect_pvs()

    @EpicsFunction
    def onEntry(self, evt=None, key='name', **kw):
        if evt is None:
            return
        if key == 'start':
            self.n_img   = 0
            self.n_drawn = 0
            self.starttime = time.time()
            self.imgcount_start = self.ad_cam.ArrayCounter_RBV
            self.ad_cam.Acquire = 1
        elif key == 'stop':
            self.ad_cam.Acquire = 0
        elif key == 'unzoom':
            self.unZoom()
        else:
            print 'unknown Entry ? ', key

    @EpicsFunction
    def connect_pvs(self, verbose=True):
        if self.prefix is None or len(self.prefix) < 2:
            return

        try:
            self.ad_cam.Acquire = 0
        except:
            pass

        if self.prefix.endswith(':'):
            self.prefix = self.prefix[:-1]
        if self.prefix.endswith(':image1'):
            self.prefix = self.prefix[:-7]
        if self.prefix.endswith(':cam1'):
            self.prefix = self.prefix[:-5]

        if verbose:
            self.messag('Connecting to AD %s' % self.prefix)
        self.ad_img = epics.Device(self.prefix + ':image1:', delim='',
                                   attrs=self.img_attrs)
        self.ad_cam = epics.Device(self.prefix + ':cam1:', delim='',
                                   attrs=self.cam_attrs)
        self.ad_overlays = []
        if HAS_OVERLAY_DEVICE:
            for ix in (1, 2):
                pvn ='%s:Over1:%i:' % (self.prefix, ix)
                self.ad_overlays.append(AD_OverlayPlugin(pvn))

        time.sleep(0.010)
        if not self.ad_img.PV('UniqueId_RBV').connected:
            epics.poll()
            if not self.ad_img.PV('UniqueId_RBV').connected:
                self.messag('Warning:  Camera seems to not be connected!')
                return
        if verbose:
            self.messag('Connected to AD %s' % self.prefix)

        self.SetTitle("Epics Image Display: %s" % self.prefix)

        self.wids['color'].SetPV(self.ad_cam.PV('ColorMode'))
        self.wids['exptime'].SetPV(self.ad_cam.PV('AcquireTime'))
        self.wids['period'].SetPV(self.ad_cam.PV('AcquirePeriod'))
        self.wids['gain'].SetPV(self.ad_cam.PV('Gain'))
        self.wids['numimages'].SetPV(self.ad_cam.PV('NumImages'))
        self.wids['imagemode'].SetPV(self.ad_cam.PV('ImageMode'))
        self.wids['triggermode'].SetPV(self.ad_cam.PV('TriggerMode'))

        sizex = self.ad_cam.MaxSizeX_RBV
        sizey = self.ad_cam.MaxSizeY_RBV

        if HAS_OVERLAY_DEVICE:
            over = self.ad_overlays[0]
            c1 = (over.Red, over.Green, over.Blue)
            self.wids['o1color'].SetColour(hexcolor(c1))
            self.wids['o1posx'].SetPV(over.PV('PositionX'))
            self.wids['o1posx'].SetMax(sizex)
            self.wids['o1posy'].SetPV(over.PV('PositionY'))
            self.wids['o1posy'].SetMax(sizey)
            self.wids['o1sizx'].SetPV(over.PV('SizeX'))
            self.wids['o1sizx'].SetMax(sizex)
            self.wids['o1sizy'].SetPV(over.PV('SizeY'))
            self.wids['o1sizy'].SetMax(sizey)
            self.wids['o1shape'].SetPV(over.PV('Shape'))
            self.wids['o1name'].SetPV(over.PV('Name'))
            self.wids['o1use'].SetPV(over.PV('Use'))

            over = self.ad_overlays[1]
            c1 = (over.Red, over.Green, over.Blue)
            self.wids['o2color'].SetColour(hexcolor(c1))
            self.wids['o2posx'].SetPV(over.PV('PositionX'))
            self.wids['o2posx'].SetMax(sizex)
            self.wids['o2posy'].SetPV(over.PV('PositionY'))
            self.wids['o2posy'].SetMax(sizey)
            self.wids['o2sizx'].SetPV(over.PV('SizeX'))
            self.wids['o2sizx'].SetMax(sizex)
            self.wids['o2sizy'].SetPV(over.PV('SizeY'))
            self.wids['o2sizy'].SetMax(sizey)
            self.wids['o2shape'].SetPV(over.PV('Shape'))
            self.wids['o2name'].SetPV(over.PV('Name'))
            self.wids['o2use'].SetPV(over.PV('Use'))

        sizelabel = 'Image Size: %i x %i pixels'
        try:
            sizelabel = sizelabel  % (sizex, sizey)
        except:
            sizelabel = sizelabel  % (0, 0)

        self.wids['fullsize'].SetLabel(sizelabel)
        self.showZoomsize()

        self.ad_img.add_callback('ArrayCounter_RBV',   self.onNewImage)
        self.ad_img.add_callback('ArraySize0_RBV', self.onProperty, dim=0)
        self.ad_img.add_callback('ArraySize1_RBV', self.onProperty, dim=1)
        self.ad_img.add_callback('ArraySize2_RBV', self.onProperty, dim=2)
        self.ad_img.add_callback('ColorMode_RBV',  self.onProperty, dim='color')
        self.ad_cam.add_callback('DetectorState_RBV',  self.onDetState)

        epics.caput("%s:cam1:ArrayCallbacks" % self.prefix, 1)
        for p in self.enabled_plugins:
            epics.caput("%s:%s:EnableCallbacks" % (self.prefix, p), 1)
        epics.caput("%s:JPEG1:NDArrayPort" % self.prefix, "OVER1")
        epics.caput("%s:TIFF1:NDArrayPort" % self.prefix, "OVER1")
        epics.caput("%s:image1:NDArrayPort"% self.prefix, "OVER1")

        self.ad_cam.Acquire = 1
        self.GetImageSize()
        self.unZoom()

        epics.poll()
        self.RefreshImage()

    @EpicsFunction
    def GetImageSize(self):
        self.arrsize = [1,1,1]
        self.arrsize[0] = self.ad_img.ArraySize0_RBV
        self.arrsize[1] = self.ad_img.ArraySize1_RBV
        self.arrsize[2] = self.ad_img.ArraySize2_RBV
        self.colormode = self.ad_img.ColorMode_RBV


        self.img_w = self.arrsize[1]
        self.img_h = self.arrsize[0]
        if self.colormode == 2:
            self.img_w = self.arrsize[2]
            self.img_h = self.arrsize[1]

    @DelayedEpicsCallback
    def onDetState(self, pvname=None, value=None, char_value=None, **kw):
        self.messag(char_value, panel=1)

    @DelayedEpicsCallback
    def onProperty(self, pvname=None, value=None, dim=None, **kw):
        if dim=='color':
            self.colormode=value
        else:
            self.arrsize[dim] = value

    @DelayedEpicsCallback
    def onNewImage(self, pvname=None, value=None, **kw):
        if value != self.img_id:
            self.img_id = value
            if not self.drawing:
                self.drawing = True
                self.RefreshImage()

    @EpicsFunction
    def RefreshImage(self, pvname=None, **kws):
        try:
            wx.Yield()
        except:
            pass
        d = debugtime()

        if self.ad_img is None or self.ad_cam is None:
            return
        imgdim = self.ad_img.NDimensions_RBV
        imgcount = self.ad_cam.ArrayCounter_RBV
        now = time.time()
        if (imgcount == self.imgcount or abs(now - self.last_update) < 0.025):
            self.drawing = False
            return
        d.add('refresh img start')
        self.imgcount = imgcount
        self.drawing = True
        self.n_drawn += 1
        self.n_img = imgcount - self.imgcount_start
        #print 'ImgCount, n_drawn: ', imgcount, self.n_img, self.n_drawn

        self.last_update = time.time()
        self.image.can_resize = False

        xmin = self.ad_cam.MinX
        ymin = self.ad_cam.MinY
        width = self.ad_cam.SizeX
        height = self.ad_cam.SizeY

        arraysize = self.arrsize[0] * self.arrsize[1]
        if imgdim == 3:
            arraysize = arraysize * self.arrsize[2]
        if not self.ad_img.PV('ArrayData').connected:
            self.drawing = False
            return

        d.add('refresh img before raw get %i' % arraysize)
        rawdata = self.ad_img.PV('ArrayData').get(count=arraysize)
        d.add('refresh img after raw get')
        im_mode = 'L'
        im_size = (self.arrsize[0], self.arrsize[1])

        if self.colormode == 2:
            im_mode = 'RGB'
            im_size = [self.arrsize[1], self.arrsize[2]]
        if (self.colormode == 0 and isinstance(rawdata, np.ndarray) and
            rawdata.dtype != np.uint8):
            im_mode = 'I'
            rawdata = rawdata.astype(np.uint32)

        d.add('refresh img before msg')
        self.messag(' Image # %i ' % self.ad_cam.ArrayCounter_RBV, panel=2)
        d.add('refresh img before get image size')
        self.GetImageSize()

        self.im_size = im_size
        self.im_mode = im_mode
        self.data = rawdata
        d.add('refresh img before data to image')
        self.DatatoImage()
        d.add('refresh img after data to image')
        self.image.can_resize = True
        nmissed = max(0, self.n_img-self.n_drawn)

        delt = time.time()-self.starttime
        percent_drawn = self.n_drawn * 100 / (self.n_drawn+nmissed)
        smsg = self.stat_msg % (percent_drawn, self.n_drawn/delt)
        self.messag(smsg, panel=0)

        self.drawing = False
        d.add('refresh img done')
Example #17
0
class EigerFrame(wx.Frame):
    """AreaDetector Display """

    img_attrs = ('ArrayData', 'UniqueId_RBV')
    cam_attrs = ('Acquire', 'DetectorState_RBV',
                 'ArrayCounter', 'ArrayCounter_RBV',
                 'ThresholdEnergy', 'ThresholdEnergy_RBV',
                 'PhotonEnergy', 'PhotonEnergy_RBV',
                 'NumImages', 'NumImages_RBV',
                 'AcquireTime', 'AcquireTime_RBV',
                 'AcquirePeriod', 'AcquirePeriod_RBV',
                 'TriggerMode', 'TriggerMode_RBV')

    # plugins to enable
    enabled_plugins = ('image1', 'Over1', 'ROI1', 'JPEG1', 'TIFF1')

    def __init__(self, prefix=None, url=None, scale=1.0):
        self.ad_img = None
        self.ad_cam = None
        if prefix is None:
            dlg = SavedParameterDialog(label='Detector Prefix',
                                       title='Connect to Eiger Detector',
                                       configfile='.ad_eigerdisplay.dat')
            res = dlg.GetResponse()
            dlg.Destroy()
            if res.ok:
                prefix = res.value

        self.prefix = prefix
        self.fname = 'Eiger.tif'
        self.esimplon = None
        if url is not None and HAS_SIMPLON:
            self.esimplon = EigerSimplon(url, prefix=prefix+'cam1:')

        self.lineplotter = None
        self.calib = {}
        self.integrator = None
        self.int_panel = None
        self.int_lastid = None
        self.contrast_levels = None
        self.scandb = None
        wx.Frame.__init__(self, None, -1, "Eiger500K Area Detector Display",
                          style=wx.DEFAULT_FRAME_STYLE)

        self.buildMenus()
        self.buildFrame()

        wx.CallAfter(self.connect_escandb)

    def connect_escandb(self):
        if HAS_ESCAN and os.environ.get('ESCAN_CREDENTIALS', None) is not None:
            self.scandb = ScanDB()
            calib_loc = self.scandb.get_info('eiger_calibration')
            cal = self.scandb.get_detectorconfig(calib_loc)
            self.setup_calibration(json.loads(cal.text))

    def buildFrame(self):
        sbar = self.CreateStatusBar(3, wx.CAPTION) # |wx.THICK_FRAME)
        self.SetStatusWidths([-1, -1, -1])
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(10)
        sbar.SetFont(sfont)

        self.SetStatusText('',0)

        sizer = wx.GridBagSizer(3, 3)
        panel = self.panel = wx.Panel(self)

        pvpanel = PVConfigPanel(panel, self.prefix, display_pvs)

        wsize = (100, -1)
        lsize = (250, -1)

        start_btn = wx.Button(panel, label='Start',    size=wsize)
        stop_btn  = wx.Button(panel, label='Stop',     size=wsize)
        free_btn  = wx.Button(panel, label='Free Run', size=wsize)
        start_btn.Bind(wx.EVT_BUTTON, partial(self.onButton, key='start'))
        stop_btn.Bind(wx.EVT_BUTTON,  partial(self.onButton, key='stop'))
        free_btn.Bind(wx.EVT_BUTTON,  partial(self.onButton, key='free'))

        self.cmap_choice = wx.Choice(panel, size=(80, -1),
                                             choices=colormaps)
        self.cmap_choice.SetSelection(0)
        self.cmap_choice.Bind(wx.EVT_CHOICE,  self.onColorMap)

        self.cmap_reverse = wx.CheckBox(panel, label='Reverse', size=(60, -1))
        self.cmap_reverse.Bind(wx.EVT_CHECKBOX,  self.onColorMap)

        self.show1d_btn =  wx.Button(panel, label='Show 1D Integration', size=(200, -1))
        self.show1d_btn.Bind(wx.EVT_BUTTON, self.onShowIntegration)
        self.show1d_btn.Disable()

        self.imagesize = wx.StaticText(panel, label='? x ?',
                                       size=(250, 30), style=txtstyle)

        self.contrast = ContrastChoice(panel, callback=self.set_contrast_level)

        def lin(len=200, wid=2, style=wx.LI_HORIZONTAL):
            return wx.StaticLine(panel, size=(len, wid), style=style)


        irow = 0
        sizer.Add(pvpanel,  (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(start_btn, (irow, 0), (1, 1), labstyle)
        sizer.Add(stop_btn,  (irow, 1), (1, 1), labstyle)
        sizer.Add(free_btn,  (irow, 2), (1, 1), labstyle)

        irow += 1
        sizer.Add(lin(300),  (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(self.imagesize, (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(wx.StaticText(panel, label='Color Map: '),
                  (irow, 0), (1, 1), labstyle)

        sizer.Add(self.cmap_choice,  (irow, 1), (1, 1), labstyle)
        sizer.Add(self.cmap_reverse, (irow, 2), (1, 1), labstyle)

        irow += 1
        sizer.Add(self.contrast.label,  (irow, 0), (1, 1), labstyle)
        sizer.Add(self.contrast.choice, (irow, 1), (1, 1), labstyle)

        irow += 1
        sizer.Add(self.show1d_btn, (irow, 0), (1, 2), labstyle)

        panel.SetSizer(sizer)
        sizer.Fit(panel)

        # image panel
        self.image = ADMonoImagePanel(self, prefix=self.prefix,
                                      rot90=DEFAULT_ROTATION,
                                      size=(400, 750),
                                      writer=partial(self.write, panel=2))

        mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        mainsizer.Add(panel, 0, wx.LEFT|wx.GROW|wx.ALL)
        mainsizer.Add(self.image, 1, wx.CENTER|wx.GROW|wx.ALL)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.SetAutoLayout(True)

        try:
            self.SetIcon(wx.Icon(ICONFILE, wx.BITMAP_TYPE_ICO))
        except:
            pass

        wx.CallAfter(self.connect_pvs )

    def onColorMap(self, event=None):
        cmap_name = self.cmap_choice.GetStringSelection()
        if self.cmap_reverse.IsChecked():
            cmap_name = cmap_name + '_r'
        self.image.colormap = getattr(colormap, cmap_name)
        self.image.Refresh()

    def onCopyImage(self, event=None):
        "copy bitmap of canvas to system clipboard"
        bmp = wx.BitmapDataObject()
        bmp.SetBitmap(wx.Bitmap(self.image.GrabWxImage()))
        wx.TheClipboard.Open()
        wx.TheClipboard.SetData(bmp)
        wx.TheClipboard.Close()
        wx.TheClipboard.Flush()

    def onReadCalibFile(self, event=None):
        "read calibration file"
        wcards = "Poni Files(*.poni)|*.poni|All files (*.*)|*.*"
        dlg = wx.FileDialog(None, message='Read Calibration File',
                            defaultDir=os.getcwd(),
                            wildcard=wcards,
                            style=wx.FD_OPEN)
        ppath = None
        if dlg.ShowModal() == wx.ID_OK:
            ppath = os.path.abspath(dlg.GetPath())

        if os.path.exists(ppath):
            if self.scandb is not None:
                CalibrationDialog(self, ppath).Show()
            else:
                self.setup_calibration(read_poni(ppath))

    def setup_calibration(self, calib):
        """set up calibration from calibration dict"""
        if self.image.rot90 in (1, 3):
            calib['rot3'] = np.pi/2.0
        self.calib = calib
        if HAS_PYFAI:
            self.integrator = AzimuthalIntegrator(**calib)
            self.show1d_btn.Enable()

    def onShowIntegration(self, event=None):

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()

    def onAutoIntegration(self, event=None):
        if not event.IsChecked():
            self.int_timer.Stop()
            return

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()
        self.int_timer.Start(500)

    def show_1dpattern(self, init=False):
        if self.calib is None or not HAS_PYFAI:
            return

        img = self.ad_img.PV('ArrayData').get()


        h, w = self.image.GetImageSize()
        img.shape = (w, h)
        img = img[3:-3, 1:-1][::-1, :]

        img_id = self.ad_cam.ArrayCounter_RBV
        q, xi = self.integrator.integrate1d(img, 2048, unit='q_A^-1',
                                            correctSolidAngle=True,
                                            polarization_factor=0.999)
        if init:
            self.int_panel.plot(q, xi, xlabel=r'$Q (\rm\AA^{-1})$', marker='+',
                                title='Image %d' % img_id)
            self.int_panel.Raise()
            self.int_panel.Show()
        else:
            self.int_panel.update_line(0, q, xi, draw=True)
            self.int_panel.set_title('Image %d' % img_id)

    @EpicsFunction
    def onSaveImage(self, event=None):
        "prompts for and save image to file"
        defdir = os.getcwd()
        self.fname = "Image_%i.tiff"  % self.ad_cam.ArrayCounter_RBV
        dlg = wx.FileDialog(None, message='Save Image as',
                            defaultDir=os.getcwd(),
                            defaultFile=self.fname,
                            style=wx.FD_SAVE)
        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = os.path.abspath(dlg.GetPath())


        root, fname = os.path.split(path)
        epics.caput("%sTIFF1:FileName" % self.prefix, fname)
        epics.caput("%sTIFF1:FileWriteMode" % self.prefix, 0)
        time.sleep(0.05)
        epics.caput("%sTIFF1:WriteFile" % self.prefix, 1)
        time.sleep(0.05)

        print("Saved TIFF File ",
              epics.caget("%sTIFF1:FullFileName_RBV" % self.prefix, as_string=True))

    def onExit(self, event=None):
        try:
            wx.Yield()
        except:
            pass
        self.Destroy()

    def onAbout(self, event=None):
        msg =  """Eiger Image Display version 0.1
Matt Newville <*****@*****.**>"""

        dlg = wx.MessageDialog(self, msg, "About Epics Image Display",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def buildMenus(self):
        fmenu = wx.Menu()
        MenuItem(self, fmenu, "&Save\tCtrl+S", "Save Image", self.onSaveImage)
        MenuItem(self, fmenu, "&Copy\tCtrl+C", "Copy Image to Clipboard",
                 self.onCopyImage)
        MenuItem(self, fmenu, "Read Calibration File", "Read PONI Calibration",
                 self.onReadCalibFile)
        fmenu.AppendSeparator()
        MenuItem(self, fmenu, "E&xit\tCtrl+Q",  "Exit Program", self.onExit)

        omenu = wx.Menu()
        MenuItem(self, omenu,  "&Rotate CCW\tCtrl+R", "Rotate Counter Clockwise", self.onRot90)
        MenuItem(self, omenu,  "Flip Up/Down\tCtrl+T", "Flip Up/Down", self.onFlipV)
        MenuItem(self, omenu,  "Flip Left/Right\tCtrl+F", "Flip Left/Right", self.onFlipH)
        MenuItem(self, omenu,  "Reset Rotations and Flips", "Reset", self.onResetRotFlips)
        omenu.AppendSeparator()

        hmenu = wx.Menu()
        MenuItem(self, hmenu, "About", "About Epics AreadDetector Display", self.onAbout)

        mbar = wx.MenuBar()
        mbar.Append(fmenu, "File")
        mbar.Append(omenu, "Options")

        mbar.Append(hmenu, "&Help")
        self.SetMenuBar(mbar)

    def onResetRotFlips(self, event):
        self.image.rot90 = DEFAULT_ROTATION
        self.image.flipv = self.fliph = False

    def onRot90(self, event):
        self.image.rot90 = (self.image.rot90 - 1) % 4

    def onFlipV(self, event):
        self.image.flipv= not self.image.flipv

    def onFlipH(self, event):
        self.image.fliph = not self.image.fliph

    def set_contrast_level(self, contrast_level=0):
        self.image.contrast_levels = [contrast_level, 100.0-contrast_level]

    def write(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(text=s, number=panel)

    @EpicsFunction
    def onButton(self, event=None, key='free'):
        key = key.lower()
        if key.startswith('free'):
            self.image.restart_fps_counter()
            self.ad_cam.AcquireTime = 0.25
            self.ad_cam.AcquirePeriod = 0.25
            self.ad_cam.NumImages = 345600
            self.ad_cam.Acquire = 1
        elif key.startswith('start'):
            self.image.restart_fps_counter()
            self.ad_cam.Acquire = 1
        elif key.startswith('stop'):
            self.ad_cam.Acquire = 0

    @EpicsFunction
    def connect_pvs(self, verbose=True):
        if self.prefix is None or len(self.prefix) < 2:
            return

        if self.prefix.endswith(':'):
            self.prefix = self.prefix[:-1]
        if self.prefix.endswith(':image1'):
            self.prefix = self.prefix[:-7]
        if self.prefix.endswith(':cam1'):
            self.prefix = self.prefix[:-5]

        self.write('Connecting to AD %s' % self.prefix)
        self.ad_img = epics.Device(self.prefix + ':image1:', delim='',
                                   attrs=self.img_attrs)
        self.ad_cam = epics.Device(self.prefix + ':cam1:', delim='',
                                   attrs=self.cam_attrs)

        epics.caput("%s:TIFF1:EnableCallbacks" % self.prefix, 1)
        epics.caput("%s:TIFF1:AutoSave" % self.prefix, 0)
        epics.caput("%s:TIFF1:AutoIncrement" % self.prefix, 0)
        epics.caput("%s:TIFF1:FileWriteMode" % self.prefix, 0)

        time.sleep(0.002)
        if not self.ad_img.PV('UniqueId_RBV').connected:
            epics.poll()
            if not self.ad_img.PV('UniqueId_RBV').connected:
                self.write('Warning:  Camera seems to not be connected!')
                return
        if verbose:
            self.write('Connected to AD %s' % self.prefix)

        self.SetTitle("Epics Image Display: %s" % self.prefix)

        sizex = self.ad_cam.MaxSizeX_RBV
        sizey = self.ad_cam.MaxSizeY_RBV

        sizelabel = 'Image Size: %i x %i pixels'
        try:
            sizelabel = sizelabel  % (sizex, sizey)
        except:
            sizelabel = sizelabel  % (0, 0)

        self.imagesize.SetLabel(sizelabel)

        self.ad_cam.add_callback('DetectorState_RBV',  self.onDetState)
        self.contrast.set_level_str('0.05')

    @DelayedEpicsCallback
    def onDetState(self, pvname=None, value=None, char_value=None, **kw):
        self.write(char_value, panel=1)
class ArlissMonitoringFrame(wx.Frame):

    title = 'Sensors Monitoring'

    def __init__(self):
        wx.Frame.__init__(self, None, -1, self.title, size=(700, 700))

        os.system("banner ARLISS")

        #Partiendo la ventana en 2 paneles, en uno de ellos van los graficos
        ##en otro los botones y demas

        self.Maximize()
        #Funcion para abrir la ventana maximizada

        self.sp = wx.SplitterWindow(self)
        self.p1 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
        self.p2 = wx.Panel(self.sp, style=wx.SUNKEN_BORDER)
        self.sp.SplitVertically(self.p1, self.p2, 250)

        self.keycode = ''
        self.Pause = False

        self.plotframe = None

        #Se crean los arreglos que van a guardar los datos

        self.dataAQ = DataAQ()

        #Clase que genera datos random, para pruebas

        self.datagen = DataGen()

        #Arreglo con los datos

        self.datos = [[], [], [], [], [],
         [], [], [], [], [], [], [], [], [], []]

        self.datosGPS = [[], []]

        for line in open('GPS.txt', 'r'):
            self.datosGPS[0].append(line.split()[0])
            self.datosGPS[1].append(line.split()[1])

        #Se corren funciones para inicializar y crear paneles y el menu
        #En el panel es donde esta todo

        self.create_menu()
        self.create_status_bar()
        self.create_main_panel()

        #se inicializan los timers
        #Super importantes, cada 100ms ocurre un evento y se corre una funcion
        #en este caso: self.on_redraw_timer, la cual redibuja los graficos

        self.redraw_timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.on_redraw_timer, self.redraw_timer)
        self.redraw_timer.Start(100)

        #Texto estatico

        wx.StaticText(self.p1, -1, "Latitud \t\t\t Longitud", (20, 80))
        wx.StaticText(self.p1, -1, "Altura: ", (20, 605))
        wx.StaticText(self.p1, -1, "Distancia: ", (20, 620))
        wx.StaticText(self.p1, -1, "Estado: ", (20, 635))
        wx.StaticText(self.p1, -1, "Moving ", (20, 650))
        wx.StaticText(self.p1, -1, "Fix: ", (20, 665))

        self.textoAltura = wx.StaticText(self.p1, -1, "0", (100, 605))
        self.textoDistancia = wx.StaticText(self.p1, -1, "0", (100, 620))
        self.textoEstado = wx.StaticText(self.p1, -1, "0", (100, 635))
        self.textoMoviendose = wx.StaticText(self.p1, -1, "0", (100, 650))
        self.textoFix = wx.StaticText(self.p1, -1, "0", (100, 665))

        #Se crea una ventana para imprimir los datos de latitud y longitud

        self.logger = wx.TextCtrl(self.p1, 5, "", wx.Point(0, 100),
             wx.Size(250, 500), wx.TE_MULTILINE | wx.TE_READONLY)

        #Boton de prueba, cuando se clickea se crea un evento
        #y se corre una funcion

        self.pauseButton = wx.Button(
            self.p1, wx.ID_STOP, pos=(10, 25))
        self.pauseButton.Bind(wx.EVT_BUTTON, self.onPause)

        self.saveButton = wx.Button(
            self.p1, wx.ID_SAVE, pos=(150, 25))
        self.saveButton.Bind(wx.EVT_BUTTON, self.Save)

    #Funcion que se corre cada vez que se presiona el boton

    def Save(self, event):
        self.saveData(self)

    def onPause(self, event):

        if not self.Pause:
            self.Pause = True
        else:
            self.Pause = False

    def ShowPlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self)
            self.has_plot = False
        try:
            self.plotframe.Show()
        except wx.PyDeadObjectError:
            self.plotframe = PlotFrame(self)
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()

    #Creando el menu con todos las diferentes pesta;as y accesos

    def create_menu(self):
        self.menubar = wx.MenuBar()

        menu_file = wx.Menu()
        m_expt = menu_file.Append(
            -1, "&Save plot\tCtrl-S", "Save plot to file")
        self.Bind(wx.EVT_MENU, self.on_save_plot, m_expt)
        menu_file.AppendSeparator()
        m_exit = menu_file.Append(-1, "E&xit\tCtrl-X", "Exit")
        self.Bind(wx.EVT_MENU, self.on_exit, m_exit)
        self.menubar.Append(menu_file, "&File")

        saveMenu = wx.Menu()

        m_Compass = saveMenu.Append(-1, "Plot Compass",
             "Plotear y guardar los datos de la brujula")
        self.Bind(wx.EVT_MENU, self.wxmPlotBrujula, m_Compass)

        m_CompassGoal = saveMenu.Append(-1, "Plot CompassGoal",
             "Plotear y guardar los datos del angulo con respecto a la meta")
        self.Bind(wx.EVT_MENU, self.wxmPlotBrujulaGoal, m_CompassGoal)

        m_PWM1 = saveMenu.Append(-1, "Plot PWM 1",
             "Plotear y guardar los datos del PWM del Motor 1")
        self.Bind(wx.EVT_MENU, self.wxmPlotPWM1, m_PWM1)

        m_PWM2 = saveMenu.Append(-1, "Plot PWM 2",
             "Plotear y guardar los datos del PWM del Motor 2")
        self.Bind(wx.EVT_MENU, self.wxmPlotPWM2, m_PWM2)

        m_V1 = saveMenu.Append(-1, "Plot V1",
             "Plotear y guardar los datos de la velocidad del Motor 1")
        self.Bind(wx.EVT_MENU, self.wxmPlotV1, m_V1)

        m_V2 = saveMenu.Append(-1, "Plot V2",
             "Plotear y guardar los datos de la velocidad del Motor 2")
        self.Bind(wx.EVT_MENU, self.wxmPlotV2, m_V2)

        m_GPS = saveMenu.Append(-1, "Google Earth GPS",
             "Mostrar en Google Earth los datos del GPS")
        self.Bind(wx.EVT_MENU, self.googleEarth, m_GPS)

        m_Altitud = saveMenu.Append(-1, "Plot Altitud",
             "Plotear y guardar los datos de la Altitud")
        self.Bind(wx.EVT_MENU, self.wxmPlotAltitud, m_Altitud)

        m_Target = saveMenu.Append(-1, "Plot Target",
             "Plotear y guardar los datos de la distancia de la meta")
        self.Bind(wx.EVT_MENU, self.wxmPlotTarget, m_Target)

        #Dejemos en standby lo de posX y posY

        m_Estado = saveMenu.Append(-1, "Plot Estado",
             "Plotear y guardar los datos del Estado del Rover")
        self.Bind(wx.EVT_MENU, self.wxmPlotEstado, m_Estado)

        m_Moviendose = saveMenu.Append(-1, "Plot Moviendose",
             "Plotear y guardar los datos del Estado del Movimiento del Rover")
        self.Bind(wx.EVT_MENU, self.wxmPlotMoviendose, m_Moviendose)

        m_Fix = saveMenu.Append(-1, "Plot GPS Fix",
             "Plotear y guardar los datos del Fix del GPS")
        self.Bind(wx.EVT_MENU, self.wxmPlotFix, m_Fix)

        self.menubar.Append(saveMenu, "Plotear Datos")
        self.SetMenuBar(self.menubar)

    #Se crea un panel, el q va a contener los graficos, se inicializan los
    #graficos y se imprimen en el panel self.p2 como una figura.

    def create_main_panel(self):

        self.init_plot()
        self.canvas = FigCanvas(self.p2, -1, self.fig)

    #Se crea la barra de estado que esta en la parte de abajo de la ventana

    def create_status_bar(self):
        self.statusbar = self.CreateStatusBar()

        #Texto que va en la barra de estado, se puede
        #cambiar por medio de eventos

        self.statusbar.SetStatusText("Sensors Monitoring")

    #Inicializando los graficos, aqui se utiliza mayormente
    #la libreria matplotlib
    #Se indican las propiedades de los graficos y otras cosas

    def init_plot(self):

        #Resolucion del grafico

        self.dpi = 100

        #Se crea el objeto que va a tener el o los graficos,
        #se le indica la resolucion
        #y el tamano

        self.fig = Figure((11, 7.0), dpi=self.dpi)

        #Se le agrega un subplot a la figura llamada PWM,
        #Esta figura va a tener los datos de los 2 PWM
        #se indica que la figura
        #va a tener un arreglo de graficos 2x2 (fila x columna) y que subplot
        #PWM va a ser el primero de los dos subplots.

        self.PWM = self.fig.add_subplot(221)
        self.PWM2 = self.fig.add_subplot(221)

        self.PWM.set_axis_bgcolor('black')
        self.PWM.set_title('PWM', size=12)

        pylab.setp(self.PWM.get_xticklabels(), fontsize=8)
        pylab.setp(self.PWM.get_yticklabels(), fontsize=8)

        #Se plotean datos, pero por primera vez,
        #luego se actualizan con el timer

        self.plot_PWM = self.PWM.plot(
            self.datos[PWM1], linewidth=1, color=(1, 1, 0),)[0]

        self.plot_PWM2 = self.PWM2.plot(
            (self.datos[PWM2]), linewidth=1, color=(1, 0, 0),)[0]
            #Falta PWM2

        self.PWM.legend([self.plot_PWM, self.plot_PWM2], ["PWM1", "PWM2"])

        #Agregando plot de Brujula
        #Aqui van a ir ploteados los datos del angulo con respecto al norte
        #Y el angulo con respecto al goal

        self.Brujula = self.fig.add_subplot(222)
        self.BrujulaGoal = self.fig.add_subplot(222)
        self.Brujula.set_axis_bgcolor('black')
        self.Brujula.set_title('Angulos', size=12)

        pylab.setp(self.Brujula.get_xticklabels(), fontsize=8)
        pylab.setp(self.Brujula.get_yticklabels(), fontsize=8)

        self.plot_Brujula = self.Brujula.plot(
            self.datos[COMPASS], linewidth=1, color=(0, 0, 1),)[0]

        self.plot_BrujulaGoal = self.BrujulaGoal.plot(
            self.datos[COMPASSGOAL], linewidth=1, color=(1, 0, 1),)[0]

        self.Brujula.legend([self.plot_Brujula, self.plot_BrujulaGoal], ["Norte", "Meta"])

        #Agregando plot de Velocidades

        self.Vel = self.fig.add_subplot(223)
        self.Vel2 = self.fig.add_subplot(223)
        self.Vel.set_axis_bgcolor('black')
        self.Vel.set_title('Velocidades', size=12)

        pylab.setp(self.Vel.get_xticklabels(), fontsize=8)
        pylab.setp(self.Vel.get_yticklabels(), fontsize=8)

        self.plot_Vel = self.Vel.plot(
            self.datos[V1], linewidth=1, color=(0, 1, 0),)[0]

        self.plot_Vel2 = self.Vel2.plot(
            self.datos[V2], linewidth=1, color=(1, 1, 0),)[0]

        self.Vel.legend([self.plot_Vel, self.plot_Vel2], ["M1", "M2"])

        #Agregando plot de POS

        self.POS = self.fig.add_subplot(224)
        self.POS.set_axis_bgcolor('black')
        self.POS.set_title('Posiciones', size=12)

        pylab.setp(self.POS.get_xticklabels(), fontsize=8)
        pylab.setp(self.POS.get_yticklabels(), fontsize=8)

        self.plot_POS = self.POS.plot(
            self.datos[POSX], self.datos[POSY], linewidth=1, color=(0, 0, 1),)[0]

    def draw_plot(self):

        xmax_PWM = len(self.datos[PWM1]) if len(self.datos[PWM1]) > 50 else 50
        xmin_PWM = xmax_PWM - 50

        ymin_PWM = round(min(min(self.datos[PWM1]),
         min(self.datos[PWM2])), 0) - 1
        ymax_PWM = round(max(max(self.datos[PWM1]),
         max(self.datos[PWM2])), 0) + 1
        #SACAR EL MINIMO Y MAX DE 2 ARRAYS, PWM1 Y PWM2

        self.PWM.set_xbound(lower=xmin_PWM, upper=xmax_PWM)
        self.PWM.set_ybound(lower=ymin_PWM, upper=ymax_PWM)

        self.PWM.grid(True, color='w')

        self.plot_PWM.set_xdata(np.arange(len(self.datos[PWM1])))
        self.plot_PWM.set_ydata(np.array(self.datos[PWM1]))

        self.plot_PWM2.set_xdata(np.arange(len(self.datos[PWM2])))
        self.plot_PWM2.set_ydata(np.array(self.datos[PWM2]))

        #Plot de Brujula

        xmax_Comp = len(self.datos[COMPASS]) \
        if len(self.datos[COMPASS]) > 50 else 50
        xmin_Comp = xmax_Comp - 50

        ymin_Comp = round(min(min(self.datos[COMPASS]),
         min(self.datos[COMPASSGOAL])), 0) + 1
        ymax_Comp = round(max(max(self.datos[COMPASS]),
         max(self.datos[COMPASSGOAL])), 0) + 1
        #SACAR EL MINIMO DE COMPASS Y COMPASSGOAL

        self.Brujula.set_xbound(lower=xmin_Comp, upper=xmax_Comp)
        self.Brujula.set_ybound(lower=ymin_Comp, upper=ymax_Comp)

        self.Brujula.grid(True, color='w')

        self.plot_Brujula.set_xdata(np.arange(len(self.datos[COMPASS])))
        self.plot_Brujula.set_ydata(np.array(self.datos[COMPASS]))

        self.plot_BrujulaGoal.set_xdata(np.arange(len(self.datos[COMPASSGOAL])))
        self.plot_BrujulaGoal.set_ydata(np.array(self.datos[COMPASSGOAL]))

        #Plot de Velocidades

        xmax_Vel = len(self.datos[V1]) \
        if len(self.datos[V1]) > 50 else 50

        xmin_Vel = xmax_Vel - 50

        ymin_Vel = round(min(min(self.datos[V1]), min(self.datos[V2])), 0) - 1
        ymax_Vel = round(max(max(self.datos[V1]), max(self.datos[V2])), 0) + 1

        self.Vel.set_xbound(lower=xmin_Vel, upper=xmax_Vel)
        self.Vel.set_ybound(lower=ymin_Vel, upper=ymax_Vel)

        self.Vel.grid(True, color='w')

        self.plot_Vel.set_xdata(np.arange(len(self.datos[V1])))
        self.plot_Vel.set_ydata(np.array(self.datos[V1]))

        self.plot_Vel2.set_xdata(np.arange(len(self.datos[V2])))
        self.plot_Vel2.set_ydata(np.array(self.datos[V2]))

        #Plot de POS

        xmax_POS = round(max(self.datos[POSX]), 0) - 1
        xmin_POS = round(min(self.datos[POSX]), 0) - 1

        ymin_POS = round(min(self.datos[POSY]), 0) - 1
        ymax_POS = round(max(self.datos[POSY]), 0) + 1

        self.POS.set_xbound(lower=xmin_POS, upper=xmax_POS)
        self.POS.set_ybound(lower=ymin_POS, upper=ymax_POS)

        self.POS.grid(True, color='w')

        self.plot_POS.set_xdata(np.array(self.datos[POSX]))
        self.plot_POS.set_ydata(np.array(self.datos[POSY]))

        #Dibujando Plot

        self.canvas.draw()

    def on_save_plot(self, event):
        file_choices = "PNG (*.png)|*.png"

        dlg = wx.FileDialog(
            self,
            message="Save plot as...",
            defaultDir=os.getcwd(),
            defaultFile="plot.png",
            wildcard=file_choices,
            style=wx.SAVE)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            self.canvas.print_figure(path, dpi=self.dpi)
            self.flash_status_message("Saved to %s" % path)

    def on_redraw_timer(self, event):

        wx.Yield()

        if not self.Pause:

            tempDatos = self.dataAQ.get()

            for i in range(15):
                self.datos[i].append(tempDatos[i])

            self.logger.AppendText(("%0.10f" % tempDatos[LATITUD])
            + "\t" + ("%0.10f" % tempDatos[LONGITUD]) + "\n")

            self.textoAltura.SetLabel(str(tempDatos[ALTITUD]))
            self.textoDistancia.SetLabel(str(tempDatos[TARGET]))
            self.textoEstado.SetLabel(str(tempDatos[ESTADO]))
            self.textoMoviendose.SetLabel(str(tempDatos[MOVIENDOSE]))
            self.textoFix.SetLabel(str(tempDatos[FIX]))

            self.draw_plot()

    def on_exit(self, event):
        self.Destroy()

    def getPath(self):
        strTime = (str(time.localtime()[0]) + "-" + str(time.localtime()[1]) +
             "-" + str(time.localtime()[2]) + "_" + str(time.localtime()[3]) +
              ":" + str(time.localtime()[4]))

        path = 'Datos_{}'.format(strTime)
        return path

    def saveData(self, event):

        #En esta funcion se van a guardar todos los datos que entran en un .txt
        #Los datos son:
        #COMPASS, PWM1, PWM2, V1, V2, LATITUD, LONGITUD, ALTITUD, COMPASSGOAL,
        #TARGET, POSX, POSY, ESTADO, MOVIENDOSE, FIX

        newpath = self.getPath()

        if not os.path.exists(newpath):
            os.makedirs(newpath)

        brujulaPath = newpath + "/datos_Brujula.txt"
        brujulaGoalPath = newpath + "/datos_BrujulaGoal.txt"
        PWM1Path = newpath + "/datos_PWM1.txt"
        PWM2Path = newpath + "/datos_PWM2.txt"
        V1Path = newpath + "/datos_V1.txt"
        V2Path = newpath + "/datos_V2.txt"
        GPSPath = newpath + "/datos_GPS.txt"
        self.GPSKMLPath = newpath + "/datos_GPS.kml"
        AltitudPath = newpath + "/datos_Altitud.txt"
        TargetPath = newpath + "/datos_Target.txt"
        PosPath = newpath + "/datos_POS.txt"
        EstadoPath = newpath + "/datos_Estado.txt"
        MoviendosePath = newpath + "/datos_Moviendose.txt"
        FixPath = newpath + "/datos_Fix.txt"

        self.fileBrujula = open(brujulaPath, 'w')
        self.fileBrujula.write("#Datos de Brujula\n")
        for i in range(len(self.datos[COMPASS])):
            txt = str(i) + '\t' + str(self.datos[COMPASS][i]) + '\n'
            self.fileBrujula.write(txt)
        self.fileBrujula.close()

        self.fileBrujulaGoal = open(brujulaGoalPath, 'w')
        self.fileBrujulaGoal.write("#Datos de BrujulaGoal\n")
        for i in range(len(self.datos[COMPASSGOAL])):
            txt = str(i) + '\t' + str(self.datos[COMPASSGOAL][i]) + '\n'
            self.fileBrujulaGoal.write(txt)
        self.fileBrujulaGoal.close()

        self.filePWM1 = open(PWM1Path, 'w')
        self.filePWM1.write("#Datos de PWM de Motor 1\n")
        for i in range(len(self.datos[PWM1])):
            txt = str(i) + '\t' + str(self.datos[PWM1][i]) + '\n'
            self.filePWM1.write(txt)
        self.filePWM1.close()

        self.filePWM2 = open(PWM2Path, 'w')
        self.filePWM2.write("#Datos de PWM de Motor 2\n")
        for i in range(len(self.datos[PWM2])):
            txt = str(i) + '\t' + str(self.datos[PWM2][i]) + '\n'
            self.filePWM2.write(txt)
        self.filePWM2.close()

        self.fileV1 = open(V1Path, 'w')
        self.fileV1.write("#Datos de velocidad del motor 1\n")
        for i in range(len(self.datos[V1])):
            txt = str(i) + '\t' + str(self.datos[V1][i]) + '\n'
            self.fileV1.write(txt)
        self.fileV1.close()

        self.fileV2 = open(V2Path, 'w')
        self.fileV2.write("#Datos de Velocidad del motor 2\n")
        for i in range(len(self.datos[V2])):
            txt = str(i) + '\t' + str(self.datos[V2][i]) + '\n'
            self.fileV2.write(txt)
        self.fileV2.close()

        self.fileAltitud = open(AltitudPath, 'w')
        self.fileAltitud.write("#Datos de Altitud dada por el barometro\n")
        for i in range(len(self.datos[ALTITUD])):
            txt = str(i) + '\t' + str(self.datos[ALTITUD][i]) + '\n'
            self.fileAltitud.write(txt)
        self.fileAltitud.close()

        self.fileTarget = open(TargetPath, 'w')
        self.fileTarget.write("#Datos de la distancia de la meta\n")
        for i in range(len(self.datos[TARGET])):
            txt = str(i) + '\t' + str(self.datos[TARGET][i]) + '\n'
            self.fileTarget.write(txt)
        self.fileTarget.close()

        self.filePOS = open(PosPath, 'w')
        self.filePOS.write("#Datos de la posicion en X y en Y\n")
        for i in range(len(self.datos[POSX])):
            txt = str(self.datos[POSX][i]) + \
            '\t' + str(self.datos[POSY][i]) + '\n'
            self.filePOS.write(txt)
        self.filePOS.close()

        self.fileEstado = open(EstadoPath, 'w')
        self.fileEstado.write("#Datos del estado del Rover\n")
        for i in range(len(self.datos[ESTADO])):
            txt = str(i) + '\t' + str(self.datos[ESTADO][i]) + '\n'
            self.fileEstado.write(txt)
        self.fileEstado.close()

        self.fileMoviendose = open(MoviendosePath, 'w')
        self.fileMoviendose.write("#Datos binarios del movimiento del Rover\n")
        for i in range(len(self.datos[MOVIENDOSE])):
            txt = str(i) + '\t' + str(self.datos[MOVIENDOSE][i]) + '\n'
            self.fileMoviendose.write(txt)
        self.fileMoviendose.close()

        self.fileFix = open(FixPath, 'w')
        self.fileFix.write("#Datos del Fix del GPS\n")
        for i in range(len(self.datos[FIX])):
            txt = str(i) + '\t' + str(self.datos[FIX][i]) + '\n'
            self.fileFix.write(txt)
        self.fileFix.close()

        self.fileGPS = open(GPSPath, 'w')
        self.fileGPS.write("#Datos del GPS\n")
        for i in range(len(self.datos[LATITUD])):
            txt = str(self.datos[LATITUD][i]) +\
             '\t' + str(self.datos[LONGITUD][i]) + '\n'
            self.fileGPS.write(txt)
        self.fileGPS.close()

        #GUARDANDO DATOS EN .KML

        kml = '<Placemark><LineString><coordinates>'

        for i in range(len(self.datosGPS[1])):
            kml += '\n' + str(self.datosGPS[1][i]) + \
            ',' + str(self.datosGPS[0][i])

        #for i in range(len(self.datos[LATITUD])):
            #kml += '\n' + str(self.datos[LONGITUD][i]) + \
                #',' + str(self.datos[LATITUD][i])

        kml += '\n </coordinates></LineString></Placemark>'

        with open(self.GPSKMLPath, 'w+') as data_file:
            data_file.write(kml)
            data_file.flush()

        self.flash_status_message("Guardado en %s" % newpath)

    def googleEarth(self, event):
        os.system("banner GOOGLE EARTH")
        command = "gnome-open " + self.GPSKMLPath
        os.system(command)

    def wxmPlotBrujula(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[COMPASS]), 1)
        self.plotframe.plot(ndato, self.datos[COMPASS], color='red',
             title='Datos Brujula')

    def wxmPlotBrujulaGoal(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[COMPASSGOAL]), 1)
        self.plotframe.plot(ndato, self.datos[COMPASSGOAL], color='red',
             title='Datos BrujulaGoal')

    def wxmPlotPWM1(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[PWM1]), 1)
        self.plotframe.plot(ndato, self.datos[PWM1], color='red',
             title='Datos PWM 1')

    def wxmPlotPWM2(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[PWM2]), 1)
        self.plotframe.plot(ndato, self.datos[PWM2], color='red',
             title='Datos PWM 2')

    def wxmPlotV1(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[V1]), 1)
        self.plotframe.plot(ndato, self.datos[V1], color='red',
             title='Datos V1')

    def wxmPlotV2(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[V2]), 1)
        self.plotframe.plot(ndato, self.datos[V2], color='red',
             title='Datos V2')

    def wxmPlotAltitud(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[ALTITUD]), 1)
        self.plotframe.plot(ndato, self.datos[ALTITUD], color='red',
             title='Datos Altitud')

    def wxmPlotTarget(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[TARGET]), 1)
        self.plotframe.plot(ndato, self.datos[TARGET], color='red',
             title='Datos distancia de la Meta')

    def wxmPlotEstado(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[ESTADO]), 1)
        self.plotframe.plot(ndato, self.datos[ESTADO], color='red',
             title='Datos Estado del Rover')

    def wxmPlotMoviendose(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[MOVIENDOSE]), 1)
        self.plotframe.plot(ndato, self.datos[MOVIENDOSE], color='red',
             title='Datos Estado del movimiento del Rover')

    def wxmPlotFix(self, event):
        self.ShowPlotFrame()
        ndato = np.arange(0, len(self.datos[FIX]), 1)
        self.plotframe.plot(ndato, self.datos[FIX], color='red',
             title='Datos del FIX del GPS')

    def flash_status_message(self, msg, flash_len_ms=1500):
        self.statusbar.SetStatusText(msg)
        self.timeroff = wx.Timer(self)
        self.Bind(
            wx.EVT_TIMER,
            self.on_flash_status_off,
            self.timeroff)
        self.timeroff.Start(flash_len_ms, oneShot=True)

    def on_flash_status_off(self, event):
        self.statusbar.SetStatusText('Sensors Monitoring')
Example #19
0
class XAFSviewerFrame(wx.Frame):
    def __init__(self, parent=None, *args, **kwds):

        #kwds["style"] = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL
        wx.Frame.__init__(self, parent, wx.NewId(), '', wx.DefaultPosition, wx.Size(-1, -1), **kwds)
        #self.SetTitle(" WXMPlot Plotting Demo")
        """
        self.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, False))
        menu = wx.Menu()
        ID_EXIT = wx.NewId()
        ID_TIMER = wx.NewId()

        menu.Append(ID_EXIT, "E&xit", "Terminate the program")

        menuBar = wx.MenuBar()
        menuBar.Append(menu, "&File")
        self.SetMenuBar(menuBar)

        wx.EVT_MENU(self, ID_EXIT, self.OnExit)

        self.Bind(wx.EVT_CLOSE, self.OnExit)
        """
        self.plotframe = None
        """
        framesizer = wx.BoxSizer(wx.VERTICAL)

        panel = wx.Panel(self, -1, size=(-1, -1))
        panelsizer = wx.BoxSizer(wx.VERTICAL)

        panelsizer.Add(wx.StaticText(panel, -1, 'XAFS Spectra viewer '),
                       0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT | wx.EXPAND, 10)

        b40 = wx.Button(panel, -1, 'Start Timed Plot',    size=(-1, -1))
        #b40.Bind(wx.EVT_BUTTON,self.onStartTimer)
        panelsizer.Add(b40, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)

        panel.SetSizer(panelsizer)
        panelsizer.Fit(panel)

        framesizer.Add(panel, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.EXPAND, 2)
        self.SetSizer(framesizer)
        framesizer.Fit(self)
        """

        #----------- added by LWW -----------------------------
        #====== self.showPlotFrame(do_raise=False, clear=False)
        """
        self.plotYdata = []
        self.plotXdata = []

        # ----------epics PVs-----------------------
        self.i0 = PV('BL10C:scaler1_calc2.VAL')
        self.it = PV('BL10C:scaler1_calc3.VAL')
        self.iF = PV('BL10C:scaler1_calc4.VAL')
        self.trans = PV('BL10C:scaler1_calc8.VAL')
        self.motorPos = PV('mobiis:m2.RBV')
        
        self.scanStart = PV('lww:scan2.EXSC.VAL', callback=self.scanStartCALLBACK)

        while self.motorPos.get() is None:
            print self.motorPos.get()

        self.countDonePV = PV('BL10C:scaler1.CNT', callback=self.countDoneCALLBACK)
        """

        self.time0 = time.time()
        self.datrange = None
        #----------- end of add by LWW -----------------------
        
        #wx.EVT_TIMER(self, ID_TIMER, self.onTimer)
        #self.timer = wx.Timer(self, ID_TIMER)
        """
        self.Refresh()
        """

    # --------------epics callback method---------------------
    def scanStartCALLBACK(self, **kwargs):
        if kwargs['value'] is 1:  # 0:Done, 1: scanning
            self.showPlotFrame(do_raise=True, clear=False)
            print 'New Scan Started!!!'
        else:
            print 'scan stopped!!!'
        return
    
    def countDoneCALLBACK(self, **kwargs):
        """
        if kwargs['value'] is 1:  # 0:Done, 1:Counting
            return

        ## self._flag = True
        self.plotYdata.append(self.trans.get())
        self.plotXdata.append(self.motorPos.get())
        ## self._flag = False
        """
        self.plotXdata = kwargs['plotXdata']
        self.plotYdata = kwargs['plotYdata']
        print 'X:%s, Y:%s' % (len(self.plotXdata), len(self.plotYdata))
        
        # Todo: we need new scan start sequence.
        #       new list, graph clear, data save...,
        # print 'timer ', self.count, time.time()
        ## self.count += 1
        #self.showPlotFrame(do_raise=False, clear=False)
        ## n = self.count
        if len(self.plotXdata) < 2:
            return
        # Todo: implementation of scan finish sequence.
        '''
        if n >= self.npts:
            self.timer.Stop()
            self.timer_results()
        elif n <= 3:
        '''
        if len(self.plotXdata) <= 3:
            self.plotframe.plot(self.plotXdata, self.plotYdata,
                                linewidth=0.5, marker='o',
                                markersize=6, xlabel='energy[eV]',
                                ylabel='[count]')
                                # , grid=False)

        else:
            xx = np.array(self.plotXdata)
            yy = np.array(self.plotYdata)
            
            self.plotframe.update_line(0, xx, yy, update_limits=len(xx) < 10, draw=True)
            
            etime = time.time() - self.time0
            s = " %i / %i points in %8.4f s" % (len(self.plotXdata), len(self.plotYdata), etime)
            self.plotframe.write_message(s)

        if self.datrange is None:
            self.datrange = [min(self.plotXdata), max(self.plotXdata), min(self.plotYdata), max(self.plotYdata)]

        dr = [min(self.plotXdata), max(self.plotXdata),
              min(self.plotYdata), max(self.plotYdata)]
        
        lims = self.plotframe.panel.get_viewlimits()
        if dr[0] < lims[0] or dr[1] > lims[1] or dr[2] < lims[2] or dr[3] > lims[3]:
            self.datrange = dr
            ## if len(self.plotXdata) < len(self.x):
            ##     nmax = min(int(n*1.6), len(self.x)-1)
            ##     self.datrange[1] = self.x[nmax]
            self.plotframe.panel.set_xylims(self.datrange)
            
    def showPlotFrame(self, do_raise=True, clear=True):
        """make sure plot frame is enabled, and visible"""
        if self.plotframe is None:
            self.plotframe = PlotFrame(self, axissize=[0.08, 0.06, 0.91, 0.92])
            # self.has_plot = False
        try:
            self.plotframe.Show()
        except wx.PyDeadObjectError:
            self.plotframe = PlotFrame(self, axissize=[0.08, 0.06, 0.91, 0.92])
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        '''
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()

            self.plotYdata = []
            self.plotXdata = []
        '''
        if clear is True:
            self.clearPlot()

    def clearPlot(self):
        self.plotframe.panel.clear()
        self.plotframe.reset_config()

        self.plotYdata = []
        self.plotXdata = []

    '''    
    def onStartTimer(self,event=None):
        self.count    = 0
        self.up_count = 0
        self.n_update = 1
        self.datrange = None
        self.time0    = time.time()
        ### LWW self.start_mem= self.report_memory()
        self.timer.Start(10)
        # self.timer.Start(500)
    
    def timer_results(self):
        if (self.count < 2): return
        etime = time.time() - self.time0
        tpp   = etime/max(1,self.count)
        s = "drew %i points in %8.3f s: time/point= %8.4f s" % (self.count,etime,tpp)
        self.plotframe.write_message(s)
        self.time0 = 0
        self.count = 0
        self.datrange = None
    '''
    '''
    def onTimer(self, event):
        # print 'timer ', self.count, time.time()
        self.count += 1
        self.showPlotFrame(do_raise=False, clear=False)
        n = self.count
        if n < 2:
            return
        if n >= self.npts:
            self.timer.Stop()
            self.timer_results()
        elif n <= 3:
            self.plotframe.plot(self.x[:n], self.y1[:n])# , grid=False)

        else:
            self.plotframe.update_line(0, self.x[:n], self.y1[:n], update_limits=n<10, draw=True)

            etime = time.time() - self.time0
            s = " %i / %i points in %8.4f s" % (n,self.npts,etime)
            self.plotframe.write_message(s)

        if self.datrange is None:
            self.datrange = [min(self.x[:n]), max(self.x[:n]),
                             min(self.y1[:n]),max(self.y1[:n])]

        dr = [min(self.x[:n]),  max(self.x[:n]),
              min(self.y1[:n]), max(self.y1[:n])]
        
        lims = self.plotframe.panel.get_viewlimits()
        if dr[0] < lims[0] or dr[1] > lims[1] or dr[2] < lims[2] or dr[3] > lims[3]:
            self.datrange = dr
            if n < len(self.x):
                nmax = min(int(n*1.6), len(self.x)-1)
                self.datrange[1] = self.x[nmax]
            self.plotframe.panel.set_xylims(self.datrange)
    '''
    def OnAbout(self, event):
        dlg = wx.MessageDialog(self, "This program shows MCA Spectra\n"
                                     "message dialog.",
                                     "About MPlot test", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def OnExit(self, event):
        """
        # 1st. disconnect PV(s)
        self.countDonePV.clear_callbacks()
        self.i0.disconnect()
        self.it.disconnect()
        self.iF.disconnect()
        self.trans.disconnect()
        self.motorPos.disconnect()
        """
        try:
            if self.plotframe is not None:
                self.plotframe.onExit()
        except:
            pass
        self.Destroy()
Example #20
0
class EigerFrame(wx.Frame):
    """AreaDetector Display """

    img_attrs = ('ArrayData', 'UniqueId_RBV')
    cam_attrs = ('Acquire', 'DetectorState_RBV', 'ArrayCounter',
                 'ArrayCounter_RBV', 'ThresholdEnergy', 'ThresholdEnergy_RBV',
                 'PhotonEnergy', 'PhotonEnergy_RBV', 'NumImages',
                 'NumImages_RBV', 'AcquireTime', 'AcquireTime_RBV',
                 'AcquirePeriod', 'AcquirePeriod_RBV', 'TriggerMode',
                 'TriggerMode_RBV')

    # plugins to enable
    enabled_plugins = ('image1', 'Over1', 'ROI1', 'JPEG1', 'TIFF1')

    def __init__(self, prefix=None, url=None, scale=1.0):
        self.ad_img = None
        self.ad_cam = None
        if prefix is None:
            dlg = SavedParameterDialog(label='Detector Prefix',
                                       title='Connect to Eiger Detector',
                                       configfile='.ad_eigerdisplay.dat')
            res = dlg.GetResponse()
            dlg.Destroy()
            if res.ok:
                prefix = res.value

        self.prefix = prefix
        self.fname = 'Eiger.tif'
        self.esimplon = None
        if url is not None and HAS_SIMPLON:
            self.esimplon = EigerSimplon(url, prefix=prefix + 'cam1:')

        self.lineplotter = None
        self.calib = {}
        self.integrator = None
        self.int_panel = None
        self.int_lastid = None
        self.contrast_levels = None
        self.scandb = None
        wx.Frame.__init__(self,
                          None,
                          -1,
                          "Eiger500K Area Detector Display",
                          style=wx.DEFAULT_FRAME_STYLE)

        self.buildMenus()
        self.buildFrame()

        wx.CallAfter(self.connect_escandb)

    def connect_escandb(self):
        if HAS_ESCAN and os.environ.get('ESCAN_CREDENTIALS', None) is not None:
            self.scandb = ScanDB()
            calib_loc = self.scandb.get_info('eiger_calibration')
            cal = self.scandb.get_detectorconfig(calib_loc)
            self.setup_calibration(json.loads(cal.text))

    def buildFrame(self):
        sbar = self.CreateStatusBar(3, wx.CAPTION)  # |wx.THICK_FRAME)
        self.SetStatusWidths([-1, -1, -1])
        sfont = sbar.GetFont()
        sfont.SetWeight(wx.BOLD)
        sfont.SetPointSize(10)
        sbar.SetFont(sfont)

        self.SetStatusText('', 0)

        sizer = wx.GridBagSizer(3, 3)
        panel = self.panel = wx.Panel(self)

        pvpanel = PVConfigPanel(panel, self.prefix, display_pvs)

        wsize = (100, -1)
        lsize = (250, -1)

        start_btn = wx.Button(panel, label='Start', size=wsize)
        stop_btn = wx.Button(panel, label='Stop', size=wsize)
        free_btn = wx.Button(panel, label='Free Run', size=wsize)
        start_btn.Bind(wx.EVT_BUTTON, partial(self.onButton, key='start'))
        stop_btn.Bind(wx.EVT_BUTTON, partial(self.onButton, key='stop'))
        free_btn.Bind(wx.EVT_BUTTON, partial(self.onButton, key='free'))

        self.cmap_choice = wx.Choice(panel, size=(80, -1), choices=colormaps)
        self.cmap_choice.SetSelection(0)
        self.cmap_choice.Bind(wx.EVT_CHOICE, self.onColorMap)

        self.cmap_reverse = wx.CheckBox(panel, label='Reverse', size=(60, -1))
        self.cmap_reverse.Bind(wx.EVT_CHECKBOX, self.onColorMap)

        self.show1d_btn = wx.Button(panel,
                                    label='Show 1D Integration',
                                    size=(200, -1))
        self.show1d_btn.Bind(wx.EVT_BUTTON, self.onShowIntegration)
        self.show1d_btn.Disable()

        self.imagesize = wx.StaticText(panel,
                                       label='? x ?',
                                       size=(250, 30),
                                       style=txtstyle)

        self.contrast = ContrastChoice(panel, callback=self.set_contrast_level)

        def lin(len=200, wid=2, style=wx.LI_HORIZONTAL):
            return wx.StaticLine(panel, size=(len, wid), style=style)

        irow = 0
        sizer.Add(pvpanel, (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(start_btn, (irow, 0), (1, 1), labstyle)
        sizer.Add(stop_btn, (irow, 1), (1, 1), labstyle)
        sizer.Add(free_btn, (irow, 2), (1, 1), labstyle)

        irow += 1
        sizer.Add(lin(300), (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(self.imagesize, (irow, 0), (1, 3), labstyle)

        irow += 1
        sizer.Add(wx.StaticText(panel, label='Color Map: '), (irow, 0), (1, 1),
                  labstyle)

        sizer.Add(self.cmap_choice, (irow, 1), (1, 1), labstyle)
        sizer.Add(self.cmap_reverse, (irow, 2), (1, 1), labstyle)

        irow += 1
        sizer.Add(self.contrast.label, (irow, 0), (1, 1), labstyle)
        sizer.Add(self.contrast.choice, (irow, 1), (1, 1), labstyle)

        irow += 1
        sizer.Add(self.show1d_btn, (irow, 0), (1, 2), labstyle)

        panel.SetSizer(sizer)
        sizer.Fit(panel)

        # image panel
        self.image = ADMonoImagePanel(self,
                                      prefix=self.prefix,
                                      rot90=DEFAULT_ROTATION,
                                      size=(400, 750),
                                      writer=partial(self.write, panel=2))

        mainsizer = wx.BoxSizer(wx.HORIZONTAL)
        mainsizer.Add(panel, 0, wx.LEFT | wx.GROW | wx.ALL)
        mainsizer.Add(self.image, 1, wx.CENTER | wx.GROW | wx.ALL)
        self.SetSizer(mainsizer)
        mainsizer.Fit(self)

        self.SetAutoLayout(True)

        try:
            self.SetIcon(wx.Icon(ICONFILE, wx.BITMAP_TYPE_ICO))
        except:
            pass

        wx.CallAfter(self.connect_pvs)

    def onColorMap(self, event=None):
        cmap_name = self.cmap_choice.GetStringSelection()
        if self.cmap_reverse.IsChecked():
            cmap_name = cmap_name + '_r'
        self.image.colormap = getattr(colormap, cmap_name)
        self.image.Refresh()

    def onCopyImage(self, event=None):
        "copy bitmap of canvas to system clipboard"
        bmp = wx.BitmapDataObject()
        bmp.SetBitmap(wx.Bitmap(self.image.GrabWxImage()))
        wx.TheClipboard.Open()
        wx.TheClipboard.SetData(bmp)
        wx.TheClipboard.Close()
        wx.TheClipboard.Flush()

    def onReadCalibFile(self, event=None):
        "read calibration file"
        wcards = "Poni Files(*.poni)|*.poni|All files (*.*)|*.*"
        dlg = wx.FileDialog(None,
                            message='Read Calibration File',
                            defaultDir=os.getcwd(),
                            wildcard=wcards,
                            style=wx.FD_OPEN)
        ppath = None
        if dlg.ShowModal() == wx.ID_OK:
            ppath = os.path.abspath(dlg.GetPath())

        if os.path.exists(ppath):
            if self.scandb is not None:
                CalibrationDialog(self, ppath).Show()
            else:
                self.setup_calibration(read_poni(ppath))

    def setup_calibration(self, calib):
        """set up calibration from calibration dict"""
        if self.image.rot90 in (1, 3):
            calib['rot3'] = np.pi / 2.0
        self.calib = calib
        if HAS_PYFAI:
            self.integrator = AzimuthalIntegrator(**calib)
            self.show1d_btn.Enable()

    def onShowIntegration(self, event=None):

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()

    def onAutoIntegration(self, event=None):
        if not event.IsChecked():
            self.int_timer.Stop()
            return

        if self.calib is None or 'poni1' not in self.calib:
            return
        shown = False
        try:
            self.int_panel.Raise()
            shown = True
        except:
            self.int_panel = None
        if not shown:
            self.int_panel = PlotFrame(self)
            self.show_1dpattern(init=True)
        else:
            self.show_1dpattern()
        self.int_timer.Start(500)

    def show_1dpattern(self, init=False):
        if self.calib is None or not HAS_PYFAI:
            return

        img = self.ad_img.PV('ArrayData').get()

        h, w = self.image.GetImageSize()
        img.shape = (w, h)
        img = img[3:-3, 1:-1][::-1, :]

        img_id = self.ad_cam.ArrayCounter_RBV
        q, xi = self.integrator.integrate1d(img,
                                            2048,
                                            unit='q_A^-1',
                                            correctSolidAngle=True,
                                            polarization_factor=0.999)
        if init:
            self.int_panel.plot(q,
                                xi,
                                xlabel=r'$Q (\rm\AA^{-1})$',
                                marker='+',
                                title='Image %d' % img_id)
            self.int_panel.Raise()
            self.int_panel.Show()
        else:
            self.int_panel.update_line(0, q, xi, draw=True)
            self.int_panel.set_title('Image %d' % img_id)

    @EpicsFunction
    def onSaveImage(self, event=None):
        "prompts for and save image to file"
        defdir = os.getcwd()
        self.fname = "Image_%i.tiff" % self.ad_cam.ArrayCounter_RBV
        dlg = wx.FileDialog(None,
                            message='Save Image as',
                            defaultDir=os.getcwd(),
                            defaultFile=self.fname,
                            style=wx.FD_SAVE)
        path = None
        if dlg.ShowModal() == wx.ID_OK:
            path = os.path.abspath(dlg.GetPath())

        root, fname = os.path.split(path)
        epics.caput("%sTIFF1:FileName" % self.prefix, fname)
        epics.caput("%sTIFF1:FileWriteMode" % self.prefix, 0)
        time.sleep(0.05)
        epics.caput("%sTIFF1:WriteFile" % self.prefix, 1)
        time.sleep(0.05)

        print(
            "Saved TIFF File ",
            epics.caget("%sTIFF1:FullFileName_RBV" % self.prefix,
                        as_string=True))

    def onExit(self, event=None):
        try:
            wx.Yield()
        except:
            pass
        self.Destroy()

    def onAbout(self, event=None):
        msg = """Eiger Image Display version 0.1
Matt Newville <*****@*****.**>"""

        dlg = wx.MessageDialog(self, msg, "About Epics Image Display",
                               wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def buildMenus(self):
        fmenu = wx.Menu()
        MenuItem(self, fmenu, "&Save\tCtrl+S", "Save Image", self.onSaveImage)
        MenuItem(self, fmenu, "&Copy\tCtrl+C", "Copy Image to Clipboard",
                 self.onCopyImage)
        MenuItem(self, fmenu, "Read Calibration File", "Read PONI Calibration",
                 self.onReadCalibFile)
        fmenu.AppendSeparator()
        MenuItem(self, fmenu, "E&xit\tCtrl+Q", "Exit Program", self.onExit)

        omenu = wx.Menu()
        MenuItem(self, omenu, "&Rotate CCW\tCtrl+R",
                 "Rotate Counter Clockwise", self.onRot90)
        MenuItem(self, omenu, "Flip Up/Down\tCtrl+T", "Flip Up/Down",
                 self.onFlipV)
        MenuItem(self, omenu, "Flip Left/Right\tCtrl+F", "Flip Left/Right",
                 self.onFlipH)
        MenuItem(self, omenu, "Reset Rotations and Flips", "Reset",
                 self.onResetRotFlips)
        omenu.AppendSeparator()

        hmenu = wx.Menu()
        MenuItem(self, hmenu, "About", "About Epics AreadDetector Display",
                 self.onAbout)

        mbar = wx.MenuBar()
        mbar.Append(fmenu, "File")
        mbar.Append(omenu, "Options")

        mbar.Append(hmenu, "&Help")
        self.SetMenuBar(mbar)

    def onResetRotFlips(self, event):
        self.image.rot90 = DEFAULT_ROTATION
        self.image.flipv = self.fliph = False

    def onRot90(self, event):
        self.image.rot90 = (self.image.rot90 - 1) % 4

    def onFlipV(self, event):
        self.image.flipv = not self.image.flipv

    def onFlipH(self, event):
        self.image.fliph = not self.image.fliph

    def set_contrast_level(self, contrast_level=0):
        self.image.contrast_levels = [contrast_level, 100.0 - contrast_level]

    def write(self, s, panel=0):
        """write a message to the Status Bar"""
        self.SetStatusText(text=s, number=panel)

    @EpicsFunction
    def onButton(self, event=None, key='free'):
        key = key.lower()
        if key.startswith('free'):
            self.image.restart_fps_counter()
            self.ad_cam.AcquireTime = 0.25
            self.ad_cam.AcquirePeriod = 0.25
            self.ad_cam.NumImages = 345600
            self.ad_cam.Acquire = 1
        elif key.startswith('start'):
            self.image.restart_fps_counter()
            self.ad_cam.Acquire = 1
        elif key.startswith('stop'):
            self.ad_cam.Acquire = 0

    @EpicsFunction
    def connect_pvs(self, verbose=True):
        if self.prefix is None or len(self.prefix) < 2:
            return

        if self.prefix.endswith(':'):
            self.prefix = self.prefix[:-1]
        if self.prefix.endswith(':image1'):
            self.prefix = self.prefix[:-7]
        if self.prefix.endswith(':cam1'):
            self.prefix = self.prefix[:-5]

        self.write('Connecting to AD %s' % self.prefix)
        self.ad_img = epics.Device(self.prefix + ':image1:',
                                   delim='',
                                   attrs=self.img_attrs)
        self.ad_cam = epics.Device(self.prefix + ':cam1:',
                                   delim='',
                                   attrs=self.cam_attrs)

        epics.caput("%s:TIFF1:EnableCallbacks" % self.prefix, 1)
        epics.caput("%s:TIFF1:AutoSave" % self.prefix, 0)
        epics.caput("%s:TIFF1:AutoIncrement" % self.prefix, 0)
        epics.caput("%s:TIFF1:FileWriteMode" % self.prefix, 0)

        time.sleep(0.002)
        if not self.ad_img.PV('UniqueId_RBV').connected:
            epics.poll()
            if not self.ad_img.PV('UniqueId_RBV').connected:
                self.write('Warning:  Camera seems to not be connected!')
                return
        if verbose:
            self.write('Connected to AD %s' % self.prefix)

        self.SetTitle("Epics Image Display: %s" % self.prefix)

        sizex = self.ad_cam.MaxSizeX_RBV
        sizey = self.ad_cam.MaxSizeY_RBV

        sizelabel = 'Image Size: %i x %i pixels'
        try:
            sizelabel = sizelabel % (sizex, sizey)
        except:
            sizelabel = sizelabel % (0, 0)

        self.imagesize.SetLabel(sizelabel)

        self.ad_cam.add_callback('DetectorState_RBV', self.onDetState)
        self.contrast.set_level_str('0.05')

    @DelayedEpicsCallback
    def onDetState(self, pvname=None, value=None, char_value=None, **kw):
        self.write(char_value, panel=1)
Example #21
0
class TestFrame(wx.Frame):
    def __init__(self, parent=None, *args, **kwds):

        kwds[
            "style"] = wx.DEFAULT_FRAME_STYLE | wx.RESIZE_BORDER | wx.TAB_TRAVERSAL

        wx.Frame.__init__(self, parent, -1, '', wx.DefaultPosition,
                          wx.Size(-1, -1), **kwds)
        self.SetTitle(" WXMPlot Plotting Demo")

        self.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD, False))
        menu = wx.Menu()
        menu_exit = menu.Append(-1, "E&xit", "Terminate the program")

        menuBar = wx.MenuBar()
        menuBar.Append(menu, "&File")
        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.OnExit, menu_exit)

        self.Bind(wx.EVT_CLOSE, self.OnExit)

        self.plotframe = None

        self.create_data()
        framesizer = wx.BoxSizer(wx.VERTICAL)

        panel = wx.Panel(self, -1, size=(-1, -1))
        panelsizer = wx.BoxSizer(wx.VERTICAL)

        panelsizer.Add(
            wx.StaticText(panel, -1, 'wxmplot 2D PlotPanel examples '), 0,
            wx.ALIGN_LEFT | wx.LEFT | wx.EXPAND, 10)

        b10 = wx.Button(panel, -1, 'Example #1', size=(-1, -1))
        b20 = wx.Button(panel, -1, 'Example #2', size=(-1, -1))
        b22 = wx.Button(panel, -1, 'Plot with 2 axes', size=(-1, -1))
        b31 = wx.Button(panel, -1, 'Plot with Errorbars', size=(-1, -1))
        b32 = wx.Button(panel, -1, 'SemiLog Plot', size=(-1, -1))
        b40 = wx.Button(panel, -1, 'Start Timed Plot', size=(-1, -1))
        b50 = wx.Button(panel, -1, 'Stop Timed Plot', size=(-1, -1))
        b60 = wx.Button(panel, -1, 'Plot 500,000 points', size=(-1, -1))
        bmany1 = wx.Button(panel,
                           -1,
                           'Plot 20 traces (delay_draw=False)',
                           size=(-1, -1))
        bmany2 = wx.Button(panel,
                           -1,
                           'Plot 20 traces (delay_draw=True)',
                           size=(-1, -1))
        bmany3 = wx.Button(panel,
                           -1,
                           'Plot 20 traces (use plot_many())',
                           size=(-1, -1))

        b10.Bind(wx.EVT_BUTTON, self.onPlot1)
        b20.Bind(wx.EVT_BUTTON, self.onPlot2)
        b22.Bind(wx.EVT_BUTTON, self.onPlot2Axes)
        b31.Bind(wx.EVT_BUTTON, self.onPlotErr)
        b32.Bind(wx.EVT_BUTTON, self.onPlotSLog)
        b40.Bind(wx.EVT_BUTTON, self.onStartTimer)
        b50.Bind(wx.EVT_BUTTON, self.onStopTimer)
        b60.Bind(wx.EVT_BUTTON, self.onPlotBig)

        bmany1.Bind(wx.EVT_BUTTON, self.onPlotMany_Slow)
        bmany2.Bind(wx.EVT_BUTTON, self.onPlotMany_Delay)
        bmany3.Bind(wx.EVT_BUTTON, self.onPlotMany_Fast)

        panelsizer.Add(b10, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b20, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b22, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b31, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b32, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b40, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b50, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(b60, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)

        panelsizer.Add(bmany1, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(bmany2, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)
        panelsizer.Add(bmany3, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER | wx.LEFT, 5)

        panel.SetSizer(panelsizer)
        panelsizer.Fit(panel)

        framesizer.Add(panel, 0, wx.ALIGN_LEFT | wx.EXPAND, 2)
        self.SetSizer(framesizer)
        framesizer.Fit(self)

        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer = wx.Timer(self)
        self.Refresh()

    def create_data(self):
        self.count = 0
        self.x = x = arange(0.0, 25.0, 0.1)
        self.y1 = 4 * cos(2 * pi * (x - 1) / 5.7) / (6 + x) + 2 * sin(
            2 * pi * (x - 1) / 2.2) / (10)
        self.y2 = sin(2 * pi * x / 30.0)
        self.y3 = -pi + 2 * (x / 10. + exp(-(x - 3) / 5.0))
        self.y4 = exp(0.01 + 0.5 * x) / (x + 2)
        self.y5 = 3000 * self.y3
        self.npts = len(self.x)
        self.bigx = linspace(0, 2500, 500000)
        self.bigy = (sin(pi * self.bigx / 140.0) +
                     cos(pi * self.bigx / 277.0) + cos(pi * self.bigx / 820.0))

        self.many_dlist = [(self.x, self.y1)]
        for i in range(19):
            self.many_dlist.append((self.x, sin(2 * (i + 1) * x / 23.0)))

    def ShowPlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self)
            self.has_plot = False
        try:
            self.plotframe.Show()
        except PyDeadObjectError:
            self.plotframe = PlotFrame(self)
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()

    def onPlot1(self, event=None):
        self.ShowPlotFrame()
        self.plotframe.plot(self.x, self.y1)
        self.plotframe.oplot(self.x, self.y2)
        self.plotframe.write_message("Plot 1")

    def onPlot2(self, event=None):
        self.ShowPlotFrame()
        x = arange(100)
        y1 = cos(pi * x / 72)
        y2 = sin(pi * x / 23)
        self.plotframe.plot(x, y1, color='red')
        self.plotframe.oplot(x, y2, color='green3', marker='+')
        self.plotframe.write_message("Plot 2")

    def onPlotErr(self, event=None):
        self.ShowPlotFrame()
        npts = 81
        x = linspace(0, 40.0, npts)
        y = 0.4 * cos(x / 2.0) + random.normal(scale=0.03, size=npts)
        dy = 0.03 * (ones(npts) + random.normal(scale=0.2, size=npts))

        self.plotframe.plot(x,
                            y,
                            dy=dy,
                            color='red',
                            linewidth=0,
                            xlabel='x',
                            ylabel='y',
                            marker='o',
                            title='Plot with error bars')
        self.plotframe.write_message("Errorbars!")

    def onPlot2Axes(self, event=None):
        self.ShowPlotFrame()

        self.plotframe.plot(self.x, self.y2, color='black', style='dashed')
        self.plotframe.oplot(self.x, self.y5, color='red', side='right')
        self.plotframe.write_message("Plot with 2 axes")

    def onPlotSLog(self, event=None):
        self.ShowPlotFrame()

        self.plotframe.plot(self.x,
                            self.y4,
                            ylog_scale=True,
                            color='black',
                            style='dashed')
        self.plotframe.write_message("Semi Log Plot")

    def onPlotBig(self, event=None):
        self.ShowPlotFrame()

        t0 = time.time()
        self.plotframe.plot(self.bigx, self.bigy, marker='+', linewidth=0)
        dt = time.time() - t0
        self.plotframe.write_message(
            "Plot array with npts=%i, elapsed time=%8.3f s" %
            (len(self.bigx), dt))

    def onPlotMany_Slow(self, event=None):
        self.ShowPlotFrame()
        dlist = self.many_dlist

        t0 = time.time()
        opts = dict(title='Plot 20 traces without delay_draw',
                    show_legend=True,
                    xlabel='x')

        self.plotframe.plot(dlist[0][0], dlist[0][1], **opts)
        for tdat in dlist[1:]:
            self.plotframe.oplot(tdat[0], tdat[1])

        dt = time.time() - t0
        self.plotframe.write_message(
            "Plot 20 traces without delay_draw=True, elapsed time=%8.3f s" %
            (dt))

    def onPlotMany_Delay(self, event=None):
        self.ShowPlotFrame()
        dlist = self.many_dlist

        t0 = time.time()
        opts = dict(title='Plot 20 traces with delay_draw',
                    show_legend=True,
                    xlabel='x')

        self.plotframe.plot(dlist[0][0], dlist[0][1], delay_draw=True, **opts)
        for tdat in dlist[1:-1]:
            self.plotframe.oplot(tdat[0], tdat[1], delay_draw=True)
        self.plotframe.oplot(dlist[-1][0], dlist[-1][1])
        dt = time.time() - t0
        self.plotframe.write_message(
            "Plot 20 traces with delay_draw=True, elapsed time=%8.3f s" % (dt))

    def onPlotMany_Fast(self, event=None):
        self.ShowPlotFrame()
        dlist = self.many_dlist

        t0 = time.time()
        opts = dict(title='Plot 20 traces using plot_many()',
                    show_legend=True,
                    xlabel='x')
        self.plotframe.plot_many(dlist, **opts)

        dt = time.time() - t0
        self.plotframe.write_message(
            "Plot 20 traces with plot_many(), elapsed time=%8.3f s" % (dt))

    def report_memory(i):
        pid = os.getpid()
        if os.name == 'posix':
            mem = os.popen("ps -o rss -p %i" % pid).readlines()[1].split()[0]
        else:
            mem = 0
        return int(mem)

    def onStartTimer(self, event=None):
        self.count = 0
        self.up_count = 0
        self.n_update = 1
        self.datrange = None
        self.time0 = time.time()
        self.start_mem = self.report_memory()
        self.timer.Start(10)

    def timer_results(self):
        if (self.count < 2): return
        etime = time.time() - self.time0
        tpp = etime / max(1, self.count)
        s = "drew %i points in %8.3f s: time/point= %8.4f s" % (self.count,
                                                                etime, tpp)
        self.plotframe.write_message(s)
        self.time0 = 0
        self.count = 0
        self.datrange = None

    def onStopTimer(self, event=None):
        self.timer.Stop()
        try:
            self.timer_results()
        except:
            pass

    def onTimer(self, event):
        # print 'timer ', self.count, time.time()
        self.count += 1
        n = self.count
        if n < 2:
            self.ShowPlotFrame(do_raise=False, clear=False)
            return
        if n >= self.npts:
            self.timer.Stop()
            self.timer_results()
        elif n <= 3:
            self.plotframe.plot(self.x[:n], self.y1[:n])  # , grid=False)

        else:
            self.plotframe.update_line(0,
                                       self.x[:n],
                                       self.y1[:n],
                                       update_limits=True,
                                       draw=True)
            etime = time.time() - self.time0
            s = " %i / %i points in %8.4f s" % (n, self.npts, etime)
            self.plotframe.write_message(s)

    def OnAbout(self, event):
        dlg = wx.MessageDialog(
            self, "This sample program shows some\n"
            "examples of WXMPlot PlotFrame.\n"
            "message dialog.", "About WXMPlot test",
            wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def OnExit(self, event):
        try:
            if self.plotframe != None: self.plotframe.onExit()
        except:
            pass
        self.Destroy()
Example #22
0
class TestFrame(wx.Frame):
    def __init__(self, parent=None, *args,**kwds):

        kwds["style"] = wx.DEFAULT_FRAME_STYLE|wx.RESIZE_BORDER|wx.TAB_TRAVERSAL

        wx.Frame.__init__(self, parent, -1, '',
                         wx.DefaultPosition, wx.Size(-1,-1), **kwds)
        self.SetTitle(" WXMPlot Plotting Demo")

        self.SetFont(wx.Font(12,wx.SWISS,wx.NORMAL,wx.BOLD,False))
        menu = wx.Menu()
        menu_exit = menu.Append(-1, "E&xit", "Terminate the program")

        menuBar = wx.MenuBar()
        menuBar.Append(menu, "&File");
        self.SetMenuBar(menuBar)

        self.Bind(wx.EVT_MENU, self.OnExit, menu_exit)

        self.Bind(wx.EVT_CLOSE, self.OnExit)

        self.plotframe  = None

        self.create_data()
        framesizer = wx.BoxSizer(wx.VERTICAL)

        panel      = wx.Panel(self, -1, size=(-1, -1))
        panelsizer = wx.BoxSizer(wx.VERTICAL)

        panelsizer.Add( wx.StaticText(panel, -1, 'wxmplot 2D PlotPanel examples '),
                        0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT|wx.EXPAND, 10)

        b10 = wx.Button(panel, -1, 'Example #1',          size=(-1,-1))
        b20 = wx.Button(panel, -1, 'Example #2',          size=(-1,-1))
        b22 = wx.Button(panel, -1, 'Plot with 2 axes',    size=(-1,-1))
        b31 = wx.Button(panel, -1, 'Plot with Errorbars', size=(-1,-1))
        b32 = wx.Button(panel, -1, 'SemiLog Plot',        size=(-1,-1))
        b40 = wx.Button(panel, -1, 'Start Timed Plot',    size=(-1,-1))
        b50 = wx.Button(panel, -1, 'Stop Timed Plot',     size=(-1,-1))
        b60 = wx.Button(panel, -1, 'Plot 500,000 points',  size=(-1,-1))
        bmany1 = wx.Button(panel, -1, 'Plot 20 traces (delay_draw=False)', size=(-1,-1))
        bmany2 = wx.Button(panel, -1, 'Plot 20 traces (delay_draw=True)', size=(-1,-1))
        bmany3 = wx.Button(panel, -1, 'Plot 20 traces (use plot_many())', size=(-1,-1))

        b10.Bind(wx.EVT_BUTTON,self.onPlot1)
        b20.Bind(wx.EVT_BUTTON,self.onPlot2)
        b22.Bind(wx.EVT_BUTTON,self.onPlot2Axes)
        b31.Bind(wx.EVT_BUTTON,self.onPlotErr)
        b32.Bind(wx.EVT_BUTTON,self.onPlotSLog)
        b40.Bind(wx.EVT_BUTTON,self.onStartTimer)
        b50.Bind(wx.EVT_BUTTON,self.onStopTimer)
        b60.Bind(wx.EVT_BUTTON,self.onPlotBig)

        bmany1.Bind(wx.EVT_BUTTON,self.onPlotMany_Slow)
        bmany2.Bind(wx.EVT_BUTTON,self.onPlotMany_Delay)
        bmany3.Bind(wx.EVT_BUTTON,self.onPlotMany_Fast)

        panelsizer.Add(b10, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(b20, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(b22, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(b31, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(b32, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(b40, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(b50, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(b60, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)

        panelsizer.Add(bmany1, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(bmany2, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)
        panelsizer.Add(bmany3, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.LEFT, 5)

        panel.SetSizer(panelsizer)
        panelsizer.Fit(panel)

        framesizer.Add(panel, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER|wx.EXPAND,2)
        self.SetSizer(framesizer)
        framesizer.Fit(self)

        self.Bind(wx.EVT_TIMER, self.onTimer)
        self.timer = wx.Timer(self)
        self.Refresh()

    def create_data(self):
        self.count = 0
        self.x  = x = arange(0.0,25.0,0.1)
        self.y1 = 4*cos(2*pi*(x-1)/5.7)/(6+x) + 2*sin(2*pi*(x-1)/2.2)/(10)
        self.y2 = sin(2*pi*x/30.0)
        self.y3 =  -pi + 2*(x/10. + exp(-(x-3)/5.0))
        self.y4 =  exp(0.01 + 0.5*x ) / (x+2)
        self.y5 =  3000 * self.y3
        self.npts = len(self.x)
        self.bigx   = linspace(0, 2500, 500000)
        self.bigy   = (sin(pi*self.bigx/140.0) +
                       cos(pi*self.bigx/277.0) +
                       cos(pi*self.bigx/820.0))


        self.many_dlist = [(self.x, self.y1)]
        for i in range(19):
            self.many_dlist.append((self.x, sin(2*(i+1)*x/23.0)))


    def ShowPlotFrame(self, do_raise=True, clear=True):
        "make sure plot frame is enabled, and visible"
        if self.plotframe is None:
            self.plotframe = PlotFrame(self)
            self.has_plot = False
        try:
            self.plotframe.Show()
        except PyDeadObjectError:
            self.plotframe = PlotFrame(self)
            self.plotframe.Show()

        if do_raise:
            self.plotframe.Raise()
        if clear:
            self.plotframe.panel.clear()
            self.plotframe.reset_config()


    def onPlot1(self,event=None):
        self.ShowPlotFrame()
        self.plotframe.plot(self.x,self.y1)
        self.plotframe.oplot(self.x,self.y2)
        self.plotframe.write_message("Plot 1")

    def onPlot2(self,event=None):
        self.ShowPlotFrame()
        x  = arange(100)
        y1 = cos(pi*x/72)
        y2 = sin(pi*x/23)
        self.plotframe.plot(x, y1, color='red')
        self.plotframe.oplot(x, y2, color='green3', marker='+')
        self.plotframe.write_message("Plot 2")


    def onPlotErr(self,event=None):
        self.ShowPlotFrame()
        npts = 81
        x  = linspace(0, 40.0, npts)
        y  = 0.4 * cos(x/2.0) + random.normal(scale=0.03, size=npts)
        dy = 0.03 * (ones(npts) + random.normal(scale=0.2, size=npts))

        self.plotframe.plot(x, y, dy=dy, color='red', linewidth=0,
                            xlabel='x', ylabel='y', marker='o',
                            title='Plot with error bars')
        self.plotframe.write_message("Errorbars!")


    def onPlot2Axes(self,event=None):
        self.ShowPlotFrame()

        self.plotframe.plot( self.x,self.y2, color='black',style='dashed')
        self.plotframe.oplot(self.x,self.y5, color='red', side='right')
        self.plotframe.write_message("Plot with 2 axes")


    def onPlotSLog(self,event=None):
        self.ShowPlotFrame()

        self.plotframe.plot( self.x,self.y4,ylog_scale=True,
                             color='black',style='dashed')
        self.plotframe.write_message("Semi Log Plot")

    def onPlotBig(self,event=None):
        self.ShowPlotFrame()

        t0 = time.time()
        self.plotframe.plot(self.bigx, self.bigy, marker='+', linewidth=0)
        dt = time.time()-t0
        self.plotframe.write_message(
            "Plot array with npts=%i, elapsed time=%8.3f s" % (len(self.bigx),dt))

    def onPlotMany_Slow(self, event=None):
        self.ShowPlotFrame()
        dlist = self.many_dlist

        t0 = time.time()
        opts = dict(title='Plot 20 traces without delay_draw',
            show_legend=True, xlabel='x')

        self.plotframe.plot(dlist[0][0], dlist[0][1], **opts)
        for tdat in dlist[1:]:
            self.plotframe.oplot(tdat[0], tdat[1])

        dt = time.time()-t0
        self.plotframe.write_message(
            "Plot 20 traces without delay_draw=True, elapsed time=%8.3f s" % (dt))

    def onPlotMany_Delay(self, event=None):
        self.ShowPlotFrame()
        dlist = self.many_dlist

        t0 = time.time()
        opts = dict(title='Plot 20 traces with delay_draw',
            show_legend=True, xlabel='x')

        self.plotframe.plot(dlist[0][0], dlist[0][1], delay_draw=True, **opts)
        for tdat in dlist[1:-1]:
            self.plotframe.oplot(tdat[0], tdat[1], delay_draw=True)
        self.plotframe.oplot(dlist[-1][0], dlist[-1][1])
        dt = time.time()-t0
        self.plotframe.write_message(
            "Plot 20 traces with delay_draw=True, elapsed time=%8.3f s" % (dt))


    def onPlotMany_Fast(self, event=None):
        self.ShowPlotFrame()
        dlist = self.many_dlist

        t0 = time.time()
        opts = dict(title='Plot 20 traces using plot_many()',
            show_legend=True, xlabel='x')
        self.plotframe.plot_many(dlist, **opts)

        dt = time.time()-t0
        self.plotframe.write_message(
            "Plot 20 traces with plot_many(), elapsed time=%8.3f s" % (dt))

    def report_memory(i):
        pid = os.getpid()
        if os.name == 'posix':
            mem = os.popen("ps -o rss -p %i" % pid).readlines()[1].split()[0]
        else:
            mem = 0
        return int(mem)

    def onStartTimer(self,event=None):
        self.count    = 0
        self.up_count = 0
        self.n_update = 1
        self.datrange = None
        self.time0    = time.time()
        self.start_mem= self.report_memory()
        self.timer.Start(10)

    def timer_results(self):
        if (self.count < 2): return
        etime = time.time() - self.time0
        tpp   = etime/max(1,self.count)
        s = "drew %i points in %8.3f s: time/point= %8.4f s" % (self.count,etime,tpp)
        self.plotframe.write_message(s)
        self.time0 = 0
        self.count = 0
        self.datrange = None

    def onStopTimer(self,event=None):
        self.timer.Stop()
        try:
            self.timer_results()
        except:
            pass

    def onTimer(self, event):
        # print 'timer ', self.count, time.time()
        self.count += 1
        n = self.count
        if n < 2:
            self.ShowPlotFrame(do_raise=False, clear=False)
            return
        if n >= self.npts:
            self.timer.Stop()
            self.timer_results()
        elif n <= 3:
            self.plotframe.plot(self.x[:n], self.y1[:n])# , grid=False)

        else:
            self.plotframe.update_line(0, self.x[:n], self.y1[:n], update_limits=True, draw=True)
            etime = time.time() - self.time0
            s = " %i / %i points in %8.4f s" % (n,self.npts,etime)
            self.plotframe.write_message(s)

    def OnAbout(self, event):
        dlg = wx.MessageDialog(self, "This sample program shows some\n"
                              "examples of WXMPlot PlotFrame.\n"
                              "message dialog.",
                              "About WXMPlot test", wx.OK | wx.ICON_INFORMATION)
        dlg.ShowModal()
        dlg.Destroy()

    def OnExit(self, event):
        try:
            if self.plotframe != None:  self.plotframe.onExit()
        except:
            pass
        self.Destroy()