Beispiel #1
0
 def traits_view(self):
     view = self.view_klass(
         HSplit(
             VGroup(
                 Tabbed(
                     Item("_scrollable_column_names",
                          style="custom",
                          editor=InstanceEditor(),
                          show_label=False,
                          label="Column Names"),
                     *self._included_col_scroll_list),
                 HGroup(Item('click_type', style='custom',
                             show_label=False),
                        Spring(),
                        label="When clicking a button...",
                        show_border=True)),
             VGroup(Item("expr",
                         style="custom",
                         show_label=False,
                         width=450),
                    show_border=True)),
         resizable=True,
         buttons=OKCancelButtons,
         title="Edit the filter...",
         statusbar=StatusItem(name="status_bar_message"),
     )
     return view
Beispiel #2
0
class TextEditor(HasPrivateTraits):

    # The text being edited:
    text = Str()

    # The current length of the text being edited:
    length = Property(observe='text')

    # The current time:
    time = Str()

    # The view definition:
    view = View(
        Label('Type into the text editor box:'),
        Item('text', style='custom', show_label=False),
        title='Text Editor',
        id='traitsui.demo.advanced.statusbar_demo',
        width=0.4,
        height=0.4,
        resizable=True,
        statusbar=[
            StatusItem(name='length', width=0.5),
            StatusItem(name='time', width=85),
        ],
    )

    # -- Property Implementations ---------------------------------------------

    def _get_length(self):
        return 'Length: %d characters' % len(self.text)

    # -- Default Trait Values -------------------------------------------------

    def _time_default(self):
        thread = Thread(target=self._clock)
        thread.daemon = True
        thread.start()

        return ''

    # -- Private Methods ------------------------------------------------------

    def _clock(self):
        """Update the statusbar time once every second."""
        while True:
            self.time = strftime('%I:%M:%S %p')
            sleep(1.0)
class calterm_data_viewer(HasTraits):
    """
    This is the user interface for plotting results from data acquisition
    supplemented with log file data from Calterm III, the Cummins ECM
    interface application. The UI is built with Enthought's Traits and TraitsUI
    """
    parameters = List(Parameter)
    selected_params = List
    parameter_names = Property(List(String), depends_on=['parameters'])
    parameter_units = Property(List(String), depends_on=['parameters'])

    channels = List(Channel)
    channel_names = Property(List(String), depends_on=['channels'])
    channel_gains = Property(List(String), depends_on=['channels'])
    selected_channels = List
    selected_channels_gains = Property(List(Float),
                                       depends_on=['selected_channels'])
    ## UI elements
    align_button = Button()
    plot_button = Button()
    save_button = Button()

    param_select_button = Button()
    channel_select_button = Button()
    gain_set_button = Button()

    sensor_data = Data()
    log_data = Data()

    data_file = File(filter=['csv'])
    log_file = File(filter=['csv'])

    data_file_status = Str('none loaded')
    log_file_status = Str('none loaded')

    # The text being edited:
    text = Str

    # The current length of the text being edited:
    length = Property(depends_on='text')

    # The current time:
    time = Str

    main_view = View(Group(Group(Group(Item(name='data_file', style='simple'),
                                       Item('channel_select_button',
                                            label='Ch. Select',
                                            show_label=False),
                                       Item('gain_set_button',
                                            label='Gain Set',
                                            show_label=False),
                                       orientation='horizontal'),
                                 Group(Item(name='log_file', style='simple'),
                                       Item('param_select_button',
                                            label='Parameter Select',
                                            show_label=False),
                                       orientation='horizontal'),
                                 orientation='vertical'),
                           Group(Item(name='align_button',
                                      label="Align Data",
                                      show_label=False),
                                 Item(name='plot_button',
                                      label="Plot",
                                      show_label=False),
                                 Item(name='save_button',
                                      label="Save",
                                      show_label=False),
                                 orientation="vertical"),
                           orientation="horizontal"),
                     statusbar=[
                         StatusItem(name='data_file_status', width=85),
                         StatusItem(name='log_file_status', width=85)
                     ],
                     title="Calterm III data alignment and analysis",
                     buttons=[OKButton])

    parameter_view = View(Item(name='selected_params',
                               show_label=False,
                               style='custom',
                               editor=SetEditor(
                                   name='parameter_names',
                                   ordered=True,
                                   can_move_all=True,
                                   left_column_title="Available parameters",
                                   right_column_title="Parameters to plot")),
                          title="Select parameters to plot",
                          buttons=[OKButton, CancelButton])

    channel_view = View(Item(name='selected_channels',
                             show_label=False,
                             style='custom',
                             editor=SetEditor(
                                 name='channel_names',
                                 ordered=True,
                                 can_move_all=True,
                                 left_column_title="Available channels",
                                 right_column_title="Channels to plot")),
                        title="Select channels to plot",
                        buttons=[OKButton, CancelButton])

    gains_view = View(
        Item(
            name='channels',
            style='custom',
            #             editor=TableEditor()),
            editor=ListEditor(use_notebook=True)),
        title="Set the gains for each channel",
        buttons=[OKButton, CancelButton])

    def _get_parameter_names(self):
        return [n.name for n in self.parameters]

    def _get_parameter_units(self):
        return [n.unit for n in self.parameters]

    def _get_channel_names(self):
        return [n.name for n in self.channels]

    def _get_channel_gains(self):
        return [n.gain for n in self.channels]

    def _channel_gains_changed(self):
        print "setting gains.\n"
        print self.channel_gains
        for n in range(self.channel_gains):
            self.channels[n].gain = channel_gains[n]

    def _get_selected_channels_gains(self):
        return [
            self.channel_gains[self.channel_names.index(n)]
            for n in self.selected_channels
        ]

    def _log_file_changed(self):
        [self.log_data.time, self.log_data.data, err] = \
                             import_calterm_log_file(self.log_file)
        if not err:
            self.log_data.loaded = True
            [p, u] = import_calterm_log_param_names(self.log_file)
            p_raw = p.split(',')
            u_raw = u.split(',')
            self.parameters = []
            for i in range(len(p_raw)):
                self.parameters.append(Parameter(name=p_raw[i], unit=u_raw[i]))
            self.configure_traits(view='parameter_view')
        else:
            print "Deal with the error here."
            self.log_data.loaded = False

    def _param_select_button_fired(self):
        self.configure_traits(view='parameter_view')

    def _channel_select_button_fired(self):
        self.configure_traits(view='channel_view')

    def _gain_set_button_fired(self):
        self.configure_traits(view='gains_view')

    def _data_file_changed(self):
        from os.path import splitext
        DEFAULT_GAIN = 1.875  ## nA/V
        DEFAULT_UNIT = 'nA'

        def npz_open():
            npz = np.load(self.data_file)
            return ([npz['time'], npz['data']])

        def csv_open():
            import re
            f = open(self.data_file)
            date_str = f.readline()
            step_str = f.readline()
            [a, b] = re.split("=", step_str.strip('\r\n'))
            step = float(b)
            del a, b
            data = np.genfromtxt(f, delimiter=',', unpack=True, names=True)
            f.close()
            length = data.shape[0]
            time = np.linspace(0, step * (length - 1), length)
            return ([time, data])

        fileopen = {
            '.npz': npz_open,
            '.csv': csv_open,
        }
        [self.sensor_data.time, self.sensor_data.data] = \
                                fileopen[splitext(self.data_file)[1]]()
        for i in self.sensor_data.data.dtype.names:
            self.channels.append(
                Channel(name=i, gain=DEFAULT_GAIN, unit=DEFAULT_UNIT))
        self.sensor_data.loaded = True
        self.configure_traits(view='channel_view')

    def _plot_button_fired(self):
        import matplotlib as mpl
        import matplotlib.pyplot as plt

        pad = 0.05
        fig_width = 8.5
        ax_left = 0.18
        ax_width = 0.75

        #Count how many axes need to be plotted
        num_axes = 0 + self.sensor_data.loaded
        #ax[i].set_ylabel(self.selected_param

        if self.log_data.loaded:
            num_axes += len(self.selected_params)
        if not (num_axes):
            print "No files loaded or no parameters selected.\n"
            return

        fig_height = 11  ## 2. * num_axes + 1.5
        fig = plt.figure(1, figsize=[fig_width, fig_height])
        fig.clf()

        #calculate the geometry for displaying the axes
        total_pad = pad * (num_axes + 1)
        ax_height = (1. - total_pad) / num_axes
        ax_bottom = np.linspace(pad, 1. - (ax_height + pad), num_axes)
        ax_top = ax_bottom + ax_height
        ax = {}

        for i in range(num_axes - self.sensor_data.loaded):
            ax[i] = fig.add_axes([ax_left, ax_bottom[i], ax_width, ax_height])
            ax[i].plot(self.log_data.time - self.log_data.time[0],
                       self.log_data.data[self.selected_params[i]])
            ax[i].set_ylabel(self.selected_params[i].replace('_', ' '))

        i = num_axes - 1
        if self.sensor_data.loaded:
            ax[i] = fig.add_axes([ax_left, ax_bottom[i], ax_width, ax_height])
            for j in range(len(self.selected_channels)):
                ax[i].plot(self.sensor_data.time,
                           self.sensor_data.data[self.selected_channels[j]] \
                           * self.selected_channels_gains[j],
                           label=self.selected_channels[j].replace('_', ' '))
            ax[i].set_xlabel('Time (s)')
            ax[i].set_ylabel('Sensor Current (nA)')
            ax[i].legend(loc='best')
        fig.show()

    def start(self):
        self.configure_traits(view='main_view')
Beispiel #4
0
# -----------------------------------------------------------#
# Main Control Panel View

ControlPanelView = View(HSplit(
    UItem('sofq_plot', width=0.8, style='custom', editor=InstanceEditor()),
    VSplit(
        UItem('experiment_file',
              height=0.1,
              style='custom',
              editor=InstanceEditor()),
        UItem('controls', height=0.9, style='custom', editor=InstanceEditor()),
    ),
),
                        resizable=True,
                        statusbar=[StatusItem(name='load_status')])

# -----------------------------------------------------------#
# Main Control Panel Controller


class ControlPanelHandler(Handler):
    def get_parents(self, info, node):
        # Grab selected Dataset
        selected = info.object.selected

        # Get the TreeEditor for the Experiment
        controls_editors = info.ui.get_editors("controls")
        experiment_editors = list()
        for editor in controls_editors:
            experiment_editors.extend(editor._ui.get_editors("experiment"))
Beispiel #5
0
class tcWindow(HasTraits):
    project = tcProject
    plot = tcPlot
    assert True, "tcWindow"

    def __init__(self, project):
        self.project = project
        self.plot = create_timechart_container(project)
        self.plot_range_tools = self.plot.range_tools
        self.plot_range_tools.on_trait_change(self._selection_time_changed,
                                              "time")
        self.trait_view().title = self.get_title()

    def get_title(self):
        if self.project.filename == "dummy":
            return "PyTimechart: Please Open a File"
        return "PyTimechart:" + self.project.filename

    # Create an action that exits the application.
    status = Str("Welcome to PyTimechart")
    traits_view = View(
        HSplit(
            VSplit(
                Item('project',
                     show_label=False,
                     editor=InstanceEditor(view='process_view'),
                     style='custom',
                     width=150),
                #                Item('plot_range_tools', show_label = False, editor=InstanceEditor(view = 'selection_view'), style='custom',width=150,height=100)
            ),
            Item('plot', show_label=False, editor=ComponentEditor()),
        ),
        toolbar=ToolBar(*_create_toolbar_actions(),
                        image_size=(24, 24),
                        show_tool_names=False),
        menubar=MenuBar(*_create_menubar_actions()),
        statusbar=[
            StatusItem(name='status'),
        ],
        resizable=True,
        width=1280,
        height=1024,
        handler=tcActionHandler())

    def _on_open_trace_file(self):
        if open_file(None) and self.project.filename == "dummy":
            self._ui.dispose()

    def _on_view_properties(self):
        self.plot.options.edit_traits()

    def _on_exit(self, n=None):
        self.close()
        sys.exit(0)

    def close(self, n=None):
        pass

    def _on_about(self):
        aboutBox().edit_traits()

    def _on_doc(self):
        browse_doc()

    def _selection_time_changed(self):
        self.status = "selection time:%s" % (self.plot_range_tools.time)
class ResultExplorer(HasTraits):

    # source of result data
    Beamformer = Instance(BeamformerBase)

    # traits for the plots
    plot_data = Instance(ArrayPlotData, transient=True)

    # the map
    map_plot = Instance(Plot, transient=True)
    imgp = Instance(ImagePlot, transient=True)

    # map interpolation
    interpolation = DelegatesTo('imgp', transient=True)

    # the colorbar for the map
    colorbar = Instance(ColorBar, transient=True)

    # the spectrum
    spec_plot = Instance(Plot, transient=True)

    # the main container for the plots
    plot_container = Instance(BasePlotContainer, transient=True)

    # zoom and integration box tool for map plot
    zoom = Instance(RectZoomSelect, transient=True)

    # selection of freqs
    synth = Instance(FreqSelector, transient=True)

    # cursor tool for spectrum plot
    cursor = Instance(BaseCursorTool, transient=True)

    # dynamic range of the map
    drange = Instance(DataRange1D, transient=True)

    # dynamic range of the spectrum plot
    yrange = Instance(DataRange1D, transient=True)

    # set if plots are invalid
    invalid = Bool(False, transient=True)

    # remember the last valid result
    last_valid_digest = Str(transient=True)

    # starts calculation thread
    start_calc = Button(transient=True)

    # signals end of calculation
    calc_ready = Event(transient=True)

    # calculation thread
    CThread = Instance(Thread, transient=True)

    # is calculation active ?
    running = Bool(False, transient=True)
    rmesg = Property(depends_on='running')

    # automatic recalculation ?
    automatic = Bool(False, transient=True)

    # picture
    pict = File(filter=['*.png', '*.jpg'],
                desc="name of picture file",
                transient=True)

    pic_x_min = Float(-1.0, desc="minimum  x-value picture plane")

    pic_y_min = Float(-0.75, desc="minimum  y-value picture plane")

    pic_scale = Float(400, desc="maximum  x-value picture plane")

    pic_flag = Bool(False, desc="show picture ?")

    view = View(
        HSplit(
            VGroup(
                HFlow(Item('synth{}', style='custom', width=0.8),
                      Item('start_calc{Recalc}', enabled_when='invalid'),
                      show_border=True),
                TGroup(
                    Item('plot_container{}', editor=ComponentEditor()),
                    dock='vertical',
                ),
            ),
            Tabbed(
                [Item('Beamformer', style='custom'), '-<>[Beamform]'],
                [
                    Item('Beamformer',
                         style='custom',
                         editor=InstanceEditor(view=fview)), '-<>[Data]'
                ],
            ),
            #                ['invalid{}~','last_valid_digest{}~',
            #                'calc_ready','running',
            #                '|'],
            dock='vertical'),  #HSplit
        statusbar=[StatusItem(name='rmesg', width=0.5)],
        #            icon= ImageResource('py.ico'),
        title="Beamform Result Explorer",
        resizable=True,
        menubar=MenuBarManager(
            MenuManager(
                MenuManager(Action(name='Open', action='load'),
                            Action(name='Save as', action='save_as'),
                            name='&Project'),
                MenuManager(Action(name='VI logger csv',
                                   action='import_time_data'),
                            Action(name='Pulse mat',
                                   action='import_bk_mat_data'),
                            Action(name='td file', action='import_td'),
                            name='&Import'),
                MenuManager(Action(name='NI-DAQmx', action='import_nidaqmx'),
                            name='&Acquire'),
                Action(name='R&un script', action='run_script'),
                Action(name='E&xit', action='_on_close'),
                name='&File',
            ),
            MenuManager(
                Group(
                    Action(name='&Delay+Sum',
                           style='radio',
                           action='set_Base',
                           checked=True),
                    Action(name='&Eigenvalue', style='radio',
                           action='set_Eig'),
                    Action(name='&Capon', style='radio', action='set_Capon'),
                    Action(name='M&usic', style='radio', action='set_Music'),
                    Action(name='D&amas', style='radio', action='set_Damas'),
                    Action(name='Clea&n', style='radio', action='set_Clean'),
                    Action(name='C&lean-SC',
                           style='radio',
                           action='set_Cleansc'),
                    Action(name='&Orthogonal',
                           style='radio',
                           action='set_Ortho'),
                    Action(name='&Functional',
                           style='radio',
                           action='set_Functional'),
                    Action(name='C&MF', style='radio', action='set_CMF'),
                ),
                Separator(),
                Action(name='Auto &recalc',
                       style='toggle',
                       checked_when='automatic',
                       action='toggle_auto'),
                name='&Options',
            ),
            MenuManager(
                Group(
                    #                            Action(name='&Frequency', action='set_Freq'),
                    Action(name='&Interpolation method', action='set_interp'),
                    Action(name='&Map dynamic range', action='set_drange'),
                    Action(name='&Plot dynamic range', action='set_yrange'),
                    Action(name='Picture &underlay', action='set_pic'),
                ),
                name='&View',
            ),
        ))  #View

    # init the app
    def __init__(self, **kwtraits):
        super(ResultExplorer, self).__init__(**kwtraits)
        # containers
        bgcolor = "sys_window"  #(212/255.,208/255.,200/255.) # Windows standard background
        self.plot_container = container = VPlotContainer(use_backbuffer=True,
                                                         padding=0,
                                                         fill_padding=False,
                                                         valign="center",
                                                         bgcolor=bgcolor)
        subcontainer = HPlotContainer(use_backbuffer=True,
                                      padding=0,
                                      fill_padding=False,
                                      halign="center",
                                      bgcolor=bgcolor)
        # freqs
        self.synth = FreqSelector(parent=self)
        # data source
        self.plot_data = pd = ArrayPlotData()
        self.set_result_data()
        self.set_pict()
        # map plot
        self.map_plot = Plot(pd, padding=40)
        self.map_plot.img_plot("image", name="image")
        imgp = self.map_plot.img_plot("map_data", name="map", colormap=jet)[0]
        self.imgp = imgp
        t1 = self.map_plot.plot(("xpoly", "ypoly"),
                                name="sector",
                                type="polygon")
        t1[0].face_color = (0, 0, 0, 0)  # set face color to transparent
        # map plot tools and overlays
        imgtool = ImageInspectorTool(imgp)
        imgp.tools.append(imgtool)
        overlay = ImageInspectorOverlay(component=imgp,
                                        image_inspector=imgtool,
                                        bgcolor="white",
                                        border_visible=True)
        self.map_plot.overlays.append(overlay)
        self.zoom = RectZoomSelect(self.map_plot,
                                   drag_button='right',
                                   always_on=True,
                                   tool_mode='box')
        self.map_plot.overlays.append(self.zoom)
        self.map_plot.tools.append(PanTool(self.map_plot))
        # colorbar
        colormap = imgp.color_mapper
        self.drange = colormap.range
        self.drange.low_setting = "track"
        self.colorbar = cb = ColorBar(
            index_mapper=LinearMapper(range=colormap.range),
            color_mapper=colormap,
            plot=self.map_plot,
            orientation='v',
            resizable='v',
            width=10,
            padding=20)
        # colorbar tools and overlays
        range_selection = RangeSelection(component=cb)
        cb.tools.append(range_selection)
        cb.overlays.append(
            RangeSelectionOverlay(component=cb,
                                  border_color="white",
                                  alpha=0.8,
                                  fill_color=bgcolor))
        range_selection.listeners.append(imgp)
        # spectrum plot
        self.spec_plot = Plot(pd, padding=25)
        px = self.spec_plot.plot(("freqs", "spectrum"),
                                 name="spectrum",
                                 index_scale="log")[0]
        self.yrange = self.spec_plot.value_range
        px.index_mapper = MyLogMapper(range=self.spec_plot.index_range)
        # spectrum plot tools
        self.cursor = CursorTool(
            px)  #, drag_button="left", color='blue', show_value_line=False)
        px.overlays.append(self.cursor)
        self.cursor.current_position = 0.3, 0.5
        px.index_mapper.map_screen(0.5)
        #        self.map_plot.tools.append(SaveTool(self.map_plot, filename='pic.png'))

        # layout
        self.set_map_details()
        self.reset_sector()
        subcontainer.add(self.map_plot)
        subcontainer.add(self.colorbar)
        #        subcontainer.tools.append(SaveTool(subcontainer, filename='pic.png'))
        container.add(self.spec_plot)
        container.add(subcontainer)
        container.tools.append(SaveTool(container, filename='pic.pdf'))
        self.last_valid_digest = self.Beamformer.ext_digest

    def _get_rmesg(self):
        if self.running:
            return "Running ..."
        else:
            return "Ready."

    @on_trait_change('Beamformer.ext_digest')
    def invalidate(self):
        if self.last_valid_digest != "" and self.Beamformer.ext_digest != self.last_valid_digest:
            self.invalid = True

    def _start_calc_fired(self):
        if self.CThread and self.CThread.isAlive():
            pass
        else:
            self.CThread = CalcThread()
            self.CThread.b = self.Beamformer
            self.CThread.caller = self
            self.CThread.start()

    def _calc_ready_fired(self):
        f = self.Beamformer.freq_data
        low, high = f.freq_range
        print low, high
        fr = f.fftfreq()
        if self.synth.synth_freq < low:
            self.synth.synth_freq = fr[1]
        if self.synth.synth_freq > high:
            self.synth.synth_freq = fr[-2]
        self.set_result_data()
        self.set_map_details()
        self.plot_container.request_redraw()
        self.map_plot.request_redraw()

    @on_trait_change('invalid')
    def activate_plot(self):
        self.plot_container.visible = not self.invalid
        self.plot_container.request_redraw()
        if self.invalid and self.automatic:
            self._start_calc_fired()

    @on_trait_change('cursor.current_position')
    def update_synth_freq(self):
        self.synth.synth_freq = self.cursor.current_position[0]

    def reset_sector(self):
        g = self.Beamformer.grid
        if self.zoom:
            self.zoom.x_min = g.x_min
            self.zoom.y_min = g.y_min
            self.zoom.x_max = g.x_max
            self.zoom.y_max = g.y_max

    @on_trait_change(
        'zoom.box,synth.synth_freq,synth.synth_type,drange.+,yrange.+')
    def set_result_data(self):
        if self.invalid:
            return
        if self.cursor:
            self.cursor.current_position = self.synth.synth_freq, 0
        pd = self.plot_data
        if not pd:
            return
        g = self.Beamformer.grid
        try:
            map_data = self.Beamformer.synthetic(self.synth.synth_freq,
                                                 self.synth.synth_type_).T
            map_data = L_p(map_data)
        except:
            map_data = arange(0, 19.99, 20. / g.size).reshape(g.shape)
        pd.set_data("map_data", map_data)
        f = self.Beamformer.freq_data
        if self.zoom and self.zoom.box:
            sector = self.zoom.box
        else:
            sector = (g.x_min, g.y_min, g.x_max, g.y_max)
        pd.set_data("xpoly", array(sector)[[0, 2, 2, 0]])
        pd.set_data("ypoly", array(sector)[[1, 1, 3, 3]])
        ads = pd.get_data("freqs")
        if not ads:
            freqs = ArrayDataSource(f.fftfreq()[f.ind_low:f.ind_high],
                                    sort_order='ascending')
            pd.set_data("freqs", freqs)
        else:
            ads.set_data(f.fftfreq()[f.ind_low:f.ind_high],
                         sort_order='ascending')
        self.synth.enumerate()
        try:
            spectrum = self.Beamformer.integrate(sector)[f.ind_low:f.ind_high]
            spectrum = L_p(spectrum)
        except:
            spectrum = f.fftfreq()[f.ind_low:f.ind_high]
        pd.set_data("spectrum", spectrum)

    @on_trait_change('pic+')
    def set_map_details(self):
        if self.invalid:
            return
        mp = self.map_plot
        # grid
        g = self.Beamformer.grid
        xs = linspace(g.x_min, g.x_max, g.nxsteps)
        ys = linspace(g.y_min, g.y_max, g.nysteps)
        mp.range2d.sources[1].set_data(xs,
                                       ys,
                                       sort_order=('ascending', 'ascending'))
        mp.aspect_ratio = (xs[-1] - xs[0]) / (ys[-1] - ys[0])
        yl, xl = self.plot_data.get_data("image").shape[0:2]
        xp = (self.pic_x_min, self.pic_x_min + xl * 1.0 / self.pic_scale)
        yp = (self.pic_y_min, self.pic_y_min + yl * 1.0 / self.pic_scale)
        mp.range2d.sources[0].set_data(xp,
                                       yp,
                                       sort_order=('ascending', 'ascending'))
        mp.range2d.low_setting = (g.x_min, g.y_min)
        mp.range2d.high_setting = (g.x_max, g.y_max)

        # dynamic range
        map = mp.plots["map"][0]
        #map.color_mapper.range.low_setting="track"
        # colormap
        map.color_mapper._segmentdata['alpha'] = [(0.0, 0.0, 0.0),
                                                  (0.001, 0.0, 1.0),
                                                  (1.0, 1.0, 1.0)]
        map.color_mapper._recalculate()
        mp.request_redraw()

    @on_trait_change('pict')
    def set_pict(self):
        pd = self.plot_data
        if not pd:
            return
        try:
            imgd = ImageData.fromfile(self.pict)._data[::-1]
        except:
            imgd = ImageData()
            imgd.set_data(255 * ones((2, 2, 3), dtype='uint8'))
            imgd = imgd._data
        pd.set_data("image", imgd)

    def save_as(self):
        dlg = FileDialog(action='save as', wildcard='*.rep')
        dlg.open()
        if dlg.filename != '':
            fi = file(dlg.filename, 'w')
            dump(self, fi)
            fi.close()

    def load(self):
        dlg = FileDialog(action='open', wildcard='*.rep')
        dlg.open()
        if dlg.filename != '':
            fi = file(dlg.filename, 'rb')
            s = load(fi)
            self.copy_traits(s)
            fi.close()

    def run_script(self):
        dlg = FileDialog(action='open', wildcard='*.py')
        dlg.open()
        if dlg.filename != '':
            #~ try:
            rx = self
            b = rx.Beamformer
            script = dlg.path
            execfile(dlg.path)
            #~ except:
            #~ pass

    def import_time_data(self):
        t = self.Beamformer.freq_data.time_data
        ti = csv_import()
        ti.from_file = 'C:\\tyto\\array\\07.03.2007 16_45_59,203.txt'
        ti.configure_traits(kind='modal')
        t.name = ""
        ti.get_data(t)

    def import_bk_mat_data(self):
        t = self.Beamformer.freq_data.time_data
        ti = bk_mat_import()
        ti.from_file = 'C:\\work\\1_90.mat'
        ti.configure_traits(kind='modal')
        t.name = ""
        ti.get_data(t)

    def import_td(self):
        t = self.Beamformer.freq_data.time_data
        ti = td_import()
        ti.from_file = 'C:\\work\\x.td'
        ti.configure_traits(kind='modal')
        t.name = ""
        ti.get_data(t)

    def import_nidaqmx(self):
        t = self.Beamformer.freq_data.time_data
        ti = nidaq_import()
        ti.configure_traits(kind='modal')
        t.name = ""
        ti.get_data(t)

    def set_Base(self):
        b = self.Beamformer
        self.Beamformer = BeamformerBase(freq_data=b.freq_data,
                                         grid=b.grid,
                                         mpos=b.mpos,
                                         c=b.c,
                                         env=b.env)
        self.invalid = True

    def set_Eig(self):
        b = self.Beamformer
        self.Beamformer = BeamformerEig(freq_data=b.freq_data,
                                        grid=b.grid,
                                        mpos=b.mpos,
                                        c=b.c,
                                        env=b.env)
        self.invalid = True

    def set_Capon(self):
        b = self.Beamformer
        self.Beamformer = BeamformerCapon(freq_data=b.freq_data,
                                          grid=b.grid,
                                          mpos=b.mpos,
                                          c=b.c,
                                          env=b.env)
        self.invalid = True

    def set_Music(self):
        b = self.Beamformer
        self.Beamformer = BeamformerMusic(freq_data=b.freq_data,
                                          grid=b.grid,
                                          mpos=b.mpos,
                                          c=b.c,
                                          env=b.env)
        self.invalid = True

    def set_Damas(self):
        b = self.Beamformer
        self.Beamformer = BeamformerDamas(beamformer=BeamformerBase(
            freq_data=b.freq_data, grid=b.grid, mpos=b.mpos, c=b.c, env=b.env))
        self.invalid = True

    def set_Cleansc(self):
        b = self.Beamformer
        self.Beamformer = BeamformerCleansc(freq_data=b.freq_data,
                                            grid=b.grid,
                                            mpos=b.mpos,
                                            c=b.c,
                                            env=b.env)
        self.invalid = True

    def set_Ortho(self):
        b = self.Beamformer
        self.Beamformer = BeamformerOrth(beamformer=BeamformerEig(
            freq_data=b.freq_data, grid=b.grid, mpos=b.mpos, c=b.c, env=b.env))
        self.Beamformer.n = 10
        self.invalid = True

    def set_Functional(self):
        b = self.Beamformer
        self.Beamformer = BeamformerFunctional(freq_data=b.freq_data,
                                               grid=b.grid,
                                               mpos=b.mpos,
                                               c=b.c,
                                               env=b.env)
        self.invalid = True

    def set_Clean(self):
        b = self.Beamformer
        self.Beamformer = BeamformerClean(beamformer=BeamformerBase(
            freq_data=b.freq_data, grid=b.grid, mpos=b.mpos, c=b.c, env=b.env))
        self.invalid = True

    def set_CMF(self):
        b = self.Beamformer
        self.Beamformer = BeamformerCMF(freq_data=b.freq_data,
                                        grid=b.grid,
                                        mpos=b.mpos,
                                        c=b.c,
                                        env=b.env)
        self.invalid = True

    def toggle_auto(self):
        self.automatic = not self.automatic

    def set_interp(self):
        self.configure_traits(kind='live', view=interpview)

    def set_drange(self):
        self.drange.configure_traits(kind='live', view=drangeview)

    def set_yrange(self):
        self.yrange.configure_traits(kind='live', view=drangeview)

    def set_pic(self):
        self.configure_traits(kind='live', view=picview)
Beispiel #7
0
class multicolorfits_viewer(HasTraits):
    """The main window. Has instructions for creating and destroying the app.
    """

    panel1 = Instance(ControlPanel)
    panel2 = Instance(ControlPanel)
    panel3 = Instance(ControlPanel)
    panel4 = Instance(ControlPanel)

    figure_combined = Instance(Figure, ())
    image = Array()
    image_axes = Instance(Axes)
    image_axesimage = Instance(AxesImage)
    image_xsize = Int(256)
    image_ysize = Int(256)

    gamma = Float(2.2)

    tickcolor = Str(
        '0.9'
    )  #,auto_set=False,enter_set=True) #Apparently need to set to TextEditor explicitly below...
    tickcolor_picker = ColorTrait((230, 230, 230))
    sexdec = Enum('Sexagesimal', 'Decimal')

    plotbutton_combined = Button(u"Plot Combined")
    plotbutton_inverted_combined = Button(u"Plot Inverted Combined")
    clearbutton_combined = Button(u"Clear Combined")
    save_the_image = Button(u"Save Image")
    save_the_fits = Button(u"Save RGB Fits")
    print_params = Button(u"Print Params")

    status_string_left = Str('')
    status_string_right = Str('')

    def _panel1_default(self):
        return ControlPanel()  #figure=self.figure)

    def _panel2_default(self):
        return ControlPanel()  #figure=self.figure)

    def _panel3_default(self):
        return ControlPanel()  #figure=self.figure)

    def _panel4_default(self):
        return ControlPanel()  #figure=self.figure)

    def __init__(self):
        super(multicolorfits_viewer, self).__init__()

        self._init_params(
        )  #Set placeholder things like the WCS, tick color, map units...
        self.image = self._fresh_image()  #Sets a blank image
        self.image_axes = self.figure_combined.add_subplot(111, aspect=1)
        self.image_axesimage = self.image_axes.imshow(self.image,
                                                      cmap='gist_gray',
                                                      origin='lower',
                                                      interpolation='nearest')
        self.image_axes.set_xlabel(self.xlabel)
        self.image_axes.set_ylabel(self.ylabel)
        self.image_axes.tick_params(
            axis='both',
            color=self.tickcolor)  #colors=... also sets label color
        try:
            self.image_axes.coords.frame.set_color(
                self.tickcolor
            )  #Updates the frame color.  .coords won't exist until WCS set
        except:
            [
                self.image_axes.spines[s].set_color(self.tickcolor)
                for s in ['top', 'bottom', 'left', 'right']
            ]

    view = View(Item("gamma",label=u"Gamma",show_label=True),
                Item('_'),

                HSplit(
                  Group(
                    Group(Item('panel1', style="custom",show_label=False),label='Image 1'),
                    Group(Item('panel2', style="custom",show_label=False),label='Image 2'),
                    Group(Item('panel3', style="custom",show_label=False),label='Image 3'),
                    Group(Item('panel4', style="custom",show_label=False),label='Image 4'),
                  orientation='horizontal',layout='tabbed',springy=True),

                VGroup(
                    HGroup(
                      Item('tickcolor',label='Tick Color',show_label=True, \
                          tooltip='Color of ticks: standard name float[0..1], or #hex', \
                          editor=TextEditor(auto_set=False, enter_set=True,)),
                      Item('tickcolor_picker',label='Pick',show_label=True,editor=ColorEditor()),
                      Item('sexdec',label='Coordinate Style',tooltip=u'Display coordinates in sexagesimal or decimal', \
                           show_label=True),
                      ),
                    Item('figure_combined', editor=MPLFigureEditor(),show_label=False, width=900, height=800,resizable=True),
                  HGroup(

                    Item('plotbutton_combined', tooltip=u"Plot the image",show_label=False),
                    Item('plotbutton_inverted_combined', tooltip=u"Plot the inverted image",show_label=False),
                    Item('clearbutton_combined',tooltip=u'Clear the combined figure',show_label=False),
                    Item("save_the_image", tooltip=u"Save current image. Mileage may vary...",show_label=False),
                    Item("save_the_fits", tooltip=u"Save RGB frames as single fits file with header.",show_label=False),
                    Item("print_params", tooltip=u"Print out current settings for use in manual image scripting.",show_label=False),
                  ), #HGroup
                ), #VGroup
                show_labels=False,),
           resizable=True,
           height=0.75, width=0.75,
           statusbar = [StatusItem(name = 'status_string_left', width = 0.5),
                        StatusItem(name = 'status_string_right', width = 0.5)],
           title=u"Fits Multi-Color Combiner",handler=MPLInitHandler ) #View

    def _init_params(self):
        plt.rcParams.update({'font.family': 'serif','xtick.major.size':6,'ytick.major.size':6, \
                             'xtick.major.width':1.,'ytick.major.width':1., \
                             'xtick.direction':'in','ytick.direction':'in'})
        try:
            plt.rcParams.update({
                'xtick.top': True,
                'ytick.right': True
            })  #apparently not in mpl v<2.0...
        except:
            pass  #Make a workaround for mpl<2.0 later...
        self.datamin_initial = 0.
        self.datamax_initial = 1.
        self.datamin = 0.
        self.datamax = 1.  #This will be the displayed value of the scaling min/max
        #self.mapunits='Pixel Value'
        #self.tickcolor='0.5'#'white', 'black', '0.5'
        self.wcs = WCS()
        self.xlabel = 'x'
        self.ylabel = 'y'

    def _fresh_image(self):
        #self.norm=ImageNormalize(self.image,stretch=scaling_fns['linear']() )
        blankdata = np.zeros([100, 100])
        blankdata[-1, -1] = 1
        return blankdata

    def update_radecpars(self):
        self.rapars = self.image_axes.coords[0]
        self.decpars = self.image_axes.coords[1]
        self.rapars.set_ticks(color=self.tickcolor)
        self.decpars.set_ticks(color=self.tickcolor)
        self.rapars.set_ticks(number=6)
        self.decpars.set_ticks(number=6)
        #self.rapars.set_ticklabel(size=8); self.decpars.set_ticklabel(size=8); #size here means the tick length
        ##self.rapars.set_ticks(spacing=10*u.arcmin, color='white', exclude_overlapping=True)
        ##self.decpars.set_ticks(spacing=5*u.arcmin, color='white', exclude_overlapping=True)
        self.rapars.display_minor_ticks(True)
        #self.rapars.set_minor_frequency(10)
        self.decpars.display_minor_ticks(True)
        if self.sexdec == 'Sexagesimal':
            self.rapars.set_major_formatter('hh:mm:ss.ss')
            self.decpars.set_major_formatter('dd:mm:ss.ss')
            #self.rapars.set_separator(('$^\mathrm{H}$', "'", '"'))
            self.rapars.set_separator(('H ', "' ", '" '))
            #format_xcoord=lambda x,y: '{}i$^\mathrm{H}${}{}{}'.format(x[0],x[1],"'",x[2],'"')
            #self.image_axes.format_coord=format_xcoord
        else:
            self.rapars.set_major_formatter('d.dddddd')
            self.decpars.set_major_formatter('d.dddddd')
        ##self.decpars.ticklabels.set_rotation(45) #Rotate ticklabels
        ##self.decpars.ticklabels.set_color(xkcdrust) #Ticklabel Color

    @on_trait_change('tickcolor')
    def update_tickcolor(self):
        try:
            #Catch case when you've predefined a color variable in hex string format, e.g., mynewred='#C11B17'
            #--> Need to do this first, otherwise traits throws a fit up the stack even despite the try/except check
            globals()[
                self.tickcolor]  #This check should catch undefined inputs
            self.image_axes.tick_params(axis='both',
                                        color=globals()[self.tickcolor])
            self.image_axes.coords.frame.set_color(self.tickcolor)
            self.tickcolor_picker = hex_to_rgb(globals()[self.tickcolor])
            self.status_string_right = 'Tick color changed to ' + self.tickcolor
        except:
            try:
                self.tickcolor = to_hex(self.tickcolor)
                try:
                    self.update_radecpars()
                except:
                    self.image_axes.tick_params(axis='both',
                                                color=to_hex(self.tickcolor))
                    self.image_axes.coords.frame.set_color(
                        to_hex(self.tickcolor))
                self.status_string_right = 'Tick color changed to ' + self.tickcolor
            except:
                self.status_string_right = "Color name %s not recognized.  Must be standard mpl.colors string, float[0..1] or #hex string" % (
                    self.tickcolor)
        try:
            self.tickcolor_picker = hex_to_rgb(to_hex(
                self.tickcolor))  #update the picker color...
        except:
            pass
        self.figure_combined.canvas.draw()

    @on_trait_change('tickcolor_picker')
    def update_tickcolorpicker(self):
        #print self.tickcolor_picker.name()
        self.tickcolor = self.tickcolor_picker.name()

    @on_trait_change('sexdec')
    def update_sexdec(self):
        self.update_radecpars()
        self.figure_combined.canvas.draw()
        self.status_string_right = 'Coordinate style changed to ' + self.sexdec

    def _plotbutton_combined_fired(self):
        try:
            self.panel1.data
        except:
            self.status_string_right = "No fits file loaded yet!"
            return
        #self.image=self.panel1.data
        self.wcs = WCS(self.panel1.hdr)
        self.hdr = self.panel1.hdr

        self.combined_RGB = combine_multicolor([
            pan.image_colorRGB
            for pan in [self.panel1, self.panel2, self.panel3, self.panel4]
            if pan.in_use == True
        ],
                                               gamma=self.gamma)

        ###Using this command is preferable, as long as the projection doesn't need to be updated...
        #  The home zoom button will work, but no WCS labels because projection wasn't set during init.
        #self.image_axesimage.set_data(self.data)
        ###Using this set instead properly updates the axes labels to WCS, but the home zoom button won't work
        self.figure_combined.clf()
        self.image_axes = self.figure_combined.add_subplot(111,
                                                           aspect=1,
                                                           projection=self.wcs)
        self.image_axesimage = self.image_axes.imshow(self.combined_RGB,
                                                      origin='lower',
                                                      interpolation='nearest')

        self.update_radecpars()
        self.figure_combined.canvas.draw()
        self.status_string_right = "Plot updated"

    def _plotbutton_inverted_combined_fired(self):
        try:
            self.panel1.data
        except:
            self.status_string_right = "No fits file loaded yet!"
            return
        self.wcs = WCS(self.panel1.hdr)
        self.hdr = self.panel1.hdr
        self.combined_RGB = combine_multicolor(
            [
                pan.image_colorRGB for pan in
                [self.panel1, self.panel2, self.panel3, self.panel4]
                if pan.in_use == True
            ],
            inverse=True,
            gamma=self.gamma,
        )
        self.figure_combined.clf()
        self.image_axes = self.figure_combined.add_subplot(111,
                                                           aspect=1,
                                                           projection=self.wcs)
        self.image_axesimage = self.image_axes.imshow(self.combined_RGB,
                                                      origin='lower',
                                                      interpolation='nearest')
        self.update_radecpars()
        self.figure_combined.canvas.draw()
        self.status_string_right = "Plot updated"

    def _clearbutton_combined_fired(self):
        try:
            del self.combined_RGB  #If clear already pressed once, data will already have been deleted...
        except:
            pass
        self.in_use = False
        self.figure_combined.clf()
        self.image = self._fresh_image()
        self.image_axes = self.figure_combined.add_subplot(111, aspect=1)
        self.image_axesimage = self.image_axes.imshow(self.image,
                                                      cmap='gist_gray',
                                                      origin='lower',
                                                      interpolation='nearest')
        self.xlabel = 'x'
        self.ylabel = 'y'
        self.image_axes.set_xlabel(self.xlabel)
        self.image_axes.set_ylabel(self.ylabel)
        self.image_axes.tick_params(axis='both', color=self.tickcolor)
        try:
            self.image_axes.coords.frame.set_color(self.tickcolor)
        except:
            self.tickcolor_picker = hex_to_rgb(to_hex(self.tickcolor))
        self.figure_combined.canvas.draw()
        self.status_string_right = "Plot cleared"

    def setup_mpl_events(self):
        self.image_axeswidget = AxesWidget(self.image_axes)
        self.image_axeswidget.connect_event('motion_notify_event',
                                            self.image_on_motion)
        self.image_axeswidget.connect_event('figure_leave_event',
                                            self.on_cursor_leave)
        self.image_axeswidget.connect_event('figure_enter_event',
                                            self.on_cursor_enter)
        self.image_axeswidget.connect_event('button_press_event',
                                            self.image_on_click)

    def image_on_motion(self, event):
        if event.xdata is None or event.ydata is None: return
        x = int(np.round(event.xdata))
        y = int(np.round(event.ydata))
        if ((x >= 0) and (x < self.image.shape[1]) and (y >= 0)
                and (y < self.image.shape[0])):
            imval = self.image[y, x]
            self.status_string_left = "x,y={},{}  {:.5g}".format(x, y, imval)
        else:
            self.status_string_left = ""

    def image_on_click(self, event):
        if event.xdata is None or event.ydata is None or event.button is not 1:
            return  #Covers when click outside of main plot
        #print event
        x = int(
            np.round(event.xdata)
        )  #xdata is the actual pixel position.  xy is in 'display space', i.e. pixels in the canvas
        y = int(np.round(event.ydata))
        xwcs, ywcs = self.wcs.wcs_pix2world([[x, y]], 0)[0]
        #print xwcs,ywcs
        if ((x >= 0) and (x < self.image.shape[1]) and (y >= 0)
                and (y < self.image.shape[0])):
            imval = self.image[y, x]
            self.status_string_right = "x,y=[{},{}], RA,DEC=[{}, {}], value = {:.5g}".format(
                x, y, xwcs, ywcs, imval)
            #self.status_string_right = "x,y[{},{}] = {:.3f},{:.3f}  {:.5g}".format(x, y,event.xdata,event.ydata, imval)
        else:
            self.status_string_right = ""
        ## left-click: event.button = 1, middle-click: event.button=2, right-click: event.button=3.
        ## For double-click, event.dblclick = False for first click, True on second
        #print event.button, event.dblclick

    def on_cursor_leave(self, event):
        QApplication.restoreOverrideCursor()
        self.status_string_left = ''

    def on_cursor_enter(self, event):
        QApplication.setOverrideCursor(Qt.CrossCursor)

    def _save_the_image_fired(self):
        dlg = FileDialog(action='save as')
        if dlg.open() == OK: plt.savefig(dlg.path, size=(800, 800), dpi=300)

    def _save_the_fits_fired(self):
        #Generate a generic header with correct WCS and comments about the colors that made it
        #... come back and finish this later...
        dlg = FileDialog(action='save as')
        if dlg.open() == OK:
            pyfits.writeto(
                dlg.path,
                np.swapaxes(np.swapaxes(self.combined_RGB, 0, 2), 2, 1),
                self.hdr)

    def _print_params_fired(self):
        print('\n\nRGB Image plot params:')
        pan_i = 0
        for pan in [self.panel1, self.panel2, self.panel3, self.panel4]:
            pan_i += 1
            if pan.in_use == True:
                print('image%i: ' % (pan_i))
                print('    vmin = %.3e , vmax = %.3e, scale = %s' %
                      (pan.datamin, pan.datamax, pan.image_scale))
                print("    image color = '%s'" % (pan.imagecolor))
        print("gamma = %.1f , tick color = '%s'\n" %
              (self.gamma, self.tickcolor))
Beispiel #8
0
class ControlPanel(HasTraits):
    """This is the control panel where the various parameters for the images are specified
    """

    gamma = 2.2

    fitsfile = File(filter=[u"*.fits"])
    image_figure = Instance(Figure, ())
    image = Array()
    image_axes = Instance(Axes)
    image_axesimage = Instance(AxesImage)
    image_xsize = Int(256)
    image_ysize = Int(256)

    datamin = Float(0.0, auto_set=False, enter_set=True)  #Say, in mJy
    datamax = Float(
        1.0, auto_set=False, enter_set=True
    )  #auto_set=input set on each keystroke, enter_set=set after Enter
    percent_min = Range(value=0.0, low=0.0, high=100.)
    percent_max = Range(value=100.0, low=0.0,
                        high=100.)  #Percentile of data values for rescaling
    minmaxbutton = Button('Min/Max')
    zscalebutton = Button('Zscale')

    image_scale = Str('linear')
    scale_dropdown = Enum(
        ['linear', 'sqrt', 'squared', 'log', 'power', 'sinh', 'asinh'])

    imagecolor = Str('#FFFFFF')
    imagecolor_picker = ColorTrait((255, 255, 255))

    #plotbeam_button=Button('Add Beam (FWHM)')

    plotbutton_individual = Button(u"Plot Single")
    plotbutton_inverted_individual = Button(u"Plot Inverted Single")
    clearbutton_individual = Button(u"Clear Single")

    status_string_left = Str('')
    status_string_right = Str('')

    def __init__(self):
        self._init_params(
        )  #Set placeholder things like the WCS, tick color, map units...
        self.image = self._fresh_image()  #Sets a blank image
        self.image_axes = self.image_figure.add_subplot(111, aspect=1)
        self.image_axesimage = self.image_axes.imshow(self.image,
                                                      cmap='gist_gray',
                                                      origin='lower',
                                                      interpolation='nearest')
        self.image_axes.axis('off')

    view = View(
      HSplit(
        VGroup(
            Item("fitsfile", label=u"Select 2D FITS file", show_label=True), #,height=100),

            HGroup(
              VGroup(
                     Item('plotbutton_individual', tooltip=u"Plot the single image",show_label=False),
                     Item('plotbutton_inverted_individual', tooltip=u"Plot the single inverted image",show_label=False),
                     Item('clearbutton_individual', tooltip=u"Clear the single image",show_label=False),
                     Item('_'),

                     Item('imagecolor',label='Image Color',show_label=True, \
                      tooltip='Color of ticks: standard name float[0..1], or #hex', \
                      editor=TextEditor(auto_set=False, enter_set=True,)),
                     Item('imagecolor_picker',label='Pick',show_label=True,editor=ColorEditor()),

                     ),
              Item('image_figure', editor=MPLFigureEditor(), show_label=False, width=300, height=300,resizable=True),
            ),
            HGroup(Item('datamin', tooltip=u"Minimum data val for scaling", show_label=True),
                   Item('datamax', tooltip=u"Maximum data val for scaling", show_label=True)),
            Item('percent_min', tooltip=u"Min. percentile for scaling", show_label=True),
            Item('percent_max', tooltip=u"Max. percentile for scaling", show_label=True),
            HGroup(Item('minmaxbutton', tooltip=u"Reset to data min/max", show_label=False),
                   Item('zscalebutton', tooltip=u"Compute scale min/max from zscale algorithm", show_label=False)),
            Item('scale_dropdown',label='Scale',show_label=True),

        ), #End of Left column

      ), #End of HSplit
      resizable=True, #height=0.75, width=0.75, #title=u"Multi-Color Image Combiner", 
      handler=MPLInitHandler,
      statusbar = [StatusItem(name = 'status_string_left', width = 0.5), StatusItem(name = 'status_string_right', width = 0.5)]
    ) #End of View

    def _init_params(self):
        self.in_use = False
        plt.rcParams.update({'font.family': 'serif','xtick.major.size':6,'ytick.major.size':6, \
                             'xtick.major.width':1.,'ytick.major.width':1., \
                             'xtick.direction':'in','ytick.direction':'in'})
        try:
            plt.rcParams.update({
                'xtick.top': True,
                'ytick.right': True
            })  #apparently not in mpl v<2.0...
        except:
            pass  #Make a workaround for mpl<2.0 later...
        self.datamin_initial = 0.
        self.datamax_initial = 1.
        self.datamin = 0.
        self.datamax = 1.  #This will be the displayed value of the scaling min/max

    def _fresh_image(self):
        blankdata = np.zeros([100, 100])
        blankdata[-1, -1] = 1
        return blankdata

    def _fitsfile_changed(self):
        self.data, self.hdr = pyfits.getdata(self.fitsfile, header=True)
        force_hdr_floats(
            self.hdr
        )  #Ensure that WCS cards such as CDELT are floats instead of strings

        naxis = int(self.hdr['NAXIS'])
        if naxis > 2:
            #print('Dropping Extra axes')
            self.hdr = force_hdr_to_2D(self.hdr)
            try:
                self.data = self.data[0, 0, :, :]
            except:
                self.data = self.data[0, :, :]
            self.status_string_right = 'Dropped extra axes'

        self.datamax_initial = np.asscalar(np.nanmax(self.data))
        self.datamin_initial = np.asscalar(np.nanmin(self.data))
        self.datamax = np.asscalar(np.nanmax(self.data))
        self.datamin = np.asscalar(np.nanmin(self.data))

        self.in_use = True

    #@on_trait_change('imagecolor')
    #def update_imagecolor(self):
    def _imagecolor_changed(self):
        try:
            #Catch case when you've predefined a color variable in hex string format, e.g., mynewred='#C11B17'
            #--> Need to do this first, otherwise traits throws a fit up the stack even despite the try/except check
            globals()[
                self.imagecolor]  #This check should catch undefined inputs
            self.imagecolor_picker = hex_to_rgb(globals()[self.imagecolor])
            self.status_string_right = 'Image color changed to ' + self.imagecolor
        except:
            try:
                self.imagecolor = to_hex(self.imagecolor)
                self.status_string_right = 'Image color changed to ' + self.imagecolor
            except:
                self.status_string_right = "Color name %s not recognized.  Must be standard mpl.colors string, float[0..1] or #hex string" % (
                    self.imagecolor)
        try:
            self.imagecolor_picker = hex_to_rgb(to_hex(
                self.imagecolor))  #update the picker color...
        except:
            pass
        ### self.image_greyRGB and self.image_colorRGB may not yet be instantiated if the color is changed before clicking 'plot'
        try:
            self.image_colorRGB = colorize_image(self.image_greyRGB,
                                                 self.imagecolor,
                                                 colorintype='hex',
                                                 gammacorr_color=self.gamma)
        except:
            pass
        try:
            self.image_axesimage.set_data(self.image_colorRGB**(1. /
                                                                self.gamma))
        except:
            pass
        self.in_use = True
        self.image_figure.canvas.draw()

    #@on_trait_change('imagecolor_picker')
    #def update_imagecolorpicker(self):
    def _imagecolor_picker_changed(self):
        #print self.tickcolor_picker.name()
        self.imagecolor = self.imagecolor_picker.name()

    #@on_trait_change('percent_min')
    #def update_scalepercmin(self):
    def _percent_min_changed(self):
        self.datamin = np.nanpercentile(self.data, self.percent_min)
        self.data_scaled = (
            scaling_fns[self.image_scale]() +
            ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data)
        self.image_greyRGB = ski_color.gray2rgb(
            adjust_gamma(self.data_scaled, self.gamma))
        self.image_colorRGB = colorize_image(self.image_greyRGB,
                                             self.imagecolor,
                                             colorintype='hex',
                                             gammacorr_color=self.gamma)
        self.image_axesimage.set_data(self.image_colorRGB**(1. / self.gamma))
        self.image_figure.canvas.draw()
        self.status_string_right = "Updated scale using percentiles"

    #@on_trait_change('percent_max')
    #def update_scalepercmax(self):
    def _percent_max_changed(self):
        self.datamax = np.nanpercentile(self.data, self.percent_max)
        self.data_scaled = (
            scaling_fns[self.image_scale]() +
            ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data)
        self.image_greyRGB = ski_color.gray2rgb(
            adjust_gamma(self.data_scaled, self.gamma))
        self.image_colorRGB = colorize_image(self.image_greyRGB,
                                             self.imagecolor,
                                             colorintype='hex',
                                             gammacorr_color=self.gamma)
        self.image_axesimage.set_data(self.image_colorRGB**(1. / self.gamma))
        self.image_figure.canvas.draw()
        self.status_string_right = "Updated scale using percentiles"

    ### Very slow to update datamin and datamax as well as percs... Can comment these if desired and just hit plot after datamin

    #@on_trait_change('datamin')
    #def update_datamin(self): self.percent_min=np.round(percentileofscore(self.data.ravel(),self.datamin,kind='strict'),2)
    def _datamin_changed(self):
        self.percent_min = np.round(
            percentileofscore(self.data.ravel(), self.datamin, kind='strict'),
            2)

    #@on_trait_change('datamax')
    #def update_datamax(self): self.percent_max=np.round(percentileofscore(self.data.ravel(),self.datamax,kind='strict'),2)
    def _datamax_changed(self):
        self.percent_max = np.round(
            percentileofscore(self.data.ravel(), self.datamax, kind='strict'),
            2)

    #@on_trait_change('scale_dropdown')
    #def update_image_scale(self):
    def _scale_dropdown_changed(self):
        self.image_scale = self.scale_dropdown
        #self.norm=ImageNormalize(self.sregion,stretch=scaling_fns[self.image_scale]() )
        self.data_scaled = (
            scaling_fns[self.image_scale]() +
            ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data)
        #*** Instead, should I just integrate my imscale class here instead of astropy? ...
        self.image_greyRGB = ski_color.gray2rgb(
            adjust_gamma(self.data_scaled, self.gamma))
        self.image_colorRGB = colorize_image(self.image_greyRGB,
                                             self.imagecolor,
                                             colorintype='hex',
                                             gammacorr_color=self.gamma)

        self.image_axesimage.set_data(self.image_colorRGB**(1. / self.gamma))

        self.in_use = True

        self.image_figure.canvas.draw()
        self.status_string_right = 'Image scale function changed to ' + self.image_scale

    def _minmaxbutton_fired(self):
        self.datamin = self.datamin_initial
        self.datamax = self.datamax_initial
        #self.image_axesimage.norm.vmin=self.datamin
        #self.image_axesimage.norm.vmax=self.datamax
        self.percent_min = np.round(
            percentileofscore(self.data.ravel(), self.datamin, kind='strict'),
            2)
        self.percent_max = np.round(
            percentileofscore(self.data.ravel(), self.datamax, kind='strict'),
            2)
        #self.image_figure.canvas.draw()
        self.status_string_right = "Scale reset to min/max"

    def _zscalebutton_fired(self):
        tmpZscale = ZScaleInterval().get_limits(self.data)
        self.datamin = float(tmpZscale[0])
        self.datamax = float(tmpZscale[1])
        self.percent_min = np.round(
            percentileofscore(self.data.ravel(), self.datamin, kind='strict'),
            2)
        self.percent_max = np.round(
            percentileofscore(self.data.ravel(), self.datamax, kind='strict'),
            2)
        #self.image_figure.canvas.draw()
        self.status_string_right = "Min/max determined by zscale"

    def _plotbutton_individual_fired(self):
        try:
            self.data
        except:
            self.status_string_right = "No fits file loaded yet!"
            return
        #self.image=self.data
        ###Using this command is preferable, as long as the projection doesn't need to be updated...
        #  The home zoom button will work, but no WCS labels because projection wasn't set during init.
        #Scale the data to [0,1] range
        self.data_scaled = (
            scaling_fns[self.image_scale]() +
            ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data)
        #Convert scale[0,1] image to greyscale RGB image
        self.image_greyRGB = ski_color.gray2rgb(
            adjust_gamma(self.data_scaled, self.gamma))
        self.image_colorRGB = colorize_image(self.image_greyRGB,
                                             self.imagecolor,
                                             colorintype='hex',
                                             gammacorr_color=self.gamma)
        self.image_axesimage.set_data(self.image_colorRGB**(1. / self.gamma))
        ###Using this set instead properly updates the axes labels to WCS, but the home zoom button won't work
        #self.image_figure.clf()
        #self.image_axes = self.image_figure.add_subplot(111,aspect=1)#,projection=self.wcs)
        #self.image_axesimage = self.image_axes.imshow(self.image, cmap=self.image_cmap,origin='lower',interpolation='nearest', norm=self.norm)

        self.percent_min = np.round(
            percentileofscore(self.data.ravel(), self.datamin, kind='strict'),
            2)
        self.percent_max = np.round(
            percentileofscore(self.data.ravel(), self.datamax, kind='strict'),
            2)

        self.in_use = True

        #self.update_radecpars()
        self.image_figure.canvas.draw()
        self.status_string_right = "Plot updated"

    def _plotbutton_inverted_individual_fired(self):
        try:
            self.data
        except:
            self.status_string_right = "No fits file loaded yet!"
            return
        self.data_scaled = (
            scaling_fns[self.image_scale]() +
            ManualInterval(vmin=self.datamin, vmax=self.datamax))(self.data)
        self.image_greyRGB = ski_color.gray2rgb(
            adjust_gamma(self.data_scaled, self.gamma))
        self.image_colorRGB = colorize_image(self.image_greyRGB,
                                             hexinv(self.imagecolor),
                                             colorintype='hex',
                                             gammacorr_color=self.gamma)
        #self.image_axesimage.set_data(1.-self.image_colorRGB**(1./self.gamma))
        self.image_axesimage.set_data(
            combine_multicolor([
                self.image_colorRGB,
            ],
                               gamma=self.gamma,
                               inverse=True))
        self.percent_min = np.round(
            percentileofscore(self.data.ravel(), self.datamin, kind='strict'),
            2)
        self.percent_max = np.round(
            percentileofscore(self.data.ravel(), self.datamax, kind='strict'),
            2)
        self.in_use = True
        self.image_figure.canvas.draw()
        self.status_string_right = "Plot updated"

    def _clearbutton_individual_fired(self):
        try:
            del self.data, self.data_scaled, self.image_greyRGB
            self.image_colorRGB  #In case clear already pressed once
        except:
            pass
        self.in_use = False
        self.image_figure.clf()
        self.image = self._fresh_image()
        self.image_axes = self.image_figure.add_subplot(111, aspect=1)
        self.image_axesimage = self.image_axes.imshow(self.image,
                                                      cmap='gist_gray',
                                                      origin='lower',
                                                      interpolation='nearest')
        self.image_axes.axis('off')
        self.image_figure.canvas.draw()
        self.status_string_right = "Plot cleared"

    def setup_mpl_events(self):
        self.image_axeswidget = AxesWidget(self.image_axes)
        self.image_axeswidget.connect_event('motion_notify_event',
                                            self.image_on_motion)
        self.image_axeswidget.connect_event('figure_leave_event',
                                            self.on_cursor_leave)
        self.image_axeswidget.connect_event('figure_enter_event',
                                            self.on_cursor_enter)
        self.image_axeswidget.connect_event('button_press_event',
                                            self.image_on_click)

    def image_on_motion(self, event):
        if event.xdata is None or event.ydata is None: return
        x = int(np.round(event.xdata))
        y = int(np.round(event.ydata))
        if ((x >= 0) and (x < self.image.shape[1]) and (y >= 0)
                and (y < self.image.shape[0])):
            imval = self.image[y, x]
            self.status_string_left = "x,y={},{}  {:.5g}".format(x, y, imval)
        else:
            self.status_string_left = ""

    def image_on_click(self, event):
        if event.xdata is None or event.ydata is None or event.button is not 1:
            return  #Covers when click outside of main plot
        #print event
        x = int(
            np.round(event.xdata)
        )  #xdata is the actual pixel position.  xy is in 'display space', i.e. pixels in the canvas
        y = int(np.round(event.ydata))
        #xwcs,ywcs=self.wcs.wcs_pix2world([[x,y]],0)[0]; #print xwcs,ywcs
        if ((x >= 0) and (x < self.image.shape[1]) and (y >= 0)
                and (y < self.image.shape[0])):
            imval = self.image[y, x]
            #self.status_string_right = "x,y=[{},{}], RA,DEC=[{}, {}], value = {:.5g}".format(x, y,xwcs,ywcs, imval)
            self.status_string_right = "x,y[{},{}] = {:.3f},{:.3f}  {:.5g}".format(
                x, y, event.xdata, event.ydata, imval)
        else:
            self.status_string_right = ""
        ## left-click: event.button = 1, middle-click: event.button=2, right-click: event.button=3.
        ## For double-click, event.dblclick = False for first click, True on second
        #print event.button, event.dblclick

    def on_cursor_leave(self, event):
        QApplication.restoreOverrideCursor()
        self.status_string_left = ''

    def on_cursor_enter(self, event):
        QApplication.setOverrideCursor(Qt.CrossCursor)
Beispiel #9
0
class SMRCWindow(HasTraits):
    """
    SMRCWindow is the Mainwindow of the application SmartRecord. The window 
    shows the time and the current phase of the experiment when it's running. 
    Furthermore the window interacts with the SMRCModel and 
    make it possible that the user can start and 
    cancel the experiment by clicking a icon.
    """

    model = Instance(SMRCModel)

    smrc_handler = SMRCHandler()

    current_phase = Str("Current Phase - Not Started")

    clock = Str(secs_to_time(0))

    record_mode = Bool(True)

    def __init__(self, model):
        self.logger = getLogger("application")
        self.logger.debug("Initializes SMRCWindow")
        self.record_mode = model.record_mode
        self.model = model
        self.model.experiment.window = self

    def start_clock(self):
        """Run the clock in the status bar."""
        self.logger.info("Start the time-thread [SMRCWindow]")
        self.clock = secs_to_time(0)
        RunThread(target=self._run_clock)

    def _run_clock(self):
        # Updates the status bar time once every second.
        self.clock_running = True
        self.start_time = time()
        while self.clock_running:
            self.td = time() - self.start_time
            self.clock = secs_to_time(self.td)
            sleep(1.0)

    #=========================================================================
    # Traitsview
    #=========================================================================

    # Switch to stop the running thread
    clock_running = Bool(False)

    view = View(UItem("model", style="custom"),
                menubar=MenuBar(Menu(*file_actions, name="File"),
                                Menu(*configure_actions, name="Configuration"),
                                Menu(*import_action, name="Import"),
                                Menu(help_docs, name="Help")),
                toolbar=ToolBar(*toolbar_actions,
                                show_tool_names=False,
                                image_size=(30, 30)),
                statusbar=[
                    StatusItem(name="current_phase", width=0.5),
                    StatusItem(name="clock", width=85)
                ],
                handler=smrc_handler,
                resizable=True,
                height=680,
                width=1300,
                title="SmartRecord",
                icon=ImageResource("../../icons/smrc_icon.png"))