예제 #1
0
    def __init__(self, default_value=None, iotype=None, desc=None,
                 low=None, high=None, exclude_low=False, exclude_high=False,
                 **metadata):

        # Range trait didn't seem to handle "None" correctly when passed on
        # the  command line.
        assumed_default = False
        if default_value is None:
            assumed_default = True
            if low is None and high is None:
                default_value = 0
            elif low is None:
                default_value = high
            else:
                default_value = low

        if low is None:
            low = -maxint
        if high is None:
            high = maxint

        if not isinstance(default_value, int):
            raise ValueError("Default value for an Int must be an integer.")

        if not isinstance(low, int):
            raise ValueError("Lower bound for an Int must be an integer.")

        if not isinstance(high, int):
            raise ValueError("Upper bound for an Int must be an integer.")

        if low > high:
            raise ValueError("Lower bound is greater than upper bound.")

        if default_value > high or default_value < low:
            raise ValueError("Default value is outside of bounds [%s, %s]." %
                             (str(low), str(high)))

        # Put iotype in the metadata dictionary
        if iotype is not None:
            metadata['iotype'] = iotype

        # Put desc in the metadata dictionary
        if desc is not None:
            metadata['desc'] = desc

        if 'assumed_default' in metadata:
            del metadata['assumed_default']

        self._validator = Range(value=default_value, low=low,
                                high=high, exclude_low=exclude_low,
                                exclude_high=exclude_high, **metadata)

        # Add low and high to the trait's dictionary so they can be accessed
        metadata['low'] = low
        metadata['high'] = high
        metadata['exclude_low'] = exclude_low
        metadata['exclude_high'] = exclude_high

        super(Int, self).__init__(default_value=default_value,
                                  assumed_default=assumed_default, **metadata)
예제 #2
0
class Animator(HasTraits):
    """ Convenience class to manage a timer and present a convenient
        UI.  This is based on the code in `tvtk.tools.visual`.
        Here is a simple example of using this class::

            >>> from mayavi import mlab
            >>> def anim():
            ...     f = mlab.gcf()
            ...     while 1:
            ...         f.scene.camera.azimuth(10)
            ...         f.scene.render()
            ...         yield
            ...
            >>> anim = anim()
            >>> t = Animator(500, anim.next)
            >>> t.edit_traits()

        This makes it very easy to animate your visualizations and control
        it from a simple UI.

        **Notes**

        If you want to modify the data plotted by an `mlab` function call,
        please refer to the section on: :ref:`mlab-animating-data`
    """

    ########################################
    # Traits.

    start = Button('Start Animation')
    stop = Button('Stop Animation')
    delay = Range(10, 100000, 500,
                  desc='frequency with which timer is called')

    # The internal timer we manage.
    timer = Instance(Timer)

    ######################################################################
    # User interface view

    traits_view = View(Group(Item('start'),
                             Item('stop'),
                             show_labels=False),
                       Item('_'),
                       Item(name='delay'),
                       title='Animation Controller',
                       buttons=['OK'])

    ######################################################################
    # Initialize object
    def __init__(self, millisec, callable, *args, **kwargs):
        """Constructor.

        **Parameters**

          :millisec: int specifying the delay in milliseconds
                     between calls to the callable.

          :callable: callable function to call after the specified
                     delay.

          :\*args: optional arguments to be passed to the callable.

          :\*\*kwargs: optional keyword arguments to be passed to the callable.

        """
        HasTraits.__init__(self)
        self.delay = millisec
        self.ui = None
        self.timer = Timer(millisec, callable, *args, **kwargs)

    ######################################################################
    # `Animator` protocol.
    ######################################################################
    def show(self):
        """Show the animator UI.
        """
        self.ui = self.edit_traits()

    def close(self):
        """Close the animator UI.
        """
        if self.ui is not None:
            self.ui.dispose()

    ######################################################################
    # Non-public methods, Event handlers
    def _start_fired(self):
        self.timer.Start(self.delay)

    def _stop_fired(self):
        self.timer.Stop()

    def _delay_changed(self, value):
        t = self.timer
        if t is None:
            return
        if t.IsRunning():
            t.Stop()
            t.Start(value)
예제 #3
0
from .include import Include

from .ui_traits import SequenceTypes, ATheme, ContainerDelegate, Orientation, Layout

from .dock_window_theme import dock_window_theme, DockWindowTheme

#-------------------------------------------------------------------------------
#  Trait definitions:
#-------------------------------------------------------------------------------

# Delegate trait to the object being "shadowed"
ShadowDelegate = Delegate('shadow')

# Amount of padding to add around item
Padding = Range(0, 15, desc='amount of padding to add around each item')

#-------------------------------------------------------------------------------
#  'Group' class:
#-------------------------------------------------------------------------------


class Group(ViewSubElement):
    """ Represents a grouping of items in a user interface view.
    """

    #---------------------------------------------------------------------------
    # Trait definitions:
    #---------------------------------------------------------------------------

    # A list of Group, Item, and Include objects in this group.
예제 #4
0
파일: item.py 프로젝트: yjkominy/traitsui
# Pattern for finding size infomation embedded in an item description:
size_pat = re.compile(r"^(.*)<(.*)>(.*)$", re.MULTILINE | re.DOTALL)

# Pattern for finding tooltip infomation embedded in an item description:
tooltip_pat = re.compile(r"^(.*)`(.*)`(.*)$", re.MULTILINE | re.DOTALL)

# -------------------------------------------------------------------------
#  Trait definitions:
# -------------------------------------------------------------------------

# Reference to an EditorFactory:
ItemEditor = Instance(EditorFactory, allow_none=True)

# Amount of padding to add around an item:
Padding = Range(-15, 15, 0, desc="amount of padding to add around item")

# -------------------------------------------------------------------------
#  'Item' class:
# -------------------------------------------------------------------------


class Item(ViewSubElement):
    """ An element in a Traits-based user interface.

    Magic:

    - Items are rendered as layout elements if :attr:`name` is set to
      special values:

      * ``name=''``, the item is rendered as a static label
예제 #5
0
파일: yasso.py 프로젝트: SoilTSSM/Yasso15
class Yasso(HasTraits):
    """
    The Yasso model
    """
    # Parameters
    p_sets = _get_parameter_files()
    parameter_set = Enum(p_sets)
    
    leaching = Float()
    # Initial condition
    initial_mode = Enum(['non zero', 'zero', 'steady state'])
    initial_litter = List(trait=LitterComponent)
    steady_state = List(trait=LitterComponent)
    # Litter input at each timestep in the simulation
    litter_mode = Enum(['zero', 'yearly', 'constant yearly', 'monthly'])
    constant_litter = List(trait=LitterComponent)
    monthly_litter = List(trait=TimedLitterComponent)
    yearly_litter = List(trait=TimedLitterComponent)
    zero_litter = List(trait=LitterComponent) # Assumes that this defaults to 0
    woody_size_limit = Float(default_value=3.0)
    area_change = List(trait=AreaChange)
    # Climate definition for the simulation
    climate_mode = Enum(['yearly', 'constant yearly', 'monthly'])
    constant_climate = YearlyClimate()
    monthly_climate = List(trait=MonthlyClimate,
            value=[MonthlyClimate(month=1),
                   MonthlyClimate(month=2),
                   MonthlyClimate(month=3),
                   MonthlyClimate(month=4),
                   MonthlyClimate(month=5),
                   MonthlyClimate(month=6),
                   MonthlyClimate(month=7),
                   MonthlyClimate(month=8),
                   MonthlyClimate(month=9),
                   MonthlyClimate(month=10),
                   MonthlyClimate(month=11),
                   MonthlyClimate(month=12)]
            )
    yearly_climate = List(trait=YearlyClimate)
    # All data as text
    all_data = Str()
    data_file = Str()
    # How the model will be run
    sample_size = Int()
    duration_unit = Enum(['year', 'month'])
    timestep_length = Range(low=1)
    simulation_length = Range(low=1)
    result_type = Enum(['C stock', 'C change', 'CO2 production'])
    presentation_type = Enum(['chart', 'array'])
    chart_type = Enum(['common scale', 'autofit'])
    # Buttons
    new_data_file_event = Button('New...')
    open_data_file_event = Button('Open...')
    save_data_file_event = Button('Save')
    save_as_file_event = Button('Save as...')
    modelrun_event = Button('Run model')
    save_result_event = Button('Save raw results...')
    save_moment_event = Button('Save moment results...')
    # and the results stored
    # Individual model calls
    #     iteration,time, total, woody, acid, water, ethanol, non_soluble, humus
    c_stock = Array(dtype=float32, shape=(None, 10))
    #     iteration,time, total, woody, acid, water, ethanol, non_soluble, humus
    c_change = Array(dtype=float32, shape=(None, 10))
    #     time, iteration, CO2 production
    co2_yield = Array(dtype=float32, shape=(None, 3))
    # time, mean, mode, var, skewness, kurtosis, 95% conf-, 95% conf+
    stock_tom = Array(dtype=float32, shape=(None, 8))
    stock_woody = Array(dtype=float32, shape=(None, 8))
    stock_non_woody = Array(dtype=float32, shape=(None, 8))
    stock_acid = Array(dtype=float32, shape=(None, 8))
    stock_water = Array(dtype=float32, shape=(None, 8))
    stock_ethanol = Array(dtype=float32, shape=(None, 8))
    stock_non_soluble = Array(dtype=float32, shape=(None, 8))
    stock_humus = Array(dtype=float32, shape=(None, 8))
    change_tom = Array(dtype=float32, shape=(None, 8))
    change_woody = Array(dtype=float32, shape=(None, 8))
    change_non_woody = Array(dtype=float32, shape=(None, 8))
    change_acid = Array(dtype=float32, shape=(None, 8))
    change_water = Array(dtype=float32, shape=(None, 8))
    change_ethanol = Array(dtype=float32, shape=(None, 8))
    change_non_soluble = Array(dtype=float32, shape=(None, 8))
    change_humus = Array(dtype=float32, shape=(None, 8))
    co2 = Array(dtype=float32, shape=(None, 8))
    # plot variables
    stock_plots = Instance(GridContainer)
    change_plots = Instance(GridContainer)
    co2_plot = Instance(GridContainer)
    p_timestep = Array()
    ps_tom = Array()
    ps_woody = Array()
    ps_non_woody = Array()
    ps_acid = Array()
    ps_water = Array()
    ps_ethanol = Array()
    ps_non_soluble = Array()
    ps_humus = Array()
    pc_tom = Array()
    pc_non_woody = Array()
    pc_acid = Array()
    pc_water = Array()
    pc_ethanol = Array()
    pc_non_soluble = Array()
    pc_humus = Array()
    

#############################################################
# UI view
#############################################################

    view = View(
        VGroup(
            HGroup(
                Item('new_data_file_event', show_label=False,),
                Item('open_data_file_event', show_label=False,),
                Item('save_data_file_event', show_label=False,),
                Item('save_as_file_event', show_label=False,),
                Item('data_file', style='readonly', show_label=False,),
                ),
            HGroup(
                Item('all_data', show_label=False, editor=CodeEditor(),
                     has_focus=True,
                     width=300, height=400,
                     ),
                ),
            label='All data',
            ),
        VGroup(
            HGroup(
                Item('parameter_set', width=-145),
                Item('leaching', width=-45,
                     label='Leaching parameter',
                     visible_when='initial_mode!="steady state"'),
                show_border=True,
                
            ),
            VGroup(
                HGroup(
                    Item(name='initial_mode', style='custom',
                         label='Initial state:', emphasized=True,
                         ),
                    ),
                Item('initial_litter',
                     visible_when='initial_mode=="non zero"',
                     show_label=False, editor=litter_te,
                     width=790, height=75,
                    ),
                ),
            VGroup(
                HGroup(
                    Item('litter_mode', style='custom',
                         label='Soil carbon input:', emphasized=True
                         )
                    ),
                HGroup(
                    Item('constant_litter',
                         visible_when='litter_mode=="constant yearly"',
                         show_label=False, editor=litter_te,
                         full_size=False, springy=False,
                         #width=-790, height=-75
                         ),
                    Item('monthly_litter',
                         visible_when='litter_mode=="monthly"',
                         show_label=False, editor=timed_litter_te,
                         full_size=False, springy=False,
                         #width=-790, height=-75
                         ),
                    Item('yearly_litter',
                         visible_when='litter_mode=="yearly"',
                         show_label=False, editor=timed_litter_te,
                         full_size=False, springy=False,
                         #width=-790,height=-75
                         ),
                    ),
                HGroup(
                    Item('area_change',
                         visible_when='litter_mode=="yearly" or '\
                                      'litter_mode=="monthly"',
                         show_label=False, editor=change_te,
                         full_size=False, springy=False,
                         width=-150,height=-75
                         ),
                    spring,
                    ),
                ),
            VGroup(
                HGroup(
                    Item('climate_mode', style='custom',
                        label='Climate:', emphasized=True,
                        ),
                    ),
                HGroup(
                    Item('monthly_climate', show_label=False,
                         visible_when='climate_mode=="monthly"',
                         editor=monthly_climate_te, width=200, height=75
                         ),
                    Item('yearly_climate', show_label=False,
                        visible_when='climate_mode=="yearly"',
                        editor=yearly_climate_te, width=200, height=75
                        ),
                    VGroup(
                        Item('object.constant_climate.mean_temperature',
                              style='readonly',),
                        Item('object.constant_climate.annual_rainfall',
                              style='readonly',),
                        Item('object.constant_climate.variation_amplitude',
                              style='readonly',),
                        show_border=True,
                        visible_when='climate_mode=="constant yearly"'
                        ),
                    ),
                ),
            label='Data to use',
            ),
        VGroup(
            Group(
                HGroup(
                    Item('sample_size', width=-45,
                         ),
                    Item('simulation_length', width=-45,
                         label='Number of timesteps',
                         ),
                    Item('timestep_length', width=-45,
                         ),
                    Item('duration_unit', style='custom',
                         show_label=False,),
                    ),
                HGroup(
                    Item('woody_size_limit', width=-45,
                         ),
                    Item('modelrun_event', show_label=False),
                    ),
                show_border=True
            ),
            HGroup(
                Item('result_type', style='custom', label='Show',
                     emphasized=True, ),
                Item('save_result_event', show_label=False,),
                Item('save_moment_event', show_label=False,),
                ),
            HGroup(
                Item('presentation_type', style='custom', label='As',
                     emphasized=True, ),
                Item('chart_type', style='custom', label='Chart type',
                     visible_when='presentation_type=="chart"'),
                ),
            HGroup(
                Item('c_stock', visible_when='result_type=="C stock" and \
                      presentation_type=="array"', show_label=False,
                      editor=c_stock_te, #width=600
                      ),
                Item('c_change', visible_when='result_type=="C change" and \
                      presentation_type=="array"', show_label=False,
                      editor=c_stock_te,),
                Item('co2_yield', visible_when='result_type=="CO2 production" '\
                      'and presentation_type=="array"', show_label=False,
                      editor=co2_yield_te,),
                Item('stock_plots', editor=ComponentEditor(),
                     show_label=False,
                     visible_when='result_type=="C stock" and \
                                  presentation_type=="chart"',),
                Item('change_plots', editor=ComponentEditor(),
                     show_label=False,
                     visible_when='result_type=="C change" and \
                                  presentation_type=="chart"',),
                Item('co2_plot', editor=ComponentEditor(),
                     show_label=False,
                     visible_when='result_type=="CO2 production" and \
                                  presentation_type=="chart"',),
                ),
            label='Model run',
            ),
        VGroup(
            Label(label='Yasso15 soil carbon model', emphasized=True),
            Label(label="<placeholder>", id="about_text"),
            label='About',
            ),
        title     = 'Yasso 15',
        id        = 'simosol.yasso15',
        dock      = 'horizontal',
        width     = 800,
        height    = 600,
        resizable = True,
        scrollable= True,
        buttons=NoButtons,
        icon=app_ir,
        menubar = MenuBar(
            Menu(CloseAction, name = 'File'),
            Menu(UndoAction, RedoAction, RevertAction, name = 'Edit'),
            ),
        help=False,
        )


###############################################################################
# Initialisation
###############################################################################

    def __init__(self):
        self.sample_size = 10
        self.simulation_length = 10
        fn = os.path.split(sys.executable)
        if fn[1].lower().startswith('python'):
            exedir = os.path.abspath(os.path.split(sys.argv[0])[0])
            self.data_file = self._get_data_file_path(exedir)
        else:
            self.data_file = self._get_data_file_path(fn[0])
        try:
            f = codecs.open(self.data_file, 'r', 'utf8')
            self._load_all_data(f)
            f.close()
        except:
            self.all_data = DATA_STRING
            self.data_file = ''
            
        try:
            cfg = ConfigParser.ConfigParser()

            
            fn = os.path.split(sys.executable)
            if fn[1].lower().startswith('python'):
                exedir = os.path.abspath(os.path.split(sys.argv[0])[0])
            else:
                exedir = fn[0]
            
            inipath = os.path.join(exedir, 'yasso.ini')
            cfg.readfp(codecs.open(inipath, "r", "utf8"))
            about_text = cfg.get("about", "text")
            about_text = about_text.replace("\\n", "\n")
            
            default_param = cfg.get("data", "default_param")
            if default_param in self.p_sets:
                self.parameter_set = default_param
            
            self.trait_view('about_text').label = about_text
            
        except Exception as error:
            print "Error reading yasso.ini. See the error log for details."
            raise error
            
                

    def _get_data_file_path(self, exedir):
        join = os.path.join
        self.state_file = join(exedir, 'yasso.state')
        if os.path.exists(self.state_file):
            f = codecs.open(self.state_file, 'r', 'utf8')
            datafile = f.read()
            if len(datafile)>0 and datafile[-1]=='\n':
                datafile = datafile[:-1]
            f.close()
            if not os.path.exists(datafile):
                os.remove(self.state_file)
                datafile = join(exedir, 'demo_data.txt')
        else:
            datafile = join(exedir, 'demo_data.txt')
        return datafile

    def _write_state(self, filename):
        f = codecs.open(self.state_file, 'w', 'utf8')
        f.write(filename)
        f.close()
        
###############################################################################
# Custom derived properties
###############################################################################

    @property
    def leach_parameter(self):
        """Leach parameter can only be 0 when the initialization mode is
        by steady state. In other cases, the leaching parameter is the
        trait "leaching". This is to be called
        from the YassoModel instead of the traits themselves."""
        if self.initial_mode=='steady state':
            return 0
        else:
            return self.leaching

###############################################################################
# Event handlers
###############################################################################

#########################
# for plot data
#########################

    def _create_stock_plots(self, common_scale=False):
        max = None
        min = 0
        stom, max, min = self._create_plot(max, min, self.stock_tom,
                                      'Total organic matter')
        swoody, max, min = self._create_plot(max, min, self.stock_woody,
                                        'Woody matter')
        snonwoody, max, min = self._create_plot(max, min, self.stock_non_woody,
                                        'Non-woody matter')
        sa, max, min = self._create_plot(max, min, self.stock_acid,
                                         'A')
        sw, max, min = self._create_plot(max, min, self.stock_water,
                                         'W')
        se, max, min = self._create_plot(max, min, self.stock_ethanol,
                                         'E')
        sn, max, min = self._create_plot(max, min, self.stock_non_soluble,
                                         'N')
        sh, max, min = self._create_plot(max, min, self.stock_humus, 'H')
        if common_scale:
            for pl in (stom, swoody, snonwoody, sa, sw, se, sn, sh):
                pl.value_range.set_bounds(min, max)
        container = GridContainer(stom, swoody, snonwoody, sa, sw, se, sn, sh)
        container.shape = (3,3)
        container.spacing = (-8,-8)
        self.stock_plots = container

    def _create_change_plots(self, common_scale=False):
        max = None
        min = 0
        ctom, max, min = self._create_plot(max, min, self.change_tom,
                                           'Total organic matter')
        cwoody, max, min = self._create_plot(max, min, self.change_woody,
                                             'Woody matter')
        cnonwoody, max, min = self._create_plot(max, min, self.change_non_woody,
                                             'Non-woody matter')
        ca, max, min = self._create_plot(max, min, self.change_acid,
                                         'A')
        cw, max, min = self._create_plot(max, min, self.change_water,
                                         'W')
        ce, max, min = self._create_plot(max, min, self.change_ethanol,
                                         'E')
        cn, max, min = self._create_plot(max, min, self.change_non_soluble,
                                         'N')
        ch, max, min = self._create_plot(max, min, self.change_humus, 'H')
        if common_scale:
            for pl in (ctom, cwoody, cnonwoody, ca, cw, ce, cn, ch):
                pl.value_range.set_bounds(min, max)
        container = GridContainer(ctom, cwoody, cnonwoody, ca, cw, ce, cn, ch)
        container.shape = (3,3)
        container.spacing = (-15,-15)
        self.change_plots = container

    def _create_co2_plot(self):
        max = None
        min = 0
        co2, max, min = self._create_plot(max, min, self.co2,
                 'CO2 production (in carbon)')
        container = GridContainer(co2, Plot(), Plot(), Plot())
        container.shape= (2,2)
        self.co2_plot = container

    def _create_plot(self, max, min, dataobj, title):
        x = dataobj[:,0]
        y = dataobj[:,1]
        if y.max()>max:
            max = y.max()
        if y.min()<min:
            min = y.min()
        if self.sample_size>1:
            y2 = dataobj[:,6]
            y3 = dataobj[:,7]
            if y3.max()>max:
                max = y3.max()
            if y2.min()<min:
                min = y2.min()
            plotdata = ArrayPlotData(x=x, y=y, y2=y2, y3=y3)
        else:
            plotdata = ArrayPlotData(x=x, y=y)
        plot = Plot(plotdata)
        plot.plot(("x", "y"), type="line", color="blue")
        if self.sample_size>1:
            plot.plot(("x", "y2"), type="line", color="red")
            plot.plot(("x", "y3"), type="line", color="red")
        plot.title = title
        plot.title_font = 'Arial 10'
        return plot, max, min

########################
# for running the model
########################

    def _modelrun_event_fired(self):
        # set the parameter set to use
        fn = os.path.split(sys.executable)
        if fn[1].lower().startswith('python'):
            exedir = os.path.abspath(os.path.split(sys.argv[0])[0])
        else:
            exedir = fn[0]
        pdir = os.path.join(exedir, 'param')
        parfile = os.path.join(pdir, '%s.dat' % self.parameter_set)
        
        if self.initial_mode=='zero' and self.litter_mode=='zero':
            errmsg = ("Both soil carbon input and initial state may not be "
                     "zero simultaneously.")
            error(errmsg, title='Invalid model parameters', buttons=['OK'])
            return
        
        if self.climate_mode=='yearly' and not self.yearly_climate:
            errmsg = ("Climate mode may not be 'yearly' if there are no "
                      "yearly climate entries in the data file.")
            error(errmsg, title='Invalid model parameters', buttons=['OK'])
            return

        if self.leaching>0:
            errmsg = ("Leaching parameter may not be larger than 0.")
            error(errmsg, title='Invalid model parameters', buttons=['OK'])
            return
        
        if self.climate_mode=='monthly' and not self.monthly_climate:
            errmsg = ("Climate mode may not be 'monthly' if there are no "
                      "monthly climate entries in the data file.")
            error(errmsg, title='Invalid model parameters', buttons=['OK'])
            return
            
            
        yassorunner = ModelRunner(parfile)
        
        if not yassorunner.is_usable_parameter_file():
            errmsg = ("The selected parameter file has wrong number of columns "
                "and cannot be used.")
            error(errmsg, title='Invalid model parameters', buttons=['OK'])
            return
        
        self.yassorunner = yassorunner   
        if self.initial_mode=='steady state':
            steady_state = self.yassorunner.compute_steady_state(self)
            self._set_steady_state(steady_state)
        self._init_results()
        self.c_stock, self.c_change, self.co2_yield = \
                self.yassorunner.run_model(self)
                
        self._create_co2_plot()
        self._chart_type_changed()

########################
# for chart type
########################

    def _chart_type_changed(self):
        if self.chart_type=='autofit':
            self._create_stock_plots()
            self._create_change_plots()
        elif self.chart_type=='common scale':
            self._create_stock_plots(common_scale=True)
            self._create_change_plots(common_scale=True)

########################
# for buttons
########################

    def _new_data_file_event_fired(self):
        filename = save_file()
        if filename != '':
            try:
                self._reset_data()
                f=codecs.open(filename, 'w', 'utf8')
                f.close()
                self.data_file = filename
                self._write_state(filename)
                self.all_data=DATA_STRING
            except:
                pass

    def _open_data_file_event_fired(self):
        filename = open_file()
        if filename != '':
            try:
                f=codecs.open(filename, 'r', 'utf8')
                self.data_file = filename
                self._write_state(filename)
                self._load_all_data(f)
                f.close()
            except:
                pass

    def _save_data_file_event_fired(self):
        if self.data_file=='':
            filename = save_file()
            if filename=='':
                return
            self.data_file = filename
            self._write_state(filename)
        self._save_all_data()

    def _save_as_file_event_fired(self):
        filename = save_file()
        if filename=='':
            return
        self.data_file = filename
        self._write_state(filename)
        self._save_all_data()

    def _load_all_data(self, datafile):
        """
        Loads all data from a single file. Data in sections defined by [name],
        data in whitespace delimited rows
        """
        self._reset_data()
        sectionp = re.compile('\[([\w+\s*]+)\]')
        datap = re.compile('[+-Ee\d+\.\d*\s*]+')
        active = None
        data = defaultdict(list)
        alldata = ''
        linecount = 0
        for line in datafile:
            linecount += 1
            alldata += line
            m = re.match(sectionp, line)
            if m is not None:
                active = m.group(1)
            d = re.match(datap, line)
            if d is not None:
                try:
                    vals = [float(val) for val in d.group(0).split()]
                    data[active].append(vals)
                except ValueError:
                    errmsg="There's an error on line %s\n  %s"\
                        "for section %s\n"\
                        "Values must be space separated and . is the decimal"\
                        " separator" % (linecount, d.group(0), active)
                    error(errmsg, title='Error saving data', buttons=['OK'])
        self.all_data = alldata
        for section, vallist in data.items():
            if section=='Initial state':
                self._set_initial_state(vallist)
            elif section=='Constant soil carbon input':
                self._set_constant_litter(vallist)
            elif section=='Monthly soil carbon input':
                self._set_monthly_litter(vallist)
            elif section=='Yearly soil carbon input':
                self._set_yearly_litter(vallist)
            elif section=='Relative area change':
                self._set_area_change(vallist)
            elif section=='Constant climate':
                self._set_constant_climate(vallist)
            elif section=='Monthly climate':
                self._set_monthly_climate(vallist)
            elif section=='Yearly climate':
                self._set_yearly_climate(vallist)

    def _save_all_data(self):
        f = codecs.open(self.data_file, 'w', 'utf8')
        f.write(self.all_data)
        f.close()
        f = codecs.open(self.data_file, 'r', 'utf8')
        self._load_all_data(f)
        f.close()

    def _reset_data(self):
        """
        Empties all input data structures
        """
        self.initial_litter = []
        self.steady_state = []
        self.constant_litter = []
        self.monthly_litter = []
        self.yearly_litter = []
        self.area_change = []
        self.constant_climate.mean_temperature = 0
        self.constant_climate.annual_rainfall = 0
        self.constant_climate.variation_amplitude = 0
        self.yearly_climate = []
        self.monthly_climate = []

    def _set_initial_state(self, data):
        errmsg = 'Soil carbon components should contain: \n'\
                      ' mass, mass std, acid, acid std, water, water std,\n'\
                      ' ethanol, ethanol std, non soluble, non soluble std,'\
                      '\n humus, humus std, size class'
        for vals in data:
            ok, obj = self._load_litter_object(vals, errmsg)
            if not ok:
                break
            self.initial_litter.append(obj)

    def _set_steady_state(self, data):
        errmsg = 'Soil carbon components should contain: \n'\
                      ' mass, mass std, acid, acid std, water, water std,\n'\
                      ' ethanol, ethanol std, non soluble, non soluble std,'\
                      '\n humus, humus std, size class'
        self.steady_state = []
        for vals in data:
            ok, obj = self._load_litter_object(vals, errmsg)
            if not ok:
                break
            self.steady_state.append(obj)

    def _set_constant_litter(self, data):
        errmsg = 'Soil carbon components should contain: \n'\
                      ' mass, mass std, acid, acid std, water, water std,\n'\
                      ' ethanol, ethanol std, non soluble, non soluble std,'\
                      '\n humus, humus std, size class'
        for vals in data:
            ok, obj = self._load_litter_object(vals, errmsg)
            if not ok:
                break
            self.constant_litter.append(obj)

    def _set_monthly_litter(self, data):
        errmsg = 'timed soil carbon components should contain: \n'\
                      ' timestep, mass, mass std, acid, acid std, water, '\
                      'water std,\n'\
                      ' ethanol, ethanol std, non soluble, non soluble std,'\
                      '\n humus, humus std, size class'
        for vals in data:
            ok, obj = self._load_litter_object(vals, errmsg, True)
            if not ok:
                break
            self.monthly_litter.append(obj)

    def _set_yearly_litter(self, data):
        errmsg = 'timed soil carbon components should contain: \n'\
                  ' timestep, mass, mass std, acid, acid std, water, '\
                  'water std,\n'\
                  ' ethanol, ethanol std, non soluble, non soluble std,'\
                  '\n humus, humus std, size class'
        for vals in data:
            ok, obj = self._load_litter_object(vals, errmsg, True)
            if not ok:
                break
            self.yearly_litter.append(obj)

    def _set_area_change(self, data):
        errmsg = 'Area change should contain:\n  timestep, relative area change'
        for vals in data:
            if len(vals)==2:
                obj = AreaChange(timestep=int(vals[0]),
                          rel_change=vals[1])
                self.area_change.append(obj)
            elif vals!=[]:
                errmsg = errmsg + '\n%s data values found, 2 needed' % (len(data))
                error(errmsg, title='error reading data',
                      buttons=['OK'])
                break

    def _set_yearly_climate(self, data):
        errmsg = 'Yearly climate should contain: timestep, mean temperature,\n'\
                 'annual rainfall and temperature variation amplitude'
        for vals in data:
            if len(vals)==4:
                obj = YearlyClimate(timestep=int(vals[0]),
                          mean_temperature=vals[1],
                          annual_rainfall=vals[2],
                          variation_amplitude=vals[3])
                self.yearly_climate.append(obj)
            elif vals!=[]:
                errmsg = errmsg + '\n%s data values found, 4 needed' % (len(data))
                error(errmsg, title='error reading data',
                      buttons=['OK'])
                break

    def _set_constant_climate(self, data):
        errmsg = 'Constant climate should contain: mean temperature,\n'\
                 'annual rainfall and temperature variation amplitude'
        if len(data[0])==3:
            self.constant_climate.mean_temperature = data[0][0]
            self.constant_climate.annual_rainfall = data[0][1]
            self.constant_climate.variation_amplitude = data[0][2]
        elif data[0]!=[]:
            errmsg = errmsg + '\n%s data values found, 3 needed' % (len(data))
            error(errmsg, title='error reading data',
                  buttons=['OK'])

    def _set_monthly_climate(self, data):
        errmsg = 'Monthly climate data should contain: month,\n'\
                 'temperature and rainfall'
        for vals in data:
            if len(vals)==3:
                obj = MonthlyClimate(month=int(vals[0]),
                          temperature=vals[1],
                          rainfall=vals[2])
                self.monthly_climate.append(obj)
            elif vals!=[]:
                errmsg = errmsg + '\n%s data values found, 3 needed' % (len(data))
                error(errmsg, title='Error reading data',
                      buttons=['OK'])
                break

    def _load_litter_object(self, data, errmsg, hastime=False):
        obj = None
        loaded = True
        if hastime:
            if len(data)==14:
                obj = TimedLitterComponent(timestep=int(data[0]),
                        mass=data[1],
                        mass_std=data[2],
                        acid=data[3],
                        acid_std=data[4],
                        water=data[5],
                        water_std=data[6],
                        ethanol=data[7],
                        ethanol_std=data[8],
                        non_soluble=data[9],
                        non_soluble_std=data[10],
                        humus=data[11],
                        humus_std=data[12],
                        size_class=data[13])
            elif data!=[]:
                errmsg = errmsg + '\n%s data values found, 14 needed' % (len(data))
                error(errmsg, title='Error reading data',
                      buttons=['OK'])
                loaded = False
            elif data==[]:
                loaded = False
        else:
            if len(data)==13:
                obj = LitterComponent(mass=data[0],
                        mass_std=data[1],
                        acid=data[2],
                        acid_std=data[3],
                        water=data[4],
                        water_std=data[5],
                        ethanol=data[6],
                        ethanol_std=data[7],
                        non_soluble=data[8],
                        non_soluble_std=data[9],
                        humus=data[10],
                        humus_std=data[11],
                        size_class=data[12])
            elif data!=[]:
                errmsg = errmsg + '\n%s data values found, 13 needed' % (len(data))
                error(errmsg, title='Error reading data',
                      buttons=['OK'])
                loaded = False
            elif data==[]:
                loaded = False
        return loaded, obj

    def _save_moment_event_fired(self):
        filename = save_file()
        if filename != '':
            f=codecs.open(filename, 'w', 'utf8')
            if self.result_type=='C stock':
                comps = (('tom', self.stock_tom), ('woody', self.stock_woody),
                        ('non-woody', self.stock_non_woody),
                       ('acid', self.stock_acid), ('water', self.stock_water),
                       ('ethanol', self.stock_ethanol),
                       ('non-soluble', self.stock_non_soluble),
                       ('humus', self.stock_humus))
            elif self.result_type=='C change':
                comps = (('tom', self.change_tom), ('woody', self.change_woody),
                        ('non-woody', self.change_non_woody),
                       ('acid', self.change_acid), ('water', self.change_water),
                       ('ethanol', self.change_ethanol),
                       ('non-soluble', self.change_non_soluble),
                       ('humus', self.change_humus))
            elif self.result_type=='CO2 production':
                comps = (('CO2', self.co2),)
            header = '# component, time step, mean, mode, var, skewness, '\
                     'kurtosis, 95% confidence lower limit, 95% upper limit'
            header = self._make_result_header(header)
            f.write(header+'\n')
            for comp, res in comps:
                for row in res:
                    resrow = ''
                    for num in row:
                        resrow = ' '.join([resrow, str(num)])
                    resrow = ' '.join((comp, resrow))
                    f.write(resrow+'\n')
            f.close()

    def _save_result_event_fired(self):
        filename = save_file()
        if filename != '':
            f=codecs.open(filename, 'w', 'utf8')
            if self.result_type=='C stock':
                res = self.c_stock
                header = '# sample, time step, total om, woody om, non-woody om,'\
                         ' acid, water, ethanol, non-soluble, humus'
            elif self.result_type=='C change':
                res = self.c_change
                header = '# sample, time step, total om, woody om, non-woody om,'\
                         ' acid, water, ethanol, non soluble, humus'
            elif self.result_type=='CO2 production':
                res = self.co2_yield
                header = '# sample, time step, CO2 production (in carbon)'
            header = self._make_result_header(header)
            f.write(header+'\n')
            for row in res:
                resrow = ''
                for num in row:
                    resrow = ' '.join([resrow, str(num)])
                f.write(resrow+'\n')
            f.close()

    def _make_result_header(self, header):
        '''Adds metadata about the results into the header'''
        hstr = '#########################################################\n'
        hstr += '# ' + self.result_type + '\n'
        hstr += '#########################################################\n'
        hstr += '# Datafile used: ' + self.data_file + '\n'
        hstr += '# Settings:\n'
        hstr += '#   initial state: ' + self.initial_mode + '\n'
        hstr += '#   soil carbon input: ' + self.litter_mode + '\n'
        hstr += '#   climate: ' + self.climate_mode + '\n'
        hstr += '#   sample size: ' + str(self.sample_size) + '\n'
        hstr += ''.join(['#   timestep length: ', str(self.timestep_length),
                         ' (', self.duration_unit, ')\n'])
        hstr += '#   woody litter size limit: ' + str(self.woody_size_limit)+'\n'
        hstr += '#\n'
        return hstr + header

    def _init_results(self):
        """
        model results: stock & change
         sample, timestep, tom, woody, non-woody, acid, water, ethanol,
         non soluble humus
        model results: CO2
         sample, timestep, CO2 production
        summary results
         common format: time, mean, mode, var, skewness, kurtosis,
         95% confidence-, 95% confidence+
        """
        self.c_stock = empty(dtype=float32, shape=(0, 10))
        self.c_change = empty(dtype=float32, shape=(0, 10))
        self.co2_yield = empty(dtype=float32, shape=(0, 3))
        self.stock_tom = empty(dtype=float32, shape=(0, 8))
        self.stock_woody = empty(dtype=float32, shape=(0, 8))
        self.stock_non_woody = empty(dtype=float32, shape=(0, 8))
        self.stock_acid = empty(dtype=float32, shape=(0, 8))
        self.stock_water = empty(dtype=float32, shape=(0, 8))
        self.stock_ethanol = empty(dtype=float32, shape=(0, 8))
        self.stock_non_soluble = empty(dtype=float32, shape=(0, 8))
        self.stock_humus = empty(dtype=float32, shape=(0, 8))
        self.change_tom = empty(dtype=float32, shape=(0, 8))
        self.change_woody = empty(dtype=float32, shape=(0, 8))
        self.change_non_woody = empty(dtype=float32, shape=(0, 8))
        self.change_acid = empty(dtype=float32, shape=(0, 8))
        self.change_water = empty(dtype=float32, shape=(0, 8))
        self.change_ethanol = empty(dtype=float32, shape=(0, 8))
        self.change_non_soluble = empty(dtype=float32, shape=(0, 8))
        self.change_humus = empty(dtype=float32, shape=(0, 8))
        self.co2 = empty(dtype=float32, shape=(0, 8))
예제 #6
0
class LearningGUI(HasTraits):
        plot = Instance(Plot)
        meanrate = CFloat(0.0)
        cv = CFloat(0.0)
        teach = Bool(0)
        teach_active = Bool(0)
        teach_high = Range(100., 1000.)
        teach_low = Range(100., 1000.)
        f_max = Range(0., 1000.)
        f_min = Range(0., 1000.)
        updater = Instance(EventsUpdater)
        npre = Int(1)
        f_max_demo = Range(0., 1000.)
        durationl = Range(0., 10000.)
        
        stimlearn = traitsButton()
        inilearn = traitsButton()
        set_wij = traitsButton()
        get_wij = traitsButton()
        reset0_wij = traitsButton()
        reset1_wij = traitsButton()
        learning = Bool

        #Plot properties
        tDuration = Range(0.,20) 
        channel = Enum(range(getDefaultMonChannelAddress().nChannels))
        
        period = 1
        port = 50002
        host = nsetup.communicator.kwargs['host']
        stimulator = PoissonStimulator(SeqChannelAddress=None,
                                            channel=1,
                                            host=host,
                                            port_stim=port,
                                            rates=[],
                                            period=period)

        def _tDuration_default(self): return 5.
        
        def _meanrate_default(self): return 0.
        
        def _cv_default(self): return 0.
        
        def _learning_default(self): return True
        
        def _teach_high_default(self): return 200.
        def _teach_low_default(self): return 500.
        def _f_max_default(self): return 55.
        def _f_min_default(self): return 10.
        def _f_max_demo_default(self): return 55.
        def _durationl_default(self): return 200.
        
        def __init__(self, markersize=4, marker='circle', color='black'):
                super(LearningGUI, self).__init__()
                self.plotdata = ArrayPlotData(neurons = [0], times = [0])
                plot = Plot(self.plotdata)
                plot.plot(( "times", "neurons" ), 
                          type = "scatter",
                          marker = marker,
                          marker_size = markersize,
                          color=color)
                self.plot = plot
                
                self.wijstate = ArrayPlotData(imagedata=zeros((124, 28)))
                wijstate_plot = Plot(self.wijstate)
                wijstate_plot.img_plot("imagedata")
                self.wijstate_plot = wijstate_plot
        
                self.char = ArrayPlotData(imagedata=zeros((28, 28)))
                char_plot = Plot(self.char)
                char_plot.img_plot("imagedata")
                self.char_plot = char_plot
        
        def _channel_changed(self):
                print('Switching to channel: %d' % self.channel)
                self.updater.channel = self.channel
                self.updater.tot_neurons = []
                self.updater.tot_times = []
                try:
                        self.updater.eventsQueue.stop()
                except:
                        pass
                #addrBuildHashTable(self.updater.stcs[self.channel])
                self.updater.eventsQueue = pyAex.netMonClient(MonChannelAddress=self.updater.stcs,
                                                           channels = [self.channel],
                                                           host = self.updater.host,
                                                           port = self.updater.port,
                                                           autostart = True,
                                                           fps = self.updater.fps)


        def _teach_active_changed(self):
            if self.teach_active:
                host = nsetup.communicator.kwargs['host']
                self.stimulator = PoissonStimulator(SeqChannelAddress=None,
                                                    channel=1,
                                                    seq_export=False,
                                                    host=host,
                                                    port_stim=50002,
                                                    rates=[[SYN_PADDR,
                                                            self.teach_low]],
                                                    period=self.period)
                self.set_teacher()
                self.stimulator.start()
            else:
                self.stimulator.stop()

        def _teach_changed(self):
            self.set_teacher()

        def set_teacher(self):
            if self.teach:
                self.stimulator.rates = [[SYN_PADDR,
                                          self.teach_high]]
            else:
                self.stimulator.rates = [[SYN_PADDR,
                                          self.teach_low]]
        
        def _teach_high_changed(self):
            if self.teach:
                self.stimulator.rates = [[SYN_PADDR,
                                          self.teach_high]]
        
        def _teach_low_changed(self):
            if not self.teach:
                self.stimulator.rates = [[SYN_PADDR,
                                          self.teach_low]]

        def _learning_changed(self):
            if self.learning:
                chip.setBias(learning_on_biases)
            else: 
                chip.setBias(learning_off_biases)

        traits_view = View(
            Group(
                Group(
                    Group(
                        Item('teach_active', label='Teacher active   '),
                        Group(
                            Item('teach_low', label='NO freq   ',
                                 editor=RangeEditor(low=100, high=1000, mode='xslider')),
                            Item('teach_high', label='YES freq   ',
                                 editor=RangeEditor(low=100, high=1000, mode='xslider')),
                            orientation='vertical'
                        ),
                        Item('teach', label='Teach!   '),
                        label='Teacher',
                        orientation='vertical',
                    ),
                    #Group(
                        #Item('f_max_demo', label="f_max   "),
                        #Item('npre', label="Rounds   "),
                        #Item('durationl', label="Stim duration   "),
                        #Item('inilearn', show_label=False),
                        #label='Demo stimulator',
                        #orientation='vertical',
                    #),
                    Group(
                        # can't resize to fit in the window
                        #Item('char_plot', editor=ComponentEditor(), show_label=False),
                        Item('f_max', label="f_max   "),
                        Item('f_min', label="f_min   "),
                        Item('durationl', label="Stim duration   "),
                        Item('learning', label="Plasticity   "),
                        Item('stimlearn', show_label=False),
                        label='Stimulator',
                        orientation='vertical',
                    ),
                    Group(
                        Item('meanrate', label='MeanRate(Hz)    ', style='readonly'),
                        Item('cv', label='ISI CV    ', style='readonly'),
                        label='Quick measures',
                        orientation='vertical'
                    ),
                ),
                Group(
                    Item('plot', editor=ComponentEditor(), show_label=False),
                    label='Viewer',
                    orientation='vertical',
                ),
                orientation='horizontal'
            ),
            dock='tab',
            menubar=MenuBar(Menu(Action(name="Edit Plot",
                                        action="edit_plot"),
                                 CloseAction,
                                 name="File"),
                            Menu(Action(name="Default",
                                        action="load_default_biases"),
                                 Action(name="Set scan 0",
                                        action="setscanx_0"),
                                 name="Biases")),
            buttons=LiveButtons,
            handler = Controller,
            width=1600, 
            height=600, 
            resizable=True, 
            title="Leonardo",
        )
        
        plot_edit_view = View(Group(Item('tDuration'),
                                    #Item('colormap'),
                                    Item('channel')),
                              buttons=['OK','Cancel'])
예제 #7
0
class LUTManager(Base):

    # The version of this class.  Used for persistence.
    __version__ = 0

    # The lookup table.
    lut = Instance(tvtk.LookupTable, (), record=False)
    # The scalar bar.
    scalar_bar = Instance(tvtk.ScalarBarActor, (), record=True)
    # The scalar_bar_widget
    scalar_bar_widget = Instance(tvtk.ScalarBarWidget, ())

    # The representation associated with the scalar_bar_widget.  This
    # only exists in VTK versions about around 5.2.
    scalar_bar_representation = Instance(tvtk.Object,
                                         allow_none=True,
                                         record=True)

    # The title text property of the axes.
    title_text_property = Property(record=True)

    # The label text property of the axes.
    label_text_property = Property(record=True)

    # The current mode of the LUT.
    lut_mode = Enum('blue-red',
                    lut_mode_list(),
                    desc='the type of the lookup table')

    # File name of the LUT file to use.
    file_name = Str('',
                    editor=FileEditor,
                    desc='the filename containing the LUT')

    # Reverse the colors of the LUT.
    reverse_lut = Bool(False, desc='if the lut is to be reversed')

    # Turn on/off the visibility of the scalar bar.
    show_scalar_bar = Bool(False, desc='if scalar bar is shown or not')

    # This is an alias for show_scalar_bar.
    show_legend = Property(Bool, desc='if legend is shown or not')

    # The number of labels to use for the scalar bar.
    number_of_labels = Range(0,
                             64,
                             8,
                             enter_set=True,
                             auto_set=False,
                             desc='the number of labels to display')

    # Number of colors for the LUT.
    number_of_colors = Range(2,
                             2147483647,
                             256,
                             enter_set=True,
                             auto_set=False,
                             desc='the number of colors for the LUT')

    # Enable shadowing of the labels and text.
    shadow = Bool(False, desc='if the labels and text have shadows')

    # Use the default data name or the user specified one.
    use_default_name = Bool(True,
                            desc='if the default data name is to be used')

    # The default data name -- set by the module manager.
    default_data_name = Str('data',
                            enter_set=True,
                            auto_set=False,
                            desc='the default data name')

    # The optionally user specified name of the data.
    data_name = Str('',
                    enter_set=True,
                    auto_set=False,
                    desc='the title of the legend')

    # Use the default range or user specified one.
    use_default_range = Bool(True,
                             desc='if the default data range is to be used')
    # The default data range -- this is computed and set by the
    # module manager.
    default_data_range = Array(shape=(2, ),
                               value=[0.0, 1.0],
                               dtype=float,
                               enter_set=True,
                               auto_set=False,
                               desc='the default range of the data mapped')

    # The optionally user defined range of the data.
    data_range = Array(shape=(2, ),
                       value=[0.0, 1.0],
                       dtype=float,
                       enter_set=True,
                       auto_set=False,
                       desc='the range of the data mapped')

    # Create a new LUT.
    create_lut = Button('Launch LUT editor',
                        desc='if we launch a Lookup table editor in'
                        ' a separate process')

    ########################################
    ## Private traits.
    # The original range of the data.
    _orig_data_range = Array(shape=(2, ), value=[0.0, 1.0], dtype=float)
    _title_text_property = Instance(tvtk.TextProperty)
    _label_text_property = Instance(tvtk.TextProperty)

    ######################################################################
    # `object` interface
    ######################################################################
    def __init__(self, **traits):
        super(LUTManager, self).__init__(**traits)

        # Initialize the scalar bar.
        sc_bar = self.scalar_bar
        sc_bar.set(lookup_table=self.lut,
                   title=self.data_name,
                   number_of_labels=self.number_of_labels,
                   orientation='horizontal',
                   width=0.8,
                   height=0.17)
        pc = sc_bar.position_coordinate
        pc.set(coordinate_system='normalized_viewport', value=(0.1, 0.01, 0.0))
        self._shadow_changed(self.shadow)

        # Initialize the lut.
        self._lut_mode_changed(self.lut_mode)

        # Set the private traits.
        ttp = self._title_text_property = sc_bar.title_text_property
        ltp = self._label_text_property = sc_bar.label_text_property

        # Call render when the text properties are changed.
        ttp.on_trait_change(self.render)
        ltp.on_trait_change(self.render)

        # Initialize the scalar_bar_widget
        self.scalar_bar_widget.set(scalar_bar_actor=self.scalar_bar,
                                   key_press_activation=False)
        self._number_of_colors_changed(self.number_of_colors)

    ######################################################################
    # `Base` interface
    ######################################################################
    def start(self):
        """This is invoked when this object is added to the mayavi
        pipeline.
        """
        # Do nothing if we are already running.
        if self.running:
            return

        # Show the legend if necessary.
        self._show_scalar_bar_changed(self.show_scalar_bar)

        # Call parent method to set the running state.
        super(LUTManager, self).start()

    def stop(self):
        """Invoked when this object is removed from the mayavi
        pipeline.
        """
        if not self.running:
            return

        # Hide the scalar bar.
        sbw = self.scalar_bar_widget
        if sbw.interactor is not None:
            sbw.off()

        # Call parent method to set the running state.
        super(LUTManager, self).stop()

    ######################################################################
    # Non-public interface
    ######################################################################
    def _lut_mode_changed(self, value):

        if value == 'file':
            if self.file_name:
                self.load_lut_from_file(self.file_name)
            #self.lut.force_build()
            return

        reverse = self.reverse_lut
        if value in pylab_luts:
            lut = pylab_luts[value]
            if reverse:
                lut = lut[::-1, :]
            n_total = len(lut)
            n_color = self.number_of_colors
            if not n_color >= n_total:
                lut = lut[::round(n_total / float(n_color))]
            self.load_lut_from_list(lut.tolist())
            #self.lut.force_build()
            return
        elif value == 'blue-red':
            if reverse:
                hue_range = 0.0, 0.6667
                saturation_range = 1.0, 1.0
                value_range = 1.0, 1.0
            else:
                hue_range = 0.6667, 0.0
                saturation_range = 1.0, 1.0
                value_range = 1.0, 1.0
        elif value == 'black-white':
            if reverse:
                hue_range = 0.0, 0.0
                saturation_range = 0.0, 0.0
                value_range = 1.0, 0.0
            else:
                hue_range = 0.0, 0.0
                saturation_range = 0.0, 0.0
                value_range = 0.0, 1.0
        lut = self.lut
        lut.set(hue_range=hue_range,
                saturation_range=saturation_range,
                value_range=value_range,
                number_of_table_values=self.number_of_colors,
                ramp='sqrt')
        lut.modified()
        lut.force_build()

        self.render()

    def _scene_changed(self, value):
        sbw = self.scalar_bar_widget
        if value is None:
            return
        if sbw.interactor is not None:
            sbw.off()
        value.add_widgets(sbw, enabled=False)
        if self.show_scalar_bar:
            sbw.on()
        self._foreground_changed_for_scene(None, value.foreground)

    def _foreground_changed_for_scene(self, old, new):
        # Change the default color for the text.
        self.title_text_property.color = new
        self.label_text_property.color = new
        self.render()

    def _number_of_colors_changed(self, value):
        if self.lut_mode == 'file':
            return
        elif self.lut_mode in pylab_luts:
            # We can't interpolate these LUTs, as they are defined from a
            # table. We hack around this limitation
            reverse = self.reverse_lut
            lut = pylab_luts[self.lut_mode]
            if reverse:
                lut = lut[::-1, :]
            n_total = len(lut)
            if value > n_total:
                return
            lut = lut[::round(n_total / float(value))]
            self.load_lut_from_list(lut.tolist())
        else:
            lut = self.lut
            lut.number_of_table_values = value
            lut.modified()
            lut.build()
            self.render()  # necessary to flush.
        sc_bar = self.scalar_bar
        sc_bar.maximum_number_of_colors = value
        sc_bar.modified()
        self.render()

    def _number_of_labels_changed(self, value):
        sc_bar = self.scalar_bar
        sc_bar.number_of_labels = value
        sc_bar.modified()
        self.render()

    def _file_name_changed(self, value):
        if self.lut_mode == 'file':
            self.load_lut_from_file(value)
        else:
            # This will automagically load the LUT from the file.
            self.lut_mode = 'file'

    def _reverse_lut_changed(self, value):
        # This will do the needful.
        self._lut_mode_changed(self.lut_mode)

    def _show_scalar_bar_changed(self, value):
        if self.scene is not None:
            # Without a title for scalar bar actor, vtkOpenGLTexture logs this:
            # Error: No scalar values found for texture input!
            if self.scalar_bar.title == '':
                self.scalar_bar.title = ' '
            self.scalar_bar_widget.enabled = value
            self.render()

    def _get_show_legend(self):
        return self.show_scalar_bar

    def _set_show_legend(self, value):
        old = self.show_scalar_bar
        if value != old:
            self.show_scalar_bar = value
            self.trait_property_changed('show_legend', old, value)

    def _shadow_changed(self, value):
        sc_bar = self.scalar_bar
        sc_bar.title_text_property.shadow = self.shadow
        sc_bar.label_text_property.shadow = self.shadow
        self.render()

    def _use_default_name_changed(self, value):
        self._default_data_name_changed(self.default_data_name)

    def _data_name_changed(self, value):
        sc_bar = self.scalar_bar
        sc_bar.title = value
        sc_bar.modified()
        self.render()

    def _default_data_name_changed(self, value):
        if self.use_default_name:
            self.data_name = value

    def _use_default_range_changed(self, value):
        self._default_data_range_changed(self.default_data_range)

    def _data_range_changed(self, value):
        try:
            self.lut.set_range(value[0], value[1])
        except TypeError:
            self.lut.set_range((value[0], value[1]))
        except AttributeError:
            self.lut.range = value
        self.scalar_bar.modified()
        self.render()

    def _default_data_range_changed(self, value):
        if self.use_default_range:
            self.data_range = value

    def _visible_changed(self, value):
        state = self.show_scalar_bar and value
        self._show_scalar_bar_changed(state)
        super(LUTManager, self)._visible_changed(value)

    def load_lut_from_file(self, file_name):
        lut_list = []
        if len(file_name) > 0:
            try:
                f = open(file_name, 'r')
            except IOError:
                msg = "Cannot open Lookup Table file: %s\n" % file_name
                error(msg)
            else:
                f.close()
                try:
                    lut_list = parse_lut_file(file_name)
                except IOError, err_msg:
                    msg = "Sorry could not parse LUT file: %s\n" % file_name
                    msg += err_msg
                    error(msg)
                else:
                    if self.reverse_lut:
                        lut_list.reverse()
                    self.lut = set_lut(self.lut, lut_list)
                    self.render()
예제 #8
0
#  Imports:
#-------------------------------------------------------------------------

from traits.api \
    import HasTraits, Trait, Enum, Range

from traitsui.api \
    import EnumEditor

#-------------------------------------------------------------------------
#  Trait definitions:
#-------------------------------------------------------------------------

values = ['one', 'two', 'three', 'four']
enum = Enum(*values)
range = Range(1, 4)

#-------------------------------------------------------------------------
#  'TestEnumEditor' class:
#-------------------------------------------------------------------------


class TestEnumEditor(HasTraits):

    #-------------------------------------------------------------------------
    #  Trait definitions:
    #-------------------------------------------------------------------------

    value = Trait(1,
                  enum,
                  range,
class MayaviViewer(HasTraits):
    """
    This class represents a Mayavi based viewer for the particles.  They
    are queried from a running solver.
    """

    particle_arrays = List(Instance(ParticleArrayHelper), [])
    pa_names = List(Str, [])

    interpolator = Instance(InterpolatorView)

    # The default scalar to load up when running the viewer.
    scalar = Str("rho")

    scene = Instance(MlabSceneModel, ())

    ########################################
    # Traits to pull data from a live solver.
    live_mode = Bool(False,
                     desc='if data is obtained from a running solver '
                     'or from saved files')

    shell = Button('Launch Python Shell')
    host = Str('localhost', desc='machine to connect to')
    port = Int(8800, desc='port to use to connect to solver')
    authkey = Password('pysph', desc='authorization key')
    host_changed = Bool(True)
    client = Instance(MultiprocessingClient)
    controller = Property(depends_on='live_mode, host_changed')

    ########################################
    # Traits to view saved solver output.
    files = List(Str, [])
    directory = Directory()
    current_file = Str('', desc='the file being viewed currently')
    update_files = Button('Refresh')
    file_count = Range(low='_low',
                       high='_n_files',
                       value=0,
                       desc='the file counter')
    play = Bool(False, desc='if all files are played automatically')
    play_delay = Float(0.2, desc='the delay between loading files')
    loop = Bool(False, desc='if the animation is looped')
    # This is len(files) - 1.
    _n_files = Int(0)
    _low = Int(0)

    ########################################
    # Timer traits.
    timer = Instance(Timer)
    interval = Range(0.5,
                     20.0,
                     2.0,
                     desc='frequency in seconds with which plot is updated')

    ########################################
    # Solver info/control.
    current_time = Float(0.0, desc='the current time in the simulation')
    time_step = Float(0.0, desc='the time-step of the solver')
    iteration = Int(0, desc='the current iteration number')
    pause_solver = Bool(False, desc='if the solver should be paused')

    ########################################
    # Movie.
    record = Bool(False, desc='if PNG files are to be saved for animation')
    frame_interval = Range(1, 100, 5, desc='the interval between screenshots')
    movie_directory = Str
    # internal counters.
    _count = Int(0)
    _frame_count = Int(0)
    _last_time = Float
    _solver_data = Any
    _file_name = Str
    _particle_array_updated = Bool

    ########################################
    # The layout of the dialog created
    view = View(HSplit(
        Group(
            Group(Group(
                Item(name='directory'),
                Item(name='current_file'),
                Item(name='file_count'),
                HGroup(Item(name='play'),
                       Item(name='play_delay', label='Delay', resizable=True),
                       Item(name='loop'),
                       Item(name='update_files', show_label=False),
                       padding=0),
                padding=0,
                label='Saved Data',
                selected=True,
                enabled_when='not live_mode',
            ),
                  Group(
                      Item(name='live_mode'),
                      Group(
                          Item(name='host'),
                          Item(name='port'),
                          Item(name='authkey'),
                          enabled_when='live_mode',
                      ),
                      label='Connection',
                  ),
                  layout='tabbed'),
            Group(
                Group(
                    Item(name='current_time'),
                    Item(name='time_step'),
                    Item(name='iteration'),
                    Item(name='pause_solver', enabled_when='live_mode'),
                    Item(name='interval', enabled_when='not live_mode'),
                    label='Solver',
                ),
                Group(
                    Item(name='record'),
                    Item(name='frame_interval'),
                    Item(name='movie_directory'),
                    label='Movie',
                ),
                layout='tabbed',
            ),
            Group(Item(name='particle_arrays',
                       style='custom',
                       show_label=False,
                       editor=ListEditor(use_notebook=True,
                                         deletable=False,
                                         page_name='.name')),
                  Item(name='interpolator', style='custom', show_label=False),
                  layout='tabbed'),
            Item(name='shell', show_label=False),
        ),
        Group(
            Item('scene',
                 editor=SceneEditor(scene_class=MayaviScene),
                 height=400,
                 width=600,
                 show_label=False), )),
                resizable=True,
                title='PySPH Particle Viewer',
                height=640,
                width=1024,
                handler=ViewerHandler)

    ######################################################################
    # `MayaviViewer` interface.
    ######################################################################
    def on_close(self):
        self._handle_particle_array_updates()

    @on_trait_change('scene:activated')
    def start_timer(self):
        if not self.live_mode:
            # No need for the timer if we are rendering files.
            return

        # Just accessing the timer will start it.
        t = self.timer
        if not t.IsRunning():
            t.Start(int(self.interval * 1000))

    @on_trait_change('scene:activated')
    def update_plot(self):

        # No need to do this if files are being used.
        if not self.live_mode:
            return

        # do not update if solver is paused
        if self.pause_solver:
            return

        if self.client is None:
            self.host_changed = True

        controller = self.controller
        if controller is None:
            return

        self.current_time = t = controller.get_t()
        self.time_step = controller.get_dt()
        self.iteration = controller.get_count()

        arrays = []
        for idx, name in enumerate(self.pa_names):
            pa = controller.get_named_particle_array(name)
            arrays.append(pa)
            pah = self.particle_arrays[idx]
            pah.set(particle_array=pa, time=t)

        self.interpolator.particle_arrays = arrays

        if self.record:
            self._do_snap()

    def run_script(self, path):
        """Execute a script in the namespace of the viewer.
        """
        with open(path) as fp:
            data = fp.read()
            ns = self._get_shell_namespace()
            exec(compile(data, path, 'exec'), ns)

    ######################################################################
    # Private interface.
    ######################################################################
    def _do_snap(self):
        """Generate the animation."""
        p_arrays = self.particle_arrays
        if len(p_arrays) == 0:
            return
        if self.current_time == self._last_time:
            return

        if len(self.movie_directory) == 0:
            controller = self.controller
            output_dir = controller.get_output_directory()
            movie_dir = os.path.join(output_dir, 'movie')
            self.movie_directory = movie_dir
        else:
            movie_dir = self.movie_directory
        if not os.path.exists(movie_dir):
            os.mkdir(movie_dir)

        interval = self.frame_interval
        count = self._count
        if count % interval == 0:
            fname = 'frame%06d.png' % (self._frame_count)
            p_arrays[0].scene.save_png(os.path.join(movie_dir, fname))
            self._frame_count += 1
            self._last_time = self.current_time
        self._count += 1

    @on_trait_change('host,port,authkey')
    def _mark_reconnect(self):
        if self.live_mode:
            self.host_changed = True

    @cached_property
    def _get_controller(self):
        ''' get the controller, also sets the iteration count '''
        if not self.live_mode:
            return None

        reconnect = self.host_changed
        if not reconnect:
            try:
                c = self.client.controller
            except Exception as e:
                logger.info('Error: no connection or connection closed: '
                            'reconnecting: %s' % e)
                reconnect = True
                self.client = None
            else:
                try:
                    self.client.controller.get_count()
                except IOError:
                    self.client = None
                    reconnect = True

        if reconnect:
            self.host_changed = False
            try:
                if MultiprocessingClient.is_available((self.host, self.port)):
                    self.client = MultiprocessingClient(address=(self.host,
                                                                 self.port),
                                                        authkey=self.authkey)
                else:
                    logger.info('Could not connect: Multiprocessing Interface'
                                ' not available on %s:%s' %
                                (self.host, self.port))
                    return None
            except Exception as e:
                logger.info('Could not connect: check if solver is '
                            'running:%s' % e)
                return None
            c = self.client.controller
            self.iteration = c.get_count()

        if self.client is None:
            return None
        else:
            return self.client.controller

    def _client_changed(self, old, new):
        if not self.live_mode:
            return

        self._clear()
        if new is None:
            return
        else:
            self.pa_names = self.client.controller.get_particle_array_names()

        self.particle_arrays = [
            self._make_particle_array_helper(self.scene, x)
            for x in self.pa_names
        ]
        self.interpolator = InterpolatorView(scene=self.scene)
        # Turn on the legend for the first particle array.
        if len(self.particle_arrays) > 0:
            self.particle_arrays[0].set(show_legend=True, show_time=True)

    def _timer_event(self):
        # catch all Exceptions else timer will stop
        try:
            self.update_plot()
        except Exception as e:
            logger.info('Exception: %s caught in timer_event' % e)

    def _interval_changed(self, value):
        t = self.timer
        if t is None:
            return
        if t.IsRunning():
            t.Stop()
            t.Start(int(value * 1000))

    def _timer_default(self):
        return Timer(int(self.interval * 1000), self._timer_event)

    def _pause_solver_changed(self, value):
        if self.live_mode:
            c = self.controller
            if c is None:
                return
            if value:
                c.pause_on_next()
            else:
                c.cont()

    def _record_changed(self, value):
        if value:
            self._do_snap()

    def _files_changed(self, value):
        if len(value) == 0:
            return
        else:
            d = os.path.dirname(os.path.abspath(value[0]))
            self.movie_directory = os.path.join(d, 'movie')
            self.set(directory=d, trait_change_notify=False)
        self._n_files = len(value) - 1
        self._frame_count = 0
        self._count = 0
        self.frame_interval = 1
        fc = self.file_count
        self.file_count = 0
        if fc == 0:
            # Force an update when our original file count is 0.
            self._file_count_changed(fc)
        t = self.timer
        if not self.live_mode:
            if t.IsRunning():
                t.Stop()
        else:
            if not t.IsRunning():
                t.Stop()
                t.Start(self.interval * 1000)

    def _file_count_changed(self, value):
        # Save out any updates for the previous file if needed.
        self._handle_particle_array_updates()
        # Load the new file.
        fname = self.files[value]
        self._file_name = fname
        self.current_file = os.path.basename(fname)
        # Code to read the file, create particle array and setup the helper.
        data = load(fname)
        solver_data = data["solver_data"]
        arrays = data["arrays"]
        self._solver_data = solver_data
        self.current_time = t = float(solver_data['t'])
        self.time_step = float(solver_data['dt'])
        self.iteration = int(solver_data['count'])
        names = list(arrays.keys())
        pa_names = self.pa_names

        if len(pa_names) == 0:
            self.interpolator = InterpolatorView(scene=self.scene)
            self.pa_names = names
            pas = []
            for name in names:
                pa = arrays[name]
                pah = self._make_particle_array_helper(self.scene, name)
                # Must set this after setting the scene.
                pah.set(particle_array=pa, time=t)
                pas.append(pah)
            self.particle_arrays = pas
        else:
            for idx, name in enumerate(pa_names):
                pa = arrays[name]
                pah = self.particle_arrays[idx]
                pah.set(particle_array=pa, time=t)

        self.interpolator.particle_arrays = list(arrays.values())

        if self.record:
            self._do_snap()

    def _loop_changed(self, value):
        if value and self.play:
            self._play_changed(self.play)

    def _play_changed(self, value):
        t = self.timer
        if value:
            t.Stop()
            t.callable = self._play_event
            t.Start(1000 * self.play_delay)
        else:
            t.Stop()
            t.callable = self._timer_event

    def _clear(self):
        self.pa_names = []
        self.scene.mayavi_scene.children[:] = []

    def _play_event(self):
        nf = self._n_files
        pc = self.file_count
        pc += 1
        if pc > nf:
            if self.loop:
                pc = 0
            else:
                self.timer.Stop()
                pc = nf
        self.file_count = pc
        self._handle_particle_array_updates()

    def _play_delay_changed(self):
        if self.play:
            self._play_changed(self.play)

    def _scalar_changed(self, value):
        for pa in self.particle_arrays:
            pa.scalar = value

    def _update_files_fired(self):
        fc = self.file_count
        files = glob_files(self.files[fc])
        sort_file_list(files)
        self.files = files
        self.file_count = fc
        if self.play:
            self._play_changed(self.play)

    def _shell_fired(self):
        ns = self._get_shell_namespace()
        obj = PythonShellView(ns=ns)
        obj.edit_traits()

    def _get_shell_namespace(self):
        return dict(viewer=self,
                    particle_arrays=self.particle_arrays,
                    interpolator=self.interpolator,
                    scene=self.scene,
                    mlab=self.scene.mlab)

    def _directory_changed(self, d):
        ext = os.path.splitext(self.files[-1])[1]
        files = glob.glob(os.path.join(d, '*' + ext))
        if len(files) > 0:
            self._clear()
            sort_file_list(files)
            self.files = files
            self.file_count = min(self.file_count, len(files))
        else:
            pass

    def _live_mode_changed(self, value):
        if value:
            self._file_name = ''
            self.client = None
            self._clear()
            self._mark_reconnect()
            self.start_timer()
        else:
            self.client = None
            self._clear()
            self.timer.Stop()

    def _particle_array_helper_updated(self, value):
        self._particle_array_updated = True

    def _handle_particle_array_updates(self):
        # Called when the particle array helper fires an updated event.
        if self._particle_array_updated and self._file_name:
            sd = self._solver_data
            arrays = [x.particle_array for x in self.particle_arrays]
            dump(self._file_name, arrays, sd)
            self._particle_array_updated = False

    def _make_particle_array_helper(self, scene, name):
        pah = ParticleArrayHelper(scene=scene, name=name, scalar=self.scalar)
        pah.on_trait_change(self._particle_array_helper_updated, 'updated')
        return pah
class FieldViewer(HasTraits):

    # 三个轴的取值范围
    x0, x1 = Float(-5), Float(5)
    y0, y1 = Float(-5), Float(5)
    z0, z1 = Float(-5), Float(5)
    points = Int(50)  # 分割点数
    autocontour = Bool(True)  # 是否自动计算等值面
    v0, v1 = Float(0.0), Float(1.0)  # 等值面的取值范围
    contour = Range("v0", "v1", 0.5)  # 等值面的值
    function = Str("x*x*0.5 + y*y + z*z*2.0")  # 标量场函数
    function_list = [
        "x*x*0.5 + y*y + z*z*2.0", "x*y*0.5 + np.sin(2*x)*y +y*z*2.0", "x*y*z",
        "np.sin((x*x+y*y)/z)"
    ]
    plotbutton = Button(u"描画")
    scene = Instance(MlabSceneModel, ())  #❶

    view = View(
        HSplit(
            VGroup(
                "x0",
                "x1",
                "y0",
                "y1",
                "z0",
                "z1",
                Item('points', label=u"点数"),
                Item('autocontour', label=u"自动等值"),
                Item('plotbutton', show_label=False),
            ),
            VGroup(
                Item(
                    'scene',
                    editor=SceneEditor(scene_class=MayaviScene),  #❷
                    resizable=True,
                    height=300,
                    width=350),
                Item('function',
                     editor=EnumEditor(name='function_list',
                                       evaluate=lambda x: x)),
                Item('contour',
                     editor=RangeEditor(format="%1.2f",
                                        low_name="v0",
                                        high_name="v1")),
                show_labels=False)),
        width=500,
        resizable=True,
        title=u"三维标量场观察器")

    def _plotbutton_fired(self):
        self.plot()

    def plot(self):
        # 产生三维网格
        x, y, z = np.mgrid[  #❸
            self.x0:self.x1:1j * self.points, self.y0:self.y1:1j * self.points,
            self.z0:self.z1:1j * self.points]

        # 根据函数计算标量场的值
        scalars = eval(self.function)  #❹
        self.scene.mlab.clf()  # 清空当前场景

        # 绘制等值平面
        g = self.scene.mlab.contour3d(x,
                                      y,
                                      z,
                                      scalars,
                                      contours=8,
                                      transparent=True)  #❺
        g.contour.auto_contours = self.autocontour
        self.scene.mlab.axes(figure=self.scene.mayavi_scene)  # 添加坐标轴

        # 添加一个X-Y的切面
        s = self.scene.mlab.pipeline.scalar_cut_plane(g)
        cutpoint = (self.x0 + self.x1) / 2, (self.y0 + self.y1) / 2, (
            self.z0 + self.z1) / 2
        s.implicit_plane.normal = (0, 0, 1)  # x cut
        s.implicit_plane.origin = cutpoint

        self.g = g  #❻
        self.scalars = scalars
        # 计算标量场的值的范围
        self.v0 = np.min(scalars)
        self.v1 = np.max(scalars)

    def _contour_changed(self):  #❼
        if hasattr(self, "g"):
            if not self.g.contour.auto_contours:
                self.g.contour.contours = [self.contour]

    def _autocontour_changed(self):  #❽
        if hasattr(self, "g"):
            self.g.contour.auto_contours = self.autocontour
            if not self.autocontour:
                self._contour_changed()
예제 #11
0
class SpectrumOptions(PlateauOptions):
    naux_plots = 8
    aux_plot_klass = SpectrumAuxPlot

    integrated_age_weighting = Enum(WEIGHTINGS)

    include_j_error_in_integrated = Bool(False)
    include_j_error_in_plateau = Bool(True)
    weighted_age_error_kind = Enum(*ERROR_TYPES)
    integrated_age_error_kind = Enum(*ERROR_TYPES)

    display_extract_value = Bool(False)
    display_step = Bool(False)
    display_plateau_info = Bool(True)
    display_integrated_info = Bool(True)
    display_weighted_mean_info = Bool(True)
    display_weighted_bar = Bool(True)

    plateau_sig_figs = Enum(*SIG_FIGS)
    integrated_sig_figs = Enum(*SIG_FIGS)
    weighted_mean_sig_figs = Enum(*SIG_FIGS)

    plateau_font = Property
    integrated_font = Property

    plateau_fontname = Enum(*FONTS)
    plateau_fontsize = Enum(*SIZES)
    integrated_fontname = Enum(*FONTS)
    integrated_fontsize = Enum(*SIZES)
    # step_label_font_size = Enum(*SIZES)

    envelope_alpha = Range(0, 100, style='simple')
    envelope_color = Color
    user_envelope_color = Bool
    # center_line_style = Enum('No Line', 'solid', 'dash', 'dot dash', 'dot', 'long dash')
    extend_plateau_end_caps = Bool(True)
    plateau_arrow_visible = Bool
    dim_non_plateau = Bool
    # plateau_line_width = Float
    # plateau_line_color = Color
    # user_plateau_line_color = Bool

    error_calc_method = Property
    use_error_envelope_fill = Bool

    include_plateau_sample = Bool
    include_plateau_identifier = Bool
    use_isochron_trapped = Bool
    include_isochron_trapped_error = Bool
    integrated_include_omitted = Bool

    group_options_klass = SpectrumGroupOptions

    def initialize(self):
        self.subview_names = [
            MAIN, 'Spectrum', APPEARANCE, 'Plateau', DISPLAY, GROUPS
        ]

    def _get_subview(self, name):
        return VIEWS[name]

    # handlers
    @on_trait_change('display_step,display_extract_value')
    def _handle_labels(self):
        labels_enabled = self.display_extract_value or self.display_step
        self.aux_plots[-1].show_labels = labels_enabled

    #
    # def _edit_groups_button_fired(self):
    #     eg = SpectrumGroupEditor(error_envelopes=self.groups)
    #     info = eg.edit_traits()
    #     if info.result:
    #         self.refresh_plot_needed = True

    def _get_error_calc_method(self):
        return self.plateau_age_error_kind

    def _set_error_calc_method(self, v):
        self.plateau_age_error_kind = v

    def _get_plateau_font(self):
        return '{} {}'.format(self.plateau_fontname, self.plateau_fontsize)

    def _get_integrated_font(self):
        return '{} {}'.format(self.integrated_fontname,
                              self.integrated_fontsize)
예제 #12
0
class TraitsTest(HasTraits):

    #-------------------------------------------------------------------------
    #  Trait definitions:
    #-------------------------------------------------------------------------

    enabled = Bool(True)
    integer_text = Int(1)
    enumeration = Trait('one', 'two', 'three', 'four', 'five', 'six', cols=3)
    float_range = Range(0.0, 10.0, 10.0)
    int_range = Range(1, 6)
    int_range2 = Range(1, 50)
    compound = Trait(1, Range(1, 6), 'one', 'two', 'three', 'four', 'five',
                     'six')
    boolean = Bool(True)
    instance = Trait(Instance())
    color = Color('cyan')
    font = Font()
    check_list = List(
        editor=CheckListEditor(values=['one', 'two', 'three', 'four'], cols=4))
    list = List(Str,
                ['East of Eden', 'The Grapes of Wrath', 'Of Mice and Men'])
    button = Event(0, editor=ButtonEditor(label='Click'))
    file = File()
    directory = Directory()
    image_enum = Trait(editor=ImageEnumEditor(values=origin_values,
                                              suffix='_origin',
                                              cols=4,
                                              klass=Instance),
                       *origin_values)

    #-------------------------------------------------------------------------
    #  View definitions:
    #-------------------------------------------------------------------------

    view = View(
        ('|{Enum}', ('enabled', ),
         ('|<[Enumeration]', 'f1:enumeration[Simple]', '_',
          'f2:enumeration[Custom]@', '_', 'f3:enumeration[Text]*', '_',
          'f4:enumeration[Readonly]~'),
         ('|<[Check List]', 'f5:check_list[Simple]', '_',
          'f6:check_list[Custom]@', '_', 'f7:check_list[Text]*', '_',
          'f8:check_list[Readonly]~')),
        ('|{Range}',
         ('|<[Float Range]', 'f9:float_range[Simple]', '_',
          'f10:float_range[Custom]@', '_', 'f11:float_range[Text]*', '_',
          'f12:float_range[Readonly]~'),
         ('|<[Int Range]', 'f13:int_range[Simple]', '_',
          'f14:int_range[Custom]@', '_', 'f15:int_range[Text]*', '_',
          'f16:int_range[Readonly]~'),
         ('|<[Int Range 2]', 'f17:int_range2[Simple]', '_',
          'f18:int_range2[Custom]@', '_', 'f19:int_range2[Text]*', '_',
          'f20:int_range2[Readonly]~')),
        ('|{Misc}',
         ('|<[Integer Text]', 'f21:integer_text[Simple]', '_',
          'f22:integer_text[Custom]@', '_', 'f23:integer_text[Text]*', '_',
          'f24:integer_text[Readonly]~'),
         ('|<[Compound]', 'f25:compound[Simple]', '_', 'f26:compound[Custom]@',
          '_', 'f27:compound[Text]*', '_', 'f28:compound[Readonly]~'),
         ('|<[Boolean]', 'f29:boolean[Simple]', '_', 'f30:boolean[Custom]@',
          '_', 'f31:boolean[Text]*', '_', 'f32:boolean[Readonly]~')),
        ('|{Color/Font}',
         ('|<[Color]', 'f33:color[Simple]', '_', 'f34:color[Custom]@', '_',
          'f35:color[Text]*', '_', 'f36:color[Readonly]~'),
         ('|<[Font]', 'f37:font[Simple]', '_', 'f38:font[Custom]@', '_',
          'f39:font[Text]*', '_', 'f40:font[Readonly]~')),
        ('|{List}', ('|<[List]', 'f41:list[Simple]', '_', 'f42:list[Custom]@',
                     '_', 'f43:list[Text]*', '_', 'f44:list[Readonly]~')),
        (
            '|{Button}',
            ('|<[Button]', 'f45:button[Simple]', '_', 'f46:button[Custom]@'),
            #                                        'button[Text]*',
            #                                        'button[Readonly]~' ),
            ('|<[Image Enum]', 'f47:image_enum[Simple]', '_',
             'f48:image_enum[Custom]@', '_', 'f49:image_enum[Text]*', '_',
             'f50:image_enum[Readonly]~'),
            ('|<[Instance]', 'f51:instance[Simple]', '_',
             'f52:instance[Custom]@', '_', 'f53:instance[Text]*', '_',
             'f54:instance[Readonly]~'),
        ),
        ('|{File}', (
            '|<[File]',
            'f55:file[Simple]',
            '_',
            'f56:file[Custom]@',
            '_',
            'f57:file[Text]*',
            '_',
            'f58:file[Readonly]~',
        ), ('|<[Directory]', 'f59:directory[Simple]', '_',
            'f60:directory[Custom]@', '_', 'f61:directory[Text]*', '_',
            'f62:directory[Readonly]~')),
        buttons=['Apply', 'Revert', 'Undo', 'OK'],
        handler=TraitsTestHandler())
예제 #13
0
def RangeCompound(*args, **kwargs):
    """
    Compound trait including a Range.
    """
    return Either(impossible, Range(*args, **kwargs))
예제 #14
0
파일: spylot.py 프로젝트: eteq/astropysics
class Spylot(HasTraits):
    """
    This class represents the spylot application state.
    """

    defaultlines = 'galaxy'  #can be 'galaxy' or 'stellar' or None
    """
    This class attribute sets the default line lists to use - 'galaxy' or
    'stellar'
    """

    plot = Instance(Plot)
    histplot = Bool(True)

    majorlineeditor = LineListEditor
    minorlineeditor = LineListEditor
    linenamelist = Property(Tuple)
    showmajorlines = Bool(True)
    showminorlines = Bool(False)

    labels = List(DataLabel)
    showlabels = Bool(False)
    editmajor = Button('Edit Major')
    editminor = Button('Edit Minor')

    specs = List(Instance(spec.Spectrum))
    currspeci = Int
    currspecip1 = Property(depends_on='currspeci')
    lowerspecip1 = Property(depends_on='currspeci')
    upperspecip1 = Property(depends_on='currspeci')
    currspec = Property
    lastspec = Instance(spec.Spectrum)
    z = Float
    lowerz = Float(0.0)
    upperz = Float(1.0)
    zviewtype = Enum('redshift', 'velocity')
    zview = Property(Float, depends_on='z,zviewtype')
    uzview = Property(Float, depends_on='upperz,zviewtype')
    lzview = Property(Float, depends_on='lowerz,zviewtype')
    coarserz = Button('Coarser')
    finerz = Button('Finer')
    _zql, _zqh = min(spec.Spectrum._zqmap.keys()), max(
        spec.Spectrum._zqmap.keys())
    zqual = Range(_zql, _zqh, -1)

    spechanged = Event
    specleft = Button('<')
    specright = Button('>')

    scaleerr = Bool(False)
    scaleerrfraclow = Range(0.0, 1.0, 1.0)
    scaleerrfrachigh = Float(1.0)
    fluxformat = Button('Flux Line Format')
    errformat = Button('Error Line Format')
    showcoords = Bool(False)
    showgrid = Bool(True)

    dosmoothing = Bool(False)
    smoothing = Float(3)

    contsub = Button('Fit Continuum...')
    contclear = Button('Clear Continuum')
    showcont = Bool(False)
    contformat = Button('Continuum Line Format')

    _titlestr = Str('Spectrum 0/0')
    _oldunit = Str('')
    maintool = Tuple(Instance(Interactor), Instance(AbstractOverlay))

    featureselmode = Enum([
        'No Selection', 'Click Select', 'Range Select', 'Base Select',
        'Click Delete'
    ])
    editfeatures = Button('Features...')
    showfeatures = Bool(True)
    featurelocsmooth = Float(None)
    featurelocsize = Int(200)
    featurelist = List(Instance(spec.SpectralFeature))

    selectedfeatureindex = Int
    deletefeature = Button('Delete')
    idfeature = Button('Identify')
    recalcfeature = Button('Recalculate')
    clearfeatures = Button('Clear')

    delcurrspec = Button('Delete Current')
    saveloadfile = File(filter=['*.specs'])
    savespeclist = Button('Save Spectra')
    loadspeclist = Button('Load Spectra')
    loadaddfile = File(filter=['*.fits'])
    loadaddspec = Button('Add Spectrum')
    loadaddspectype = Enum('wcs', 'deimos', 'astropysics')

    titlegroup = HGroup(
        Item('specleft', show_label=False, enabled_when='currspeci>0'), spring,
        Label('Spectrum #', height=0.5),
        Item('currspecip1',
             show_label=False,
             editor=RangeEditor(low_name='lowerspecip1',
                                high_name='upperspecip1',
                                mode='spinner')),
        Item('_titlestr', style='readonly', show_label=False), spring,
        Item('specright',
             show_label=False,
             enabled_when='currspeci<(len(specs)-1)'))

    speclistgroup = HGroup(
        Label('Spectrum List:'), spring,
        Item('delcurrspec', show_label=False, enabled_when='len(specs)>1'),
        Item('saveloadfile', show_label=False),
        Item('savespeclist', show_label=False),
        Item('loadspeclist',
             show_label=False,
             enabled_when='os.path.exists(saveloadfile)'),
        Item('loadaddfile', show_label=False),
        Item('loadaddspec',
             show_label=False,
             enabled_when='os.path.exists(saveloadfile)'),
        Item('loadaddspectype', show_label=False), spring)

    plotformatgroup = HGroup(
        spring, Item('fluxformat', show_label=False),
        Item('errformat', show_label=False),
        Item('scaleerr', label='Scale Error?'),
        Item('scaleerrfraclow',
             label='Lower',
             enabled_when='scaleerr',
             editor=TextEditor(evaluate=float)),
        Item('scaleerrfrachigh', label='Upper', enabled_when='scaleerr'),
        Item('showgrid', label='Grid?'), Item('showcoords', label='Coords?'),
        spring)

    featuregroup = HGroup(spring, Item('showmajorlines', label='Show major?'),
                          Item('editmajor', show_label=False),
                          Item('showlabels', label='Labels?'),
                          Item('showminorlines', label='Show minor?'),
                          Item('editminor', show_label=False), spring,
                          Item('editfeatures', show_label=False),
                          Item('featureselmode', show_label=False), spring)

    continuumgroup = HGroup(
        spring, Item('contsub', show_label=False),
        Item('contclear', show_label=False),
        Item('showcont', label='Continuum line?'),
        Item('contformat', show_label=False),
        Item('dosmoothing', label='Smooth?'),
        Item('smoothing', show_label=False, enabled_when='dosmoothing'),
        spring)

    zgroup = VGroup(
        HGroup(
            Item('zviewtype', show_label=False),
            Item('zview',
                 editor=RangeEditor(low_name='lzview',
                                    high_name='uzview',
                                    format='%5.4g ',
                                    mode='slider'),
                 show_label=False,
                 springy=True)),
        HGroup(
            Item('lzview', show_label=False), Item('coarserz',
                                                   show_label=False), spring,
            Item('zqual',
                 style='custom',
                 label='Z quality',
                 editor=RangeEditor(cols=_zqh - _zql + 1, low=_zql,
                                    high=_zqh)), spring,
            Item('finerz', show_label=False), Item('uzview',
                                                   show_label=False)))

    features_view = View(VGroup(
        HGroup(Item('showfeatures', label='Show'),
               Item('featurelocsmooth', label='Locator Smoothing'),
               Item('featurelocsize', label='Locator Window size')),
        Item('featurelist',
             editor=TabularEditor(adapter=FeaturesAdapter(),
                                  selected_row='selectedfeatureindex'),
             show_label=False),
        HGroup(
            Item(
                'deletefeature',
                show_label=False,
                enabled_when='len(featurelist)>0 and selectedfeatureindex>=0'),
            Item(
                'idfeature',
                show_label=False,
                enabled_when='len(featurelist)>0 and selectedfeatureindex>=0'),
            Item(
                'recalcfeature',
                show_label=False,
                enabled_when='len(featurelist)>0 and selectedfeatureindex>=0'),
            Item('clearfeatures',
                 show_label=False,
                 enabled_when='len(featurelist)>0'))),
                         resizable=True,
                         title='Spylot Features')

    traits_view = View(VGroup(
        Include('titlegroup'), Include('speclistgroup'),
        Include('plotformatgroup'), Include('featuregroup'),
        Include('continuumgroup'),
        Item('plot', editor=ComponentEditor(), show_label=False, width=768),
        Include('zgroup')),
                       resizable=True,
                       title='Spectrum Plotter',
                       handler=SpylotHandler(),
                       key_bindings=spylotkeybindings)

    def __init__(self, specs, **traits):
        """
        :param specs:
            The spectra/um to be analyzed as a sequence or a single object.
        :type specs: :class:`astropysics.spec.Spectrum`

        kwargs are passed in as additional traits.
        """

        #pd = ArrayPlotData(x=[1],x0=[1],flux=[1],err=[1]) #reset by spechanged event
        pd = ArrayPlotData(x=[1], flux=[1],
                           err=[1])  #reset by spechanged event
        pd.set_data('majorx', [1, 1])  #reset by majorlines change
        pd.set_data('majory', [0, 1])  #reset by majorlines change
        pd.set_data('minorx', [1, 1])  #reset by minorlines change
        pd.set_data('minory', [0, 1])  #reset by minorlines change
        pd.set_data('continuum', [0, 0])  #reset

        self.plot = plot = Plot(pd, resizeable='hv')
        ploi = plot.draw_order.index('plot')
        plot.draw_order[ploi:ploi] = [
            'continuum', 'err', 'flux', 'annotations'
        ]
        plot.plot(('x', 'flux'),
                  name='flux',
                  type='line',
                  line_style='solid',
                  color='blue',
                  draw_layer='flux',
                  unified_draw=True)
        plot.plot(('x', 'err'),
                  name='err',
                  type='line',
                  line_style='dash',
                  color='green',
                  draw_layer='err',
                  unified_draw=True)

        topmapper = LinearMapper(range=DataRange1D())
        plot.x_mapper.range.on_trait_change(self._update_upperaxis_range,
                                            'updated')
        plot.x_mapper.on_trait_change(self._update_upperaxis_screen, 'updated')
        self.upperaxis = PlotAxis(plot, orientation='top', mapper=topmapper)
        plot.overlays.append(self.upperaxis)

        self.errmapperfixed = plot.plots['err'][0].value_mapper
        self.errmapperscaled = LinearMapper(range=DataRange1D(high=1.0, low=0))
        plot.x_mapper.on_trait_change(self._update_errmapper_screen, 'updated')

        plot.padding_top = 30  #default is a bit much
        plot.padding_left = 70  #default is a bit too little

        majorlineplot = plot.plot(('majorx', 'majory'),
                                  name='majorlineplot',
                                  type='line',
                                  line_style='dash',
                                  color='red')[0]
        majorlineplot.set(draw_layer='annotations', unified_draw=True)
        majorlineplot.value_mapper = LinearMapper(
            range=DataRange1D(high=0.9, low=0.1))
        majorlineplot.visible = self.showmajorlines
        del plot.x_mapper.range.sources[
            -1]  #remove the line plot from the x_mapper sources so scaling is only on the spectrum
        self.majorlineeditor = LineListEditor(lineplot=majorlineplot)

        minorlineplot = plot.plot(('minorx', 'minory'),
                                  name='minorlineplot',
                                  type='line',
                                  line_style='dot',
                                  color='red')[0]
        minorlineplot.set(draw_layer='annotations', unified_draw=True)
        minorlineplot.value_mapper = LinearMapper(
            range=DataRange1D(high=0.9, low=0.1))
        minorlineplot.visible = self.showminorlines
        del plot.x_mapper.range.sources[
            -1]  #remove the line plot from the x_mapper sources so scaling is only on the spectrum
        self.minorlineeditor = LineListEditor(lineplot=minorlineplot)

        self.contline = plot.plot(('x', 'continuum'),
                                  name='continuum',
                                  type='line',
                                  line_style='solid',
                                  color='black')[0]
        self.contline.set(draw_layer='continuum', unified_draw=True)
        self.contline.visible = self.showcont
        #        idat = ArrayDataSource((0.0,1.0))
        #        vdat = ArrayDataSource((0.0,0.0))
        #        self.zeroline = LinePlot(index=idat,value=vdat,line_style='solid',color='black')
        #        self.zeroline.index_mapper = LinearMapper(range=DataRange1D(high=0.9,low=0.1))
        #        self.zeroline.value_mapper = self.plot.y_mapper
        #        self.zeroline.visible = self.showcont
        #        self.plot.add(self.zeroline)

        if Spylot.defaultlines:
            defaultlines = _get_default_lines(Spylot.defaultlines)
            self.majorlineeditor.candidates = defaultlines[0]
            self.majorlineeditor.selectednames = defaultlines[1]
            self.minorlineeditor.candidates = defaultlines[0]
            self.minorlineeditor.selectednames = defaultlines[2]

        plot.tools.append(PanTool(plot))
        plot.tools.append(ZoomTool(plot))
        plot.overlays.append(plot.tools[-1])

        self.coordtext = TextBoxOverlay(component=plot, align='ul')
        plot.overlays.append(self.coordtext)
        plot.tools.append(MouseMoveReporter(overlay=self.coordtext, plot=plot))
        self.coordtext.visible = self.showcoords

        self.linehighlighter = lho = LineHighlighterOverlay(component=plot)
        lho.visible = self.showfeatures
        plot.overlays.append(lho)

        if specs is None:
            specs = []
        elif isinstance(specs, spec.Spectrum):
            specs = [specs]
        self.specs = specs

        self.spechanged = True

        self.on_trait_change(self._majorlines_changed,
                             'majorlineeditor.selectedobjs')
        self.on_trait_change(self._minorlines_changed,
                             'minorlineeditor.selectedobjs')

        super(Spylot, self).__init__(**traits)

    def __del__(self):
        try:
            self.currspec._features = list(self.currspec._features)
        except (AttributeError, IndexError), e:
            pass
예제 #15
0
class TraitsTest(HasTraits):

    #-------------------------------------------------------------------------
    #  Trait definitions:
    #-------------------------------------------------------------------------

    integer_text = Int(1)
    enumeration = Enum('one', 'two', 'three', 'four', 'five', 'six', cols=3)
    float_range = Range(0.0, 10.0, 10.0)
    int_range = Range(1, 6)
    int_range2 = Range(1, 50)
    compound = Trait(1, Range(1, 6), 'one', 'two', 'three', 'four', 'five',
                     'six')
    boolean = Bool(True)
    instance = Trait(Instance())
    color = Color
    font = Font
    check_list = List(
        editor=CheckListEditor(values=['one', 'two', 'three', 'four'], cols=4))
    list = List(Str,
                ['East of Eden', 'The Grapes of Wrath', 'Of Mice and Men'])
    button = Event(0, editor=ButtonEditor(label='Click'))
    file = File()
    directory = Directory()
    image_enum = Trait(editor=ImageEnumEditor(values=origin_values,
                                              suffix='_origin',
                                              cols=4,
                                              klass=Instance),
                       *origin_values)

    #-------------------------------------------------------------------------
    #  View definitions:
    #-------------------------------------------------------------------------

    view = View(
        ('|{Enum}', ('|<[Enumeration]', 'enumeration[Simple]', '_',
                     'enumeration[Custom]@', '_', 'enumeration[Text]*', '_',
                     'enumeration[Readonly]~'),
         ('|<[Check List]', 'check_list[Simple]', '_', 'check_list[Custom]@',
          '_', 'check_list[Text]*', '_', 'check_list[Readonly]~')),
        ('|{Range}', ('|<[Float Range]', 'float_range[Simple]', '_',
                      'float_range[Custom]@', '_', 'float_range[Text]*', '_',
                      'float_range[Readonly]~'),
         ('|<[Int Range]', 'int_range[Simple]', '_', 'int_range[Custom]@', '_',
          'int_range[Text]*', '_', 'int_range[Readonly]~'),
         ('|<[Int Range 2]', 'int_range2[Simple]', '_', 'int_range2[Custom]@',
          '_', 'int_range2[Text]*', '_', 'int_range2[Readonly]~')),
        ('|{Misc}', ('|<[Integer Text]', 'integer_text[Simple]', '_',
                     'integer_text[Custom]@', '_', 'integer_text[Text]*', '_',
                     'integer_text[Readonly]~'),
         ('|<[Compound]', 'compound[Simple]', '_', 'compound[Custom]@', '_',
          'compound[Text]*', '_', 'compound[Readonly]~'),
         ('|<[Boolean]', 'boolean[Simple]', '_', 'boolean[Custom]@', '_',
          'boolean[Text]*', '_', 'boolean[Readonly]~')),
        ('|{Color/Font}', ('|<[Color]', 'color[Simple]', '_', 'color[Custom]@',
                           '_', 'color[Text]*', '_', 'color[Readonly]~'),
         ('|<[Font]', 'font[Simple]', '_', 'font[Custom]@', '_', 'font[Text]*',
          '_', 'font[Readonly]~')),
        ('|{List}', ('|<[List]', 'list[Simple]', '_', 'list[Custom]@', '_',
                     'list[Text]*', '_', 'list[Readonly]~')),
        (
            '|{Button}',
            ('|<[Button]', 'button[Simple]', '_', 'button[Custom]@'),
            #                                        'button[Text]*',
            #                                        'button[Readonly]~' ),
            ('|<[Image Enum]', 'image_enum[Simple]', '_',
             'image_enum[Custom]@', '_', 'image_enum[Text]*', '_',
             'image_enum[Readonly]~'),
            ('|<[Instance]', 'instance[Simple]', '_', 'instance[Custom]@', '_',
             'instance[Text]*', '_', 'instance[Readonly]~'),
        ),
        ('|{File}', (
            '|<[File]',
            'file[Simple]',
            '_',
            'file[Custom]@',
            '_',
            'file[Text]*',
            '_',
            'file[Readonly]~',
        ), ('|<[Directory]', 'directory[Simple]', '_', 'directory[Custom]@',
            '_', 'directory[Text]*', '_', 'directory[Readonly]~')),
        buttons=['Apply', 'Revert', 'Undo', 'OK'])
예제 #16
0
class Float(Variable):
    """A Variable wrapper for floating point number valid within a
    specified range of values.
    """
    
    def __init__(self, default_value=None, iotype=None, desc=None, 
                 low=None, high=None, exclude_low=False, exclude_high=False, 
                 units=None, **metadata):

        _default_set = False
        
        # Determine defalt_value if unspecified
        if default_value is None:
            if low is None and high is None:
                default_value = 0.0
            elif low is None:
                default_value = high
            else:
                default_value = low
        else:
            _default_set = True
            if not isinstance(default_value, float):
                if isinstance(default_value, int):
                    default_value = float(default_value)
                else:
                    raise ValueError("Default value should be a float.")
              
        # excludes must be saved locally because we override error()
        self.exclude_low = exclude_low
        self.exclude_high = exclude_high
        
        # Put iotype in the metadata dictionary
        if iotype is not None:
            metadata['iotype'] = iotype
            
        # Put desc in the metadata dictionary
        if desc is not None:
            metadata['desc'] = desc
            
        # Put units in the metadata dictionary
        if units is not None:
            metadata['units'] = units
            
        # The Range trait must be used if High or Low is set
        if low is None and high is None:
            self._validator = TraitFloat(default_value, **metadata)
        else:
            if low is None:
                low = -float_info.max
            else:
                low = float(low)
                
            if high is None:
                high = float_info.max
            else:
                high = float(high)

            if low > high:
                raise ValueError("Lower bound is greater than upper bound.")
        
            if default_value > high or default_value < low:
                raise ValueError("Default value is outside of bounds [%s, %s]." %
                                 (str(low), str(high)))
                     
            # Range can be float or int, so we need to force these to be float.
            default_value = float(default_value)
                
            self._validator = Range(low=low, high=high, value=default_value,
                                          exclude_low=exclude_low,
                                          exclude_high=exclude_high,
                                          **metadata)
            
        # If there are units, test them by creating a physical quantity
        if 'units' in metadata:
            try:
                pq = PhysicalQuantity(0., metadata['units'])
            except:
                raise ValueError("Units of '%s' are invalid" %
                                 metadata['units'])
            
        # Add low and high to the trait's dictionary so they can be accessed
        metadata['low'] = low
        metadata['high'] = high
        if not _default_set and metadata.get('required') == True:
            super(Float, self).__init__(**metadata)
        else:
            super(Float, self).__init__(default_value=default_value,
                                        **metadata)

    def validate(self, obj, name, value):
        """ Validates that a specified value is valid for this trait.
        Units are converted as needed.
        """
        
        # pylint: disable-msg=E1101
        # If both source and target have units, we need to process differently
        if isinstance(value, AttrWrapper):
            if self.units:
                valunits = value.metadata.get('units')
                if valunits and isinstance(valunits, basestring) and \
                   self.units != valunits:
                    return self._validate_with_metadata(obj, name, 
                                                        value.value, 
                                                        valunits)
            
            value = value.value
        elif isinstance(value, UncertainDistribution):
            value = value.getvalue()
        try:
            return self._validator.validate(obj, name, value)
        except Exception:
            self.error(obj, name, value)

    def error(self, obj, name, value):
        """Returns a descriptive error string."""
        
        # pylint: disable-msg=E1101
        if self.low is None and self.high is None:
            if self.units:
                info = "a float having units compatible with '%s'" % self.units
            else:
                info = "a float"
        elif self.low is not None and self.high is not None:
            right = ']'
            left = '['
            if self.exclude_high is True:
                right = ')'
            if self.exclude_low is True:
                left = '('
            info = "a float in the range %s%s, %s%s"% \
                   (left,self.low,self.high,right)
        elif self.low is not None:
            info = "a float with a value > %s"% self.low
        else: # self.high is not None
            info = "a float with a value < %s"% self.high

        vtype = type( value )
        msg = "Variable '%s' must be %s, but a value of %s %s was specified." % \
                               (name, info, value, vtype)
        try:
            obj.raise_exception(msg, ValueError)
        except AttributeError:
            raise ValueError(msg)

    def get_val_wrapper(self, value, index=None):
        """Return a UnitsAttrWrapper object.  Its value attribute
        will be filled in by the caller.
        """
        if index is not None:
            raise ValueError("Float does not support indexing")
        # pylint: disable-msg=E1101
        if self.units is None:
            return value
        return UnitsAttrWrapper(value, units=self.units)
            
    def _validate_with_metadata(self, obj, name, value, src_units):
        """Perform validation and unit conversion using metadata from
        the source trait.
        """
        
        # pylint: disable-msg=E1101
        dst_units = self.units
        
        if isinstance(value, UncertainDistribution):
            value = value.getvalue()
            
        # FIXME: The try blocks testing whether the unit is bogus or undefined
        # are generally redundant because that test is done at creation. HOWEVER
        # you might have a case where it wasn't tested because it's technically
        # not a float. NPSS wrapper may be such a case. A test needs to be 
        # constructed to test these lines.

        # Note: benchmarking showed that this check does speed things up -- KTM
        if src_units == dst_units:
            try:
                return self._validator.validate(obj, name, value)
            except Exception:
                self.error(obj, name, value)

        try:
            pq = PhysicalQuantity(value, src_units)
        except NameError:
            raise NameError("while setting value of %s: undefined unit '%s'" %
                             (src_units, name))
        
        try:
            pq.convert_to_unit(dst_units)
        except NameError:
            raise NameError("undefined unit '%s' for variable '%s'" %
                             (dst_units, name))
        except TypeError:
            msg = "%s: units '%s' are incompatible " % (name, src_units) + \
                   "with assigning units of '%s'" % (dst_units)
            raise TypeError(msg)
        
        try:
            return self._validator.validate(obj, name, pq.value)
        except Exception:
            self.error(obj, name, pq.value)

    def get_attribute(self, name, value, trait, meta):
        """Return the attribute dictionary for this variable. This dict is
        used by the GUI to populate the edit UI. The basic functionality that
        most variables need is provided here; you can overload this for
        special cases, like lists and dictionaries, or custom datatypes.
        
        name: str
          Name of variable
          
        value: object
          The value of the variable
          
        trait: CTrait
          The variable's trait
          
        meta: dict
          Dictionary of metadata for this variable
        """
        attr, other = super(Float, self).get_attribute(name, value, trait, meta)
        # Fix type 'synonym'.
        if attr['type'] == 'float64':
            attr['type'] = 'float'
            attr['value'] = float(value)
        return attr, other
예제 #17
0
class IntervalSpectrogram(PlotsInterval):
    name = 'Spectrogram'
    # overload the figure stack to use GridSpec
    _figstack = Instance(GridSpecStack, args=())

    ## channel = Str('all')
    ## _chan_list = Property(depends_on='parent.chan_map')
    # estimations details
    NW = Enum(2.5, np.arange(2, 11, 0.5).tolist())
    lag = Float(25)  # ms
    strip = Float(100)  # ms
    detrend = Bool(True)
    adaptive = Bool(True)
    over_samp = Range(0, 16, mode='spinner', value=4)
    high_res = Bool(True)
    _bandwidth = Property(Float, depends_on='NW, strip')

    baseline = Float(1.0)  # sec
    normalize = Enum('Z score', ('None', 'Z score', 'divide', 'subtract'))
    plot = Button('Plot')
    freq_hi = Float
    freq_lo = Float(0)
    log_freq = Bool(False)
    new_figure = Bool(True)

    colormap = 'Spectral_r'

    def __init__(self, **traits):
        HasTraits.__init__(self, **traits)
        self.freq_hi = round((self.parent.x_scale**-1.0) / 2.0)

    # @property_depends_on('NW')
    @cached_property
    def _get__bandwidth(self):
        #t1, t2 = self.parent._qtwindow.current_frame()
        T = self.strip * 1e-3
        # TW = NW --> W = NW / T
        return 2.0 * self.NW / T

    def __default_mtm_kwargs(self, strip):
        kw = dict()
        kw['NW'] = self.NW
        kw['adaptive_weights'] = self.adaptive
        Fs = self.parent.x_scale**-1.0
        kw['Fs'] = Fs
        kw['jackknife'] = False
        kw['detrend'] = 'linear' if self.detrend else ''
        lag = int(Fs * self.lag / 1000.)
        if strip is None:
            strip = int(Fs * self.strip / 1000.)
        kw['nfft'] = nextpow2(strip)
        kw['pl'] = 1.0 - float(lag) / strip
        if self.high_res:
            kw['samp_factor'] = self.over_samp
            kw['low_bias'] = 0.95
        return kw, strip

    def _normalize(self, tx, ptf, mode, tc):
        # ptf should be ([n_chan], n_freq, n_time)
        if not mode:
            mode = self.normalize
        if not tc:
            tc = self.baseline

        m = tx < tc
        if not m.any():
            print('Baseline too short: using 2 bins')
            m[:2] = True
        if ptf.ndim < 3:
            ptf = ptf.reshape((1, ) + ptf.shape)
        nf = ptf.shape[1]
        # subtraction and z-score normalizations should be done with log transform
        if mode.lower() in ('subtract', 'z score'):
            ptf = np.log10(ptf)
        p_bl = ptf[..., m].transpose(0, 2, 1).copy().reshape(-1, nf)

        # get mean of baseline for each freq.
        jn = Jackknife(p_bl, axis=0)
        mn = jn.estimate(np.mean, se=False)
        # smooth out mean across frequencies (5 hz sigma) but only replace after 2NW points
        bias_pts = int(2 * self.NW)
        mn[bias_pts:] = gaussian_filter1d(mn, self.NW,
                                          mode='reflect')[bias_pts:]
        assert len(mn) == nf, '?'
        if mode.lower() == 'divide':
            ptf = ptf.mean(0) / mn[:, None]
        elif mode.lower() == 'subtract':
            ptf = ptf.mean(0) - mn[:, None]
        elif mode.lower() == 'z score':
            stdev = jn.estimate(np.std, se=False)
            stdev[bias_pts:] = gaussian_filter1d(stdev,
                                                 self.NW,
                                                 mode='reflect')[bias_pts:]
            ptf = (ptf.mean(0) - mn[:, None]) / stdev[:, None]
        return ptf

    def highres_spectrogram(self, array, strip=None, **mtm_kw):
        kw, strip = self.__default_mtm_kwargs(strip)
        kw.update(**mtm_kw)
        tx, fx, ptf = msp.mtm_spectrogram(array, strip, **kw)
        n_cut = 6
        tx = tx[n_cut:-n_cut]
        ptf = ptf[..., n_cut:-n_cut].copy()
        return tx, fx, ptf

    def spectrogram(self, array, strip=None, **mtm_kw):
        kw, strip = self.__default_mtm_kwargs(strip)
        kw.update(**mtm_kw)
        tx, fx, ptf = msp.mtm_spectrogram_basic(array, strip, **kw)
        return tx, fx, ptf

    def _plot_fired(self):
        x, y = self.curve_manager.interactive_curve.current_data()
        y *= 1e6
        if self.channel.lower() != 'all':
            i, j = list(map(float, self.channel.split(',')))
            y = y[self.chan_map.lookup(i, j)]

        if self.high_res:
            tx, fx, ptf = self.highres_spectrogram(y)
        else:
            tx, fx, ptf = self.spectrogram(y)

        if self.normalize.lower() != 'none':
            ptf = self._normalize(tx, ptf, self.normalize, self.baseline)
        else:
            ptf = np.log10(ptf)
            if ptf.ndim > 2:
                ptf = ptf.mean(0)
        # cut out non-display frequencies and advance timebase to match window
        m = (fx >= self.freq_lo) & (fx <= self.freq_hi)
        ptf = ptf[m]
        fx = fx[m]
        if fx[0] == 0 and self.log_freq:
            fx[0] = 0.5 * (fx[0] + fx[1])
        tx += x[0]
        # fig, ax = self._get_fig()
        fig, gs = self._get_fig(figsize=(8, 10),
                                nrows=2,
                                ncols=2,
                                height_ratios=[1, 3],
                                width_ratios=[20, 1])
        ts_ax = fig.add_subplot(gs[0, 0])
        ts_ax.plot(x, y)
        ts_ax.set_ylabel(r'$\mu$V')
        for t in ts_ax.get_xticklabels():
            t.set_visible(False)
        sg_ax = fig.add_subplot(gs[1, 0])
        im = sg_ax.imshow(ptf,
                          extent=[tx[0], tx[-1], fx[0], fx[-1]],
                          cmap=self.colormap,
                          origin='lower')
        if self.log_freq:
            sg_ax.set_yscale('log')
            sg_ax.set_ylim(fx[1], fx[-1])
        sg_ax.axis('auto')
        sg_ax.set_xlabel('Time (s)')
        sg_ax.set_ylabel('Frequency (Hz)')
        cb_ax = fig.add_subplot(gs[:, 1])
        cbar = fig.colorbar(im, cax=cb_ax, aspect=80)
        cbar.locator = ticker.MaxNLocator(nbins=3)
        if self.normalize.lower() == 'divide':
            title = 'Normalized ratio'
        elif self.normalize.lower() == 'subtract':
            title = 'Baseline subtracted'
        elif self.normalize.lower() == 'z score':
            title = 'Z score'
        else:
            title = 'Log-power'
        cbar.set_label(title)
        # fig.tight_layout()
        gs.tight_layout(fig, w_pad=0.025)
        ts_ax.set_xlim(sg_ax.get_xlim())
        try:
            fig.canvas.draw_idle()
        except:
            pass

    def default_traits_view(self):
        v = View(
            HGroup(
                VGroup(
                    HGroup(
                        VGroup(
                            Label('Channel to plot'),
                            UItem(
                                'channel',
                                editor=EnumEditor(name='object._chan_list'))),
                        Label('Log-Hz?'), UItem('log_freq'), UItem('plot')),
                    HGroup(Item('freq_lo', label='low', width=3),
                           Item('freq_hi', label='high', width=3),
                           label='Freq. Range')),
                VGroup(Item('high_res', label='High-res SG'),
                       Item('normalize', label='Normalize'),
                       Item('baseline', label='Baseline length (sec)'),
                       label='Spectrogram setup'),
                VGroup(Item('NW'),
                       Item('_bandwidth',
                            label='BW (Hz)',
                            style='readonly',
                            width=4),
                       Item('strip', label='SG strip len (ms)'),
                       Item('lag', label='SG lag (ms)'),
                       Item('detrend', label='Detrend window'),
                       Item('adaptive', label='Adaptive MTM'),
                       label='Estimation details',
                       columns=2),
                VGroup(Item('over_samp', label='Oversamp high-res SG'),
                       enabled_when='high_res')))
        return v
예제 #18
0
class MongoDB(WritableFactorDB):
    """MongoDB"""
    Name = Str("MongoDB")
    DBType = Enum("Mongo", arg_type="SingleOption", label="数据库类型", order=0)
    DBName = Str("Scorpion", arg_type="String", label="数据库名", order=1)
    IPAddr = Str("127.0.0.1", arg_type="String", label="IP地址", order=2)
    Port = Range(low=0,
                 high=65535,
                 value=27017,
                 arg_type="Integer",
                 label="端口",
                 order=3)
    User = Str("root", arg_type="String", label="用户名", order=4)
    Pwd = Password("", arg_type="String", label="密码", order=5)
    CharSet = Enum("utf8",
                   "gbk",
                   "gb2312",
                   "gb18030",
                   "cp936",
                   "big5",
                   arg_type="SingleOption",
                   label="字符集",
                   order=6)
    Connector = Enum("default",
                     "pymongo",
                     arg_type="SingleOption",
                     label="连接器",
                     order=7)
    IgnoreFields = ListStr(arg_type="List", label="忽略字段", order=8)
    InnerPrefix = Str("qs_", arg_type="String", label="内部前缀", order=9)

    def __init__(self, sys_args={}, config_file=None, **kwargs):
        super().__init__(sys_args=sys_args,
                         config_file=(__QS_ConfigPath__ + os.sep +
                                      "MongoDBConfig.json"
                                      if config_file is None else config_file),
                         **kwargs)
        self._TableFactorDict = {}  # {表名: pd.Series(数据类型, index=[因子名])}
        self._TableFieldDataType = {}  # {表名: pd.Series(数据库数据类型, index=[因子名])}
        self.Name = "MongoDB"
        return

    def __getstate__(self):
        state = self.__dict__.copy()
        state["_Connection"] = (True if self.isAvailable() else False)
        state["_DB"] = None
        return state

    def __setstate__(self, state):
        super().__setstate__(state)
        if self._Connection: self._connect()
        else: self._Connection = None

    @property
    def Connection(self):
        if self._Connection is not None:
            if os.getpid() != self._PID: self._connect()  # 如果进程号发生变化, 重连
        return self._Connection

    def _connect(self):
        self._Connection = None
        if (self.Connector == "pymongo") or ((self.Connector == "default") and
                                             (self.DBType == "Mongo")):
            try:
                import pymongo
                self._Connection = pymongo.MongoClient(host=self.IPAddr,
                                                       port=self.Port)
            except Exception as e:
                Msg = ("'%s' 尝试使用 pymongo 连接(%s@%s:%d)数据库 '%s' 失败: %s" %
                       (self.Name, self.User, self.IPAddr, self.Port,
                        self.DBName, str(e)))
                self._QS_Logger.error(Msg)
                if self.Connector != "default": raise e
            else:
                self._Connector = "pymongo"
        else:
            Msg = ("'%s' 连接(%s@%s:%d)数据库 '%s' 失败: %s" %
                   (self.Name, self.User, self.IPAddr, self.Port, self.DBName,
                    str(e)))
            self._QS_Logger.error(Msg)
            raise e
        self._PID = os.getpid()
        self._DB = self._Connection[self.DBName]
        return 0

    def connect(self):
        self._connect()
        nPrefix = len(self.InnerPrefix)
        if self.DBType == "Mongo":
            self._TableFactorDict = {}
            for iTableName in self._DB.collection_names():
                if iTableName[:nPrefix] == self.InnerPrefix:
                    iTableInfo = self._DB[iTableName].find_one(
                        {"code": "_TableInfo"}, {
                            "datetime": 0,
                            "code": 0,
                            "_id": 0
                        })
                    if iTableInfo:
                        self._TableFactorDict[
                            iTableName[nPrefix:]] = pd.Series({
                                iFactorName: iInfo["DataType"]
                                for iFactorName, iInfo in iTableInfo.items()
                                if iFactorName not in self.IgnoreFields
                            })
        return 0

    @property
    def TableNames(self):
        return sorted(self._TableFactorDict)

    def getTable(self, table_name, args={}):
        if table_name not in self._TableFactorDict:
            Msg = ("因子库 '%s' 调用方法 getTable 错误: 不存在因子表: '%s'!" %
                   (self.Name, table_name))
            self._QS_Logger.error(Msg)
            raise __QS_Error__(Msg)
        TableType = args.get("因子表类型", "宽表")
        if TableType == "宽表":
            return _WideTable(name=table_name,
                              fdb=self,
                              sys_args=args,
                              logger=self._QS_Logger)
        else:
            Msg = ("因子库 '%s' 调用方法 getTable 错误: 不支持的因子表类型: '%s'" %
                   (self.Name, TableType))
            self._QS_Logger.error(Msg)
            raise __QS_Error__(Msg)

    def renameTable(self, old_table_name, new_table_name):
        if old_table_name not in self._TableFactorDict:
            Msg = ("因子库 '%s' 调用方法 renameTable 错误: 不存在因子表 '%s'!" %
                   (self.Name, old_table_name))
            self._QS_Logger.error(Msg)
            raise __QS_Error__(Msg)
        if (new_table_name != old_table_name) and (new_table_name
                                                   in self._TableFactorDict):
            Msg = ("因子库 '%s' 调用方法 renameTable 错误: 新因子表名 '%s' 已经存在于库中!" %
                   (self.Name, new_table_name))
            self._QS_Logger.error(Msg)
            raise __QS_Error__(Msg)
        self._DB[self.InnerPrefix + old_table_name].rename(self.InnerPrefix +
                                                           new_table_name)
        self._TableFactorDict[new_table_name] = self._TableFactorDict.pop(
            old_table_name)
        return 0

    def deleteTable(self, table_name):
        if table_name not in self._TableFactorDict: return 0
        self._DB.drop_collection(self.InnerPrefix + table_name)
        self._TableFactorDict.pop(table_name, None)
        return 0

    # 创建表, field_types: {字段名: 数据类型}
    def createTable(self, table_name, field_types):
        if self.InnerPrefix + table_name not in self._DB.collection_names():
            Doc = {
                iField: {
                    "DataType": iDataType
                }
                for iField, iDataType in field_types.items()
            }
            Doc.update({"datetime": None, "code": "_TableInfo"})
            Collection = self._DB[self.InnerPrefix + table_name]
            Collection.insert(Doc)
            # 添加索引
            if self._Connector == "pymongo":
                import pymongo
                Index1 = pymongo.IndexModel([("datetime", pymongo.ASCENDING),
                                             ("code", pymongo.ASCENDING)],
                                            name=self.InnerPrefix +
                                            "datetime_code")
                Index2 = pymongo.IndexModel([("code", pymongo.HASHED)],
                                            name=self.InnerPrefix + "code")
                try:
                    Collection.create_indexes([Index1, Index2])
                except Exception as e:
                    self._QS_Logger.warning(
                        "'%s' 调用方法 createTable 在数据库中创建表 '%s' 的索引时错误: %s" %
                        (self.Name, table_name, str(e)))
        self._TableFactorDict[table_name] = pd.Series(field_types)
        return 0

    # ----------------------------因子操作---------------------------------
    def renameFactor(self, table_name, old_factor_name, new_factor_name):
        if old_factor_name not in self._TableFactorDict[table_name]:
            Msg = ("因子库 '%s' 调用方法 renameFactor 错误: 因子表 '%s' 中不存在因子 '%s'!" %
                   (self.Name, table_name, old_factor_name))
            self._QS_Logger.error(Msg)
            raise __QS_Error__(Msg)
        if (new_factor_name != old_factor_name) and (
                new_factor_name in self._TableFactorDict[table_name]):
            Msg = (
                "因子库 '%s' 调用方法 renameFactor 错误: 新因子名 '%s' 已经存在于因子表 '%s' 中!" %
                (self.Name, new_factor_name, table_name))
            self._QS_Logger.error(Msg)
            raise __QS_Error__(Msg)
        self._DB[self.InnerPrefix + table_name].update_many(
            {}, {"$rename": {
                old_factor_name: new_factor_name
            }})
        self._TableFactorDict[table_name][
            new_factor_name] = self._TableFactorDict[table_name].pop(
                old_factor_name)
        return 0

    def deleteFactor(self, table_name, factor_names):
        if not factor_names: return 0
        FactorIndex = self._TableFactorDict.get(
            table_name, pd.Series()).index.difference(factor_names).tolist()
        if not FactorIndex: return self.deleteTable(table_name)
        self.deleteField(self.InnerPrefix + table_name, factor_names)
        for iFactorName in factor_names:
            self._DB[self.InnerPrefix + table_name].update_many(
                {}, {'$unset': {
                    iFactorName: 1
                }})
        self._TableFactorDict[table_name] = self._TableFactorDict[table_name][
            FactorIndex]
        return 0

    # 增加因子,field_types: {字段名: 数据类型}
    def addFactor(self, table_name, field_types):
        if table_name not in self._TableFactorDict:
            return self.createTable(table_name, field_types)
        Doc = {
            iField: {
                "DataType": iDataType
            }
            for iField, iDataType in field_types.items()
        }
        self._DB[self.InnerPrefix + table_name].update({"code": "_TableInfo"},
                                                       {"$set": Doc})
        self._TableFactorDict[table_name] = self._TableFactorDict[
            table_name].append(field_types)
        return 0

    def deleteData(self, table_name, ids=None, dts=None):
        Doc = {}
        if dts is not None:
            Doc["datetime"] = {"$in": dts}
        if ids is not None:
            Doc["code"] = {"$in": ids}
        if Doc:
            self._DB[self.InnerPrefix + table_name].delete_many(Doc)
        else:
            self._DB.drop_collection(self.InnerPrefix + table_name)
            self._TableFactorDict.pop(table_name)
        return 0

    def writeData(self,
                  data,
                  table_name,
                  if_exists="update",
                  data_type={},
                  **kwargs):
        if table_name not in self._TableFactorDict:
            FieldTypes = {
                iFactorName: _identifyDataType(data.iloc[i].dtypes)
                for i, iFactorName in enumerate(data.items)
            }
            self.createTable(table_name, field_types=FieldTypes)
        else:
            NewFactorNames = data.items.difference(
                self._TableFactorDict[table_name].index).tolist()
            if NewFactorNames:
                FieldTypes = {
                    iFactorName: _identifyDataType(data.iloc[i].dtypes)
                    for i, iFactorName in enumerate(NewFactorNames)
                }
                self.addFactor(table_name, FieldTypes)
            AllFactorNames = self._TableFactorDict[table_name].index.tolist()
            OldData = self.getTable(table_name).readData(
                factor_names=AllFactorNames,
                ids=data.minor_axis.tolist(),
                dts=data.major_axis.tolist())
            if if_exists == "append":
                for iFactorName in AllFactorNames:
                    if iFactorName in data:
                        data[iFactorName] = OldData[iFactorName].where(
                            pd.notnull(OldData[iFactorName]),
                            data[iFactorName])
                    else:
                        data[iFactorName] = OldData[iFactorName]
            elif if_exists == "update":
                for iFactorName in AllFactorNames:
                    if iFactorName in data:
                        data[iFactorName] = data[iFactorName].where(
                            pd.notnull(data[iFactorName]),
                            OldData[iFactorName])
                    else:
                        data[iFactorName] = OldData[iFactorName]
            else:
                Msg = ("因子库 '%s' 调用方法 writeData 错误: 不支持的写入方式 '%s'!" %
                       (self.Name, if_exists))
                self._QS_Logger.error(Msg)
                raise __QS_Error__(Msg)
        NewData = {}
        for iFactorName in data.items:
            iData = data.loc[iFactorName].stack(dropna=False)
            NewData[iFactorName] = iData
        NewData = pd.DataFrame(NewData).loc[:, data.items]
        Mask = pd.notnull(NewData).any(axis=1)
        NewData = NewData[Mask]
        if NewData.shape[0] == 0: return 0
        self.deleteData(table_name,
                        ids=data.minor_axis.tolist(),
                        dts=data.major_axis.tolist())
        NewData = NewData.reset_index()
        NewData.columns = ["datetime", "code"] + NewData.columns[2:].tolist()
        self._DB[self.InnerPrefix + table_name].insert_many(
            NewData.to_dict(orient="records"))
        return 0
예제 #19
0
class IonOpticsManager(Manager):
    reference_detector = Instance(BaseDetector)
    reference_isotope = Any

    magnet_dac = Range(0.0, 6.0)
    graph = Instance(Graph)
    peak_center_button = Button('Peak Center')
    stop_button = Button('Stop')

    alive = Bool(False)
    spectrometer = Any

    peak_center = Instance(PeakCenter)
    coincidence = Instance(Coincidence)
    peak_center_config = Instance(PeakCenterConfigurer)
    # coincidence_config = Instance(CoincidenceConfig)
    canceled = False

    peak_center_result = None

    _centering_thread = None

    def close(self):
        self.cancel_peak_center()

    def cancel_peak_center(self):
        self.alive = False
        self.canceled = True
        self.peak_center.canceled = True
        self.peak_center.stop()
        self.info('peak center canceled')

    def get_mass(self, isotope_key):
        spec = self.spectrometer
        molweights = spec.molecular_weights
        return molweights[isotope_key]

    def mftable_ctx(self, mftable):
        return MFTableCTX(self, mftable)

    def set_mftable(self, name=None):
        """
            if mt is None set to the default mftable located at setupfiles/spectrometer/mftable.csv
        :param mt:
        :return:
        """
        if name and name != os.path.splitext(os.path.basename(
                paths.mftable))[0]:
            self.spectrometer.use_deflection_correction = False
        else:
            self.spectrometer.use_deflection_correction = True

        self.spectrometer.magnet.set_mftable(name)

    def get_position(self, *args, **kw):
        kw['update_isotopes'] = False
        return self._get_position(*args, **kw)

    def av_position(self, pos, detector, *args, **kw):
        av = self._get_av_position(pos, detector)
        self.spectrometer.source.set_hv(av)
        self.info('positioning {} ({}) on {}'.format(pos, av, detector))
        return av

    def position(self, pos, detector, use_af_demag=True, *args, **kw):
        dac = self._get_position(pos, detector, *args, **kw)
        mag = self.spectrometer.magnet

        self.info('positioning {} ({}) on {}'.format(pos, dac, detector))
        return mag.set_dac(dac, use_af_demag=use_af_demag)

    def do_coincidence_scan(self, new_thread=True):

        if new_thread:
            t = Thread(name='ion_optics.coincidence', target=self._coincidence)
            t.start()
            self._centering_thread = t

    def setup_coincidence(self):
        pcc = self.coincidence_config
        pcc.dac = self.spectrometer.magnet.dac

        info = pcc.edit_traits()
        if not info.result:
            return

        detector = pcc.detector
        isotope = pcc.isotope
        detectors = [d for d in pcc.additional_detectors]
        # integration_time = pcc.integration_time

        if pcc.use_nominal_dac:
            center_dac = self.get_position(isotope, detector)
        elif pcc.use_current_dac:
            center_dac = self.spectrometer.magnet.dac
        else:
            center_dac = pcc.dac

        # self.spectrometer.save_integration()
        # self.spectrometer.set_integration(integration_time)

        cs = Coincidence(spectrometer=self.spectrometer,
                         center_dac=center_dac,
                         reference_detector=detector,
                         reference_isotope=isotope,
                         additional_detectors=detectors)
        self.coincidence = cs
        return cs

    def get_center_dac(self, det, iso):
        spec = self.spectrometer
        det = spec.get_detector(det)

        molweights = spec.molecular_weights
        mass = molweights[iso]
        dac = spec.magnet.map_mass_to_dac(mass, det.name)

        # correct for deflection
        return spec.correct_dac(det, dac)

    def do_peak_center(self,
                       save=True,
                       confirm_save=False,
                       warn=False,
                       new_thread=True,
                       message='',
                       on_end=None,
                       timeout=None):
        self.debug('doing pc')

        self.canceled = False
        self.alive = True
        self.peak_center_result = None

        args = (save, confirm_save, warn, message, on_end, timeout)
        if new_thread:
            t = Thread(name='ion_optics.peak_center',
                       target=self._peak_center,
                       args=args)
            t.start()
            self._centering_thread = t
            return t
        else:
            self._peak_center(*args)

    def setup_peak_center(self,
                          detector=None,
                          isotope=None,
                          integration_time=1.04,
                          directions='Increase',
                          center_dac=None,
                          name='',
                          show_label=False,
                          window=0.015,
                          step_width=0.0005,
                          min_peak_height=1.0,
                          percent=80,
                          deconvolve=None,
                          use_interpolation=False,
                          interpolation_kind='linear',
                          dac_offset=None,
                          calculate_all_peaks=False,
                          config_name=None,
                          use_configuration_dac=True,
                          new=False,
                          update_others=True,
                          plot_panel=None):

        if deconvolve is None:
            n_peaks, select_peak = 1, 1

        use_dac_offset = False
        if dac_offset is not None:
            use_dac_offset = True

        spec = self.spectrometer
        pcconfig = self.peak_center_config

        spec.save_integration()
        self.debug('setup peak center. detector={}, isotope={}'.format(
            detector, isotope))

        pcc = None
        dataspace = 'dac'
        use_accel_voltage = False
        use_extend = False
        self._setup_config()
        if config_name:
            pcconfig.load()
            pcconfig.active_name = config_name
            pcc = pcconfig.active_item

        elif detector is None or isotope is None:
            self.debug('ask user for peak center configuration')

            pcconfig.load()
            if config_name:
                pcconfig.active_name = config_name

            info = pcconfig.edit_traits()

            if not info.result:
                return
            else:
                pcc = pcconfig.active_item

        if pcc:
            if not detector:
                detector = pcc.active_detectors

            if not isotope:
                isotope = pcc.isotope

            directions = pcc.directions
            integration_time = pcc.integration_time

            dataspace = pcc.dataspace
            use_accel_voltage = pcc.use_accel_voltage
            use_extend = pcc.use_extend
            window = pcc.window
            min_peak_height = pcc.min_peak_height
            step_width = pcc.step_width
            percent = pcc.percent
            use_interpolation = pcc.use_interpolation
            interpolation_kind = pcc.interpolation_kind
            n_peaks = pcc.n_peaks
            select_peak = pcc.select_n_peak
            use_dac_offset = pcc.use_dac_offset
            dac_offset = pcc.dac_offset
            calculate_all_peaks = pcc.calculate_all_peaks
            update_others = pcc.update_others
            if not pcc.use_mftable_dac and center_dac is None and use_configuration_dac:
                center_dac = pcc.dac

        spec.set_integration_time(integration_time)
        period = int(integration_time * 1000 * 0.9)

        if not isinstance(detector, (tuple, list)):
            detector = (detector, )

        ref = spec.get_detector(detector[0])

        if center_dac is None:
            center_dac = self.get_center_dac(ref, isotope)

        # if mass:
        #     mag = spec.magnet
        #     center_dac = mag.map_mass_to_dac(mass, ref)
        #     low = mag.map_mass_to_dac(mass - window / 2., ref)
        #     high = mag.map_mass_to_dac(mass + window / 2., ref)
        #     window = high - low
        #     step_width = abs(mag.map_mass_to_dac(mass + step_width, ref) - center_dac)

        if len(detector) > 1:
            ad = detector[1:]
        else:
            ad = []

        pc = self.peak_center
        klass = AccelVoltagePeakCenter if use_accel_voltage else PeakCenter
        if not pc or new or (use_accel_voltage
                             and not isinstance(pc, AccelVoltagePeakCenter)):
            pc = klass()

        pc.trait_set(center_dac=center_dac,
                     dataspace=dataspace,
                     use_accel_voltage=use_accel_voltage,
                     use_extend=use_extend,
                     period=period,
                     window=window,
                     percent=percent,
                     min_peak_height=min_peak_height,
                     step_width=step_width,
                     directions=directions,
                     reference_detector=ref,
                     additional_detectors=ad,
                     reference_isotope=isotope,
                     spectrometer=spec,
                     show_label=show_label,
                     use_interpolation=use_interpolation,
                     interpolation_kind=interpolation_kind,
                     n_peaks=n_peaks,
                     select_peak=select_peak,
                     use_dac_offset=use_dac_offset,
                     dac_offset=dac_offset,
                     calculate_all_peaks=calculate_all_peaks,
                     update_others=update_others)

        graph = pc.graph
        graph.name = name
        if plot_panel:
            plot_panel.set_peak_center_graph(graph)

        self.peak_center = pc
        self.reference_detector = ref
        self.reference_isotope = isotope

        return self.peak_center

    def backup_mftable(self):
        self.spectrometer.magnet.field_table.backup()

    # private
    def _setup_config(self):
        config = self.peak_center_config
        config.detectors = self.spectrometer.detector_names
        keys = list(self.spectrometer.molecular_weights.keys())
        config.isotopes = sort_isotopes(keys)
        config.integration_times = self.spectrometer.integration_times

    # def _get_peak_center_config(self, config_name):
    #     if config_name is None:
    #         config_name = 'default'
    #
    #     config = self.peak_center_config.get(config_name)
    #
    #     config.detectors = self.spectrometer.detectors_names
    #     if config.detector_name:
    #         config.detector = next((di for di in config.detectors if di == config.detector_name), None)
    #
    #     if not config.detector:
    #         config.detector = config.detectors[0]
    #
    #     keys = self.spectrometer.molecular_weights.keys()
    #     config.isotopes = sort_isotopes(keys)
    #     config.integration_times = self.spectrometer.integration_times
    #     return config

    # def _timeout_func(self, timeout, evt):
    #     st = time.time()
    #     while not evt.is_set():
    #         if not self.alive:
    #             break
    #
    #         if time.time() - st > timeout:
    #             self.warning('Peak Centering timed out after {}s'.format(timeout))
    #             self.cancel_peak_center()
    #             break
    #
    #         time.sleep(0.01)

    def _peak_center(self, save, confirm_save, warn, message, on_end, timeout):

        pc = self.peak_center
        spec = self.spectrometer
        ref = self.reference_detector
        isotope = self.reference_isotope

        try:
            center_value = pc.get_peak_center()
        except NoIntensityChange as e:
            self.warning(
                'Peak Centering failed. No Intensity change. {}'.format(e))
            center_value = None

        self.peak_center_result = center_value
        if center_value:

            det = spec.get_detector(ref)

            if pc.use_accel_voltage:
                args = ref, isotope, center_value
            else:
                dac_a = spec.uncorrect_dac(det, center_value)
                self.info(
                    'dac uncorrected for HV and deflection {}'.format(dac_a))
                args = ref, isotope, dac_a
                self.adjusted_peak_center_result = dac_a

            self.info('new center pos {} ({}) @ {}'.format(*args))
            if save:
                if confirm_save:
                    msg = 'Update Magnet Field Table with new peak center- {} ({}) @ RefDetUnits= {}'.format(
                        *args)
                    if pc.use_accel_voltage:
                        msg = 'Update Accel Voltage Table with new peak center- {} ({}) @ RefDetUnits= {}'.format(
                            *args)

                    save = self.confirmation_dialog(msg)

                if save:
                    if pc.use_accel_voltage:
                        spec.source.update_field_table(det, isotope,
                                                       center_value, message)
                    else:
                        spec.magnet.update_field_table(
                            det,
                            isotope,
                            dac_a,
                            message,
                            update_others=pc.update_others)
                        spec.magnet.set_dac(dac_a)

        elif not self.canceled:
            msg = 'centering failed'
            if warn:
                self.warning_dialog(msg)
            self.warning(msg)

            # needs to be called on the main thread to properly update
            # the menubar actions. alive=False enables IonOptics>Peak Center
        # d = lambda:self.trait_set(alive=False)
        # still necessary with qt? and tasks

        if on_end:
            on_end()

        self.trait_set(alive=False)

        self.spectrometer.restore_integration()

    def _get_av_position(self, pos, detector, update_isotopes=True):
        self.debug('AV POSITION {} {}'.format(pos, detector))
        spec = self.spectrometer
        if not isinstance(detector, str):
            detector = detector.name

        if isinstance(pos, str):
            try:
                pos = float(pos)
            except ValueError:
                # pos is isotope
                if update_isotopes:
                    # if the pos is an isotope then update the detectors
                    spec.update_isotopes(pos, detector)
                pos = self.get_mass(pos)

        # pos is mass i.e 39.962
        av = spec.source.map_mass_to_hv(pos, detector)
        return av

    def _get_position(self,
                      pos,
                      detector,
                      use_dac=False,
                      update_isotopes=True):
        """
            pos can be str or float
            "Ar40", "39.962", 39.962

            to set in DAC space set use_dac=True
        """
        if pos == NULL_STR:
            return

        spec = self.spectrometer
        mag = spec.magnet

        if isinstance(detector, str):
            det = spec.get_detector(detector)
        else:
            det = detector

        self.debug('detector {}'.format(det))

        if use_dac:
            dac = pos
        else:
            self.debug('POSITION {} {}'.format(pos, detector))
            if isinstance(pos, str):
                try:
                    pos = float(pos)
                except ValueError:
                    # pos is isotope
                    if update_isotopes:
                        # if the pos is an isotope then update the detectors
                        spec.update_isotopes(pos, detector)
                    pos = self.get_mass(pos)

                mag.mass_change(pos)

            # pos is mass i.e 39.962
            print('det is', det)
            dac = mag.map_mass_to_dac(pos, det.name)

        dac = spec.correct_dac(det, dac)
        return dac

    def _coincidence(self):
        self.coincidence.get_peak_center()
        self.info('coincidence finished')
        self.spectrometer.restore_integration()

    # ===============================================================================
    # handler
    # ===============================================================================
    def _coincidence_config_default(self):
        config = None
        p = os.path.join(paths.hidden_dir, 'coincidence_config.p')
        if os.path.isfile(p):
            try:
                with open(p) as rfile:
                    config = pickle.load(rfile)
                    config.detectors = dets = self.spectrometer.detectors
                    config.detector = next(
                        (di for di in dets if di.name == config.detector_name),
                        None)

            except Exception as e:
                print('coincidence config', e)

        if config is None:
            config = CoincidenceConfig()
            config.detectors = self.spectrometer.detectors
            config.detector = config.detectors[0]

        keys = list(self.spectrometer.molecular_weights.keys())
        config.isotopes = sort_isotopes(keys)

        return config

    def _peak_center_config_default(self):
        config = PeakCenterConfigurer()
        return config
예제 #20
0
class PolarDiscr(HasTraits):
    '''
    Manager of the microplane arrays.

    This class is responsible for the generation and initialization
    and state management of an array of microplanes. Additionally, it
    can perform the setup of damage function parameters using the
    value of the microplane integrator object.
    '''

    mfn_class = Class(None)
    #-------------------------------------------------------------------------
    # Common parameters for for isotropic and anisotropic damage function specifications
    #-------------------------------------------------------------------------
    n_mp = Range(0, 50, 6, label='Number of microplanes', auto_set=False)

    E = Float(34e+3,
              label="E",
              desc="Young's Modulus",
              auto_set=False,
              enter_set=True)
    nu = Float(0.2,
               label='nu',
               desc="Poison's ratio",
               auto_set=False,
               enter_set=True)

    c_T = Float(
        0.0,
        label='c_T',
        desc='fraction of tangential stress accounted on each microplane',
        auto_set=False,
        enter_set=True)

    #-------------------------------------------------------------------------
    # list of angles
    #-------------------------------------------------------------------------
    alpha_list = Property(Array, depends_on='n_mp')

    @cached_property
    def _get_alpha_list(self):
        return array(
            [Pi / self.n_mp * (i - 0.5) for i in range(1, self.n_mp + 1)])

    #-------------------------------------------------------------------------
    # Damage function specification
    #-------------------------------------------------------------------------

    phi_fn = EitherType(klasses=[
        PhiFnGeneral, PhiFnGeneralExtended, PhiFnGeneralExtendedExp,
        PhiFnStrainSoftening, PhiFnStrainHardening, PhiFnStrainHardeningLinear,
        PhiFnStrainHardeningBezier
    ])

    def _phi_fn_default(self):
        print 'setting phi_fn default'
        return PhiFnStrainSoftening(polar_discr=self)

    def _phi_fn_changed(self):
        print 'setting phi_fn changed'
        self.phi_fn.polar_discr = self

    varied_params = List(Str, [])

    #-------------------------------------------------------------------------
    # Management of spatially varying parameters depending on the value of mats_eval
    #-------------------------------------------------------------------------
    varpars = Dict

    def _varpars_default(self):
        return self._get_varpars()

    @on_trait_change('phi_fn,varied_params')
    def _update_varpars(self):
        self.varpars = self._get_varpars()

    def _get_varpars(self):
        '''
        reset the varpar list according to the current phi_fn object.
        '''
        params = self.phi_fn.identify_parameters()
        varset = {}
        for key in params:
            par_val = getattr(self.phi_fn, key)
            varset[key] = VariedParam(phi_fn=self.phi_fn,
                                      mats_eval=self,
                                      varname=key)
            if key in self.varied_params:
                varset[key].switched_on = True
        return varset

    varpar_list = Property(List(VariedParam), depends_on='varpars')

    @cached_property
    def _get_varpar_list(self):
        return [self.varpars[key] for key in self.phi_fn.identify_parameters()]

    # variable selectable in the table of varied params (just for viewing)
    current_varpar = Instance(VariedParam)

    def _current_varpar_default(self):
        if len(self.varpar_list) > 0:
            return self.varpar_list[0]
        return None

    @on_trait_change('phi_fn')
    def set_current_varpar(self):
        if len(self.varpar_list) > 0:
            self.current_varpar = self.varpar_list[0]

    #-------------------------------------------------------------------------
    # Get the damage state for all microplanes
    #-------------------------------------------------------------------------
    def get_phi_arr(self, sctx, e_max_arr):
        '''
        Return the damage coefficients
        '''
        # gather the coefficients for parameters depending on the orientation
        carr_list = [
            self.varpars[key].polar_fn_vectorized(self.alpha_list)
            for key in self.phi_fn.identify_parameters()
        ]
        # vectorize the damage function evaluation
        n_arr = 1 + len(carr_list)
        phi_fn_vectorized = frompyfunc(self.phi_fn.get_value, n_arr, 1)
        # damage parameter for each microplane
        return phi_fn_vectorized(e_max_arr, *carr_list)

    def get_polar_fn_fracture_energy_arr(self, sctx, e_max_arr):
        '''
        Return the fracture energy contributions
        '''
        carr_list = [
            self.varpars[key].polar_fn_vectorized(self.alpha_list)
            for key in self.phi_fn.identify_parameters()
        ]
        # vectorize the damage function evaluation
        n_arr = 1 + len(carr_list)
        integ_phi_fn_vectorized = frompyfunc(self.phi_fn.get_integ, n_arr, 1)
        return self.E * integ_phi_fn_vectorized(e_max_arr, *carr_list)

    polar_fn_group = Group(
        Group(Item('n_mp@', width=200),
              Item('E'),
              Item('nu'),
              Item('c_T'),
              Spring(),
              label='Elasticity parameters'),
        Group(Item('phi_fn@', show_label=False), label='Damage parameters'),
        Group(VSplit(
            Item('varpar_list',
                 label='List of material variables',
                 show_label=False,
                 editor=varpar_editor),
            Item('current_varpar',
                 label='Selected variable',
                 show_label=False,
                 style='custom',
                 resizable=True),
            dock='tab',
        ),
              label='Angle-dependent variations'),
        Include('config_param_vgroup'),
        layout='tabbed',
        springy=True,
        dock='tab',
        id='ibvpy.mats.matsXD_cmdm.MATSXDPolarDiscr',
    )

    traits_view = View(Include('polar_fn_group'),
                       resizable=True,
                       scrollable=True,
                       width=0.6,
                       height=0.9)
class CSVListEditorDemo(HasTraits):

    list1 = List(Int)

    list2 = List(Float)

    list3 = List(Str, maxlen=3)

    list4 = List(Enum('red', 'green', 'blue', 2, 3))

    list5 = List(Range(low=0.0, high=10.0))

    # 'low' and 'high' are used to demonstrate lists containing dynamic ranges.
    low = Float(0.0)
    high = Float(1.0)

    list6 = List(Range(low=-1.0, high='high'))

    list7 = List(Range(low='low', high='high'))

    pop1 = Button("Pop from first list")

    sort1 = Button("Sort first list")

    # This will be str(self.list1).
    list1str = Property(Str, depends_on='list1')

    traits_view = View(
        HGroup(
            # This VGroup forms the column of CSVListEditor examples.
            VGroup(
                Item('list1',
                     label="List(Int)",
                     editor=CSVListEditor(ignore_trailing_sep=False),
                     tooltip='options: ignore_trailing_sep=False'),
                Item('list1',
                     label="List(Int)",
                     style='readonly',
                     editor=CSVListEditor()),
                Item('list2',
                     label="List(Float)",
                     editor=CSVListEditor(enter_set=True, auto_set=False),
                     tooltip='options: enter_set=True, auto_set=False'),
                Item('list3',
                     label="List(Str, maxlen=3)",
                     editor=CSVListEditor()),
                Item('list4',
                     label="List(Enum('red', 'green', 'blue', 2, 3))",
                     editor=CSVListEditor(sep=None),
                     tooltip='options: sep=None'),
                Item('list5',
                     label="List(Range(low=0.0, high=10.0))",
                     editor=CSVListEditor()),
                Item('list6',
                     label="List(Range(low=-1.0, high='high'))",
                     editor=CSVListEditor()),
                Item('list7',
                     label="List(Range(low='low', high='high'))",
                     editor=CSVListEditor()),
                springy=True,
            ),
            # This VGroup forms the right column; it will display the
            # Python str representation of the lists.
            VGroup(
                UItem('list1str',
                      editor=TextEditor(),
                      enabled_when='False',
                      width=240),
                UItem('list1str',
                      editor=TextEditor(),
                      enabled_when='False',
                      width=240),
                UItem('list2',
                      editor=TextEditor(),
                      enabled_when='False',
                      width=240),
                UItem('list3',
                      editor=TextEditor(),
                      enabled_when='False',
                      width=240),
                UItem('list4',
                      editor=TextEditor(),
                      enabled_when='False',
                      width=240),
                UItem('list5',
                      editor=TextEditor(),
                      enabled_when='False',
                      width=240),
                UItem('list6',
                      editor=TextEditor(),
                      enabled_when='False',
                      width=240),
                UItem('list7',
                      editor=TextEditor(),
                      enabled_when='False',
                      width=240),
            ),
        ),
        '_',
        HGroup('low', 'high', spring, UItem('pop1'), UItem('sort1')),
        Heading("Notes"),
        Label("Hover over a list to see which editor options are set, "
              "if any."),
        Label("The editor of the first list, List(Int), uses "
              "ignore_trailing_sep=False, so a trailing comma is "
              "an error."),
        Label("The second list is a read-only view of the first list."),
        Label("The editor of the List(Float) example has enter_set=True "
              "and auto_set=False; press Enter to validate."),
        Label("The List(Str) example will accept at most 3 elements."),
        Label("The editor of the List(Enum(...)) example uses sep=None, "
              "i.e. whitespace acts as a separator."),
        Label("The last three List(Range(...)) examples take neither, one or "
              "both of their limits from the Low and High fields below."),
        width=720,
        title="CSVListEditor Demonstration",
    )

    def _list1_default(self):
        return [1, 4, 0, 10]

    def _get_list1str(self):
        return str(self.list1)

    def _pop1_fired(self):
        if len(self.list1) > 0:
            x = self.list1.pop()
            print(x)

    def _sort1_fired(self):
        self.list1.sort()
예제 #22
0
class Slider(Control):
    """ A simple slider widget that can be used to select from a range
    of integral values.

    A `SliderTransform` can be used to transform the integer range
    of the slider into another data space. For more details, see
    `enaml.stdlib.slider_transform`.

    """
    #: The minimum slider value. If the minimum value is changed such
    #: that it becomes greater than the current value or the maximum
    #: value, then those values will be adjusted. The default is 0.
    minimum = Property(Int)

    #: The internal minimum value storage.
    _minimum = Int(0)

    #: The maximum slider value. If the maximum value is changed such
    #: that it becomes smaller than the current value or the minimum
    #: value, then those values will be adjusted. The default is 100.
    maximum = Property(Int)

    #: The internal maximum storage.
    _maximum = Int(100)

    #: The position value of the Slider. The value will be clipped to
    #: always fall between the minimum and maximum.
    value = Property(Int)

    #: The internal value storage.
    _value = Int(0)

    #: Defines the number of steps that the slider will move when the
    #: user presses the arrow keys. The default is 1. An upper limit
    #: may be imposed according the limits of the client widget.
    single_step = Range(low=1)

    #: Defines the number of steps that the slider will move when the
    #: user presses the page_up/page_down keys. The Default is 10. An
    #: upper limit may be imposed on this value according to the limits
    #: of the client widget.
    page_step = Range(low=1, value=10)

    #: A TickPosition enum value indicating how to display the tick
    #: marks. Note that the orientation takes precedence over the tick
    #: mark position and an incompatible tick position will be adapted
    #: according to the current orientation. The default tick position
    #: is 'bottom'.
    tick_position = Enum(
        'bottom',
        ('no_ticks', 'left', 'right', 'top', 'bottom', 'both'),
    )

    #: The interval to place between slider tick marks in units of
    #: value (as opposed to pixels). The minimum value is 0, which
    #: indicates that the choice is left up to the client.
    tick_interval = Range(low=0)

    #: The orientation of the slider. The default orientation is
    #: horizontal. When the orientation is flipped the tick positions
    #: (if set) also adapt to reflect the changes  (e.g. the LEFT
    #: becomes TOP when the orientation becomes horizontal).
    orientation = Enum('horizontal', 'vertical')

    #: If True, the value is updated while sliding. Otherwise, it is
    #: only updated when the slider is released. Defaults to True.
    tracking = Bool(True)

    #: Hug width is redefined as a property to be computed based on the
    #: orientation of the slider unless overridden by the user.
    hug_width = Property(PolicyEnum, depends_on=['_hug_width', 'orientation'])

    #: Hug height is redefined as a property to be computed based on the
    #: orientation of the slider unless overridden by the user.
    hug_height = Property(PolicyEnum,
                          depends_on=['_hug_height', 'orientation'])

    #: An internal override trait for hug_width
    _hug_width = Either(None, PolicyEnum, default=None)

    #: An internal override trait for hug_height
    _hug_height = Either(None, PolicyEnum, default=None)

    #--------------------------------------------------------------------------
    # Initialization
    #--------------------------------------------------------------------------
    def snapshot(self):
        """ Return a dictionary which contains all the state necessary to
        initialize a client widget.

        """
        snap = super(Slider, self).snapshot()
        snap['minimum'] = self.minimum
        snap['maximum'] = self.maximum
        snap['value'] = self.value
        snap['single_step'] = self.single_step
        snap['page_step'] = self.page_step
        snap['tick_position'] = self.tick_position
        snap['tick_interval'] = self.tick_interval
        snap['orientation'] = self.orientation
        snap['tracking'] = self.tracking
        return snap

    def bind(self):
        """ A method called after initialization which allows the widget
        to bind any event handlers necessary.

        """
        super(Slider, self).bind()
        attrs = (
            'minimum',
            'maximum',
            'value',
            'single_step',
            'page_step',
            'tick_position',
            'tick_interval',
            'orientation',
            'tracking',
        )
        self.publish_attributes(*attrs)

    #--------------------------------------------------------------------------
    # Message Handling
    #--------------------------------------------------------------------------
    def on_action_value_changed(self, content):
        """ Handle the 'value_changed' action from the client widget.

        The content will contain the 'value' of the slider.

        """
        self.set_guarded(value=content['value'])

    #--------------------------------------------------------------------------
    # Property Methods
    #--------------------------------------------------------------------------
    def _get_hug_width(self):
        """ The property getter for 'hug_width'.

        Returns a computed hug value unless overridden by the user.

        """
        res = self._hug_width
        if res is None:
            if self.orientation == 'horizontal':
                res = 'ignore'
            else:
                res = 'strong'
        return res

    def _get_hug_height(self):
        """ The proper getter for 'hug_height'.

        Returns a computed hug value unless overridden by the user.

        """
        res = self._hug_height
        if res is None:
            if self.orientation == 'vertical':
                res = 'ignore'
            else:
                res = 'strong'
        return res

    def _set_hug_width(self, value):
        """ The property setter for 'hug_width'.

        Overrides the computed value.

        """
        self._hug_width = value

    def _set_hug_height(self, value):
        """ The property setter for 'hug_height'.

        Overrides the computed value.

        """
        self._hug_height = value

    def _get_minimum(self):
        """ The property getter for the slider 'minimum'.

        """
        return self._minimum

    def _set_minimum(self, minimum):
        """ The property setter for the 'minimum' attribute.

        """
        # Manually fire the trait change notifications to avoid the
        # need for property depends_on; this saves memory overhead.
        # All data is accessed using the private attributes to avoid
        # inadvertantly triggering the evaluation of a bound Enaml
        # attribute, which could fool with the state by setting the
        # value too soon.
        old_max = self._maximum
        if minimum > old_max:
            self._maximum = minimum
            self.trait_property_changed('maximum', old_max, minimum)
        old_val = self._value
        if minimum > old_val:
            self._value = minimum
            self.trait_property_changed('value', old_val, minimum)
        old_min = self._minimum
        if minimum != old_min:
            self._minimum = minimum
            self.trait_property_changed('minimum', old_min, minimum)

    def _get_maximum(self):
        """ The property getter for the slider 'maximum'.

        """
        return self._maximum

    def _set_maximum(self, maximum):
        """ The property setter for the 'maximum' attribute.

        """
        # Manually fire the trait change notifications to avoid the
        # need for property depends_on; this saves memory overhead.
        # All data is accessed using the private attributes to avoid
        # inadvertantly triggering the evaluation of a bound Enaml
        # attribute, which could fool with the state by setting the
        # value too soon.
        old_min = self._minimum
        if maximum < old_min:
            self._minimum = maximum
            self.trait_property_changed('minimum', old_min, maximum)
        old_val = self._value
        if maximum < old_val:
            self._value = maximum
            self.trait_property_changed('value', old_val, maximum)
        old_max = self._maximum
        if maximum != old_max:
            self._maximum = maximum
            self.trait_property_changed('maximum', old_max, maximum)

    def _get_value(self):
        """ The property getter for the slider 'value'.

        """
        return self._value

    def _set_value(self, value):
        """ The property setter for the 'value' attribute.

        """
        # Manually fire the trait change notifications to avoid the
        # need for property depends_on; this saves memory overhead.
        # The minimum and maximum values are explicity accessed through
        # their property so that any bound Enaml attributes can provide
        # the proper default value. This ensures that the min and max
        # are alway up-to-date before potentially clipping the value.
        old_val = self._value
        new_val = max(self.minimum, min(self.maximum, value))
        if old_val != new_val:
            self._value = new_val
            self.trait_property_changed('value', old_val, new_val)
예제 #23
0
class Controls(HasTraits):
    if len(inputs) == 1:
        default_input = inputs

    for i in inputs:
        if "Through Port" not in i[1]:
            default_input = i
            break

    default_input = default_input if inputs else None

    default_output = -1
    through_port_output = None
    for i in outputs:
        if "Through Port" not in i[1]:
            default_output = i
            break
        else:
            through_port_output = i
    default_output = default_output if len(
        outputs) > 1 else through_port_output

    if default_input is None or default_output is None:
        print('Cannot connect to any MIDI device')

    input_device = List(value=default_input,
                        editor=CheckListEditor(values=inputs))
    output_device = List(value=default_output,
                         editor=CheckListEditor(values=outputs))

    max_temp = 2.
    min_temp = 0.5
    max_press = 10.
    min_press = 5e-4
    max_vol = 100000.
    min_vol = 50.
    max_n = 1000
    min_n = 50

    temperature = Range(min_temp, max_temp, 1., )
    volume = Float(box_l**3.)
    pressure = Float(1.)
    number_of_particles = Range(min_n, max_n, n_part, )
    ensemble = Enum('NVT', 'NPT')

    midi_input = None
    midi_output = None

    MIDI_BASE = 224
    MIDI_NUM_TEMPERATURE = MIDI_BASE + 0
    MIDI_NUM_VOLUME = MIDI_BASE + 1
    MIDI_NUM_PRESSURE = MIDI_BASE + 2
    MIDI_NUM_NUMBEROFPARTICLES = MIDI_BASE + 3

    MIDI_ROTATE = 0

    MIDI_ZOOM = 144

    _ui = Any
    view = View(
        Group(
            Item('temperature', editor=RangeEditor(
                low_name='min_temp', high_name='max_temp')),
            Item('volume', editor=RangeEditor(
                low_name='min_vol', high_name='max_vol')),
            Item('pressure', editor=RangeEditor(
                low_name='min_press', high_name='max_press')),
            Item('number_of_particles', editor=RangeEditor(
                low_name='min_n', high_name='max_n', is_float=False)),
            Item('ensemble', style='custom'),
            show_labels=True,
            label='Parameters'
        ),
        Group(
            Item('input_device'),
            Item('output_device'),
            show_labels=True,
            label='MIDI devices'
        ),
        buttons=[],
        title='Control',
        height=0.2,
        width=0.3
    )

    def __init__(self, **traits):
        super(Controls, self).__init__(**traits)
        self._ui = self.edit_traits()
        self.push_current_values()

    def push_current_values(self):
        """send the current values to the MIDI controller"""
        self._temperature_fired()
        self._volume_fired()
        self._pressure_fired()
        self._number_of_particles_fired()
        self._ensemble_fired()

    def _input_device_fired(self):
        if self.midi_input is not None:
            self.midi_input.close()
        if self.input_device:
            self.midi_input = midi.Input(self.input_device[0])

    def _output_device_fired(self):
        if self.midi_output is not None:
            self.midi_output.close()
        self.midi_output = midi.Output(self.output_device[0])
        self.push_current_values()

    def _temperature_fired(self):
        status = self.MIDI_NUM_TEMPERATURE
        data1 = int((self.temperature - self.min_temp) /
                    (self.max_temp - self.min_temp) * 127)
        data2 = data1
        if self.midi_output is not None:
            self.midi_output.write_short(status, data1, data2)

    def _volume_fired(self):
        status = self.MIDI_NUM_VOLUME
        data1 = limit_range(int((system.box_l[0]**3. - self.min_vol) / (
            self.max_vol - self.min_vol) * 127), minval=0, maxval=127)
        data2 = data1

        if self.midi_output is not None:
            self.midi_output.write_short(status, data1, data2)

    def _pressure_fired(self):
        status = self.MIDI_NUM_PRESSURE

        if pressure_log_flag:
            data1 = limit_range(int(127 *
                                    (np.log(self.pressure) -
                                     np.log(self.min_press)) /
                                    (np.log(self.max_press) -
                                        np.log(self.min_press))), minval=0, maxval=127)
        else:
            data1 = limit_range(int((self.pressure -
                                     self.min_press) /
                                    (self.max_press -
                                     self.min_press) *
                                    127), minval=0, maxval=127)
        data2 = data1
        if self.midi_output is not None:
            self.midi_output.write_short(status, data1, data2)

    def _number_of_particles_fired(self):
        status = self.MIDI_NUM_NUMBEROFPARTICLES
        data1 = int(self.number_of_particles / self.max_n * 127)
        data2 = data1
        if self.midi_output is not None:
            self.midi_output.write_short(status, data1, data2)

    def _ensemble_fired(self):
        if self.midi_output is not None:
            self.midi_output.write_short(144, 0, 127)  # T
            self.midi_output.write_short(
                144, 1, 127 * (self.ensemble != 'NPT'))  # V
            self.midi_output.write_short(
                144, 2, 127 * (self.ensemble == 'NPT'))  # P
            self.midi_output.write_short(144, 3, 127)  # N
예제 #24
0
class NHahn(Pulsed):
    """Defines a Nuclear Rabi measurement."""

    mw_frequency = Range(low=1,
                         high=20e9,
                         value=2.874356e+09,
                         desc='microwave frequency',
                         label='MW frequency [Hz]',
                         mode='text',
                         auto_set=False,
                         enter_set=True)
    mw_power = Range(low=-100.,
                     high=25.,
                     value=-18,
                     desc='microwave power',
                     label='MW power [dBm]',
                     mode='text',
                     auto_set=False,
                     enter_set=True)
    t_pi = Range(low=1.,
                 high=100000.,
                 value=1190.,
                 desc='length of pi pulse [ns]',
                 label='pi [ns]',
                 mode='text',
                 auto_set=False,
                 enter_set=True)

    rf_frequency = Range(low=1,
                         high=20e6,
                         value=2.762e6,
                         desc='RF frequency',
                         label='RF frequency [Hz]',
                         mode='text',
                         auto_set=False,
                         enter_set=True)
    rf_power = Range(low=-130.,
                     high=25.,
                     value=-14,
                     desc='RF power',
                     label='RF power [dBm]',
                     mode='text',
                     auto_set=False,
                     enter_set=True)
    t_pi2_rf = Range(low=1.,
                     high=1.0e7,
                     value=21.0e3,
                     desc='length of pi/2 pulse of RF[ns]',
                     label='pi2 [ns]',
                     mode='text',
                     auto_set=False,
                     enter_set=True)
    t_pi_rf = Range(low=1.,
                    high=1.0e7,
                    value=42.0e3,
                    desc='length of pi pulse of RF[ns]',
                    label='pi [ns]',
                    mode='text',
                    auto_set=False,
                    enter_set=True)

    tau_begin = Range(low=0.,
                      high=1e8,
                      value=1.5,
                      desc='tau begin [ns]',
                      label='tau begin [ns]',
                      mode='text',
                      auto_set=False,
                      enter_set=True)
    tau_end = Range(low=1.,
                    high=1e9,
                    value=2.4e7,
                    desc='tau end [ns]',
                    label='tau end [ns]',
                    mode='text',
                    auto_set=False,
                    enter_set=True)
    tau_delta = Range(low=1.,
                      high=1e9,
                      value=0.3e6,
                      desc='delta tau [ns]',
                      label='delta tau [ns]',
                      mode='text',
                      auto_set=False,
                      enter_set=True)
    laser = Range(low=1.,
                  high=1.0e7,
                  value=3000.0,
                  desc='laser [ns]',
                  label='laser [ns]',
                  mode='text',
                  auto_set=False,
                  enter_set=True)
    wait = Range(low=1.,
                 high=1.0e8,
                 value=1.0e6,
                 desc='wait [ns]',
                 label='wait [ns]',
                 mode='text',
                 auto_set=False,
                 enter_set=True)

    tau = Array(value=np.array((0., 1.)))

    get_set_items = Pulsed.get_set_items + [
        'mw_frequency', 'mw_power', 't_pi', 'rf_frequency', 'rf_power',
        'tau_begin', 'tau_end', 'tau_delta', 'laser', 'wait', 'tau'
    ]

    traits_view = View(
        VGroup(
            HGroup(
                Item('submit_button', show_label=False),
                Item('remove_button', show_label=False),
                Item('resubmit_button', show_label=False),
                Item('priority'),
                Item('state', style='readonly'),
            ),
            Tabbed(
                VGroup(HGroup(
                    Item('mw_frequency',
                         width=-80,
                         enabled_when='state == "idle"'),
                    Item('mw_power', width=-80,
                         enabled_when='state == "idle"'),
                    Item('t_pi', width=-80, enabled_when='state == "idle"'),
                ),
                       HGroup(
                           Item('rf_frequency',
                                width=-80,
                                enabled_when='state == "idle"'),
                           Item('rf_power',
                                width=-80,
                                enabled_when='state == "idle"'),
                           Item('t_pi2_rf',
                                width=-80,
                                enabled_when='state == "idle"'),
                           Item('t_pi_rf',
                                width=-80,
                                enabled_when='state == "idle"'),
                       ),
                       HGroup(
                           Item('tau_begin',
                                width=-80,
                                enabled_when='state == "idle"'),
                           Item('tau_end',
                                width=-80,
                                enabled_when='state == "idle"'),
                           Item('tau_delta',
                                width=-80,
                                enabled_when='state == "idle"'),
                       ),
                       label='parameter'),
                VGroup(HGroup(
                    Item('laser', width=-80, enabled_when='state == "idle"'),
                    Item('wait', width=-80, enabled_when='state == "idle"'),
                    Item('record_length',
                         width=-80,
                         enabled_when='state == "idle"'),
                    Item('bin_width',
                         width=-80,
                         enabled_when='state == "idle"'),
                ),
                       label='settings'),
            ),
        ),
        title='Nuclear Rabi Measurement',
    )

    def generate_sequence(self):
        t_pi = self.t_pi
        laser = self.laser
        tau = self.tau
        wait = self.wait
        sequence = []
        for t in tau:
            sequence.append((['mw'], t_pi))
            sequence.append((['rf'], self.t_pi2_rf))
            sequence.append(([], 0.5 * t))
            sequence.append((['rf'], self.t_pi_rf))
            sequence.append(([], 0.5 * t))
            sequence.append((['rf'], self.t_pi2_rf))
            sequence.append(([], 500))
            sequence.append((['mw'], t_pi))
            sequence.append((['laser', 'aom'], laser))
            sequence.append(([], wait))
        sequence.append((['sequence'], 100))
        return sequence

    def apply_parameters(self):
        """Overwrites apply_parameters() from pulsed. Prior to generating sequence, etc., generate the tau mesh."""
        self.tau = np.arange(self.tau_begin, self.tau_end, self.tau_delta)
        Pulsed.apply_parameters(self)

    def start_up(self):
        ha.PulseGenerator().Night()
        ha.Microwave().setOutput(self.mw_power, self.mw_frequency)
        ha.RFSource().setOutput(self.rf_power, self.rf_frequency)
        ha.RFSource().setMode()

    def shut_down(self):
        ha.PulseGenerator().Light()
        ha.Microwave().setOutput(None, self.mw_frequency)
        ha.RFSource().setOutput(None, self.rf_frequency)
예제 #25
0
class Turtle(AbstractOverlay):
    x = Float
    y = Float
    angle = Range(0.0, 360.0, value=90.0)  # degrees, clockwise
    color = ColorTrait("blue")
    line_color = ColorTrait("green")
    size = Float(10.0)
    path = Array

    _pen = Enum("down", "up")

    view = View(
        Group("x",
              "y",
              "angle",
              Item("color", style="custom"),
              Item("line_color", style="custom"),
              "size",
              orientation="vertical"))

    def __init__(self, component=None, **traits):
        super(Turtle, self).__init__(component=component, **traits)
        if 'path' not in traits:
            self.path = array([self.x, self.y], ndmin=2)

    def overlay(self, other_component, gc, view_bounds=None, mode="normal"):
        self.render(gc, other_component)

    def render_turtle(self, gc, component):
        with gc:
            x, y = component.map_screen(array([self.x, self.y], ndmin=2))[0]
            gc.translate_ctm(x, y)
            angle = self.angle * pi / 180.0
            gc.rotate_ctm(angle)
            gc.set_stroke_color(self.color_)
            gc.set_fill_color(self.color_)
            gc.begin_path()
            gc.lines([[-0.707 * self.size, 0.707 * self.size],
                      [-0.707 * self.size, -0.707 * self.size],
                      [self.size, 0.0]])
            gc.fill_path()

    def render(self, gc, component):
        # Uses the component to map our path into screen space
        nan_mask = invert(isnan(self.path[:, 0])).astype(int)
        blocks = [
            b for b in arg_find_runs(nan_mask, "flat") if nan_mask[b[0]] != 0
        ]
        screen_pts = component.map_screen(self.path)
        with gc:
            gc.clip_to_rect(component.x, component.y, component.width,
                            component.height)
            gc.set_stroke_color(self.line_color_)
            for start, end in blocks:
                gc.begin_path()
                gc.lines(screen_pts[start:end])
                gc.stroke_path()
            self.render_turtle(gc, component)

    def pendown(self):
        self._pen = "down"
        self.path = vstack((self.path, [self.x, self.y]))

    def penup(self):
        self.path = vstack((self.path, [nan, nan]))
        self._pen = "up"

    def forward(self, amt):
        angle = self.angle * pi / 180.0
        self.x += amt * cos(angle)
        self.y += amt * sin(angle)
        if self._pen == "down":
            self.path = vstack((self.path, [self.x, self.y]))

    def back(self, amt):
        self.forward(-amt)

    def left(self, angle):
        self.angle = (self.angle + angle) % 360

    def right(self, angle):
        self.angle = ((self.angle - angle) + 360) % 360

    def clear(self):
        self.path = array([self.x, self.y], ndmin=2)

    def reset(self):
        self.x = self.y = 0.0
        self.angle = 90.0
        self.clear()

    def _anytrait_changed(self, trait, val):
        self.component.request_redraw()
예제 #26
0
class VideoEditor(Editor):
    """Traits UI 'display only' video editor.

    This editor uses the Qt QMultimedia machinery to display video streams
    to the screen.  Rather than being self-contained, the editor only concerns
    itself with displaying the video, and provides traits that control
    behaviour and provide internal state of the control during playback.
    """

    #: Does the drawing onto the image plane
    control = Instance(QVideoWidget)

    #: Handles the image pulling so the frames can be processed.  Qt5 only.
    surface = Any()

    #: The QMediaObject (Qt5) or QUrl (Qt6+) that holds the connection to the
    #: video stream.
    media_content = Any()

    #: The QMediaPlayer that controls playback of the video stream.
    media_player = Instance(QMediaPlayer)

    #: The aspect ratio of the video editor.
    aspect_ratio = AspectRatio()

    #: The current state of the player, synchronized to the trait named
    #: by factory.state.
    state = PlayerState()

    #: The current playback position of the player, synchronized to the trait
    #: named by factory.position.
    position = Float()

    #: The total duration of the current video, synchronized to the trait
    #: named by factory.duration.
    duration = Float()

    #: The media player playback status (loading, buffering, etc.),
    #: synchronized to the trait named by factory.media_status.
    media_status = MediaStatus()

    #: The percentage of the buffer currently filled, synchronized to the trait
    #: named by factory.buffer.
    buffer = Range(0, 100)

    #: A string holding the video error state, or "" if no error. Synchronized
    #: to the trait named by factory.video_error.
    video_error = Str()

    #: Whether the audio is muted or not, synchronized to the trait named by
    #: factory.muted.
    muted = Bool(False)

    #: The playback volume on a logarithmic scale (perceptually linear),
    #: synchronized to the trait named by factory.volume.
    volume = Range(0.0, 100.0)

    #: The playback rate.  Negative values rewind the video.
    #: Synchronized to the trait named by factory.playback_rate.
    playback_rate = Float(1.0)

    #: Function to apply to the image. Takes ref to new frame and a size tuple.
    #: Synchronized to the trait named by factory.image_func.
    image_func = Callable()

    #: The change in position required for an update to be emitted.
    #: Synchronized to the trait named by factory.notify_interval.
    #: This is only used on Qt5.
    notify_interval = Float(1.0)

    #: Qt6-specific QAudioOutput handler.
    _audio = Any()

    def update_to_regular(self):
        if self.surface is not None:
            self.surface.frameAvailable.disconnect(self.control.setImage)
            self.surface = None

        self.control = QVideoWidget()
        self.control.setSizePolicy(
            QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
        )
        self.control.setBackgroundRole(QPalette.ColorRole.Window)
        self.media_player.setVideoOutput(self.control)

    def update_to_functional(self):
        self.control = ImageWidget(image_func=self.image_func)
        self.control.setSizePolicy(
            QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
        )
        self.control.setBackgroundRole(QPalette.ColorRole.Window)

        self.surface = VideoSurface(widget=self.control)
        self.surface.frameAvailable.connect(self.control.setImage)

        self.media_player.setVideoOutput(self.surface)

    # ------------------------------------------------------------------------
    # Editor interface
    # ------------------------------------------------------------------------

    def init(self, parent):
        """Initialize the editor by creating the underlying toolkit widget.

        Parameters
        ----------
        parent : QWidget or None
            The parent widget for this widget.
        """
        self.control = QVideoWidget()
        self.control.setSizePolicy(
            QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding
        )
        self.control.setBackgroundRole(QPalette.ColorRole.Window)

        if is_qt5:
            self.media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        else:
            self.media_player = QMediaPlayer()
        self._set_video_url()
        self.media_player.setVideoOutput(self.control)
        if is_qt5:
            self.media_player.setMuted(self.muted)
        else:
            from pyface.qt.QtMultimedia import QAudioOutput

            self._audio = QAudioOutput()
            self._audio.setMuted(self.muted)
            self.media_player.setAudioOutput(self._audio)
        self._update_state()
        self._update_aspect_ratio()
        self._update_muted()
        self._update_volume()
        self._update_playback_rate()
        self._update_notify_interval()

        self._connect_signals()

        self.set_tooltip()

    def dispose(self):
        self._disconnect_signals()
        if self.media_player is not None:
            # Avoid a segfault if the media player is currently playing
            self.media_player.setVideoOutput(None)
            if not is_qt5:
                self.media_player.setAudioOutput(None)

        super().dispose()

    def update_editor(self):
        """Update the editor when the object trait changes externally."""
        self._set_video_url()

    # ------------------------------------------------------------------------
    # Private interface
    # ------------------------------------------------------------------------

    def _connect_signals(self):
        if self.media_player is not None:
            if is_qt5:
                self.media_player.stateChanged.connect(
                    self._state_changed_emitted
                )
                self.media_player.error.connect(self._error_emitted)
                self.media_player.bufferStatusChanged.connect(
                    self._buffer_status_changed_emitted
                )
                self.media_player.notifyIntervalChanged.connect(
                    self._notify_interval_changed_emitted
                )
            else:
                self.media_player.playbackStateChanged.connect(
                    self._state_changed_emitted
                )
                self.media_player.errorOccurred.connect(self._error_emitted)
                self.media_player.bufferProgressChanged.connect(
                    self._buffer_status_changed_emitted
                )
            self.media_player.positionChanged.connect(
                self._position_changed_emitted
            )
            self.media_player.durationChanged.connect(
                self._duration_changed_emitted
            )
            self.media_player.mediaStatusChanged.connect(
                self._media_status_changed_emitted
            )

    def _disconnect_signals(self):
        if self.media_player is not None:
            if is_qt5:
                self.media_player.stateChanged.disconnect(
                    self._state_changed_emitted
                )
                self.media_player.error.disconnect(self._error_emitted)
                self.media_player.bufferStatusChanged.disconnect(
                    self._buffer_status_changed_emitted
                )
                self.media_player.notifyIntervalChanged.disconnect(
                    self._notify_interval_changed_emitted
                )
            else:
                self.media_player.playbackStateChanged.disconnect(
                    self._state_changed_emitted
                )
                self.media_player.errorOccurred.disconnect(self._error_emitted)
                self.media_player.bufferProgressChanged.disconnect(
                    self._buffer_status_changed_emitted
                )
            self.media_player.positionChanged.disconnect(
                self._position_changed_emitted
            )
            self.media_player.durationChanged.disconnect(
                self._duration_changed_emitted
            )
            self.media_player.mediaStatusChanged.disconnect(
                self._media_status_changed_emitted
            )

    def _set_video_url(self):
        qurl = QUrl.fromUserInput(self.value)
        if is_qt5:
            from pyface.qt.QtMultimedia import QMediaContent
            if qurl.isValid():
                self.media_content = QMediaContent(qurl)
            else:
                self.media_content = QMediaContent(None)
        else:
            self.media_content = qurl
        self.control.updateGeometry()

    # Signal handlers -------------------------------------------------------

    def _state_changed_emitted(self, state):
        self.state = reversed_state_map[state]

    def _position_changed_emitted(self, position):
        # Avoid telling Qt about the new position in `_position_changed`
        with self.updating_value():
            self.position = position / 1000.0

    def _duration_changed_emitted(self, duration):
        self.duration = duration / 1000.0

    def _error_emitted(self, error):
        if error != QMediaPlayer.Error.NoError:
            self.video_error = self.media_player.errorString()
        else:
            self.video_error = ''

    def _media_status_changed_emitted(self, error):
        self.media_status = media_status_map[self.media_player.mediaStatus()]

    def _buffer_status_changed_emitted(self, error):
        if is_qt5:
            self.buffer = self.media_player.bufferStatus()
        else:
            self.buffer = int(self.media_player.bufferProgress() * 100)

    def _notify_interval_changed_emitted(self, interval):
        self.notify_interval = interval / 1000.0

    # Trait change handlers -------------------------------------------------

    @observe('aspect_ratio')
    def _aspect_ratio_observer(self, event):
        if self.control is not None:
            self._update_aspect_ratio()

    @observe('image_func')
    def _image_func_observer(self, event):
        if self.image_func is None:
            self.update_to_regular()
        elif not is_qt5:
            raise ValueError("image_func is not supported on Qt6")
        else:
            self.update_to_functional()

    @observe('media_content')
    def _media_content_observer(self, event):
        self.video_error = ''
        if self.media_player is not None:
            if is_qt5:
                self.media_player.setMedia(self.media_content)
            else:
                self.media_player.setSource(self.media_content)

    @observe('muted')
    def _muted_observer(self, event):
        if self.media_player is not None:
            self._update_muted()

    @observe('playback_rate')
    def _playback_rate_observer(self, event):
        if self.media_player is not None:
            self._update_playback_rate()

    @observe('position')
    def _position_observer(self, event):
        if self.media_player is not None and not self.updating:
            # position is given in ms
            self.media_player.setPosition(int(self.position * 1000))

    @observe('state')
    def _state_observer(self, event):
        if self.media_player is not None:
            self._update_state()

    @observe('volume')
    def _volume_observer(self, event):
        if self.media_player is not None:
            self._update_volume()

    @observe('notify_interval')
    def _notify_interval_observer(self, event):
        if self.media_player is not None:
            self._update_notify_interval()

    # MediaPlayer management ------------------------------------------------

    def _update_aspect_ratio(self):
        self.control.setAspectRatioMode(aspect_ratio_map[self.aspect_ratio])

    def _update_muted(self):
        if is_qt5:
            self.media_player.setMuted(self.muted)
        else:
            self._audio.setMuted(self.muted)

    def _update_playback_rate(self):
        self.media_player.setPlaybackRate(self.playback_rate)

    def _update_state(self):
        if self.state == 'stopped':
            self.media_player.stop()
            self.control.repaint()
        elif self.state == 'playing':
            # XXX forcing a resize so video is scaled correctly on MacOS
            s = self.control.size()
            w = s.width()
            h = s.height()
            self.media_player.play()
            self.control.resize(w + 1, h + 1)
            self.control.resize(w, h)
        elif self.state == 'paused':
            self.media_player.pause()

    def _update_volume(self):
        linear_volume = QAudio.convertVolume(
            self.volume / 100.0,
            QAudio.VolumeScale.LogarithmicVolumeScale,
            QAudio.VolumeScale.LinearVolumeScale,
        )
        if is_qt5:
            self.media_player.setVolume(int(linear_volume * 100))
        else:
            self._audio.setVolume(linear_volume)

    def _update_notify_interval(self):
        # only used on Qt5
        if is_qt5:
            # interval is given in ms
            interval = int(self.notify_interval * 1000)
            self.media_player.setNotifyInterval(interval)
예제 #27
0
class Picker(HasTraits):
    """This module creates a 'Picker' that can interactively select a
    point and/or a cell in the data.  It also can use a world point
    picker (i.e. a generic point in space) and will probe for the data
    at that point.

    The Picker is usually called via a callback from the GUI
    interactor window.  After performing a pick on the VTK scene, a
    Picker object creates a `PickedData` object and passes it on to
    the pick_handler trait for further handling.
    """

    # The version of this class.  Used for persistence.
    __version__ = 0

    # Speficifies the pick type.  The 'point_picker' and 'cell_picker'
    # options are self-explanatory.  The 'world_picker' picks a point
    # using a WorldPointPicker and additionally uses a ProbeFilter to
    # probe the data at the picked point.
    pick_type = Trait('point',
                      TraitRevPrefixMap({
                          'point_picker': 1,
                          'cell_picker': 2,
                          'world_picker': 3
                      }),
                      desc='specifies the picker type to use')

    # The pick_handler.  Set this to your own subclass if you want do
    # do something different from the default.
    pick_handler = Trait(DefaultPickHandler(), Instance(PickHandler))

    # Picking tolerance.
    tolerance = Range(0.0, 0.25, 0.025)

    # show the GUI on pick ?
    show_gui = true(desc="whether to show the picker GUI on pick")

    # Raise the GUI on pick ?
    auto_raise = true(desc="whether to raise the picker GUI on pick")

    default_view = View(Group(
        Group(Item(name='pick_type'), Item(name='tolerance'),
              show_border=True),
        Group(Item(name='pick_handler', style='custom'),
              show_border=True,
              show_labels=False),
        Group(Item(name='show_gui'), Item(name='auto_raise'),
              show_border=True),
    ),
                        resizable=True,
                        buttons=['OK'],
                        handler=CloseHandler())

    #################################################################
    # `object` interface.
    #################################################################
    def __init__(self, renwin, **traits):
        super(Picker, self).__init__(**traits)

        self.renwin = renwin
        self.pointpicker = tvtk.PointPicker()
        self.cellpicker = tvtk.CellPicker()
        self.worldpicker = tvtk.WorldPointPicker()
        self.probe_data = tvtk.PolyData()
        self._tolerance_changed(self.tolerance)

        # Use a set of axis to show the picked point.
        self.p_source = tvtk.Axes()
        self.p_mapper = tvtk.PolyDataMapper()
        self.p_actor = tvtk.Actor()
        self.p_source.symmetric = 1
        self.p_actor.pickable = 0
        self.p_actor.visibility = 0
        prop = self.p_actor.property
        prop.line_width = 2
        prop.ambient = 1.0
        prop.diffuse = 0.0
        configure_input(self.p_mapper, self.p_source)
        self.p_actor.mapper = self.p_mapper

        self.probe_data.points = [[0.0, 0.0, 0.0]]

        self.ui = None

    def __get_pure_state__(self):
        d = self.__dict__.copy()
        for x in [
                'renwin', 'ui', 'pick_handler', '__sync_trait__',
                '__traits_listener__'
        ]:
            d.pop(x, None)
        return d

    def __getstate__(self):
        return state_pickler.dumps(self)

    def __setstate__(self, str_state):
        # This method is unnecessary since this object will almost
        # never be pickled by itself and only via the scene, therefore
        # __init__ will be called when the scene is constructed.
        # However, setstate is defined just for completeness.
        state_pickler.set_state(self, state_pickler.loads_state(str_state))

    #################################################################
    # `Picker` interface.
    #################################################################
    def pick(self, x, y):
        """Calls one of the current pickers and then passes the
        obtained data to the `self.pick_handler` object's
        `handle_pick` method.

        Parameters
        ----------

        - x : X position of the mouse in the window.

        - y : Y position of the mouse in the window.

          Note that the origin of x, y must be at the left bottom
          corner of the window.  Thus, for most GUI toolkits, y must
          be flipped appropriately such that y=0 is the bottom of the
          window.
        """

        data = None
        if self.pick_type_ == 1:
            data = self.pick_point(x, y)
        elif self.pick_type_ == 2:
            data = self.pick_cell(x, y)
        elif self.pick_type_ == 3:
            data = self.pick_world(x, y)

        self.pick_handler.handle_pick(data)
        if self.show_gui:
            self._setup_gui()

    def pick_point(self, x, y):
        """ Picks the nearest point. Returns a `PickedData` instance."""
        self.pointpicker.pick((float(x), float(y), 0.0), self.renwin.renderer)

        pp = self.pointpicker
        id = pp.point_id
        picked_data = PickedData()
        coord = pp.pick_position
        picked_data.coordinate = coord

        if id > -1:
            data = pp.mapper.input.point_data
            bounds = pp.mapper.input.bounds

            picked_data.valid = 1
            picked_data.point_id = id
            picked_data.data = data

            self._update_actor(coord, bounds)
        else:
            self.p_actor.visibility = 0

        self.renwin.render()
        return picked_data

    def pick_cell(self, x, y):
        """ Picks the nearest cell. Returns a `PickedData` instance."""
        try:
            self.cellpicker.pick(float(x), float(y), 0.0, self.renwin.renderer)
        except TypeError:
            # On old versions of VTK, the signature used to be different
            self.cellpicker.pick((float(x), float(y), 0.0),
                                 self.renwin.renderer)

        cp = self.cellpicker
        id = cp.cell_id
        picked_data = PickedData()
        coord = cp.pick_position
        picked_data.coordinate = coord

        if id > -1:
            data = cp.mapper.input.cell_data
            bounds = cp.mapper.input.bounds

            picked_data.valid = 1
            picked_data.cell_id = id
            picked_data.data = data

            self._update_actor(coord, bounds)
        else:
            self.p_actor.visibility = 0

        self.renwin.render()
        return picked_data

    def pick_world(self, x, y):
        """ Picks a world point and probes for data there. Returns a
        `PickedData` instance."""
        self.worldpicker.pick((float(x), float(y), 0.0), self.renwin.renderer)

        # Use the cell picker to get the data that needs to be probed.
        try:
            self.cellpicker.pick((float(x), float(y), 0.0),
                                 self.renwin.renderer)
        except TypeError:
            self.cellpicker.pick(float(x), float(y), 0.0, self.renwin.renderer)

        wp = self.worldpicker
        cp = self.cellpicker
        coord = wp.pick_position
        self.probe_data.points = [list(coord)]
        picked_data = PickedData()
        picked_data.coordinate = coord

        if cp.mapper:
            data = get_last_input(cp.mapper.input)
            # Need to create the probe each time because otherwise it
            # does not seem to work properly.
            probe = tvtk.ProbeFilter()
            if vtk_major_version >= 6:
                probe.set_source_data(data)
                probe.set_input_data(self.probe_data)
            else:
                probe.source = data
                probe.input = self.probe_data
            probe.update()
            data = probe.output.point_data
            bounds = cp.mapper.input.bounds

            picked_data.valid = 1
            picked_data.world_pick = 1
            picked_data.point_id = 0
            picked_data.data = data

            self._update_actor(coord, bounds)
        else:
            self.p_actor.visibility = 0

        self.renwin.render()
        return picked_data

    def on_ui_close(self):
        """This method makes the picker actor invisible when the GUI
        dialog is closed."""
        self.p_actor.visibility = 0
        self.renwin.renderer.remove_actor(self.p_actor)
        self.ui = None

    #################################################################
    # Non-public interface.
    #################################################################
    def _tolerance_changed(self, val):
        """ Trait handler for the tolerance trait."""
        self.pointpicker.tolerance = val
        self.cellpicker.tolerance = val

    def _update_actor(self, coordinate, bounds):
        """Updates the actor by setting its position and scale."""
        dx = 0.3 * (bounds[1] - bounds[0])
        dy = 0.3 * (bounds[3] - bounds[2])
        dz = 0.3 * (bounds[5] - bounds[4])
        scale = max(dx, dy, dz)
        self.p_source.origin = coordinate
        self.p_source.scale_factor = scale
        self.p_actor.visibility = 1

    def _setup_gui(self):
        """Pops up the GUI control widget."""
        # Popup the GUI control.
        if self.ui is None:
            self.ui = self.edit_traits()
            # Note that we add actors to the renderer rather than to
            # renwin to prevent event notifications on actor
            # additions.
            self.renwin.renderer.add_actor(self.p_actor)
        elif self.auto_raise:
            try:
                self.ui.control.Raise()
            except AttributeError:
                pass
예제 #28
0
class ToolkitEditorFactory(EditorFactory):
    """ Editor factory for range editors.
    """
    #-------------------------------------------------------------------------
    #  Trait definitions:
    #-------------------------------------------------------------------------

    # Number of columns when displayed as an enumeration
    cols = Range(1, 20)

    # Is user input set on every keystroke?
    auto_set = Bool(True)

    # Is user input set when the Enter key is pressed?
    enter_set = Bool(False)

    # Label for the low end of the range
    low_label = Unicode

    # Label for the high end of the range
    high_label = Unicode

    # FIXME: This is supported only in the wx backend so far.
    # The width of the low and high labels
    label_width = Int

    # The name of an [object.]trait that defines the low value for the range
    low_name = Str

    # The name of an [object.]trait that defines the high value for the range
    high_name = Str

    # Formatting string used to format value and labels
    format = Unicode('%s')

    # Is the range for floating pointer numbers (vs. integers)?
    is_float = Bool(Undefined)

    # Function to evaluate floats/ints when they are assigned to an object
    # trait
    evaluate = Any

    # The object trait containing the function used to evaluate floats/ints
    evaluate_name = Str

    # Low end of range
    low = Property

    # High end of range
    high = Property

    # Display mode to use
    mode = Enum(
        'auto',
        'slider',
        'xslider',
        'spinner',
        'enum',
        'text',
        'logslider')

    #-------------------------------------------------------------------------
    #  Traits view definition:
    #-------------------------------------------------------------------------

    traits_view = View([['low', 'high',
                         '|[Range]'],
                        ['low_label{Low}', 'high_label{High}',
                         '|[Range Labels]'],
                        ['auto_set{Set automatically}',
                         'enter_set{Set on enter key pressed}',
                         'is_float{Is floating point range}',
                            '-[Options]>'],
                        ['cols',
                         '|[Number of columns for integer custom style]<>']
                        ])

    #-------------------------------------------------------------------------
    #  Performs any initialization needed after all constructor traits have
    #  been set:
    #-------------------------------------------------------------------------

    def init(self, handler=None):
        """ Performs any initialization needed after all constructor traits
            have been set.
        """
        if handler is not None:
            if isinstance(handler, CTrait):
                handler = handler.handler

            if self.low_name == '':
                if isinstance(handler._low, CodeType):
                    self.low = eval(handler._low)
                else:
                    self.low = handler._low

            if self.high_name == '':
                if isinstance(handler._low, CodeType):
                    self.high = eval(handler._high)
                else:
                    self.high = handler._high
        else:
            if (self.low is None) and (self.low_name == ''):
                self.low = 0.0

            if (self.high is None) and (self.high_name == ''):
                self.high = 1.0

    #-------------------------------------------------------------------------
    #  Define the 'low' and 'high' traits:
    #-------------------------------------------------------------------------

    def _get_low(self):
        return self._low

    def _set_low(self, low):
        old_low = self._low
        self._low = low = self._cast(low)
        if self.is_float is Undefined:
            self.is_float = isinstance(low, float)

        if (self.low_label == '') or (self.low_label == six.text_type(old_low)):
            self.low_label = six.text_type(low)

    def _get_high(self):
        return self._high

    def _set_high(self, high):
        old_high = self._high
        self._high = high = self._cast(high)
        if self.is_float is Undefined:
            self.is_float = isinstance(high, float)

        if (self.high_label == '') or (self.high_label == six.text_type(old_high)):
            self.high_label = six.text_type(high)

    def _cast(self, value):
        if not isinstance(value, six.string_types):
            return value

        try:
            return int(value)
        except ValueError:
            return float(value)

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

    def _get_low_high(self, ui):
        """ Returns the low and high values used to determine the initial range.
        """
        low, high = self.low, self.high

        if (low is None) and (self.low_name != ''):
            low = self.named_value(self.low_name, ui)
            if self.is_float is Undefined:
                self.is_float = isinstance(low, float)

        if (high is None) and (self.high_name != ''):
            high = self.named_value(self.high_name, ui)
            if self.is_float is Undefined:
                self.is_float = isinstance(high, float)

        if self.is_float is Undefined:
            self.is_float = True

        return (low, high, self.is_float)

    #-------------------------------------------------------------------------
    #  Property getters.
    #-------------------------------------------------------------------------
    def _get_simple_editor_class(self):
        """ Returns the editor class to use for a simple style.

        The type of editor depends on the type and extent of the range being
        edited:

        * One end of range is unspecified: RangeTextEditor
        * **mode** is specified and not 'auto': editor corresponding to **mode**
        * Floating point range with extent > 100: LargeRangeSliderEditor
        * Integer range or floating point range with extent <= 100:
          SimpleSliderEditor
        * All other cases: SimpleSpinEditor
        """
        low, high, is_float = self._low_value, self._high_value, self.is_float

        if (low is None) or (high is None):
            return toolkit_object('range_editor:RangeTextEditor')

        if (not is_float) and (abs(high - low) > 1000000000):
            return toolkit_object('range_editor:RangeTextEditor')

        if self.mode != 'auto':
            return toolkit_object('range_editor:SimpleEditorMap')[self.mode]

        if is_float and (abs(high - low) > 100):
            return toolkit_object('range_editor:LargeRangeSliderEditor')

        if is_float or (abs(high - low) <= 100):
            return toolkit_object('range_editor:SimpleSliderEditor')

        return toolkit_object('range_editor:SimpleSpinEditor')

    def _get_custom_editor_class(self):
        """ Creates a custom style of range editor

        The type of editor depends on the type and extent of the range being
        edited:

        * One end of range is unspecified: RangeTextEditor
        * **mode** is specified and not 'auto': editor corresponding to **mode**
        * Floating point range: Same as "simple" style
        * Integer range with extent > 15: Same as "simple" style
        * Integer range with extent <= 15: CustomEnumEditor

        """
        low, high, is_float = self._low_value, self._high_value, self.is_float
        if (low is None) or (high is None):
            return toolkit_object('range_editor:RangeTextEditor')

        if self.mode != 'auto':
            return toolkit_object('range_editor:CustomEditorMap')[self.mode]

        if is_float or (abs(high - low) > 15):
            return self.simple_editor_class

        return toolkit_object('range_editor:CustomEnumEditor')

    def _get_text_editor_class(self):
        """Returns the editor class to use for a text style.
        """
        return toolkit_object('range_editor:RangeTextEditor')

    #-------------------------------------------------------------------------
    #  'Editor' factory methods:
    #-------------------------------------------------------------------------

    def simple_editor(self, ui, object, name, description, parent):
        """ Generates an editor using the "simple" style.
        Overridden to set the values of the _low_value, _high_value and
        is_float traits.

        """
        self._low_value, self._high_value, self.is_float = self._get_low_high(
            ui)
        return super(
            RangeEditor,
            self).simple_editor(
            ui,
            object,
            name,
            description,
            parent)

    def custom_editor(self, ui, object, name, description, parent):
        """ Generates an editor using the "custom" style.
        Overridden to set the values of the _low_value, _high_value and
        is_float traits.

        """
        self._low_value, self._high_value, self.is_float = self._get_low_high(
            ui)
        return super(
            RangeEditor,
            self).custom_editor(
            ui,
            object,
            name,
            description,
            parent)
예제 #29
0
class Group(ViewSubElement):
    """ Represents a grouping of items in a user interface view.
    """

    #---------------------------------------------------------------------------
    # Trait definitions:
    #---------------------------------------------------------------------------

    # A list of Group, Item, and Include objects in this group.
    content = List(ViewSubElement)

    # A unique identifier for the group.
    id = Str

    # User interface label for the group. How the label is displayed depends
    # on the **show_border** attribute, and on the **layout** attribute of
    # the group's parent group or view.
    label = Str

    style_sheet = Str

    # Default context object for group items.
    object = ContainerDelegate

    # Default editor style of items in the group.
    style = ContainerDelegate

    # Default docking style of items in group.
    dock = ContainerDelegate

    # Default image to display on notebook tabs.
    image = ContainerDelegate

    # The theme to use for a DockWindow:
    dock_theme = Instance(DockWindowTheme, allow_none=False)

    # The theme to use for the group itself:
    group_theme = ATheme

    # The theme to use for items contained in the group:
    item_theme = ContainerDelegate

    # The theme to use for the labels of items contained in the group:
    label_theme = ContainerDelegate

    # Category of elements dragged from view.
    export = ContainerDelegate

    # Spatial orientation of the group's elements. Can be 'vertical' (default)
    # or 'horizontal'.
    orientation = Orientation

    # Layout style of the group, which can be one of the following:
    #
    # * 'normal' (default): Sub-groups are displayed sequentially in a single
    #   panel.
    # * 'flow': Sub-groups are displayed sequentially, and then "wrap" when
    #   they exceed the available space in the **orientation** direction.
    # * 'split': Sub-groups are displayed in a single panel, separated by
    #   "splitter bars", which the user can drag to adjust the amount of space
    #   for each sub-group.
    # * 'tabbed': Each sub-group appears on a separate tab, labeled with the
    #   sub-group's *label* text, if any.
    #
    # This attribute is ignored for groups that contain only items, or contain
    # only one sub-group.
    layout = Layout

    # Should the group be scrollable along the direction of orientation?
    scrollable = Bool(False)

    # The number of columns in the group
    columns = Range(1, 50)

    # Should a border be drawn around group? If set to True, the **label** text
    # is embedded in the border. If set to False, the label appears as a banner
    # above the elements of the group.
    show_border = Bool(False)

    # Should labels be added to items in group? Only items that are directly
    # contained in the group are affected. That is, if the group contains
    # a sub-group, the display of labels in the sub-group is not affected by
    # the attribute on this group.
    show_labels = Bool(True)

    # Should labels be shown to the left of items (True) or the right (False)?
    # Only items that are directly contained in the group are affected. That is,
    # if the group contains a sub-group, the display of labels in the sub-group
    # is not affected by the attribute in this group. If **show_labels** is
    # False, this attribute is irrelevant.
    show_left = Bool(True)

    # Is this group the tab that is initially selected? If True, the group's
    # tab is displayed when the view is opened. If the **layout** of the group's
    # parent is not 'tabbed', this attribute is ignored.
    selected = Bool(False)

    # Should the group use extra space along its parent group's layout
    # orientation?
    springy = Bool(False)

    # Optional help text (for top-level group). This help text appears in the
    # View-level help window (created by the default help handler), for any
    # View that contains *only* this group. Group-level help is ignored for
    # nested groups and multiple top-level groups
    help = Str

    # Pre-condition for including the group in the display. If the expression
    # evaluates to False, the group is not defined in the display. Conditions
    # for **defined_when** are evaluated only once, when the display is first
    # constructed. Use this attribute for conditions based on attributes that
    # vary from object to object, but that do not change over time.
    defined_when = Str

    # Pre-condition for showing the group. If the expression evaluates to False,
    # the group and its items are not visible (and they disappear if they were
    # previously visible). If the value evaluates to True, the group and items
    # become visible. All **visible_when** conditions are checked each time
    # that any trait value is edited in the display. Therefore, you can use
    # **visible_when** conditions to hide or show groups in response to user
    # input.
    visible_when = Str

    # Pre-condition for enabling the group. If the expression evaluates to False,
    # the group is disabled, that is, none of the widgets accept input. All
    # **enabled_when** conditions are checked each time that any trait value
    # is edited in the display. Therefore, you can use **enabled_when**
    # conditions to enable or disable groups in response to user input.
    enabled_when = Str

    # Amount of padding (in pixels) to add around each item in the group. The
    # value must be an integer between 0 and 15. (Unlike the Item class, the
    # Group class does not support negative padding.) The padding for any
    # individual widget is the sum of the padding for its Group, the padding
    # for its Item, and the default spacing determined by the toolkit.
    padding = Padding

    # Requested width of the group (calculated from widths of contents)
    width = Property(Float, depends_on='content')

    # Requested height of the group (calculated from heights of contents)
    height = Property(Float, depends_on='content')

    #---------------------------------------------------------------------------
    #  Initializes the object:
    #---------------------------------------------------------------------------

    def __init__(self, *values, **traits):
        """ Initializes the group object.
        """
        super(ViewSubElement, self).__init__(**traits)

        content = self.content

        # Process any embedded Group options first:
        for value in values:
            if (isinstance(value, basestring)) and (value[0:1] in '-|'):
                # Parse Group trait options if specified as a string:
                self._parse(value)

        # Process all of the data passed to the constructor:
        for value in values:
            if isinstance(value, ViewSubElement):
                content.append(value)
            elif type(value) in SequenceTypes:
                # Map (...) or [...] to a Group():
                content.append(Group(*value))
            elif isinstance(value, basestring):
                if value[0:1] in '-|':
                    # We've already parsed Group trait options above:
                    pass
                elif (value[:1] == '<') and (value[-1:] == '>'):
                    # Convert string to an Include value:
                    content.append(Include(value[1:-1].strip()))
                else:
                    # Else let the Item class try to make sense of it:
                    content.append(Item(value))
            else:
                raise TypeError("Unrecognized argument type: %s" % value)

        # Make sure this Group is the container for all its children:
        self.set_container()

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

    def _dock_theme_default(self):
        return dock_window_theme()

    #---------------------------------------------------------------------------
    #  Gets the label to use for a specified Group in a specified UI:
    #---------------------------------------------------------------------------

    def get_label(self, ui):
        """ Gets the label to use this group.
        """
        if self.label != '':
            return self.label

        return 'Group'

    #---------------------------------------------------------------------------
    #  Returns whether or not the object is replacable by an Include object:
    #---------------------------------------------------------------------------

    def is_includable(self):
        """ Returns a Boolean value indicating whether the object is replacable
        by an Include object.
        """
        return (self.id != '')

    #---------------------------------------------------------------------------
    #  Replaces any items which have an 'id' with an Include object with the
    #  same 'id', and puts the object with the 'id' into the specified
    #  ViewElements object:
    #---------------------------------------------------------------------------

    def replace_include(self, view_elements):
        """ Replaces any items that have an **id** attribute with an Include
        object with the same ID value, and puts the object with the ID
        into the specified ViewElements object.

        Parameters
        ----------
        view_elements : ViewElements object
            A set of Group, Item, and Include objects
        """
        for i, item in enumerate(self.content):
            if item.is_includable():
                id = item.id
                if id in view_elements.content:
                    raise TraitError(
                        "Duplicate definition for view element '%s'" % id)
                self.content[i] = Include(id)
                view_elements.content[id] = item
            item.replace_include(view_elements)

    #---------------------------------------------------------------------------
    #  Returns a ShadowGroup for the Group which recursively resolves all
    #  imbedded Include objects and which replaces all imbedded Group objects
    #  with a corresponding ShadowGroup:
    #---------------------------------------------------------------------------

    def get_shadow(self, ui):
        """ Returns a ShadowGroup object for the current Group object, which
        recursively resolves all embedded Include objects and which replaces
        each embedded Group object with a corresponding ShadowGroup.
        """
        content = []
        groups = 0
        level = ui.push_level()
        for value in self.content:
            # Recursively replace Include objects:
            while isinstance(value, Include):
                value = ui.find(value)

            # Convert Group objects to ShadowGroup objects, but include Item
            # objects as is (ignore any 'None' values caused by a failed
            # Include):
            if isinstance(value, Group):
                if self._defined_when(ui, value):
                    content.append(value.get_shadow(ui))
                    groups += 1
            elif isinstance(value, Item):
                if self._defined_when(ui, value):
                    content.append(value)

            ui.pop_level(level)

        # Return the ShadowGroup:
        return ShadowGroup(shadow=self, content=content, groups=groups)

    #---------------------------------------------------------------------------
    #  Sets the correct container for the content:
    #---------------------------------------------------------------------------

    def set_container(self):
        """ Sets the correct container for the content.
        """
        for item in self.content:
            item.container = self

    #---------------------------------------------------------------------------
    #  Returns whether the object should be defined in the user interface:
    #---------------------------------------------------------------------------

    def _defined_when(self, ui, value):
        """ Should the object be defined in the user interface?
        """
        if value.defined_when == '':
            return True
        return ui.eval_when(value.defined_when)

    #---------------------------------------------------------------------------
    #  Parses Group options specified as a string:
    #---------------------------------------------------------------------------

    def _parse(self, value):
        """ Parses Group options specified as a string.
        """
        # Override the defaults, since we only allow 'True' values to be
        # specified:
        self.show_border = self.show_labels = self.show_left = False

        # Parse all of the single or multi-character options:
        value, empty = self._parse_label(value)
        value = self._parse_style(value)
        value = self._option(value, '-', 'orientation', 'horizontal')
        value = self._option(value, '|', 'orientation', 'vertical')
        value = self._option(value, '=', 'layout', 'split')
        value = self._option(value, '^', 'layout', 'tabbed')
        value = self._option(value, '>', 'show_labels', True)
        value = self._option(value, '<', 'show_left', True)
        value = self._option(value, '!', 'selected', True)

        show_labels = not (self.show_labels and self.show_left)
        self.show_left = not self.show_labels
        self.show_labels = show_labels

        # Parse all of the punctuation based sub-string options:
        value = self._split('id', value, ':', _py2to3.str_find, 0, 1)
        if value != '':
            self.object = value

    #---------------------------------------------------------------------------
    #  Handles a label being found in the string definition:
    #---------------------------------------------------------------------------

    def _parsed_label(self):
        """ Handles a label being found in the string definition.
        """
        self.show_border = True

    #---------------------------------------------------------------------------
    #  Returns a 'pretty print' version of the Group:
    #---------------------------------------------------------------------------

    def __repr__(self):
        """ Returns a "pretty print" version of the Group.
        """
        result = []
        items = ',\n'.join([item.__repr__() for item in self.content])
        if len(items) > 0:
            result.append(items)

        options = self._repr_options('orientation', 'show_border',
                                     'show_labels', 'show_left', 'selected',
                                     'id', 'object', 'label', 'style',
                                     'layout', 'style_sheet')
        if options is not None:
            result.append(options)

        content = ',\n'.join(result)
        if len(content) == 0:
            return self.__class__.__name__ + '()'

        return '%s(\n%s\n)' % (self.__class__.__name__, self._indent(content))

    #---------------------------------------------------------------------------
    #  Property getters/setters for width/height attributes
    #---------------------------------------------------------------------------

    @cached_property
    def _get_width(self):
        """ Returns the requested width of the Group.
        """
        width = 0.0
        for item in self.content:
            if item.width >= 1:
                if self.orientation == 'horizontal':
                    width += item.width
                elif self.orientation == 'vertical':
                    width = max(width, item.width)

        if width == 0:
            width = -1.0

        return width

    @cached_property
    def _get_height(self):
        """ Returns the requested height of the Group.
        """
        height = 0.0
        for item in self.content:
            if item.height >= 1:
                if self.orientation == 'horizontal':
                    height = max(height, item.height)
                elif self.orientation == 'vertical':
                    height += item.height

        if height == 0:
            height = -1.0

        return height
예제 #30
0
class ImageButton(Widget):
    """ An image and text-based control that can be used as a normal, radio or
        toolbar button.
    """

    # Pens used to draw the 'selection' marker:
    _selectedPenDark = wx.Pen(
        wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW), 1, wx.SOLID)

    _selectedPenLight = wx.Pen(
        wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DHIGHLIGHT), 1, wx.SOLID)

    # ---------------------------------------------------------------------------
    #  Trait definitions:
    # ---------------------------------------------------------------------------

    # The image:
    image = Instance(ImageResource, allow_none=True)

    # The (optional) label:
    label = Str()

    # Extra padding to add to both the left and right sides:
    width_padding = Range(0, 31, 7)

    # Extra padding to add to both the top and bottom sides:
    height_padding = Range(0, 31, 5)

    # Presentation style:
    style = Enum("button", "radio", "toolbar", "checkbox")

    # Orientation of the text relative to the image:
    orientation = Enum("vertical", "horizontal")

    # Is the control selected ('radio' or 'checkbox' style)?
    selected = Bool(False)

    # Fired when a 'button' or 'toolbar' style control is clicked:
    clicked = Event()

    # ---------------------------------------------------------------------------
    #  Initializes the object:
    # ---------------------------------------------------------------------------

    def __init__(self, parent, **traits):
        """ Creates a new image control.
        """
        self._image = None

        super(ImageButton, self).__init__(**traits)

        # Calculate the size of the button:
        idx = idy = tdx = tdy = 0
        if self._image is not None:
            idx = self._image.GetWidth()
            idy = self._image.GetHeight()

        if self.label != "":
            dc = wx.ScreenDC()
            dc.SetFont(wx.NORMAL_FONT)
            tdx, tdy = dc.GetTextExtent(self.label)

        wp2 = self.width_padding + 2
        hp2 = self.height_padding + 2
        if self.orientation == "horizontal":
            self._ix = wp2
            spacing = (idx > 0) * (tdx > 0) * 4
            self._tx = self._ix + idx + spacing
            dx = idx + tdx + spacing
            dy = max(idy, tdy)
            self._iy = hp2 + ((dy - idy) // 2)
            self._ty = hp2 + ((dy - tdy) // 2)
        else:
            self._iy = hp2
            spacing = (idy > 0) * (tdy > 0) * 2
            self._ty = self._iy + idy + spacing
            dx = max(idx, tdx)
            dy = idy + tdy + spacing
            self._ix = wp2 + ((dx - idx) // 2)
            self._tx = wp2 + ((dx - tdx) // 2)

        # Create the toolkit-specific control:
        self._dx = dx + wp2 + wp2
        self._dy = dy + hp2 + hp2
        self.control = wx.Window(parent, -1, size=wx.Size(self._dx, self._dy))
        self.control._owner = self
        self._mouse_over = self._button_down = False

        # Set up mouse event handlers:
        self.control.Bind(wx.EVT_ENTER_WINDOW, self._on_enter_window)
        self.control.Bind(wx.EVT_LEAVE_WINDOW, self._on_leave_window)
        self.control.Bind(wx.EVT_LEFT_DOWN, self._on_left_down)
        self.control.Bind(wx.EVT_LEFT_UP, self._on_left_up)
        self.control.Bind(wx.EVT_PAINT, self._on_paint)

    # ---------------------------------------------------------------------------
    #  Handles the 'image' trait being changed:
    # ---------------------------------------------------------------------------

    def _image_changed(self, image):
        self._image = self._mono_image = None
        if image is not None:
            self._img = image.create_image()
            self._image = self._img.ConvertToBitmap()

        if self.control is not None:
            self.control.Refresh()

    # ---------------------------------------------------------------------------
    #  Handles the 'selected' trait being changed:
    # ---------------------------------------------------------------------------

    def _selected_changed(self, selected):
        """ Handles the 'selected' trait being changed.
        """
        if selected and (self.style == "radio"):
            for control in self.control.GetParent().GetChildren():
                owner = getattr(control, "_owner", None)
                if (isinstance(owner, ImageButton) and owner.selected
                        and (owner is not self)):
                    owner.selected = False
                    break

        self.control.Refresh()

    # -- wx event handlers ----------------------------------------------------------

    def _on_enter_window(self, event):
        """ Called when the mouse enters the widget. """

        if self.style != "button":
            self._mouse_over = True
            self.control.Refresh()

    def _on_leave_window(self, event):
        """ Called when the mouse leaves the widget. """

        if self._mouse_over:
            self._mouse_over = False
            self.control.Refresh()

    def _on_left_down(self, event):
        """ Called when the left mouse button goes down on the widget. """
        self._button_down = True
        self.control.CaptureMouse()
        self.control.Refresh()

    def _on_left_up(self, event):
        """ Called when the left mouse button goes up on the widget. """
        control = self.control
        control.ReleaseMouse()
        self._button_down = False
        wdx, wdy = control.GetClientSize().Get()
        x, y = event.GetX(), event.GetY()
        control.Refresh()
        if (0 <= x < wdx) and (0 <= y < wdy):
            if self.style == "radio":
                self.selected = True
            elif self.style == "checkbox":
                self.selected = not self.selected
            else:
                self.clicked = True

    def _on_paint(self, event):
        """ Called when the widget needs repainting.
        """
        wdc = wx.PaintDC(self.control)
        wdx, wdy = self.control.GetClientSize().Get()
        ox = (wdx - self._dx) / 2
        oy = (wdy - self._dy) / 2

        disabled = not self.control.IsEnabled()
        if self._image is not None:
            image = self._image
            if disabled:
                if self._mono_image is None:
                    img = self._img
                    data = reshape(frombuffer(img.GetData(), dtype("uint8")),
                                   (-1, 3)) * array([[0.297, 0.589, 0.114]])
                    g = data[:, 0] + data[:, 1] + data[:, 2]
                    data[:, 0] = data[:, 1] = data[:, 2] = g
                    img.SetData(ravel(data.astype(dtype("uint8"))).tostring())
                    img.SetMaskColour(0, 0, 0)
                    self._mono_image = img.ConvertToBitmap()
                    self._img = None
                image = self._mono_image
            wdc.DrawBitmap(image, ox + self._ix, oy + self._iy, True)

        if self.label != "":
            if disabled:
                wdc.SetTextForeground(DisabledTextColor)
            wdc.SetFont(wx.NORMAL_FONT)
            wdc.DrawText(self.label, ox + self._tx, oy + self._ty)

        pens = [self._selectedPenLight, self._selectedPenDark]
        bd = self._button_down
        style = self.style
        is_rc = style in ("radio", "checkbox")
        if bd or (style == "button") or (is_rc and self.selected):
            if is_rc:
                bd = 1 - bd
            wdc.SetBrush(wx.TRANSPARENT_BRUSH)
            wdc.SetPen(pens[bd])
            wdc.DrawLine(1, 1, wdx - 1, 1)
            wdc.DrawLine(1, 1, 1, wdy - 1)
            wdc.DrawLine(2, 2, wdx - 2, 2)
            wdc.DrawLine(2, 2, 2, wdy - 2)
            wdc.SetPen(pens[1 - bd])
            wdc.DrawLine(wdx - 2, 2, wdx - 2, wdy - 1)
            wdc.DrawLine(2, wdy - 2, wdx - 2, wdy - 2)
            wdc.DrawLine(wdx - 3, 3, wdx - 3, wdy - 2)
            wdc.DrawLine(3, wdy - 3, wdx - 3, wdy - 3)

        elif self._mouse_over and (not self.selected):
            wdc.SetBrush(wx.TRANSPARENT_BRUSH)
            wdc.SetPen(pens[bd])
            wdc.DrawLine(0, 0, wdx, 0)
            wdc.DrawLine(0, 1, 0, wdy)
            wdc.SetPen(pens[1 - bd])
            wdc.DrawLine(wdx - 1, 1, wdx - 1, wdy)
            wdc.DrawLine(1, wdy - 1, wdx - 1, wdy - 1)
예제 #31
0
class VolumeFactory(PipeFactory):
    """ Applies the Volume mayavi module to the given VTK data
        source (Mayavi source, or VTK dataset).

        **Note**

        The range of the colormap can be changed simply using the
        vmin/vmax parameters (see below). For more complex modifications of
        the colormap, here is some pseudo code to change the ctf (color
        transfer function), or the otf (opacity transfer function)::

            vol = mlab.pipeline.volume(src)

            # Changing the ctf:
            from tvtk.util.ctf import ColorTransferFunction
            ctf = ColorTransferFunction()
            ctf.add_rgb_point(value, r, g, b)  # r, g, and b are float
                                               # between 0 and 1
            ctf.add_hsv_point(value, h, s, v)
            # ...
            vol._volume_property.set_color(ctf)
            vol._ctf = ctf
            vol.update_ctf = True

            # Changing the otf:
            from tvtk.util.ctf import PiecewiseFunction
            otf = PiecewiseFunction()
            otf.add_point(value, opacity)
            vol._otf = otf
            vol._volume_property.set_scalar_opacity(otf)

        Also, it might be useful to change the range of the ctf::

            ctf.range = [0, 1]
    """

    color = Trait(
        None,
        None,
        Tuple(Range(0., 1.), Range(0., 1.), Range(0., 1.)),
        help="""the color of the vtk object. Overides the colormap,
                        if any, when specified. This is specified as a
                        triplet of float ranging from 0 to 1, eg (1, 1,
                        1) for white.""",
    )

    vmin = Trait(None,
                 None,
                 CFloat,
                 help="""vmin is used to scale the transparency
                            gradient. If None, the min of the data will be
                            used""")

    vmax = Trait(None,
                 None,
                 CFloat,
                 help="""vmax is used to scale the transparency
                            gradient. If None, the max of the data will be
                            used""")

    _target = Instance(modules.Volume, ())

    __last_vrange = Any(None)

    ######################################################################
    # Non-public interface.
    ######################################################################
    def _color_changed(self):
        if not self.color:
            return
        range_min, range_max = self._target.current_range
        from tvtk.util.ctf import ColorTransferFunction
        ctf = ColorTransferFunction()
        try:
            ctf.range = (range_min, range_max)
        except Exception:
            # VTK versions < 5.2 don't seem to need this.
            pass

        r, g, b = self.color
        ctf.add_rgb_point(range_min, r, g, b)
        ctf.add_rgb_point(range_max, r, g, b)

        self._target._ctf = ctf
        self._target._volume_property.set_color(ctf)
        self._target.update_ctf = True

    def _vmin_changed(self):
        vmin = self.vmin
        vmax = self.vmax
        range_min, range_max = self._target.current_range
        if vmin is None:
            vmin = range_min
        if vmax is None:
            vmax = range_max

        # Change the opacity function
        from tvtk.util.ctf import PiecewiseFunction, save_ctfs

        otf = PiecewiseFunction()
        if range_min < vmin:
            otf.add_point(range_min, 0.)
        if range_max > vmax:
            otf.add_point(range_max, 0.2)
        otf.add_point(vmin, 0.)
        otf.add_point(vmax, 0.2)
        self._target._otf = otf
        self._target._volume_property.set_scalar_opacity(otf)
        if self.color is None and \
           ((self.vmin is not None) or (self.vmax is not None)):
            # FIXME: We don't use 'rescale_ctfs' because it screws up the
            # nodes, this is because, the values are actually scaled between
            # the specified vmin/vmax and NOT the full range of values
            # specified in the CTF or in the volume object.
            if self.__last_vrange:
                last_min, last_max = self.__last_vrange
            else:
                last_min, last_max = range_min, range_max

            def _rescale_value(x):
                nx = (x - last_min) / (last_max - last_min)
                return vmin + nx * (vmax - vmin)

            # For some reason on older versions of VTK (< 8.1 at least),
            # The range trait is not updated correctly when the rgb points
            # are added, this causes problems so we explicitly update them.
            self._target._ctf.update_traits()
            scale_min, scale_max = self._target._ctf.range

            def _rescale_node(x):
                nx = (x - scale_min) / (scale_max - scale_min)
                return range_min + nx * (range_max - range_min)

            if hasattr(self._target._ctf, 'nodes'):
                rgb = list()
                for value in self._target._ctf.nodes:
                    r, g, b = \
                            self._target._ctf.get_color(value)
                    rgb.append((_rescale_node(value), r, g, b))
            else:
                rgb = save_ctfs(self._target.volume_property)['rgb']

            from tvtk.util.ctf import ColorTransferFunction
            ctf = ColorTransferFunction()
            try:
                ctf.range = (range_min, range_max)
            except Exception:
                # VTK versions < 5.2 don't seem to need this.
                pass
            rgb.sort()
            v = rgb[0]
            ctf.add_rgb_point(range_min, v[1], v[2], v[3])
            for v in rgb:
                ctf.add_rgb_point(_rescale_value(v[0]), v[1], v[2], v[3])
            ctf.add_rgb_point(range_max, v[1], v[2], v[3])

            self._target._ctf = ctf
            self._target._volume_property.set_color(ctf)
            self.__last_vrange = vmin, vmax

        self._target.update_ctf = True

    # This is not necessary: the job is already done by _vmin_changed
    _vmax_changed = _vmin_changed
예제 #32
0
class ODMR(ManagedJob, GetSetItemsMixin):
    """Provides ODMR measurements."""

    # starting and stopping
    keep_data = Bool(
        False)  # helper variable to decide whether to keep existing data
    resubmit_button = Button(
        label='resubmit',
        desc=
        'Submits the measurement to the job manager. Tries to keep previously acquired data. Behaves like a normal submit if sequence or time bins have changed since previous run.'
    )

    # measurement parameters
    """switch      = Enum( 'mw_a', 'mw_b','mw_c',   desc='switch to use for different microwave source',     label='switch' )"""
    power = Range(low=-100.,
                  high=25.,
                  value=-12,
                  desc='Power [dBm]',
                  label='Power [dBm]',
                  mode='text',
                  auto_set=False,
                  enter_set=True)
    frequency_begin = Range(low=1,
                            high=20e9,
                            value=2.82e9,
                            desc='Start Frequency [Hz]',
                            label='Begin [Hz]',
                            editor=TextEditor(auto_set=False,
                                              enter_set=True,
                                              evaluate=float,
                                              format_str='%e'))
    frequency_end = Range(low=1,
                          high=20e9,
                          value=2.88e9,
                          desc='Stop Frequency [Hz]',
                          label='End [Hz]',
                          editor=TextEditor(auto_set=False,
                                            enter_set=True,
                                            evaluate=float,
                                            format_str='%e'))
    frequency_delta = Range(low=1e-3,
                            high=20e9,
                            value=1e6,
                            desc='frequency step [Hz]',
                            label='Delta [Hz]',
                            editor=TextEditor(auto_set=False,
                                              enter_set=True,
                                              evaluate=float,
                                              format_str='%e'))
    t_pi = Range(low=1.,
                 high=100000.,
                 value=1000.,
                 desc='length of pi pulse [ns]',
                 label='pi [ns]',
                 mode='text',
                 auto_set=False,
                 enter_set=True)
    laser = Range(low=1.,
                  high=10000.,
                  value=300.,
                  desc='laser [ns]',
                  label='laser [ns]',
                  mode='text',
                  auto_set=False,
                  enter_set=True)
    wait = Range(low=1.,
                 high=10000.,
                 value=1000.,
                 desc='wait [ns]',
                 label='wait [ns]',
                 mode='text',
                 auto_set=False,
                 enter_set=True)
    pulsed = Bool(False, label='pulsed', enabled_when='state != "run"')
    sequence = Property(trait=List, depends_on='laser,wait,t_pi')
    seconds_per_point = Range(low=20e-3,
                              high=1,
                              value=20e-3,
                              desc='Seconds per point',
                              label='Seconds per point',
                              mode='text',
                              auto_set=False,
                              enter_set=True)
    stop_time = Range(
        low=1.,
        value=np.inf,
        desc='Time after which the experiment stops by itself [s]',
        label='Stop time [s]',
        mode='text',
        auto_set=False,
        enter_set=True)
    n_lines = Range(low=1,
                    high=10000,
                    value=50,
                    desc='Number of lines in Matrix',
                    label='Matrix lines',
                    mode='text',
                    auto_set=False,
                    enter_set=True)

    # control data fitting
    perform_fit = Bool(False, label='perform fit')
    number_of_resonances = Trait(
        'auto', String('auto', auto_set=False, enter_set=True),
        Int(10000.,
            desc='Number of Lorentzians used in fit',
            label='N',
            auto_set=False,
            enter_set=True))
    threshold = Range(
        low=-99,
        high=99.,
        value=-50.,
        desc=
        'Threshold for detection of resonances [%]. The sign of the threshold specifies whether the resonances are negative or positive.',
        label='threshold [%]',
        mode='text',
        auto_set=False,
        enter_set=True)

    # fit result
    fit_parameters = Array(value=np.array((np.nan, np.nan, np.nan, np.nan)))
    fit_frequencies = Array(value=np.array((np.nan, )),
                            label='frequencies [Hz]')
    fit_line_width = Float(np.nan,
                           label='line width [Hz]',
                           editor=TextEditor(evaluate=float,
                                             format_str='%.3e'))
    fit_contrast = Float(np.nan,
                         label='contrast [%]',
                         editor=TextEditor(evaluate=float, format_str='%.1f'))

    # measurement data
    frequency = Array()
    counts = Array()
    counts_matrix = Array()
    run_time = Float(value=0.0, desc='Run time [s]', label='Run time [s]')

    # plotting
    line_label = Instance(PlotLabel)
    line_data = Instance(ArrayPlotData)
    matrix_data = Instance(ArrayPlotData)
    line_plot = Instance(Plot, editor=ComponentEditor())
    matrix_plot = Instance(Plot, editor=ComponentEditor())

    def __init__(self):
        super(ODMR, self).__init__()
        self._create_line_plot()
        self._create_matrix_plot()
        self.on_trait_change(self._update_line_data_index,
                             'frequency',
                             dispatch='ui')
        self.on_trait_change(self._update_line_data_value,
                             'counts',
                             dispatch='ui')
        self.on_trait_change(self._update_line_data_fit,
                             'fit_parameters',
                             dispatch='ui')
        self.on_trait_change(self._update_matrix_data_value,
                             'counts_matrix',
                             dispatch='ui')
        self.on_trait_change(self._update_matrix_data_index,
                             'n_lines,frequency',
                             dispatch='ui')

    def _counts_matrix_default(self):
        return np.zeros((self.n_lines, len(self.frequency)))

    def _frequency_default(self):
        return np.arange(self.frequency_begin,
                         self.frequency_end + self.frequency_delta,
                         self.frequency_delta)

    def _counts_default(self):
        return np.zeros(self.frequency.shape)

    # data acquisition

    def apply_parameters(self):
        """Apply the current parameters and decide whether to keep previous data."""
        frequency = np.arange(self.frequency_begin,
                              self.frequency_end + self.frequency_delta,
                              self.frequency_delta)

        if not self.keep_data or np.any(frequency != self.frequency):
            self.counts = np.zeros(frequency.shape)
            self.run_time = 0.0

        self.frequency = frequency
        self.keep_data = True  # when job manager stops and starts the job, data should be kept. Only new submission should clear data.

    def _run(self):

        try:
            self.state = 'run'
            self.apply_parameters()

            if self.run_time >= self.stop_time:
                self.state = 'done'
                return

            # if pulsed, turn on sequence
            if self.pulsed:
                ha.PulseGenerator().Sequence(100 *
                                             [(['laser', 'aom'], self.laser),
                                              ([], self.wait),
                                              (['mw'], self.t_pi)])
            else:
                ha.PulseGenerator().Open()

            n = len(self.frequency)
            """
            ha.MicrowaveB().setOutput( self.power, np.append(self.frequency,self.frequency[0]), self.seconds_per_point)
            self._prepareCounter(n)
            """
            ha.MicrowaveB().setPower(self.power)
            ha.MicrowaveB().initSweep(
                self.frequency, self.power * np.ones(self.frequency.shape))
            ha.CounterB().configure(n, self.seconds_per_point, DutyCycle=0.8)
            time.sleep(0.5)

            while self.run_time < self.stop_time:
                start_time = time.time()
                if threading.currentThread().stop_request.isSet():
                    break
                ha.MicrowaveB().resetListPos()
                counts = ha.CounterB().run()
                self.run_time += time.time() - start_time
                self.counts += counts
                self.counts_matrix = np.vstack(
                    (counts, self.counts_matrix[:-1, :]))
                self.trait_property_changed('counts', self.counts)
                """
                ha.MicrowaveB().doSweep()
                
                timeout = 3.
                start_time = time.time()
                while not self._count_between_markers.ready():
                    time.sleep(0.1)
                    if time.time() - start_time > timeout:
                        print "count between markers timeout in ODMR"
                        break
                        
                counts = self._count_between_markers.getData(0)
                self._count_between_markers.clean()
                """

            if self.run_time < self.stop_time:
                self.state = 'idle'
            else:
                self.state = 'done'
            ha.MicrowaveB().setOutput(None, self.frequency_begin)
            ha.PulseGenerator().Light()
            ha.CounterB().clear()
        except:
            logging.getLogger().exception('Error in odmr.')
            self.state = 'error'

    # fitting

    @on_trait_change('counts,perform_fit,number_of_resonances,threshold')
    def update_fit(self):
        if self.perform_fit:
            N = self.number_of_resonances
            if N != 'auto':
                N = int(N)
            try:
                p = fitting.fit_multiple_lorentzians(self.frequency,
                                                     self.counts,
                                                     N,
                                                     threshold=self.threshold *
                                                     0.01)
            except Exception:
                logging.getLogger().debug('ODMR fit failed.', exc_info=True)
                p = np.nan * np.empty(4)
        else:
            p = np.nan * np.empty(4)
        self.fit_parameters = p
        self.fit_frequencies = p[1::3]
        self.fit_line_width = p[2::3].mean()
        self.fit_contrast = -100 * p[3::3].mean() / (np.pi * p[2::3].mean() *
                                                     p[0])

    # plotting

    def _create_line_plot(self):
        line_data = ArrayPlotData(frequency=np.array((0., 1.)),
                                  counts=np.array((0., 0.)),
                                  fit=np.array((0., 0.)))
        line_plot = Plot(line_data,
                         padding=8,
                         padding_left=64,
                         padding_bottom=32)
        line_plot.plot(('frequency', 'counts'), style='line', color='blue')
        line_plot.index_axis.title = 'Frequency [MHz]'
        line_plot.value_axis.title = 'Fluorescence counts'
        line_label = PlotLabel(text='',
                               hjustify='left',
                               vjustify='bottom',
                               position=[64, 32])
        line_plot.overlays.append(line_label)
        self.line_label = line_label
        self.line_data = line_data
        self.line_plot = line_plot

    def _create_matrix_plot(self):
        matrix_data = ArrayPlotData(image=np.zeros((2, 2)))
        matrix_plot = Plot(matrix_data,
                           padding=8,
                           padding_left=64,
                           padding_bottom=32)
        matrix_plot.index_axis.title = 'Frequency [MHz]'
        matrix_plot.value_axis.title = 'line #'
        matrix_plot.img_plot('image',
                             xbounds=(self.frequency[0], self.frequency[-1]),
                             ybounds=(0, self.n_lines),
                             colormap=Spectral)
        self.matrix_data = matrix_data
        self.matrix_plot = matrix_plot

    def _perform_fit_changed(self, new):
        plot = self.line_plot
        if new:
            plot.plot(('frequency', 'fit'),
                      style='line',
                      color='red',
                      name='fit')
            self.line_label.visible = True
        else:
            plot.delplot('fit')
            self.line_label.visible = False
        plot.request_redraw()

    def _update_line_data_index(self):
        self.line_data.set_data('frequency', self.frequency * 1e-6)
        self.counts_matrix = self._counts_matrix_default()

    def _update_line_data_value(self):
        self.line_data.set_data('counts', self.counts)

    def _update_line_data_fit(self):
        if not np.isnan(self.fit_parameters[0]):
            self.line_data.set_data(
                'fit',
                fitting.NLorentzians(*self.fit_parameters)(self.frequency))
            p = self.fit_parameters
            f = p[1::3]
            w = p[2::3]
            c = 100 * p[3::3] / (np.pi * w * p[0])
            s = ''
            for i, fi in enumerate(f):
                s += 'f %i: %.6e Hz, HWHM %.3e Hz, contrast %.1f%%\n' % (
                    i + 1, fi, w[i], c[i])
            self.line_label.text = s

    def _update_matrix_data_value(self):
        self.matrix_data.set_data('image', self.counts_matrix)

    def _update_matrix_data_index(self):
        if self.n_lines > self.counts_matrix.shape[0]:
            self.counts_matrix = np.vstack(
                (self.counts_matrix,
                 np.zeros((self.n_lines - self.counts_matrix.shape[0],
                           self.counts_matrix.shape[1]))))
        else:
            self.counts_matrix = self.counts_matrix[:self.n_lines]
        self.matrix_plot.components[0].index.set_data(
            (self.frequency[0] * 1e-6, self.frequency[-1] * 1e-6),
            (0.0, float(self.n_lines)))

    # saving data

    def save_line_plot(self, filename):
        self.save_figure(self.line_plot, filename)

    def save_matrix_plot(self, filename):
        self.save_figure(self.matrix_plot, filename)

    def save_all(self, filename):
        self.save_line_plot(filename + '_ODMR_Line_Plot.png')
        self.save_matrix_plot(filename + '_ODMR_Matrix_Plot.png')
        self.save(filename + '_ODMR.pys')

    # react to GUI events

    def submit(self):
        """Submit the job to the JobManager."""
        self.keep_data = False
        ManagedJob.submit(self)

    def resubmit(self):
        """Submit the job to the JobManager."""
        self.keep_data = True
        ManagedJob.submit(self)

    def _resubmit_button_fired(self):
        """React to start button. Submit the Job."""
        self.resubmit()

    traits_view = View(VGroup(
        HGroup(
            Item('submit_button', show_label=False),
            Item('remove_button', show_label=False),
            Item('resubmit_button', show_label=False),
            Item('priority'),
            Item('state', style='readonly'),
            Item('run_time', style='readonly', format_str='%.f'),
        ),
        Group(
            VGroup(HGroup(
                Item('power', width=-40),
                Item('frequency_begin', width=-80),
                Item('frequency_end', width=-80),
                Item('frequency_delta', width=-80),
                Item('pulsed'),
                Item('t_pi', width=-80),
            ),
                   HGroup(
                       Item('perform_fit'),
                       Item('number_of_resonances'),
                       Item('threshold'),
                       Item('n_lines'),
                       Item('stop_time'),
                   ),
                   HGroup(
                       Item('fit_contrast', style='readonly'),
                       Item('fit_line_width', style='readonly'),
                       Item('fit_frequencies', style='readonly'),
                   ),
                   label='parameters'),
            VGroup(HGroup(Item('seconds_per_point'), ),
                   HGroup(
                       Item('laser', width=40),
                       Item('wait', width=40),
                   ),
                   label='settings'),
            layout='tabbed',
        ),
        VSplit(
            Item('matrix_plot', show_label=False, resizable=True),
            Item('line_plot', show_label=False, resizable=True),
        ),
    ),
                       menubar=MenuBar(
                           Menu(Action(action='saveLinePlot',
                                       name='SaveLinePlot (.png)'),
                                Action(action='saveMatrixPlot',
                                       name='SaveMatrixPlot (.png)'),
                                Action(action='save',
                                       name='Save (.pyd or .pys)'),
                                Action(action='saveAll',
                                       name='Save All (.png+.pys)'),
                                Action(action='export',
                                       name='Export as Ascii (.asc)'),
                                Action(action='load', name='Load'),
                                Action(action='_on_close', name='Quit'),
                                name='File')),
                       title='ODMR',
                       width=900,
                       height=800,
                       buttons=[],
                       resizable=True,
                       handler=ODMRHandler)

    get_set_items = [
        'frequency', 'counts', 'counts_matrix', 'fit_parameters',
        'fit_contrast', 'fit_line_width', 'fit_frequencies', 'perform_fit',
        'run_time', 'power', 'frequency_begin', 'frequency_end',
        'frequency_delta', 'laser', 'wait', 'pulsed', 't_pi',
        'seconds_per_point', 'stop_time', 'n_lines', 'number_of_resonances',
        'threshold', '__doc__'
    ]
예제 #33
0
    def __init__(self, default_value=None, iotype=None, desc=None, 
                 low=None, high=None, exclude_low=False, exclude_high=False, 
                 units=None, **metadata):

        _default_set = False
        
        # Determine defalt_value if unspecified
        if default_value is None:
            if low is None and high is None:
                default_value = 0.0
            elif low is None:
                default_value = high
            else:
                default_value = low
        else:
            _default_set = True
            if not isinstance(default_value, float):
                if isinstance(default_value, int):
                    default_value = float(default_value)
                else:
                    raise ValueError("Default value should be a float.")
              
        # excludes must be saved locally because we override error()
        self.exclude_low = exclude_low
        self.exclude_high = exclude_high
        
        # Put iotype in the metadata dictionary
        if iotype is not None:
            metadata['iotype'] = iotype
            
        # Put desc in the metadata dictionary
        if desc is not None:
            metadata['desc'] = desc
            
        # Put units in the metadata dictionary
        if units is not None:
            metadata['units'] = units
            
        # The Range trait must be used if High or Low is set
        if low is None and high is None:
            self._validator = TraitFloat(default_value, **metadata)
        else:
            if low is None:
                low = -float_info.max
            else:
                low = float(low)
                
            if high is None:
                high = float_info.max
            else:
                high = float(high)

            if low > high:
                raise ValueError("Lower bound is greater than upper bound.")
        
            if default_value > high or default_value < low:
                raise ValueError("Default value is outside of bounds [%s, %s]." %
                                 (str(low), str(high)))
                     
            # Range can be float or int, so we need to force these to be float.
            default_value = float(default_value)
                
            self._validator = Range(low=low, high=high, value=default_value,
                                          exclude_low=exclude_low,
                                          exclude_high=exclude_high,
                                          **metadata)
            
        # If there are units, test them by creating a physical quantity
        if 'units' in metadata:
            try:
                pq = PhysicalQuantity(0., metadata['units'])
            except:
                raise ValueError("Units of '%s' are invalid" %
                                 metadata['units'])
            
        # Add low and high to the trait's dictionary so they can be accessed
        metadata['low'] = low
        metadata['high'] = high
        if not _default_set and metadata.get('required') == True:
            super(Float, self).__init__(**metadata)
        else:
            super(Float, self).__init__(default_value=default_value,
                                        **metadata)
예제 #34
0
class Int(Variable):
    """A variable wrapper for an integer valid within a
       specified range of values.
       """

    def __init__(self, default_value=None, iotype=None, desc=None,
                 low=None, high=None, exclude_low=False, exclude_high=False,
                 **metadata):

        # Range trait didn't seem to handle "None" correctly when passed on
        # the  command line.
        assumed_default = False
        if default_value is None:
            assumed_default = True
            if low is None and high is None:
                default_value = 0
            elif low is None:
                default_value = high
            else:
                default_value = low

        if low is None:
            low = -maxint
        if high is None:
            high = maxint

        if not isinstance(default_value, int):
            raise ValueError("Default value for an Int must be an integer.")

        if not isinstance(low, int):
            raise ValueError("Lower bound for an Int must be an integer.")

        if not isinstance(high, int):
            raise ValueError("Upper bound for an Int must be an integer.")

        if low > high:
            raise ValueError("Lower bound is greater than upper bound.")

        if default_value > high or default_value < low:
            raise ValueError("Default value is outside of bounds [%s, %s]." %
                             (str(low), str(high)))

        # Put iotype in the metadata dictionary
        if iotype is not None:
            metadata['iotype'] = iotype

        # Put desc in the metadata dictionary
        if desc is not None:
            metadata['desc'] = desc

        if 'assumed_default' in metadata:
            del metadata['assumed_default']

        self._validator = Range(value=default_value, low=low,
                                high=high, exclude_low=exclude_low,
                                exclude_high=exclude_high, **metadata)

        # Add low and high to the trait's dictionary so they can be accessed
        metadata['low'] = low
        metadata['high'] = high
        metadata['exclude_low'] = exclude_low
        metadata['exclude_high'] = exclude_high

        super(Int, self).__init__(default_value=default_value,
                                  assumed_default=assumed_default, **metadata)

    def validate(self, obj, name, value):
        """ Validates that a specified value is valid for this trait."""
        try:
            return self._validator.validate(obj, name, value)
        except Exception:
            self.error(obj, name, value)

    def error(self, obj, name, value):
        """Returns a descriptive error string."""

        # pylint: disable=E1101
        right = left = '='
        if self.exclude_high is True:
            right = ''
        if self.exclude_low is True:
            left = ''

        if self.low is None and self.high is None:
            info = "an int"
        elif self.low is not None and self.high is not None:
            info = "%s <%s an integer <%s %s"% (self.low, left,
                                                right, self.high)
        elif self.low is not None:
            info = "a float with a value >%s %s"% (left, self.low)
        else: # self.high is not None
            info = "a float with a value <%s %s"% (right, self.high)

        vtype = type(value)
        msg = "Variable '%s' must be %s, but a value of %s %s was specified." % \
                               (name, info, value, vtype)
        try:
            obj.raise_exception(msg, ValueError)
        except AttributeError:
            raise ValueError(msg)