Exemple #1
0
class Model(HasTraits):

    #Traits view definitions:
    traits_view = View(Group(
        Item('function'),
        HGroup(Item('npts_x', label="Number X Points"),
               Item('npts_y', label="Number Y Points")),
        HGroup(Item('min_x', label="Min X value"),
               Item('max_x', label="Max X value")),
        HGroup(Item('min_y', label="Min Y value"),
               Item('max_y', label="Max Y value"))),
                       buttons=["OK", "Cancel"])

    function = Str("tanh(x**2+y)*cos(y)*jn(0,x+y*2)")

    npts_x = CInt(400)
    npts_y = CInt(200)

    min_x = CFloat(-2 * pi)
    max_x = CFloat(2 * pi)
    min_y = CFloat(-1.5 * pi)
    max_y = CFloat(1.5 * pi)

    xs = Array
    ys = Array
    zs = Array

    minz = Float
    maxz = Float

    model_changed = Event

    def __init__(self, *args, **kwargs):
        super(Model, self).__init__(*args, **kwargs)
        self.compute_model()

    def compute_model(self):
        # The xs and ys used for the image plot range need to be the
        # edges of the cells.
        self.xs = linspace(self.min_x, self.max_x, self.npts_x + 1)
        self.ys = linspace(self.min_y, self.max_y, self.npts_y + 1)

        # The grid of points at which we will evaluate the 2D function
        # is located at cell centers, so use halfsteps from the
        # min/max values (which are edges)
        xstep = (self.max_x - self.min_x) / self.npts_x
        #ystep = (self.max_y - self.min_y) / self.npts_y
        gridx = linspace(self.min_x + xstep / 2, self.max_x - xstep / 2,
                         self.npts_x)
        gridy = linspace(self.min_y + xstep / 2, self.max_y - xstep / 2,
                         self.npts_y)
        x, y = meshgrid(gridx, gridy)
        try:
            d = dict(x=x, y=y)
            exec("from scipy import *", d)
            exec("from scipy.special import *", d)
            self.zs = eval(self.function, d)
            self.minz = nanmin(self.zs)
            self.maxz = nanmax(self.zs)
            self.model_changed = True
            self._function = self.function
        except:
            self.set(function=self._function, trait_change_notify=False)

    def _anytrait_changed(self, name, value):
        if name in [
                'function', 'npts_x', 'npts_y', 'min_x', 'max_x', 'min_y',
                'max_y'
        ]:
            self.compute_model()
Exemple #2
0
class ProfileResults(HasTraits):
    """ Display profiling results.
    """

    # The sorted list of Records that mirrors this dictionary.
    records = List()
    selected_record = Any()
    dclicked = Event()
    column_clicked = Event()

    # The total time in seconds for the set of records.
    total_time = Float(1.0)

    # The column name to sort on.
    sort_key = Str('inline_time')
    sort_ascending = Bool(False)

    adapter = Instance(ProfileAdapter)
    basenames = Bool(True)
    percentages = Bool(True)

    def trait_view(self, name=None, view_element=None):
        if name or view_element is not None:
            return super(ProfileResults,
                         self).trait_view(name=name, view_element=view_element)

        view = tui.View(
            tui.Group(tui.Item('total_time', style='readonly'), ),
            tui.Item('records',
                     editor=get_profile_editor(self.adapter),
                     show_label=False),
            width=1024,
            height=768,
            resizable=True,
        )
        return view

    def sorter(self, record):
        """ Return the appropriate sort key for sorting the records.
        """
        return getattr(record, self.sort_key)

    def sort_records(self, records):
        """ Resort the records according to the current settings.
        """
        records = sorted(records, key=self.sorter)
        if not self.sort_ascending:
            records = records[::-1]
        return records

    def _adapter_default(self):
        return ProfileAdapter(basenames=self.basenames,
                              percentages=self.percentages,
                              total_time=self.total_time)

    @on_trait_change('total_time,percentages,basenames')
    def _adapter_traits_changed(self, object, name, old, new):
        setattr(self.adapter, name, new)

    @on_trait_change('sort_key,sort_ascending')
    def _resort(self):
        self.records = self.sort_records(self.records)

    def _column_clicked_changed(self, new):
        if new is None:
            return
        if isinstance(new.column, int):
            key = profile_columns[new.column][1]
        else:
            key = new.column
        if key == self.sort_key:
            # Just flip the order.
            self.sort_ascending = not self.sort_ascending
        else:
            self.trait_set(sort_ascending=False, sort_key=key)
Exemple #3
0
class RuleTableFilter(TableFilter):
    """ A table filter based on rules.
    """

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

    # Overrides the default **name** trait
    name = 'Default rule-based filter'

    # List of the filter rules to be applied
    rules = List(GenericTableFilterRule)

    # Event fired when the contents of the filter have changed
    modified = Event

    # Persistence ID of the view
    view_id = Str('traitsui.table_filter.RuleTableFilter')

    # Sample object that the filter will apply to
    _object = Any

    # Map of trait names and default values
    _trait_values = Any

    #-------------------------------------------------------------------------
    #  Traits view definitions:
    #-------------------------------------------------------------------------

    error_view = View(
        Item(label='A menu or rule based filter can only be created for '
             'tables with at least one entry'),
        title='Error Creating Filter',
        kind='livemodal',
        close_result=False,
        buttons=['Cancel'])

    #-------------------------------------------------------------------------
    #  Returns whether a specified object meets the filter/search criteria:
    #  (Should normally be overridden)
    #-------------------------------------------------------------------------

    def filter(self, object):
        """ Returns whether a specified object meets the filter or search
        criteria.
        """
        is_first = is_true = True
        for rule in self.rules:
            if rule.and_or == 'or':
                if is_true and (not is_first):
                    return True
                is_true = True
            if is_true:
                is_true = rule.is_true(object)
            is_first = False
        return is_true

    #-------------------------------------------------------------------------
    #  Returns a user readable description of what kind of object will
    #  satisfy the filter:
    #  (Should normally be overridden):
    #-------------------------------------------------------------------------

    def description(self):
        """ Returns a user-readable description of the kind of object that
            satisfies the filter.
        """
        ors = []
        ands = []
        if len(self.rules) > 0:
            for rule in self.rules:
                if rule.and_or == 'or':
                    if len(ands) > 0:
                        ors.append(' and '.join(ands))
                        ands = []
                ands.append(rule.description())

        if len(ands) > 0:
            ors.append(' and '.join(ands))

        if len(ors) == 1:
            return ors[0]

        if len(ors) > 1:
            return ' or '.join(['(%s)' % t for t in ors])

        return super(RuleTableFilter, self).description()

    #-------------------------------------------------------------------------
    #  Edits the contents of the filter:
    #-------------------------------------------------------------------------

    def edit_view(self, object):
        """ Return a view to use for editing the filter.

        The ''object'' parameter is a sample object for the table that the
        filter will be applied to. It is supplied in case the filter needs to
        extract data or metadata from the object. If the table is empty, the
        ''object'' argument is None.
        """
        self._object = object
        if object is None:
            return self.edit_traits(view='error_view')

        names = object.editable_traits()
        self._trait_values = object.get(names)
        return View([['name{Filter name}', '_'],
                     [
                         Item('rules',
                              id='rules_table',
                              editor=self._get_table_editor(names)), '|<>'
                     ]],
                    id=self.view_id,
                    title='Edit Filter',
                    kind='livemodal',
                    resizable=True,
                    buttons=['OK', 'Cancel'],
                    width=0.4,
                    height=0.3)

    #-------------------------------------------------------------------------
    #  Returns a table editor to use for editing the filter:
    #-------------------------------------------------------------------------

    def _get_table_editor(self, names):
        """ Returns a table editor to use for editing the filter.
        """
        from .api import TableEditor

        return TableEditor(columns=generic_table_filter_rule_columns,
                           orientation='vertical',
                           deletable=True,
                           sortable=False,
                           configurable=False,
                           auto_size=False,
                           auto_add=True,
                           row_factory=GenericTableFilterRule,
                           row_factory_kw={
                               'filter': self,
                               'name_editor': EnumEditor(values=names)
                           })

    #-------------------------------------------------------------------------
    #  Returns the state to be pickled (override of object):
    #-------------------------------------------------------------------------

    def __getstate__(self):
        """ Returns the state to be pickled.

        This definition overrides **object**.
        """
        dict = self.__dict__.copy()
        if '_object' in dict:
            del dict['_object']
            del dict['_trait_values']
        return dict

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

    def _rules_changed(self, rules):
        """ Handles a change to the **rules** trait.
        """
        for rule in rules:
            rule.filter = self
class Company(HasTraits):
    name = Str('<unknown>')
    departments = List(Department)
    employees = List(Employee)
Exemple #5
0
class IC(BaseModule):
    """IC"""
    TestFactors = ListStr(arg_type="MultiOption", label="测试因子", order=0, option_range=())
    FactorOrder = Dict(key_trait=Str(), value_trait=Enum("降序", "升序"), arg_type="ArgDict", label="排序方向", order=1)
    #PriceFactor = Enum(None, arg_type="SingleOption", label="价格因子", order=2)
    #IndustryFactor = Enum("无", arg_type="SingleOption", label="行业因子", order=3)
    #WeightFactor = Enum("等权", arg_type="SingleOption", label="权重因子", order=4)
    CalcDTs = List(dt.datetime, arg_type="DateList", label="计算时点", order=5)
    LookBack = Int(1, arg_type="Integer", label="回溯期数", order=6)
    CorrMethod = Enum("spearman", "pearson", "kendall", arg_type="SingleOption", label="相关性算法", order=7)
    IDFilter = Str(arg_type="IDFilter", label="筛选条件", order=8)
    RollAvgPeriod = Int(12, arg_type="Integer", label="滚动平均期数", order=9)
    def __init__(self, factor_table, name="IC", sys_args={}, **kwargs):
        self._FactorTable = factor_table
        super().__init__(name=name, sys_args=sys_args, **kwargs)
    def __QS_initArgs__(self):
        DefaultNumFactorList, DefaultStrFactorList = getFactorList(dict(self._FactorTable.getFactorMetaData(key="DataType")))
        self.add_trait("TestFactors", ListStr(arg_type="MultiOption", label="测试因子", order=0, option_range=tuple(DefaultNumFactorList)))
        self.TestFactors.append(DefaultNumFactorList[0])
        self.add_trait("PriceFactor", Enum(*DefaultNumFactorList, arg_type="SingleOption", label="价格因子", order=2))
        self.PriceFactor = searchNameInStrList(DefaultNumFactorList, ['价','Price','price'])
        self.add_trait("IndustryFactor", Enum(*(["无"]+DefaultStrFactorList), arg_type="SingleOption", label="行业因子", order=3))
        self.add_trait("WeightFactor", Enum(*(["等权"]+DefaultNumFactorList), arg_type="SingleOption", label="权重因子", order=4))
    @on_trait_change("TestFactors[]")
    def _on_TestFactors_changed(self, obj, name, old, new):
        self.FactorOrder = {iFactorName:self.FactorOrder.get(iFactorName, "降序") for iFactorName in self.TestFactors}
    def getViewItems(self, context_name=""):
        Items, Context = super().getViewItems(context_name=context_name)
        Items[0].editor = SetEditor(values=self.trait("TestFactors").option_range)
        return (Items, Context)
    def __QS_start__(self, mdl, dts, **kwargs):
        if self._isStarted: return ()
        super().__QS_start__(mdl=mdl, dts=dts, **kwargs)
        self._Output = {}
        self._Output["IC"] = {iFactorName:[] for iFactorName in self.TestFactors}
        self._Output["股票数"] = {iFactorName:[] for iFactorName in self.TestFactors}
        self._Output["时点"] = []
        self._CurCalcInd = 0
        return (self._FactorTable, )
    def __QS_move__(self, idt, **kwargs):
        if self._iDT==idt: return 0
        self._iDT = idt
        if self.CalcDTs:
            if idt not in self.CalcDTs[self._CurCalcInd:]: return 0
            self._CurCalcInd = self.CalcDTs[self._CurCalcInd:].index(idt) + self._CurCalcInd
            PreInd = self._CurCalcInd - self.LookBack
            LastInd = self._CurCalcInd - 1
            PreDateTime = self.CalcDTs[PreInd]
            LastDateTime = self.CalcDTs[LastInd]
        else:
            self._CurCalcInd = self._Model.DateTimeIndex
            PreInd = self._CurCalcInd - self.LookBack
            LastInd = self._CurCalcInd - 1
            PreDateTime = self._Model.DateTimeSeries[PreInd]
            LastDateTime = self._Model.DateTimeSeries[LastInd]
        if (PreInd<0) or (LastInd<0):
            for iFactorName in self.TestFactors:
                self._Output["IC"][iFactorName].append(np.nan)
                self._Output["股票数"][iFactorName].append(np.nan)
            self._Output["时点"].append(idt)
            return 0
        PreIDs = self._FactorTable.getFilteredID(idt=PreDateTime, id_filter_str=self.IDFilter)
        FactorExpose = self._FactorTable.readData(dts=[PreDateTime], ids=PreIDs, factor_names=list(self.TestFactors)).iloc[:, 0, :]
        Price = self._FactorTable.readData(dts=[LastDateTime, idt], ids=PreIDs, factor_names=[self.PriceFactor]).iloc[0, :, :]
        Ret = Price.iloc[-1] / Price.iloc[0] - 1
        if self.IndustryFactor!="无":# 进行收益率的行业调整
            IndustryData = self._FactorTable.readData(dts=[LastDateTime], ids=PreIDs, factor_names=[self.IndustryFactor]).iloc[0, 0, :]
            AllIndustry = IndustryData.unique()
            if self.WeightFactor=="等权":
                for iIndustry in AllIndustry:
                    iMask = (IndustryData==iIndustry)
                    Ret[iMask] -= Ret[iMask].mean()
            else:
                WeightData = self._FactorTable.readData(dts=[LastDateTime], ids=PreIDs, factor_names=[self.WeightFactor]).iloc[0, 0, :]
                for iIndustry in AllIndustry:
                    iMask = (IndustryData==iIndustry)
                    iWeight = WeightData[iMask]
                    iRet = Ret[iMask]
                    Ret[iMask] -= (iRet*iWeight).sum() / iWeight[pd.notnull(iWeight) & pd.notnull(iRet)].sum(skipna=False)
        for iFactorName in self.TestFactors:
            self._Output["IC"][iFactorName].append(FactorExpose[iFactorName].corr(Ret, method=self.CorrMethod))
            self._Output["股票数"][iFactorName].append(pd.notnull(FactorExpose[iFactorName]).sum())
        self._Output["时点"].append(idt)
        return 0
    def __QS_end__(self):
        if not self._isStarted: return 0
        super().__QS_end__()
        CalcDateTimes = self._Output.pop("时点")
        self._Output["股票数"] = pd.DataFrame(self._Output["股票数"], index=CalcDateTimes)
        self._Output["IC"] = pd.DataFrame(self._Output["IC"], index=CalcDateTimes)
        for i, iFactorName in enumerate(self.TestFactors):
            if self.FactorOrder[iFactorName]=="升序": self._Output["IC"][iFactorName] = -self._Output["IC"][iFactorName]
        self._Output["IC的移动平均"] = self._Output["IC"].copy()
        for i in range(len(CalcDateTimes)):
            if i<self.RollAvgPeriod-1: self._Output["IC的移动平均"].iloc[i,:] = np.nan
            else: self._Output["IC的移动平均"].iloc[i,:] = self._Output["IC"].iloc[i-self.RollAvgPeriod+1:i+1, :].mean()
        self._Output["统计数据"] = pd.DataFrame(index=self._Output["IC"].columns)
        self._Output["统计数据"]["平均值"] = self._Output["IC"].mean()
        self._Output["统计数据"]["标准差"] = self._Output["IC"].std()
        self._Output["统计数据"]["最小值"] = self._Output["IC"].min()
        self._Output["统计数据"]["最大值"] = self._Output["IC"].max()
        self._Output["统计数据"]["IC_IR"] = self._Output["统计数据"]["平均值"] / self._Output["统计数据"]["标准差"]
        self._Output["统计数据"]["t统计量"] = np.nan
        self._Output["统计数据"]["平均股票数"] = self._Output["股票数"].mean()
        self._Output["统计数据"]["IC×Sqrt(N)"] = self._Output["统计数据"]["平均值"]*np.sqrt(self._Output["统计数据"]["平均股票数"])
        self._Output["统计数据"]["有效期数"] = 0.0
        for iFactor in self._Output["IC"]: self._Output["统计数据"].loc[iFactor,"有效期数"] = pd.notnull(self._Output["IC"][iFactor]).sum()
        self._Output["统计数据"]["t统计量"] = (self._Output["统计数据"]["有效期数"]**0.5)*self._Output["统计数据"]["IC_IR"]
        return 0
    def genMatplotlibFig(self, file_path=None):
        nRow, nCol = self._Output["IC"].shape[1]//3+(self._Output["IC"].shape[1]%3!=0), min(3, self._Output["IC"].shape[1])
        Fig = plt.figure(figsize=(min(32, 16+(nCol-1)*8), 8*nRow))
        AxesGrid = gridspec.GridSpec(nRow, nCol)
        xData = np.arange(0, self._Output["IC"].shape[0])
        xTicks = np.arange(0, self._Output["IC"].shape[0], max(1, int(self._Output["IC"].shape[0]/10)))
        xTickLabels = [self._Output["IC"].index[i].strftime("%Y-%m-%d") for i in xTicks]
        yMajorFormatter = FuncFormatter(_QS_formatMatplotlibPercentage)
        for i in range(self._Output["IC"].shape[1]):
            iAxes = plt.subplot(AxesGrid[i//nCol, i%nCol])
            iAxes.yaxis.set_major_formatter(yMajorFormatter)
            iAxes.plot(xData, self._Output["IC的移动平均"].iloc[:, i].values, label="IC的移动平均", color="r", alpha=0.6, lw=3)
            iAxes.bar(xData, self._Output["IC"].iloc[:, i].values, label="IC", color="b")
            iAxes.set_xticks(xTicks)
            iAxes.set_xticklabels(xTickLabels)
            iAxes.legend(loc='best')
            iAxes.set_title(self._Output["IC"].columns[i])
        if file_path is not None: Fig.savefig(file_path, dpi=150, bbox_inches='tight')
        return Fig
    def _repr_html_(self):
        if len(self.ArgNames)>0:
            HTML = "参数设置: "
            HTML += '<ul align="left">'
            for iArgName in self.ArgNames:
                if iArgName!="计算时点":
                    HTML += "<li>"+iArgName+": "+str(self.Args[iArgName])+"</li>"
                elif self.Args[iArgName]:
                    HTML += "<li>"+iArgName+": 自定义时点</li>"
                else:
                    HTML += "<li>"+iArgName+": 所有时点</li>"
            HTML += "</ul>"
        else:
            HTML = ""
        Formatters = [_QS_formatPandasPercentage]*4+[lambda x:'{0:.4f}'.format(x)]+[lambda x:'{0:.2f}'.format(x)]*3+[lambda x:'{0:.0f}'.format(x)]
        iHTML = self._Output["统计数据"].to_html(formatters=Formatters)
        Pos = iHTML.find(">")
        HTML += iHTML[:Pos]+' align="center"'+iHTML[Pos:]
        Fig = self.genMatplotlibFig()
        # figure 保存为二进制文件
        Buffer = BytesIO()
        plt.savefig(Buffer, bbox_inches='tight')
        PlotData = Buffer.getvalue()
        # 图像数据转化为 HTML 格式
        ImgStr = "data:image/png;base64,"+base64.b64encode(PlotData).decode()
        HTML += ('<img src="%s">' % ImgStr)
        return HTML
Exemple #6
0
class Person(HasTraits):
    name = Str()
    age = Int()

    person_view = View('name', Include('extra'), 'age')
Exemple #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:
            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()
class EditedInstance(HasTraits):
    value = Str()
    traits_view = View(Item("value"), buttons=["OK"])
Exemple #9
0
class TVTKClassChooser(HasTraits):

    # The selected object, is None if no valid class_name was made.
    object = Property

    # The TVTK class name to choose.
    class_name = Str('', desc='class name of TVTK class (case sensitive)')

    # The string to search for in the class docs -- the search supports
    # 'and' and 'or' keywords.
    search = Str('', desc='string to search in TVTK class documentation '\
                          'supports the "and" and "or" keywords. '\
                          'press <Enter> to start search. '\
                          'This is case insensitive.')

    clear_search = Button

    # The class documentation.
    doc = Str(_search_help_doc)

    # Completions for the choice of class.
    completions = List(Str)

    # List of available class names as strings.
    available = List(TVTK_CLASSES)

    ########################################
    # Private traits.

    finder = Instance(DocSearch)

    n_completion = Int(25)

    ########################################
    # View related traits.

    view = View(Group(
        Item(name='class_name', editor=EnumEditor(name='available')),
        Item(name='class_name', has_focus=True),
        Item(name='search', editor=TextEditor(enter_set=True, auto_set=False)),
        Item(name='clear_search', show_label=False), Item('_'),
        Item(name='completions',
             editor=ListEditor(columns=3),
             style='readonly'),
        Item(name='doc', resizable=True, label='Documentation',
             style='custom')),
                id='tvtk_doc',
                resizable=True,
                width=800,
                height=600,
                title='TVTK class chooser',
                buttons=["OK", "Cancel"])

    ######################################################################
    # `object` interface.
    ######################################################################
    def __init__(self, **traits):
        super(TVTKClassChooser, self).__init__(**traits)
        self._orig_available = list(self.available)

    ######################################################################
    # Non-public interface.
    ######################################################################
    def _get_object(self):
        o = None
        if len(self.class_name) > 0:
            try:
                o = getattr(tvtk, self.class_name)()
            except (AttributeError, TypeError):
                pass
        return o

    def _class_name_changed(self, value):
        av = self.available
        comp = [x for x in av if x.startswith(value)]
        self.completions = comp[:self.n_completion]
        if len(comp) == 1 and value != comp[0]:
            self.class_name = comp[0]

        o = self.object
        if o is not None:
            self.doc = get_tvtk_class_doc(o)
        else:
            self.doc = _search_help_doc

    def _finder_default(self):
        return DocSearch()

    def _clear_search_fired(self):
        self.search = ''

    def _search_changed(self, value):
        if len(value) < 3:
            self.available = self._orig_available
            return

        f = self.finder
        result = f.search(str(value))
        if len(result) == 0:
            self.available = self._orig_available
        elif len(result) == 1:
            self.class_name = result[0]
        else:
            self.available = result
            self.completions = result[:self.n_completion]
Exemple #10
0
class BCDofList(BMCSTreeNode, Vis2D):
    '''
    Implements the IBC functionality for a constrained dof.
    '''
    tree_node_list = List

    tree_node_list = Property(depends_on='bcdof_list,bcdof_list_items')

    @cached_property
    def _get_tree_node_list(self):
        return self.bcdof_list

    name = Str('<unnamed>')

    node_name = Property

    def _get_node_name(self):
        s = '%s:%s=%s' % (self.var, self.slice, self.value)
        return s

    var = Enum('u', 'f', 'eps', 'sig')

    def is_essential(self):
        return self.var == 'u'

    def is_linked(self):

        return self.link_dofs != []

    def is_constrained(self):
        '''
        Return true if a DOF is either explicitly prescribed or it depends on other DOFS.
        '''
        return self.is_essential() or self.is_linked()

    def is_natural(self):
        return self.var == 'f' or self.var == 'eps' or self.var == 'sig'

    bcdof_list = List(BCDof)

    def reset(self):
        self.bcdof_list = []

    integ_domain = Enum(['global', 'local'])

    def setup(self, sctx):
        '''
        Locate the spatial context.f
        '''

    def apply_essential(self, K):

        for bcond in self.bcdof_list:
            bcond.apply_essential(K)

    def apply(self, step_flag, sctx, K, R, t_n, t_n1):

        if self.is_essential():
            for bcond in self.bcdof_list:
                bcond.apply(step_flag, sctx, K, R, t_n, t_n1)
        else:
            self.apply_natural(step_flag, sctx, K, R, t_n, t_n1)

    def apply_natural(self, step_flag, sctx, K, R, t_n, t_n1):

        raise NotImplementedError

    traits_view = View(
        VGroup(
            VSplit(
                Item('bcdof_list',
                     style='custom',
                     editor=bcond_list_editor,
                     show_label=False), ), ))

    tree_view = traits_view
class UserPerspectiveManager(HasTraits):
    """ Manages a set of user perspectives. """

    # 'UserPerspective' interface -----------------------------------------#

    # A directory on the local file system that we can read and write to at
    # will. This is used to persist window layout information, etc.
    state_location = Str()

    # Next available user perspective id.
    next_id = Property(Int)

    # Dictionary mapping perspective id to user defined perspective definition.
    id_to_perspective = Property(Dict)

    # The list of user defined perspective definitions.
    perspectives = Property(List)

    # The name of the user defined perspectives definition file.
    file_name = Property(Str)

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

    # Shadow trait for the 'id_to_perspective' property.
    _id_to_perspective = Any()

    # ------------------------------------------------------------------------
    # 'UserPerspective' interface.
    # ------------------------------------------------------------------------

    # Properties -----------------------------------------------------------

    def _get_next_id(self):
        """ Property getter. """

        # Get all of the current perspective ids:
        ids = list(self.id_to_perspective.keys())

        # If there are none:
        if len(ids) == 0:
            # Return the starting id:
            return 1

        # Else return the current highest id + 1 as the next id:
        ids.sort()

        return int(ids[-1][19:-2]) + 1

    def _get_id_to_perspective(self):
        """ Property getter. """

        if self._id_to_perspective is None:
            self._id_to_perspective = dic = {}
            try:
                fh = open(self.file_name, "r")
                for line in fh:
                    data = line.split(":", 1)
                    if len(data) == 2:
                        id, name = data[0].strip(), data[1].strip()
                        dic[id] = Perspective(
                            id=id, name=name, show_editor_area=False
                        )
                fh.close()
            except:
                pass

        return self._id_to_perspective

    def _get_perspectives(self):
        """ Property getter. """

        return list(self.id_to_perspective.values())

    def _get_file_name(self):
        """ Property getter. """

        return os.path.join(self.state_location, "__user_perspective__")

    # Methods -------------------------------------------------------------#

    def create_perspective(self, name, show_editor_area=True):
        """ Create a new (and empty) user-defined perspective. """

        perspective = Perspective(
            id="__user_perspective_%09d__" % self.next_id,
            name=name,
            show_editor_area=show_editor_area,
        )

        # Add the perspective to the map.
        self.id_to_perspective[perspective.id] = perspective

        # Update the persistent file information.
        self._update_persistent_data()

        return perspective

    def clone_perspective(self, window, perspective, **traits):
        """ Clone a perspective as a user perspective. """

        clone = perspective.clone_traits()

        # Give the clone a special user perspective Id!
        clone.id = "__user_perspective_%09d__" % self.next_id

        # Set any traits specified as keyword arguments.
        clone.trait_set(**traits)

        # Add the perspective to the map.
        self.id_to_perspective[clone.id] = clone

        # fixme: This needs to be pushed into the window API!!!!!!!
        window._memento.perspective_mementos[clone.id] = (
            window.layout.get_view_memento(),
            window.active_view and window.active_view.id or None,
            window.layout.is_editor_area_visible(),
        )

        # Update the persistent file information.
        self._update_persistent_data()

        return clone

    def save(self):
        """ Persist the current state of the user perspectives. """

        self._update_persistent_data()

    def add(self, perspective, name=None):
        """ Add a perspective with an optional name. """

        # Define the id for the new perspective:
        perspective.id = id = "__user_perspective_%09d__" % self.next_id

        # Save the new name (if specified):
        if name is not None:
            perspective.name = name

        # Create the perspective:
        self.id_to_perspective[id] = perspective

        # Update the persistent file information:
        self._update_persistent_data()

        # Return the new perspective created:
        return perspective

    def rename(self, perspective, name):
        """ Rename the user perspective with the specified id. """

        perspective.name = name

        self.id_to_perspective[perspective.id].name = name

        # Update the persistent file information:
        self._update_persistent_data()

    def remove(self, id):
        """ Remove the user perspective with the specified id.

        This method also updates the persistent data.

        """

        if id in self.id_to_perspective:
            del self.id_to_perspective[id]

            # Update the persistent file information:
            self._update_persistent_data()

            # Try to delete the associated perspective layout file:
            try:
                os.remove(os.path.join(self.state_location, id))
            except:
                pass

        return

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

    def _update_persistent_data(self):
        """ Update the persistent file information. """

        try:
            fh = open(self.file_name, "w")
            fh.write(
                "\n".join(
                    ["%s: %s" % (p.id, p.name) for p in self.perspectives]
                )
            )
            fh.close()

        except:
            logger.error(
                "Could not write the user defined perspective "
                "definition file: " + self.file_name
            )

        return
Exemple #12
0
class ExpressionContext(ListenableMixin, PersistableMixin, DictMixin):
    """Provide a context wrapper that adds the ability to request expressions on variables
    in the underlying context, and re-evaluate those expressions and fire events when the
    underlying dependencies of the variables in the expression changes"""

    name = Str('ExpressionContext')

    # The underlying context which contains variables
    # From which the expressions are calculated.
    underlying_context = AdaptsTo(IListenableContext)

    # The currently evaluated expressions, mapped to their last cached value.  None means
    # that the value is not cached.
    _expressions = Dict(Str, Any)
    # A list of variable dependencies for each expression
    _dependencies = Dict(Str, List(Str))

    def __init__(self, underlying_context, **traits):
        super(ExpressionContext, self).__init__(underlying_context=underlying_context)

    def __delitem__(self, key):
        """Delete an item from the ExpressionContext -- either in the underlying context,
        or if an already cached expression, delete it."""
        # if item is an expression, delete it from the list of dependencies, otherwise pass it down
        # to underlying
        if key in self._expressions:
            self._expressions.remove(key)
            for dep in list(Block(key).inputs):
                self._dependencies[dep].remove(key)
        else:
            del self.underlying_context[key]

    def __contains__(self, key):
        # FIXME: not sure what to do here -- maybe eval the expression in the context
        # and see if it works as an expression on this context if it's not in the underly
        # -ing
        return key in self.underlying_context

    def __getitem__(self, key):
        if key in self.underlying_context.keys():
            return self.underlying_context[key]
        else:
            try:
                # FIXME imports need to be more configurable
                # FIXME we may want to have cache rules on sizes so that we
                # don't keep around huge values that aren't needed anymore
                # however, there is a time/space tradeoff that really should be
                # used.  We currently support del so that is available if the user
                # wants to manually manage this.
                eval_globals = {}
                for lib in (__builtins__, __import__('numpy')):
                    for sym in dir(lib):
                        if not key.startswith('__'):
                            eval_globals[sym] = getattr(lib, sym)

                result = eval(key, eval_globals, self.underlying_context)
                self._expressions[key] = result
                for dep in Block(key).inputs:
                    self._dependencies.setdefault(dep, list())
                    self._dependencies[dep].append(key)
                return result
            except:
                return None

    def __setitem__(self, key, value):
        """We don't allow setting an expression per se, so it passes through
        to the underlying context.  Hopefully this won't be a problem in the
        future due to plots or other listeners trying to change values.
        Theoretically one could store the inverse of a function and allow this
        if the function was invertable"""

        self.underlying_context[key] = value
        return

    get = DictMixin.get

    def __str__(self):
        underlying_str = str(self.underlying_context)
        return '%s(%s)' % (type(self).__name__, underlying_str)

    @on_trait_change('underlying_context:items_modified')
    def _underlying_context_items_modifed(self, event):
        new_event = ItemsModified(context=self,
                                  added=[x for x in event.added],
                                  removed=[x for x in event.removed],
                                  modified=[x for x in event.modified])
        for event_list in (new_event.added, new_event.modified, new_event.removed):
            for item in event_list:
                if item in self._dependencies.keys():
                    for dep_item in self._dependencies[item]:
                        if dep_item not in event_list:
                            event_list.append(dep_item)
                        # Remove the cached value for the item
                self._expressions[item] = None
        self.items_modified = new_event
        return

    def _underlying_context_changed(self):
        self._expressions = {}
        self._dependencies = {}
        return
Exemple #13
0
class LogViewer(Controller):
    search_entry = Str(enter_set=True, auto_set=False)
    refresh_needed = Event
    use_fuzzy = Bool(True)
    use_filter = Bool(True)
    levels = List(('DEBUG', 'INFO', 'WARNING'))
    available_levels = List(('DEBUG', 'INFO', 'WARNING'))

    def init(self, info):
        info.ui.title = 'Log Viewer - {}'.format(os.path.basename(self.model.path))
        return True

    # def controller_levels_changed(self, info):
    #     if self.levels:
    #         items = filter(lambda x: x.level in self.levels, self.model.oitems)
    #         regex = self._make_search_regex()
    #         self._set_found(regex, items)

    def controller_search_entry_changed(self, info):
        regex = self._make_search_regex()
        if regex:
            self._set_found(regex, self.model.oitems)
        else:
            for i in self.model.items:
                i.found = False
        self.refresh_needed = True

    def _set_found(self, regex, items):
        if not regex:
            self.model.items = items
        else:
            if self.use_filter:
                self.model.items = filter(lambda x: regex.search(x.message), items)
            else:
                for i in items:
                    if regex.search(i.message):
                        i.found = True
                    else:
                        i.found = False
                self.model.items = items

    def _make_search_regex(self):
        v = self.search_entry
        if v:
            if self.use_fuzzy:
                pat = '.*?'.join(map(re.escape, v))
            else:
                pat = '^{}'.format(v)

            regex = re.compile(pat)
            return regex

    def traits_view(self):
        ctrlgrp = VGroup(HGroup(UItem('controller.search_entry'),
                                Item('controller.use_fuzzy'),
                                Item('controller.use_filter')),
                         HGroup(UItem('controller.levels',
                                      style='custom',
                                      editor=CheckListEditor(name='controller.available_levels',
                                                             cols=3))))

        v = View(VGroup(ctrlgrp, UItem('items', editor=TabularEditor(adapter=LogAdapter(),
                                                                     refresh='controller.refresh_needed',
                                                                     operations=[]))),
                 title='Log Viewer',
                 resizable=True,
                 width=800,
                 height=600)
        return v
class ListStrAdapter(HasPrivateTraits):
    """ The base class for adapting list items to values that can be edited
        by a ListStrEditor.
    """

    # Trait Definitions ------------------------------------------------------

    #: Specifies the default value for a new list item.
    default_value = Any("")

    #: Specifies the default text for a new list item.
    default_text = Str

    #: The default text color for even list items.
    even_text_color = Color(None, update=True)

    #: The default text color for odd list items.
    odd_text_color = Color(None, update=True)

    #: The default text color for list items.
    text_color = Color(None, update=True)

    #: The default background color for even list items.
    even_bg_color = Color(None, update=True)

    #: The default background color for odd list items.
    odd_bg_color = Color(None, update=True)

    #: The default background color for list items.
    bg_color = Color(None, update=True)

    #: The name of the default image to use for list items.
    image = Str(None, update=True)

    #: Can the text value of each list item be edited.
    can_edit = Bool(True)

    #: Specifies where a dropped item should be placed in the list relative to
    #: the item it is dropped on.
    dropped = Enum("after", "before")

    #: The index of the current item being adapter.
    index = Int

    #: The current item being adapted.
    item = Any

    #: The current value (if any).
    value = Any

    #: List of optional delegated adapters.
    adapters = List(IListStrAdapter, update=True)

    # -- Private Trait Definitions --------------------------------------------

    #: Cache of attribute handlers.
    cache = Any({})

    #: Event fired when the cache is flushed.
    cache_flushed = Event(update=True)

    # -- Adapter methods that are sensitive to item type ----------------------

    def get_can_edit(self, object, trait, index):
        """ Returns whether the user can edit a specified *object.trait[index]*
            list item. A True result indicates the value can be edited, while
            a False result indicates that it cannot be edited.
        """
        return self._result_for("get_can_edit", object, trait, index)

    def get_drag(self, object, trait, index):
        """ Returns the 'drag' value for a specified *object.trait[index]*
            list item. A result of *None* means that the item cannot be dragged.
        """
        return self._result_for("get_drag", object, trait, index)

    def get_can_drop(self, object, trait, index, value):
        """ Returns whether the specified *value* can be dropped on the
            specified *object.trait[index]* list item. A value of **True** means
            the *value* can be dropped; and a value of **False** indicates that
            it cannot be dropped.
        """
        return self._result_for("get_can_drop", object, trait, index, value)

    def get_dropped(self, object, trait, index, value):
        """ Returns how to handle a specified *value* being dropped on a
            specified *object.trait[index]* list item. The possible return
            values are:

            'before'
                Insert the specified *value* before the dropped on item.
            'after'
                Insert the specified *value* after the dropped on item.
        """
        return self._result_for("get_dropped", object, trait, index, value)

    def get_text_color(self, object, trait, index):
        """ Returns the text color for a specified *object.trait[index]* list
            item. A result of None means use the default list item text color.
        """
        return self._result_for("get_text_color", object, trait, index)

    def get_bg_color(self, object, trait, index):
        """ Returns the background color for a specified *object.trait[index]*
            list item. A result of None means use the default list item
            background color.
        """
        return self._result_for("get_bg_color", object, trait, index)

    def get_image(self, object, trait, index):
        """ Returns the name of the image to use for a specified
            *object.trait[index]* list item. A result of None means no image
            should be used. Otherwise, the result should either be the name of
            the image, or an ImageResource item specifying the image to use.
        """
        return self._result_for("get_image", object, trait, index)

    def get_item(self, object, trait, index):
        """ Returns the value of the *object.trait[index]* list item.
        """
        return self._result_for("get_item", object, trait, index)

    def get_text(self, object, trait, index):
        """ Returns the text to display for a specified *object.trait[index]*
            list item.
        """
        return self._result_for("get_text", object, trait, index)

    # -- Adapter methods that are not sensitive to item type ------------------

    def len(self, object, trait):
        """ Returns the number of items in the specified *object.trait* list.
        """
        # Sometimes, during shutdown, the object has been set to None.
        if object is None:
            return 0
        else:
            return len(getattr(object, trait))

    def get_default_value(self, object, trait):
        """ Returns a new default value for the specified *object.trait* list.
        """
        return self.default_value

    def get_default_text(self, object, trait):
        """ Returns the default text for the specified *object.trait* list.
        """
        return self.default_text

    def get_default_image(self, object, trait):
        """ Returns the default image for the specified *object.trait* list.
        """
        return self.image

    def get_default_bg_color(self, object, trait):
        """ Returns the default background color for the specified
            *object.trait* list.
        """
        return self._get_bg_color()

    def get_default_text_color(self, object, trait):
        """ Returns the default text color for the specified *object.trait*
            list.
        """
        return self._get_text_color()

    def set_text(self, object, trait, index, text):
        """ Sets the text for a specified *object.trait[index]* list item to
            *text*.
        """
        getattr(object, trait)[index] = text

    def delete(self, object, trait, index):
        """ Deletes the specified *object.trait[index]* list item.
        """
        del getattr(object, trait)[index]

    def insert(self, object, trait, index, value):
        """ Inserts a new value at the specified *object.trait[index]* list
            index.
        """
        getattr(object, trait)[index:index] = [value]

    # -- Private Adapter Implementation Methods -------------------------------

    def _get_can_edit(self):
        return self.can_edit

    def _get_drag(self):
        return six.text_type(self.item)

    def _get_can_drop(self):
        return isinstance(self.value, six.string_types)

    def _get_dropped(self):
        return self.dropped

    def _get_text_color(self):
        if (self.index % 2) == 0:
            return self.even_text_color_ or self.text_color_

        return self.odd_text_color or self.text_color_

    def _get_bg_color(self):
        if (self.index % 2) == 0:
            return self.even_bg_color_ or self.bg_color_

        return self.odd_bg_color or self.bg_color_

    def _get_image(self):
        return self.image

    def _get_item(self):
        return self.item

    def _get_text(self):
        return six.text_type(self.item)

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

    def _result_for(self, name, object, trait, index, value=None):
        """ Returns/Sets the value of the specified *name* attribute for the
            specified *object.trait[index]* list item.
        """
        self.index = index
        self.value = value
        items = getattr(object, trait)
        if index >= len(items):
            self.item = item = None
        else:
            self.item = item = items[index]

        item_class = item.__class__
        key = "%s:%s" % (item_class.__name__, name)
        handler = self.cache.get(key)
        if handler is not None:
            return handler()

        trait_name = name[4:]

        for adapter in self.adapters:
            adapter.index = index
            adapter.item = item
            adapter.value = value
            if adapter.accepts and (adapter.trait(trait_name) is not None):
                handler = lambda: getattr(
                    adapter.trait_set(
                        index=self.index, item=self.item, value=self.value),
                    trait_name,
                )

                if adapter.is_cacheable:
                    break

                return handler()
        else:
            for klass in item_class.__mro__:
                cname = "%s_%s" % (klass.__name__, trait_name)
                if self.trait(cname) is not None:
                    handler = lambda: getattr(self, cname)
                    break
            else:
                handler = getattr(self, "_" + name)

        self.cache[key] = handler
        return handler()

    @on_trait_change("adapters.+update")
    def _flush_cache(self):
        """ Flushes the cache when any trait on any adapter changes.
        """
        self.cache = {}
        self.cache_flushed = True
Exemple #15
0
class TabularAdapter(HasPrivateTraits):
    """ The base class for adapting list items to values that can be edited
        by a TabularEditor.
    """

    #-- Public Trait Definitions ---------------------------------------------

    # A list of columns that should appear in the table. Each entry can have one
    # of two forms: string or ( string, any ), where *string* is the UI name of
    # the column, and *any* is a value that identifies that column to the
    # adapter. Normally this value is either a trait name or an index, but it
    # can be any value that the adapter wants. If only *string* is specified,
    # then *any* is the index of the *string* within *columns*.
    columns = List()

    # Maps UI name of column to value identifying column to the adapter, if
    # different.
    column_dict = Property()

    # Specifies the default value for a new row:
    default_value = Any('')

    # The default text color for table rows (even, odd, any rows):
    odd_text_color = Color(None, update=True)
    even_text_color = Color(None, update=True)
    default_text_color = Color(None, update=True)

    # The default background color for table rows (even, odd, any rows):
    odd_bg_color = Color(None, update=True)
    even_bg_color = Color(None, update=True)
    default_bg_color = Color(None, update=True)

    # Alignment to use for a specified column:
    alignment = Enum('left', 'center', 'right')

    # The Python format string to use for a specified column:
    format = Str('%s')

    # Width of a specified column:
    width = Float(-1)

    # Can the text value of each item be edited:
    can_edit = Bool(True)

    # The value to be dragged for a specified row item:
    drag = Property

    # Can any arbitrary value be dropped onto the tabular view:
    can_drop = Bool(False)

    # Specifies where a dropped item should be placed in the table relative to
    # the item it is dropped on:
    dropped = Enum('after', 'before')

    # The font for a row item:
    font = Font(None)

    # The text color for a row item:
    text_color = Property

    # The background color for a row item:
    bg_color = Property

    # The name of the default image to use for column items:
    image = Str(None, update=True)

    # The text of a row/column item:
    text = Property

    # The content of a row/column item (may be any Python value):
    content = Property

    # The tooltip information for a row/column item:
    tooltip = Str

    # The context menu for a row/column item:
    menu = Any

    # The context menu for column header:
    column_menu = Any

    # List of optional delegated adapters:
    adapters = List(ITabularAdapter, update=True)

    #-- Traits Set by the Editor ---------------------------------------------

    # The object whose trait is being edited:
    object = Instance(HasTraits)

    # The name of the trait being edited:
    name = Str

    # The row index of the current item being adapted:
    row = Int

    # The column index of the current item being adapted:
    column = Int

    # The current column id being adapted (if any):
    column_id = Any

    # Current item being adapted:
    item = Any

    # The current value (if any):
    value = Any

    #-- Private Trait Definitions --------------------------------------------

    # Cache of attribute handlers:
    cache = Any({})

    # Event fired when the cache is flushed:
    cache_flushed = Event(update=True)

    # The mapping from column indices to column identifiers (defined by the
    # *columns* trait):
    column_map = Property(depends_on='columns')

    # The mapping from column indices to column labels (defined by the *columns*
    # trait):
    label_map = Property(depends_on='columns')

    # The name of the trait on a row item containing the value to use
    # as a row label. If None, the label will be the empty string.
    row_label_name = Either(None, Str)

    # For each adapter, specifies the column indices the adapter handles:
    adapter_column_indices = Property(depends_on='adapters,columns')

    # For each adapter, specifies the mapping from column index to column id:
    adapter_column_map = Property(depends_on='adapters,columns')

    #### TabularAdapter interface ####

    def cleanup(self):
        """ Clean up the adapter to remove references to objects.
        """
        self.trait_setq(
            object=None,
            item=None,
            value=None,
        )

    #-- Adapter methods that are sensitive to item type ----------------------

    def get_alignment(self, object, trait, column):
        """ Returns the alignment style to use for a specified column.
        """
        return self._result_for('get_alignment', object, trait, 0, column)

    def get_width(self, object, trait, column):
        """ Returns the width to use for a specified column.
        """
        return self._result_for('get_width', object, trait, 0, column)

    def get_can_edit(self, object, trait, row):
        """ Returns whether the user can edit a specified
            *object.trait[row]* item. A True result indicates the value
            can be edited, while a False result indicates that it cannot be
            edited.
        """
        return self._result_for('get_can_edit', object, trait, row, 0)

    def get_drag(self, object, trait, row):
        """ Returns the 'drag' value for a specified
            *object.trait[row]* item. A result of *None* means that the
            item cannot be dragged.
        """
        return self._result_for('get_drag', object, trait, row, 0)

    def get_can_drop(self, object, trait, row, value):
        """ Returns whether the specified *value* can be dropped on the
            specified *object.trait[row]* item. A value of **True** means the
            *value* can be dropped; and a value of **False** indicates that it
            cannot be dropped.
        """
        return self._result_for('get_can_drop', object, trait, row, 0, value)

    def get_dropped(self, object, trait, row, value):
        """ Returns how to handle a specified *value* being dropped on a
            specified *object.trait[row]* item. The possible return values are:

            'before'
                Insert the specified *value* before the dropped on item.
            'after'
                Insert the specified *value* after the dropped on item.
        """
        return self._result_for('get_dropped', object, trait, row, 0, value)

    def get_font(self, object, trait, row, column=0):
        """ Returns the font for a specified *object.trait[row]* item. A result
            of None means use the default font.
        """
        return self._result_for('get_font', object, trait, row, column)

    def get_text_color(self, object, trait, row, column=0):
        """ Returns the text color for a specified *object.trait[row]*
            item. A result of None means use the default text color.
        """
        return self._result_for('get_text_color', object, trait, row, column)

    def get_bg_color(self, object, trait, row, column=0):
        """ Returns the background color for a specified *object.trait[row]*
            item. A result of None means use the default background color.
        """
        return self._result_for('get_bg_color', object, trait, row, column)

    def get_image(self, object, trait, row, column):
        """ Returns the name of the image to use for a specified
            *object.trait[row].column* item. A result of None means no image
            should be used. Otherwise, the result should either be the name of
            the image, or an ImageResource item specifying the image to use.
        """
        return self._result_for('get_image', object, trait, row, column)

    def get_format(self, object, trait, row, column):
        """ Returns the Python format string to use for a specified column.
        """
        return self._result_for('get_format', object, trait, row, column)

    def get_text(self, object, trait, row, column):
        """ Returns the text to display for a specified
            *object.trait[row].column* item.
        """
        return self._result_for('get_text', object, trait, row, column)

    def get_content(self, object, trait, row, column):
        """ Returns the content to display for a specified
            *object.trait[row].column* item.
        """
        return self._result_for('get_content', object, trait, row, column)

    def set_text(self, object, trait, row, column, text):
        """ Sets the text for a specified *object.trait[row].column* item to
            *text*.
        """
        self._result_for('set_text', object, trait, row, column, text)

    def get_tooltip(self, object, trait, row, column):
        """ Returns the tooltip for a specified row.
        """
        return self._result_for('get_tooltip', object, trait, row, column)

    def get_menu(self, object, trait, row, column):
        """ Returns the context menu for a specified cell.
        """
        return self._result_for('get_menu', object, trait, row, column)

    def get_column_menu(self, object, trait, row, column):
        """ Returns the context menu for a specified column.
        """
        return self._result_for('get_column_menu', object, trait, row, column)

    #-- Adapter methods that are not sensitive to item type ------------------

    def get_item(self, object, trait, row):
        """ Returns the value of the *object.trait[row]* item.
        """
        try:
            return getattr(object, trait)[row]
        except:
            return None

    def len(self, object, trait):
        """ Returns the number of items in the specified *object.trait* list.
        """
        # Sometimes, during shutdown, the object has been set to None.
        if object is None:
            return 0
        else:
            return len(getattr(object, trait))

    def get_default_value(self, object, trait):
        """ Returns a new default value for the specified *object.trait* list.
        """
        return self.default_value

    def delete(self, object, trait, row):
        """ Deletes the specified *object.trait[row]* item.
        """
        del getattr(object, trait)[row]

    def insert(self, object, trait, row, value):
        """ Inserts a new value at the specified *object.trait[row]* index.
        """
        getattr(object, trait)[row:row] = [value]

    def get_column(self, object, trait, index):
        """ Returns the column id corresponding to a specified column index.
        """
        self.object, self.name = object, trait
        return self.column_map[index]

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

    def _get_drag(self):
        return self.item

    def _get_text_color(self):
        if (self.row % 2) == 1:
            return self.even_text_color_ or self.default_text_color

        return self.odd_text_color or self.default_text_color_

    def _get_bg_color(self):
        if (self.row % 2) == 1:
            return self.even_bg_color_ or self.default_bg_color_

        return self.odd_bg_color or self.default_bg_color_

    def _get_text(self):
        return self.get_format(
            self.object, self.name, self.row, self.column) % self.get_content(
                self.object, self.name, self.row, self.column)

    def _set_text(self, value):
        if isinstance(self.column_id, int):
            self.item[self.column_id] = self.value
        else:
            # Convert value to the correct trait type.
            try:
                trait_handler = self.item.trait(self.column_id).handler
                setattr(self.item, self.column_id,
                        trait_handler.evaluate(self.value))
            except:
                setattr(self.item, self.column_id, value)

    def _get_content(self):
        if isinstance(self.column_id, int):
            return self.item[self.column_id]

        return getattr(self.item, self.column_id)

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

    @cached_property
    def _get_column_dict(self):
        cols = {}
        for i, value in enumerate(self.columns):
            if isinstance(value, basestring):
                cols.update({value: value})
            else:
                cols.update({value[0]: value[1]})
        return cols

    @cached_property
    def _get_column_map(self):
        map = []
        for i, value in enumerate(self.columns):
            if isinstance(value, basestring):
                map.append(i)
            else:
                map.append(value[1])

        return map

    def get_label(self, section, obj=None):
        """Override this method if labels will vary from object to object."""
        return self.label_map[section]

    def get_row_label(self, section, obj=None):
        if self.row_label_name is None:
            return None
        rows = getattr(obj, self.name, None)
        if rows is None:
            return None
        item = rows[section]
        return getattr(item, self.row_label_name, None)

    @cached_property
    def _get_label_map(self):
        map = []
        for i, value in enumerate(self.columns):
            if isinstance(value, basestring):
                map.append(value)
            else:
                map.append(value[0])

        return map

    @cached_property
    def _get_adapter_column_indices(self):
        labels = self.label_map
        map = []
        for adapter in self.adapters:
            indices = []
            for label in adapter.columns:
                if not isinstance(label, basestring):
                    label = label[0]

                indices.append(labels.index(label))
            map.append(indices)
        return map

    @cached_property
    def _get_adapter_column_map(self):
        labels = self.label_map
        map = []
        for adapter in self.adapters:
            mapping = {}
            for label in adapter.columns:
                id = None
                if not isinstance(label, basestring):
                    label, id = label

                key = labels.index(label)
                if id is None:
                    id = key

                mapping[key] = id

            map.append(mapping)

        return map

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

    def _result_for(self, name, object, trait, row, column, value=None):
        """ Returns/Sets the value of the specified *name* attribute for the
            specified *object.trait[row].column* item.
        """
        self.object = object
        self.name = trait
        self.row = row
        self.column = column
        self.column_id = column_id = self.column_map[column]
        self.value = value
        self.item = item = self.get_item(object, trait, row)
        item_class = item.__class__
        key = '%s:%s:%d' % (item_class.__name__, name, column)
        handler = self.cache.get(key)
        if handler is not None:
            return handler()

        prefix = name[:4]
        trait_name = name[4:]

        for i, adapter in enumerate(self.adapters):
            if column in self.adapter_column_indices[i]:
                adapter.row = row
                adapter.item = item
                adapter.value = value
                adapter.column = column_id = self.adapter_column_map[i][column]
                if adapter.accepts:
                    get_name = '%s_%s' % (column_id, trait_name)
                    if adapter.trait(get_name) is not None:
                        if prefix == 'get_':
                            handler = lambda: getattr(
                                adapter.set(row=self.row,
                                            column=column_id,
                                            item=self.item), get_name)
                        else:
                            handler = lambda: setattr(
                                adapter.set(row=self.row,
                                            column=column_id,
                                            item=self.item), get_name, self.
                                value)

                        if adapter.is_cacheable:
                            break

                        return handler()
        else:
            if item is not None and hasattr(item_class, '__mro__'):
                for klass in item_class.__mro__:
                    handler = (self._get_handler_for(
                        '%s_%s_%s' %
                        (klass.__name__, column_id, trait_name), prefix)
                               or self._get_handler_for(
                                   '%s_%s' %
                                   (klass.__name__, trait_name), prefix))
                    if handler is not None:
                        break

            if handler is None:
                handler = (self._get_handler_for(
                    '%s_%s' % (column_id, trait_name), prefix)
                           or self._get_handler_for(trait_name, prefix))

        self.cache[key] = handler
        return handler()

    def _get_handler_for(self, name, prefix):
        """ Returns the handler for a specified trait name (or None if not
            found).
        """
        if self.trait(name) is not None:
            if prefix == 'get_':
                return lambda: getattr(self, name)

            return lambda: setattr(self, name, self.value)

        return None

    @on_trait_change('columns,adapters.+update')
    def _flush_cache(self):
        """ Flushes the cache when the columns or any trait on any adapter
            changes.
        """
        self.cache = {}
        self.cache_flushed = True
Exemple #16
0
class ListeningAction(Action):
    """ An Action that listens and makes a callback to an object.
    """

    # ListeningAction interface ----------------------------------------------

    #: The (extended) name of the method to call. By default, the on_perform
    #: function will be called with the event.
    method = Str()

    #: The (extended) name of the attribute that determines whether the action
    #: is enabled. By default, the action is always enabled when an object is
    #: set.
    enabled_name = Str()

    #: The (extended) name of the attribute that determines whether the action
    #: is visible. By default, the action is always visible.
    visible_name = Str()

    #: The object to which the names above apply.
    object = Any()

    # -------------------------------------------------------------------------
    # 'Action' interface.
    # -------------------------------------------------------------------------

    def destroy(self):
        """ Called when the action is no longer required.

        Removes all the task listeners.
        """

        if self.object:
            self.object.on_trait_change(self._enabled_update,
                                        self.enabled_name,
                                        remove=True)
            self.object.on_trait_change(self._visible_update,
                                        self.visible_name,
                                        remove=True)

    def perform(self, event=None):
        """ Call the appropriate function.

        This looks for a method to call based on the extended method name
        stored in the :py:attr:`method` trait.  If the method is empty, then
        this follows the usual Action method resolution.
        """
        if self.method != "":
            method = self._get_attr(self.object, self.method)
            if method:
                method()
        else:
            super(ListeningAction, self).perform(event)

    # -------------------------------------------------------------------------
    # Protected interface.
    # -------------------------------------------------------------------------

    def _get_attr(self, obj, name, default=None):
        """ Perform an extended look up of a dotted name. """
        try:
            for attr in name.split("."):
                # Perform the access in the Trait name style: if the object is
                # None, assume it simply hasn't been initialized and don't show
                # the warning.
                if obj is None:
                    return default
                else:
                    obj = getattr(obj, attr)
        except AttributeError:
            logger.error("Did not find name %r on %r" % (attr, obj))
            return default
        return obj

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

    def _enabled_name_changed(self, old, new):
        obj = self.object
        if obj is not None:
            if old:
                obj.on_trait_change(self._enabled_update, old, remove=True)
            if new:
                obj.on_trait_change(self._enabled_update, new)
        self._enabled_update()

    def _visible_name_changed(self, old, new):
        obj = self.object
        if obj is not None:
            if old:
                obj.on_trait_change(self._visible_update, old, remove=True)
            if new:
                obj.on_trait_change(self._visible_update, new)
        self._visible_update()

    def _object_changed(self, old, new):
        for kind in ("enabled", "visible"):
            method = getattr(self, "_%s_update" % kind)
            name = getattr(self, "%s_name" % kind)
            if name:
                if old:
                    old.on_trait_change(method, name, remove=True)
                if new:
                    new.on_trait_change(method, name)
            method()

    def _enabled_update(self):
        if self.enabled_name:
            if self.object:
                self.enabled = bool(
                    self._get_attr(self.object, self.enabled_name, False))
            else:
                self.enabled = False
        else:
            self.enabled = bool(self.object)

    def _visible_update(self):
        if self.visible_name:
            if self.object:
                self.visible = bool(
                    self._get_attr(self.object, self.visible_name, False))
            else:
                self.visible = False
        else:
            self.visible = True
Exemple #17
0
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

      * ``name='_'``, the item is rendered as a separator

      * ``name=' '``, the item is rendered as a 5 pixel spacer

      * ``name='23'`` (any number), the item is rendered as a spacer of
        the size specified (number of pixels)
    """

    # FIXME: all the logic for the name = '', '_', ' ', '23' magic is in
    # _GroupPanel._add_items in qt/ui_panel.py, which is a very unlikely place
    # to look for it. Ideally, that logic should be in this class.

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

    #: A unique identifier for the item. If not set, it defaults to the value
    #: of **name**.
    id = Str()

    #: User interface label for the item in the GUI. If this attribute is not
    #: set, the label is the value of **name** with slight modifications:
    #: underscores are replaced by spaces, and the first letter is capitalized.
    #: If an item's **name** is not specified, its label is displayed as
    #: static text, without any editor widget.
    label = Str()

    #: Name of the trait the item is editing:
    name = Str()

    #: Style-sheet to apply to item / group (Qt only)
    style_sheet = Str()

    #: Help text describing the purpose of the item. The built-in help handler
    #: displays this text in a pop-up window if the user clicks the widget's
    #: label. View-level help displays the help text for all items in a view.
    #: If this attribute is not set, the built-in help handler generates a
    #: description based on the trait definition.
    help = Str()

    #: The HasTraits object whose trait attribute the item is editing:
    object = ContainerDelegate

    #: Presentation style for the item:
    style = ContainerDelegate

    #: Docking style for the item:
    dock = ContainerDelegate

    #: Image to display on notebook tabs:
    image = ContainerDelegate

    #: Category of elements dragged from view:
    export = ContainerDelegate

    #: Should a label be displayed for the item?
    show_label = Delegate("container", "show_labels")

    #: Editor to use for the item:
    editor = ItemEditor

    #: Additional editor traits to be set if default traits editor to be used:
    editor_args = Dict()

    #: Should the item use extra space along its Group's non-layout axis? If set to
    #: True, the widget expands to fill any extra space that is available in the
    #: display. If set to True for more than one item in the same View, any extra
    #: space is divided between them. If set to False, the widget uses only
    #: whatever space it is explicitly (or implicitly) assigned. The default
    #: value of Undefined means that the use (or non-use) of extra space will be
    #: determined by the editor associated with the item.
    resizable = Bool(Undefined)

    #: Should the item use extra space along its Group's layout axis? For
    #: example, it a vertical group, should an item expand vertically to use
    #: any extra space available in the group?
    springy = Bool(False)

    #: Should the item use any extra space along its Group's non-layout
    #: orientation? For example, in a vertical group, should an item expand
    #: horizontally to the full width of the group? If left to the default value
    #: of Undefined, the decision will be left up to the associated item editor.
    full_size = Bool(Undefined)

    #: Should the item's label use emphasized text? If the label is not shown,
    #: this attribute is ignored.
    emphasized = Bool(False)

    #: Should the item receive focus initially?
    has_focus = Bool(False)

    #: Pre-condition for including the item in the display. If the expression
    #: evaluates to False, the item 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. For example,
    #: displaying a 'maiden_name' item only for female employees in a company
    #: database.
    defined_when = Str()

    #: Pre-condition for showing the item. If the expression evaluates to False,
    #: the widget is not visible (and disappears if it was previously visible).
    #: If the value evaluates to True, the widget becomes 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 widgets in response to user input.
    visible_when = Str()

    #: Pre-condition for enabling the item. If the expression evaluates to False,
    #: the widget is disabled, that is, it does not 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 widgets in response to user input.
    enabled_when = Str()

    #: Amount of extra space, in pixels, to add around the item. Values must be
    #: integers between -15 and 15. Use negative values to subtract from the
    #: default spacing.
    padding = Padding

    #: Tooltip to display over the item, when the mouse pointer is left idle
    #: over the widget. Make this text as concise as possible; use the **help**
    #: attribute to provide more detailed information.
    tooltip = Str()

    #: A Callable to use for formatting the contents of the item. This function
    #: or method is called to create the string representation of the trait value
    #: to be edited. If the widget does not use a string representation, this
    #: attribute is ignored.
    format_func = Callable()

    #: Python format string to use for formatting the contents of the item.
    #: The format string is applied to the string representation of the trait
    #: value before it is displayed in the widget. This attribute is ignored if
    #: the widget does not use a string representation, or if the
    #: **format_func** is set.
    format_str = Str()

    #: Requested width of the editor (in pixels or fraction of available width).
    #: For pixel values (i.e. values not in the range from 0.0 to 1.0), the
    #: actual displayed width is at least the maximum of **width** and the
    #: optimal width of the widget as calculated by the GUI toolkit. Specify a
    #: negative value to ignore the toolkit's optimal width. For example, use
    #: -50 to force a width of 50 pixels. The default value of -1 ensures that
    #: the toolkit's optimal width is used.
    #:
    #: A value in the range from 0.0 to 1.0 specifies the fraction of the
    #: available width to assign to the editor. Note that the value is not an
    #: absolute value, but is relative to other item's whose **width** is also
    #: in the 0.0 to 1.0 range. For example, if you have two item's with a width
    #: of 0.1, and one item with a width of 0.2, the first two items will each
    #: receive 25% of the available width, while the third item will receive
    #: 50% of the available width. The available width is the total width of the
    #: view minus the width of any item's with fixed pixel sizes (i.e. width
    #: values not in the 0.0 to 1.0 range).
    width = Float(-1.0)

    #: Requested height of the editor (in pixels or fraction of available
    #: height). For pixel values (i.e. values not in the range from 0.0 to 1.0),
    #: the actual displayed height is at least the maximum of **height** and the
    #: optimal height of the widget as calculated by the GUI toolkit. Specify a
    #: negative value to ignore the toolkit's optimal height. For example, use
    #: -50 to force a height of 50 pixels. The default value of -1 ensures that
    #: the toolkit's optimal height is used.
    #:
    #: A value in the range from 0.0 to 1.0 specifies the fraction of the
    #: available height to assign to the editor. Note that the value is not an
    #: absolute value, but is relative to other item's whose **height** is also
    #: in the 0.0 to 1.0 range. For example, if you have two item's with a height
    #: of 0.1, and one item with a height of 0.2, the first two items will each
    #: receive 25% of the available height, while the third item will receive
    #: 50% of the available height. The available height is the total height of
    #: the view minus the height of any item's with fixed pixel sizes (i.e.
    #: height values not in the 0.0 to 1.0 range).
    height = Float(-1.0)

    #: The extended trait name of the trait containing the item's invalid state
    #: status (passed through to the item's editor):
    invalid = Str()

    def __init__(self, value=None, **traits):
        """ Initializes the item object.
        """
        super(Item, self).__init__(**traits)

        if value is None:
            return

        if not isinstance(value, str):
            raise TypeError(
                "The argument to Item must be a string of the "
                "form: [id:][object.[object.]*][name]['['label']']`tooltip`"
                "[<width[,height]>][#^][$|@|*|~|;style]")

        value, empty = self._parse_label(value)
        if empty:
            self.show_label = False

        value = self._parse_style(value)
        value = self._parse_size(value)
        value = self._parse_tooltip(value)
        value = self._option(value, "#", "resizable", True)
        value = self._option(value, "^", "emphasized", True)
        value = self._split("id", value, ":", str.find, 0, 1)
        value = self._split("object", value, ".", str.rfind, 0, 1)

        if value != "":
            self.name = value

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

    def is_spacer(self):
        """ Returns True if the item represents a spacer or separator.
        """
        name = self.name.strip()

        return ((name == "") or (name == "_")
                or (all_digits.match(name) is not None))

    def get_help(self, ui):
        """ Gets the help text associated with the Item in a specified UI.
        """
        # Return 'None' if the Item is a separator or spacer:
        if self.is_spacer():
            return None

        # Otherwise, it must be a trait Item:
        if self.help != "":
            return self.help

        object = eval(self.object_, globals(), ui.context)

        return object.base_trait(self.name).get_help()

    def get_label(self, ui):
        """ Gets the label to use for a specified Item.

        If not specified, the label is set as the name of the
        corresponding trait, replacing '_' with ' ', and capitalizing
        the first letter (see :func:`user_name_for`). This is called
        the *user name*.

        Magic:

        - if attr:`item.label` is specified, and it begins with '...',
          the final label is the user name followed by the item label
        - if attr:`item.label` is specified, and it ends with '...',
          the final label is the item label followed by the user name
        """
        # Return 'None' if the Item is a separator or spacer:
        if self.is_spacer():
            return None

        label = self.label
        if label != "":
            return label

        name = self.name
        object = eval(self.object_, globals(), ui.context)
        trait = object.base_trait(name)
        label = user_name_for(name)
        tlabel = trait.label
        if tlabel is None:
            return label

        if isinstance(tlabel, str):
            if tlabel[0:3] == "...":
                return label + tlabel[3:]
            if tlabel[-3:] == "...":
                return tlabel[:-3] + label
            if self.label != "":
                return self.label
            return tlabel

        return tlabel(object, name, label)

    def get_id(self):
        """ Returns an ID used to identify the item.
        """
        if self.id != "":
            return self.id

        return self.name

    def _parse_size(self, value):
        """ Parses a '<width,height>' value from the string definition.
        """
        match = size_pat.match(value)
        if match is not None:
            data = match.group(2)
            value = match.group(1) + match.group(3)
            col = data.find(",")
            if col < 0:
                self._set_float("width", data)
            else:
                self._set_float("width", data[:col])
                self._set_float("height", data[col + 1:])

        return value

    def _parse_tooltip(self, value):
        """ Parses a *tooltip* value from the string definition.
        """
        match = tooltip_pat.match(value)
        if match is not None:
            self.tooltip = match.group(2)
            value = match.group(1) + match.group(3)

        return value

    def _set_float(self, name, value):
        """ Sets a specified trait to a specified string converted to a float.
        """
        value = value.strip()
        if value != "":
            setattr(self, name, float(value))

    def __repr__(self):
        """ Returns a "pretty print" version of the Item.
        """

        options = self._repr_options("id", "object", "label", "style",
                                     "show_label", "width", "height")
        if options is None:
            return "Item( '%s' )" % self.name

        return "Item( '%s'\n%s\n)" % (
            self.name,
            self._indent(options, "      "),
        )
Exemple #18
0
class PythonEditor(MPythonEditor, Widget):
    """ The toolkit specific implementation of a PythonEditor.  See the
    IPythonEditor interface for the API documentation.
    """

    # 'IPythonEditor' interface --------------------------------------------

    dirty = Bool(False)

    path = Str()

    show_line_numbers = Bool(True)

    # Events ----

    changed = Event()

    key_pressed = Event(KeyPressedEvent)

    # ------------------------------------------------------------------------
    # 'object' interface.
    # ------------------------------------------------------------------------

    def __init__(self, parent, **traits):
        """ Creates a new pager. """

        # Base class constructor.
        super(PythonEditor, self).__init__(**traits)

        # Create the toolkit-specific control that represents the widget.
        self.control = self._create_control(parent)

        return

    # ------------------------------------------------------------------------
    # 'PythonEditor' interface.
    # ------------------------------------------------------------------------

    def load(self, path=None):
        """ Loads the contents of the editor. """

        if path is None:
            path = self.path

        # We will have no path for a new script.
        if len(path) > 0:
            f = open(self.path, "r")
            text = f.read()
            f.close()

        else:
            text = ""

        self.control.SetText(text)
        self.dirty = False

    def save(self, path=None):
        """ Saves the contents of the editor. """

        if path is None:
            path = self.path

        f = open(path, "w")
        f.write(self.control.GetText())
        f.close()

        self.dirty = False

    def set_style(self, n, fore, back):

        self.control.StyleSetForeground(n, fore)
        # self.StyleSetBackground(n, '#c0c0c0')
        # self.StyleSetBackground(n, '#ffffff')
        self.control.StyleSetBackground(n, back)
        self.control.StyleSetFaceName(n, "courier new")
        self.control.StyleSetSize(n, faces["size"])

        # self.StyleSetForeground(n, "#f0f0f0")
        ##self.StyleSetBackground(n, "#000000")
        # self.StyleSetFaceName(n, "courier new")
        # self.StyleSetSize(n, 20)
        # self.StyleSetUnderline(n, 1)
        # self.StyleSetItalic(n, 1)
        # self.StyleSetBold(n, 1)
        # StyleClearAll
        # StyleResetDefault
        # StyleSetCase
        # StyleSetChangeable
        # StyleSetCharacterSet
        # StyleSetEOLFilled
        # StyleSetFont
        # StyleSetFontAttr
        # StyleSetHotSpot
        # StyleSetSpec --- batch
        # StyleSetVisible

    def select_line(self, lineno):
        """ Selects the specified line. """

        start = self.control.PositionFromLine(lineno)
        end = self.control.GetLineEndPosition(lineno)

        self.control.SetSelection(start, end)

        return

    # ------------------------------------------------------------------------
    # Trait handlers.
    # ------------------------------------------------------------------------

    def _path_changed(self):
        """ Handle a change to path. """

        self._changed_path()

        return

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

    def _create_control(self, parent):
        """ Creates the toolkit-specific control for the widget. """

        # Base-class constructor.
        self.control = stc = PythonSTC(parent, -1)

        # No folding!
        stc.SetProperty("fold", "0")

        # Mark the maximum line size.
        stc.SetEdgeMode(wx.stc.STC_EDGE_LINE)
        stc.SetEdgeColumn(79)

        # Display line numbers in the margin.
        if self.show_line_numbers:
            stc.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
            stc.SetMarginWidth(1, 45)
            self.set_style(wx.stc.STC_STYLE_LINENUMBER, "#000000", "#c0c0c0")
        else:
            stc.SetMarginWidth(1, 4)
            self.set_style(wx.stc.STC_STYLE_LINENUMBER, "#ffffff", "#ffffff")

        # Create 'tabs' out of spaces!
        stc.SetUseTabs(False)

        # One 'tab' is 4 spaces.
        stc.SetIndent(4)

        # Line ending mode.
        stc.SetEOLMode(wx.stc.STC_EOL_LF)  # Unix
        # self.SetEOLMode(wx.stc.STC_EOL_CR) # Apple Mac
        # self.SetEOLMode(wx.stc.STC_EOL_CRLF) # Windows

        # ------------------------------------------------------------------------
        # Global styles for all languages.
        # ------------------------------------------------------------------------

        self.set_style(wx.stc.STC_STYLE_DEFAULT, "#000000", "#ffffff")
        self.set_style(wx.stc.STC_STYLE_CONTROLCHAR, "#000000", "#ffffff")
        self.set_style(wx.stc.STC_STYLE_BRACELIGHT, "#000000", "#ffffff")
        self.set_style(wx.stc.STC_STYLE_BRACEBAD, "#000000", "#ffffff")

        # ------------------------------------------------------------------------
        # Python styles.
        # ------------------------------------------------------------------------

        # White space
        self.set_style(wx.stc.STC_P_DEFAULT, "#000000", "#ffffff")

        # Comment
        self.set_style(wx.stc.STC_P_COMMENTLINE, "#007f00", "#ffffff")

        # Number
        self.set_style(wx.stc.STC_P_NUMBER, "#007f7f", "#ffffff")

        # String
        self.set_style(wx.stc.STC_P_STRING, "#7f007f", "#ffffff")

        # Single quoted string
        self.set_style(wx.stc.STC_P_CHARACTER, "#7f007f", "#ffffff")

        # Keyword
        self.set_style(wx.stc.STC_P_WORD, "#00007f", "#ffffff")

        # Triple quotes
        self.set_style(wx.stc.STC_P_TRIPLE, "#7f0000", "#ffffff")

        # Triple double quotes
        self.set_style(wx.stc.STC_P_TRIPLEDOUBLE, "#ff0000", "#ffffff")

        # Class name definition
        self.set_style(wx.stc.STC_P_CLASSNAME, "#0000ff", "#ffffff")

        # Function or method name definition
        self.set_style(wx.stc.STC_P_DEFNAME, "#007f7f", "#ffffff")

        # Operators
        self.set_style(wx.stc.STC_P_OPERATOR, "#000000", "#ffffff")

        # Identifiers
        self.set_style(wx.stc.STC_P_IDENTIFIER, "#000000", "#ffffff")

        # Comment-blocks
        self.set_style(wx.stc.STC_P_COMMENTBLOCK, "#007f00", "#ffffff")

        # End of line where string is not closed
        self.set_style(wx.stc.STC_P_STRINGEOL, "#000000", "#ffffff")

        # ------------------------------------------------------------------------
        # Events.
        # ------------------------------------------------------------------------

        # By default, the will fire EVT_STC_CHANGE evented for all mask values
        # (STC_MODEVENTMASKALL). This generates too many events.
        stc.SetModEventMask(wx.stc.STC_MOD_INSERTTEXT
                            | wx.stc.STC_MOD_DELETETEXT
                            | wx.stc.STC_PERFORMED_UNDO
                            | wx.stc.STC_PERFORMED_REDO)

        # Listen for changes to the file.
        stc.Bind(wx.stc.EVT_STC_CHANGE, self._on_stc_changed)

        # Listen for key press events.
        stc.Bind(wx.EVT_CHAR, self._on_char)

        # Load the editor's contents.
        self.load()

        return stc

    def destroy(self):
        """ Destroy the toolkit control. """
        if self.control is not None:
            self.control.Unbind(wx.stc.EVT_STC_CHANGE)
            self.control.Unbind(wx.EVT_CHAR)
        super().destroy()

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

    def _on_stc_changed(self, event):
        """ Called whenever a change is made to the text of the document. """

        self.dirty = True
        self.changed = True

        # Give other event handlers a chance.
        event.Skip()

    def _on_char(self, event):
        """ Called whenever a change is made to the text of the document. """

        self.key_pressed = KeyPressedEvent(
            alt_down=event.altDown,
            control_down=event.controlDown,
            shift_down=event.shiftDown,
            key_code=event.KeyCode,
            event=event,
        )

        # Give other event handlers a chance.
        event.Skip()

        return
Exemple #19
0
class RegexValidator(Validator):
    """ A concrete Validator which handles text input.

    This validator ensures that the text matches a provided regular
    expression string.

    """
    #: The regular expression string to use for validation. The default
    #: regex matches everything.
    regex = Str(r'.*')

    #: A read only cached property which holds the compiled regular
    #: expression object.
    _regex = Property(depends_on='regex')

    @cached_property
    def _get__regex(self):
        """ The getter for the '_regex' property. 

        Returns
        -------
        result : sre object
            A compiled regular expression object for the current regex
            string.

        """
        return re.compile(self.regex, re.UNICODE)

    def validate(self, text, component):
        """ Validates the given text matches the regular expression.

        Parameters
        ----------
        text : unicode
            The unicode text edited by the client widget.

        component : Declarative
            The declarative component currently making use of the
            validator.

        Returns
        -------
        result : (unicode, bool)
            A 2-tuple of (optionally modified) unicode text, and whether
            or not that text should be considered valid.

        """
        return (text, bool(self._regex.match(text)))

    def client_validator(self):
        """ The client side regex validator.

        Returns
        -------
        result : dict
            The dict representation of the client side regex validator.
            
        """
        res = {}
        res['type'] = 'regex'
        res['message'] = self.message
        res['arguments'] = {'regex': self.regex}
        return res
Exemple #20
0
class _TickMarketInfo(_BarMarketInfo):
    """Tick 因子映照"""
    Bid = Str(arg_type="String", label="买盘价格", order=6)
    BidVol = Str(arg_type="String", label="买盘数量", order=7)
    Ask = Str(arg_type="String", label="卖盘价格", order=8)
    AskVol = Str(arg_type="String", label="卖盘数量", order=9)
class Department(HasTraits):
    name = Str('<unknown>')
    employees = List(Employee)
Exemple #22
0
class PolygonOp(HasStrictTraits):
    """
    Apply a polygon gate to a cytometry experiment.
    
    Attributes
    ----------
    name : Str
        The operation name.  Used to name the new metadata field in the
        experiment that's created by :meth:`apply`
        
    xchannel, ychannel : Str
        The names of the x and y channels to apply the gate.
        
    xscale, yscale : {'linear', 'log', 'logicle'} (default = 'linear')
        The scales applied to the data before drawing the polygon.
        
    vertices : List((Float, Float))
        The polygon verticies.  An ordered list of 2-tuples, representing
        the x and y coordinates of the vertices.
        
    Notes
    -----
    This module uses :meth:`matplotlib.path.Path` to represent the polygon, because
    membership testing is very fast.
    
    You can set the verticies by hand, I suppose, but it's much easier to use
    the interactive view you get from :meth:`default_view` to do so.

    
    Examples
    --------
    
    .. plot::
        :context: close-figs
        
        Make a little data set.
    
        >>> import cytoflow as flow
        >>> import_op = flow.ImportOp()
        >>> import_op.tubes = [flow.Tube(file = "Plate01/RFP_Well_A3.fcs",
        ...                              conditions = {'Dox' : 10.0}),
        ...                    flow.Tube(file = "Plate01/CFP_Well_A4.fcs",
        ...                              conditions = {'Dox' : 1.0})]
        >>> import_op.conditions = {'Dox' : 'float'}
        >>> ex = import_op.apply()
    
    Create and parameterize the operation.
    
    .. plot::
        :context: close-figs
        
        >>> p = flow.PolygonOp(name = "Polygon",
        ...                    xchannel = "V2-A",
        ...                    ychannel = "Y2-A")
        >>> p.vertices = [(23.411982294776319, 5158.7027015021222), 
        ...               (102.22182270573683, 23124.058843387455), 
        ...               (510.94519955277201, 23124.058843387455), 
        ...               (1089.5215641232173, 3800.3424832180476), 
        ...               (340.56382570202402, 801.98947404942271), 
        ...               (65.42597937575897, 1119.3133482602157)]

        
    Show the default view.  

    .. plot::
        :context: close-figs
            
        >>> df = p.default_view(huefacet = "Dox",
        ...                    xscale = 'log',
        ...                    yscale = 'log')
        
        >>> df.plot(ex)
        
    
    .. note::
       If you want to use the interactive default view in a Jupyter notebook,
       make sure you say ``%matplotlib notebook`` in the first cell 
       (instead of ``%matplotlib inline`` or similar).  Then call 
       ``default_view()`` with ``interactive = True``::
       
           df = p.default_view(huefacet = "Dox",
                               xscale = 'log',
                               yscale = 'log',
                               interactive = True)
           df.plot(ex)
        
    Apply the gate, and show the result
    
    .. plot::
        :context: close-figs
        
        >>> ex2 = p.apply(ex)
        >>> ex2.data.groupby('Polygon').size()
        Polygon
        False    15875
        True      4125
        dtype: int64
            
    """

    # traits
    id = Constant('edu.mit.synbio.cytoflow.operations.polygon')
    friendly_id = Constant("Polygon")

    name = CStr()
    xchannel = Str()
    ychannel = Str()
    vertices = List((Float, Float))

    xscale = util.ScaleEnum()
    yscale = util.ScaleEnum()

    _selection_view = Instance('PolygonSelection', transient=True)

    def apply(self, experiment):
        """Applies the threshold to an experiment.
        
        Parameters
        ----------
        experiment : Experiment
            the old :class:`Experiment` to which this op is applied
            
        Returns
        -------
        Experiment
            a new :class:'Experiment`, the same as ``old_experiment`` but with 
            a new column of type `bool` with the same as the operation name.  
            The bool is ``True`` if the event's measurement is within the 
            polygon, and ``False`` otherwise.
            
        Raises
        ------
        util.CytoflowOpError
            if for some reason the operation can't be applied to this
            experiment. The reason is in :attr:`.CytoflowOpError.args`
        """

        if experiment is None:
            raise util.CytoflowOpError('experiment', "No experiment specified")

        if self.name in experiment.data.columns:
            raise util.CytoflowOpError(
                'name', "{} is in the experiment already!".format(self.name))

        if self.name != util.sanitize_identifier(self.name):
            raise util.CytoflowOpError(
                'name',
                "Name can only contain letters, numbers and underscores.".
                format(self.name))

        if not self.xchannel:
            raise util.CytoflowOpError('xchannel', "Must specify an x channel")

        if not self.ychannel:
            raise util.CytoflowOpError('ychannel', "Must specify a y channel")

        if not self.xchannel in experiment.channels:
            raise util.CytoflowOpError(
                'xchannel',
                "xchannel {0} is not in the experiment".format(self.xchannel))

        if not self.ychannel in experiment.channels:
            raise util.CytoflowOpError(
                'ychannel',
                "ychannel {0} is not in the experiment".format(self.ychannel))

        if len(self.vertices) < 3:
            raise util.CytoflowOpError('vertices',
                                       "Must have at least 3 vertices")

        if any([len(x) != 2 for x in self.vertices]):
            return util.CytoflowOpError(
                'vertices', "All vertices must be lists or tuples "
                "of length = 2")

        # make sure name got set!
        if not self.name:
            raise util.CytoflowOpError(
                'name', "You have to set the Polygon gate's name "
                "before applying it!")

        # make sure old_experiment doesn't already have a column named self.name
        if (self.name in experiment.data.columns):
            raise util.CytoflowOpError(
                'name',
                "Experiment already contains a column {0}".format(self.name))

        # there's a bit of a subtlety here: if the vertices were
        # selected with an interactive plot, and that plot had scaled
        # axes, we need to apply that scale function to both the
        # vertices and the data before looking for path membership
        xscale = util.scale_factory(self.xscale,
                                    experiment,
                                    channel=self.xchannel)
        yscale = util.scale_factory(self.yscale,
                                    experiment,
                                    channel=self.ychannel)

        vertices = [(xscale(x), yscale(y)) for (x, y) in self.vertices]
        data = experiment.data[[self.xchannel, self.ychannel]].copy()
        data[self.xchannel] = xscale(data[self.xchannel])
        data[self.ychannel] = yscale(data[self.ychannel])

        # use a matplotlib Path because testing for membership is a fast C fn.
        path = mpl.path.Path(np.array(vertices))
        xy_data = data[[self.xchannel, self.ychannel]].values

        new_experiment = experiment.clone()
        new_experiment.add_condition(self.name, "bool",
                                     path.contains_points(xy_data))
        new_experiment.history.append(
            self.clone_traits(transient=lambda _: True))

        return new_experiment

    def default_view(self, **kwargs):
        self._selection_view = PolygonSelection(op=self)
        self._selection_view.trait_set(**kwargs)
        return self._selection_view
class Partner(HasTraits):
    name = Str('<unknown>')
    company = Instance(Company)
Exemple #24
0
class AnalysisTable(HasTraits):
    analyses = List
    oanalyses = List
    selected = Any
    dclicked = Any

    analysis_filter = Str
    analysis_filter_values = List
    analysis_filter_comparator = Enum('=', '<', '>', '>=', '<=', 'not =',
                                      'startswith')
    analysis_filter_parameter = Str('Record_id')
    analysis_filter_parameters = List(
        ['Record_id', 'Tag', 'Age', 'Labnumber', 'Aliquot', 'Step'])

    omit_invalid = Bool(True)
    configure_analysis_table = Button

    # forward = Button
    # backward = Button
    # page_width = Int(1000)
    # page = Int(1, enter_set=True, auto_set=False)
    #
    # forward_enabled = Bool
    # backward_enabled = Bool
    # n_all_analyses = Int
    # npages = Property(depends_on='n_all_analyses,page_width')

    no_update = False
    scroll_to_row = Event
    refresh_needed = Event

    # def load(self):
    #     p = os.path.join(paths.hidden_dir, 'analysis_table')
    #     if os.path.isfile(p):
    #         d={}
    #         with open(p, 'r') as fp:
    #             try:
    #                d=pickle.load(fp)
    #             except (pickle.PickleError, OSError, EOFError):
    #                 pass
    #
    #         self.trait_set(**d)
    #
    # def dump(self):
    #     p=os.path.join(paths.hidden_dir, 'analysis_table')
    #     with open(p,'w') as fp:
    #         pickle.dump({'page_width':self.page_width}, fp)

    # def _forward_fired(self):
    #     if self.page < self.npages:
    #         self.page += 1
    #         #if self.oanalyses:
    #         #    self.page+=1
    #
    # def _backward_fired(self):
    #     p = self.page
    #     p -= 1
    #     self.page = max(1, p)

    def set_analyses(self, ans, tc=None, page=None, reset_page=False):
        self.analyses = ans
        self.oanalyses = ans
        if tc is None:
            tc = len(ans)

        self.n_all_analyses = tc
        # if reset_page:
        #     self.no_update = True
        #     if page<0:
        #         self.page=self.npages
        #         self.scroll_to_row=self.page_width
        #     else:
        #         self.page = 1
        #     self.no_update = False

    def _analysis_filter_changed(self, new):
        if new:
            name = self.analysis_filter_parameter
            comp = self.analysis_filter_comparator
            if name == 'Step':
                new = new.upper()

            self.analyses = filter(self._filter_func(new, name, comp),
                                   self.oanalyses)
        else:
            self.analyses = self.oanalyses

    def _configure_analysis_table_fired(self):

        c = TableConfigurer(adapter=self.tabular_adapter,
                            title='Configure Analysis Table')
        c.edit_traits()

    # def _get_npages(self):
    #     try:
    #         return int(math.ceil(self.n_all_analyses / float(self.page_width)))
    #     except ZeroDivisionError:
    #         return 0

    def _get_analysis_filter_parameter(self):
        p = self.analysis_filter_parameter
        return p.lower()

    def _analysis_filter_comparator_changed(self):
        self._analysis_filter_changed(self.analysis_filter)

    def _analysis_filter_parameter_changed(self, new):
        if new:
            vs = []
            p = self._get_analysis_filter_parameter()
            for si in self.oanalyses:
                v = getattr(si, p)
                if not v in vs:
                    vs.append(v)

            self.analysis_filter_values = vs
Exemple #25
0
class ICDecay(BaseModule):
    """IC 衰减"""
    #TestFactor = Enum(None, arg_type="SingleOption", label="测试因子", order=0)
    FactorOrder = Enum("降序","升序", arg_type="SingleOption", label="排序方向", order=1)
    #PriceFactor = Enum(None, arg_type="SingleOption", label="价格因子", order=2)
    #IndustryFactor = Enum("无", arg_type="SingleOption", label="行业因子", order=3)
    #WeightFactor = Enum("等权", arg_type="SingleOption", label="权重因子", order=4)
    CalcDTs = List(dt.datetime, arg_type="DateList", label="计算时点", order=5)
    LookBack = ListInt(np.arange(1,13).tolist(), arg_type="NultiOpotion", label="回溯期数", order=6)
    CorrMethod = Enum("spearman", "pearson", "kendall", arg_type="SingleOption", label="相关性算法", order=7)
    IDFilter = Str(arg_type="IDFilter", label="筛选条件", order=8)
    def __init__(self, factor_table, name="IC 衰减", sys_args={}, **kwargs):
        self._FactorTable = factor_table
        super().__init__(name=name, sys_args=sys_args, **kwargs)
    def __QS_initArgs__(self):
        DefaultNumFactorList, DefaultStrFactorList = getFactorList(dict(self._FactorTable.getFactorMetaData(key="DataType")))
        self.add_trait("TestFactor", Enum(*DefaultNumFactorList, arg_type="SingleOption", label="测试因子", order=0))
        self.add_trait("PriceFactor", Enum(*DefaultNumFactorList, arg_type="SingleOption", label="价格因子", order=2))
        self.PriceFactor = searchNameInStrList(DefaultNumFactorList, ['价','Price','price'])
        self.add_trait("IndustryFactor", Enum(*(["无"]+DefaultStrFactorList), arg_type="SingleOption", label="行业因子", order=3))
        self.add_trait("WeightFactor", Enum(*(["等权"]+DefaultNumFactorList), arg_type="SingleOption", label="权重因子", order=4))
    def __QS_start__(self, mdl, dts, **kwargs):
        if self._isStarted: return ()
        super().__QS_start__(mdl=mdl, dts=dts, **kwargs)
        self._Output = {"IC":[[] for i in self.LookBack]}
        self._Output["时点"] = []
        self._CurCalcInd = 0
        return (self._FactorTable, )
    def __QS_move__(self, idt, **kwargs):
        if self._iDT==idt: return 0
        self._iDT = idt
        if self.CalcDTs:
            if idt not in self.CalcDTs[self._CurCalcInd:]: return 0
            self._CurCalcInd = self.CalcDTs[self._CurCalcInd:].index(idt) + self._CurCalcInd
            LastInd = self._CurCalcInd - 1
            LastDateTime = self.CalcDTs[LastInd]
        else:
            self._CurCalcInd = self._Model.DateTimeIndex
            LastInd = self._CurCalcInd - 1
            LastDateTime = self._Model.DateTimeSeries[LastInd]
        if (LastInd<0):
            for i, iRollBack in enumerate(self.LookBack):
                self._Output["IC"][i].append(np.nan)
            self._Output["时点"].append(idt)
            return 0
        Price = self._FactorTable.readData(dts=[LastDateTime, idt], ids=self._FactorTable.getID(ifactor_name=self.PriceFactor), factor_names=[self.PriceFactor]).iloc[0]
        Ret = Price.iloc[1] / Price.iloc[0] - 1
        for i, iRollBack in enumerate(self.LookBack):
            iPreInd = self._CurCalcInd - iRollBack
            if iPreInd<0:
                self._Output["IC"][i].append(np.nan)
                continue
            iPreDT = self.CalcDTs[iPreInd]
            iPreIDs = self._FactorTable.getFilteredID(idt=iPreDT, id_filter_str=self.IDFilter)
            iRet = Ret.loc[iPreIDs].copy()
            if self.IndustryFactor!="无":
                IndustryData = self._FactorTable.readData(dts=[iPreDT], ids=iPreIDs, factor_names=[self.IndustryFactor]).iloc[0,0,:]
                AllIndustry = IndustryData.unique()
                # 进行收益率的行业调整
                if self.WeightFactor=="等权":
                    for iIndustry in AllIndustry:
                        iRet[IndustryData==iIndustry] -= iRet[IndustryData==iIndustry].mean()
                else:
                    WeightData = self._FactorTable.readData(dts=[iPreDT], ids=iPreIDs, factor_names=[self.WeightFactor]).iloc[0,0,:]
                    for iIndustry in AllIndustry:
                        iWeight = WeightData[IndustryData==iIndustry]
                        iiRet = iRet[IndustryData==iIndustry]
                        iRet[IndustryData==iIndustry] -= (iiRet * iWeight).sum() / iWeight[pd.notnull(iWeight) & pd.notnull(iiRet)].sum(skipna=False)
            iFactorExpose = self._FactorTable.readData(dts=[iPreDT], ids=iPreIDs, factor_names=[self.TestFactor]).iloc[0,0,:]
            self._Output["IC"][i].append(iFactorExpose.corr(iRet, method=self.CorrMethod))
        self._Output["时点"].append(idt)
        return 0
    def __QS_end__(self):
        if not self._isStarted: return 0
        super().__QS_end__()
        self._Output["IC"] = pd.DataFrame(np.array(self._Output["IC"]).T, index=self._Output.pop("时点"), columns=list(self.LookBack))
        if self.FactorOrder=="升序": self._Output["IC"] = -self._Output["IC"]
        self._Output["统计数据"] = pd.DataFrame(index=self._Output["IC"].columns)
        self._Output["统计数据"]["IC平均值"] = self._Output["IC"].mean()
        nDT = pd.notnull(self._Output["IC"]).sum()
        self._Output["统计数据"]["标准差"] = self._Output["IC"].std()
        self._Output["统计数据"]["IC_IR"] = self._Output["统计数据"]["IC平均值"] / self._Output["统计数据"]["标准差"]
        self._Output["统计数据"]["t统计量"] = self._Output["统计数据"]["IC_IR"] * nDT**0.5
        self._Output["统计数据"]["胜率"] = (self._Output["IC"]>0).sum() / nDT
        return 0
    def genMatplotlibFig(self, file_path=None):
        Fig, Axes = plt.subplots(figsize=(16, 8))
        xData = np.arange(0, self._Output["统计数据"].shape[0])
        xTickLabels = [str(i) for i in self._Output["统计数据"].index]
        yMajorFormatter = FuncFormatter(_QS_formatMatplotlibPercentage)
        Axes.yaxis.set_major_formatter(yMajorFormatter)
        Axes.bar(xData, self._Output["统计数据"]["IC平均值"].values, label="IC", color="b")
        Axes.set_xticks(xData)
        Axes.set_xticklabels(xTickLabels)
        Axes.legend(loc='upper left')
        RAxes = Axes.twinx()
        RAxes.yaxis.set_major_formatter(yMajorFormatter)
        RAxes.plot(xData, self._Output["统计数据"]["胜率"].values, label="胜率", color="r", alpha=0.6, lw=3)
        RAxes.legend(loc="upper right")
        plt.setp(Axes.get_xticklabels(), visible=True, rotation=0, ha='center')
        if file_path is not None: Fig.savefig(file_path, dpi=150, bbox_inches='tight')
        return Fig
    def _repr_html_(self):
        if len(self.ArgNames)>0:
            HTML = "参数设置: "
            HTML += '<ul align="left">'
            for iArgName in self.ArgNames:
                if iArgName!="计算时点":
                    HTML += "<li>"+iArgName+": "+str(self.Args[iArgName])+"</li>"
                elif self.Args[iArgName]:
                    HTML += "<li>"+iArgName+": 自定义时点</li>"
                else:
                    HTML += "<li>"+iArgName+": 所有时点</li>"
            HTML += "</ul>"
        else:
            HTML = ""
        Formatters = [_QS_formatPandasPercentage]*2+[lambda x:'{0:.4f}'.format(x), lambda x:'{0:.2f}'.format(x), _QS_formatPandasPercentage]
        iHTML = self._Output["统计数据"].to_html(formatters=Formatters)
        Pos = iHTML.find(">")
        HTML += iHTML[:Pos]+' align="center"'+iHTML[Pos:]
        Fig = self.genMatplotlibFig()
        # figure 保存为二进制文件
        Buffer = BytesIO()
        plt.savefig(Buffer, bbox_inches='tight')
        PlotData = Buffer.getvalue()
        # 图像数据转化为 HTML 格式
        ImgStr = "data:image/png;base64,"+base64.b64encode(PlotData).decode()
        HTML += ('<img src="%s">' % ImgStr)
        return HTML
Exemple #26
0
    ViewStatus)

from .handler import Handler, default_handler

from .group import Group

from .item import Item

from .include import Include

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

# Name of the view trait:
AnId = Str(desc='the name of the view')

# Contents of the view trait (i.e., a single Group object):
Content = Instance(Group, desc='the content of the view')

# An optional model/view factory for converting the model into a viewable
# 'model_view' object
AModelView = Callable(desc='the factory function for converting a model '
                      'into a model/view object')

# Reference to a Handler object trait:
AHandler = Any(desc='the handler for the view')

# Dialog window title trait:
ATitle = Str(desc='the window title for the view')
Exemple #27
0
class Sike(HasTraits):
    """ Tie several profile-related widgets together.

    Sike is like Gotcha, only less mature.
    """

    # The main pstats.Stats() object providing the data.
    stats = Any()

    # The main results and the subcalls.
    main_results = Instance(ProfileResults, args=())
    caller_results = Instance(ProfileResults, args=())
    callee_results = Instance(ProfileResults, args=())

    # The records have list of callers. Invert this to give a map from function
    # to callee.
    callee_map = Dict()

    # Map from the (file, lineno, name) tuple to the record.
    record_map = Dict()

    #### GUI traits ############################################################

    basenames = Bool(True)
    percentages = Bool(True)
    filename = Str()
    line = Int(1)
    code = Str()

    traits_view = tui.View(
        tui.VGroup(
            tui.HGroup(
                tui.Item('basenames'),
                tui.Item('percentages'),
            ),
            tui.HGroup(
                tui.UItem('main_results'),
                tui.VGroup(
                    tui.Label('Callees'),
                    tui.UItem('callee_results'),
                    tui.Label('Callers'),
                    tui.UItem('caller_results'),
                    tui.UItem('filename', style='readonly'),
                    tui.UItem('code', editor=tui.CodeEditor(line='line')),
                ),
                style='custom',
            ),
        ),
        width=1024,
        height=768,
        resizable=True,
        title='Profiling results',
    )

    @classmethod
    def fromstats(cls, stats, **traits):
        """ Instantiate an Sike from a Stats object, Stats.stats dictionary, or
        Profile object, or a filename of the saved Stats data.
        """
        stats = SillyStatsWrapper.getstats(stats)

        self = cls(stats=stats, **traits)
        self._refresh_stats()
        return self

    def add_stats(self, stats):
        """ Add new statistics.
        """
        stats = SillyStatsWrapper.getstats(stats)
        self.stats.add(stats)
        self._refresh_stats()

    def records_from_stats(self, stats):
        """ Create a list of records from a stats dictionary.
        """
        records = []
        for file_line_name, (ncalls, nonrec_calls, inline_time, cum_time,
                             calls) in list(stats.items()):
            newcalls = []
            for sub_file_line_name, sub_call in list(calls.items()):
                newcalls.append(Subrecord((sub_file_line_name, ) + sub_call))
            records.append(
                Record((file_line_name, ncalls, nonrec_calls, inline_time,
                        cum_time, newcalls)))
        return records

    def get_callee_map(self, records):
        """ Create a callee map.
        """
        callees = defaultdict(list)
        for record in records:
            for caller in record.callers:
                callees[caller.file_line_name].append(
                    Subrecord((record.file_line_name, ) + caller[1:]))
        return callees

    @on_trait_change('percentages,basenames')
    def _adapter_traits_changed(self, object, name, old, new):
        for obj in [
                self.main_results, self.callee_results, self.caller_results
        ]:
            setattr(obj, name, new)

    @on_trait_change('main_results:selected_record')
    def update_sub_results(self, new):
        if new is None:
            return
        self.caller_results.total_time = new.cum_time
        self.caller_results.records = new.callers
        self.callee_results._resort()
        self.caller_results.selected_record = self.caller_results.activated_record = None

        self.callee_results.total_time = new.cum_time
        self.callee_results.records = self.callee_map.get(
            new.file_line_name, [])
        self.callee_results._resort()
        self.callee_results.selected_record = self.callee_results.activated_record = None

        filename, line, name = new.file_line_name
        if os.path.exists(filename):
            with open(filename, 'ru') as f:
                code = f.read()
            self.code = code
            self.filename = filename
            self.line = line
        else:
            self.trait_set(
                code='',
                filename='',
                line=1,
            )

    @on_trait_change('caller_results:dclicked,' 'callee_results:dclicked')
    def goto_record(self, new):
        if new is None:
            return
        if new.item.file_line_name in self.record_map:
            record = self.record_map[new.item.file_line_name]
            self.main_results.selected_record = record

    @on_trait_change('stats')
    def _refresh_stats(self):
        """ Refresh the records from the stored Stats object.
        """
        self.main_results.records = self.main_results.sort_records(
            self.records_from_stats(self.stats.stats))
        self.callee_map = self.get_callee_map(self.main_results.records)
        self.record_map = {}
        total_time = 0.0
        for record in self.main_results.records:
            self.record_map[record.file_line_name] = record
            total_time += record.inline_time
        self.main_results.total_time = total_time
class TabularAdapter(HasPrivateTraits):
    """ The base class for adapting list items to values that can be edited
        by a TabularEditor.
    """

    # -- Public Trait Definitions ---------------------------------------------

    #: A list of columns that should appear in the table. Each entry can have
    #: one of two forms: ``string`` or ``(string, id)``, where ``string`` is
    #: the UI name of the column, and ``id`` is a value that identifies that
    #: column to the adapter. Normally this value is either a trait name or an
    #: index, but it can be any value that the adapter wants. If only
    #: ``string`` is specified, then ``id`` is the index of the ``string``
    #: within :py:attr:`columns`.
    columns = List()

    #: Maps UI name of column to value identifying column to the adapter, if
    #: different.
    column_dict = Property()

    #: Specifies the default value for a new row.  This will usually need to be
    #: overridden.
    default_value = Any("")

    #: The default text color for odd table rows.
    odd_text_color = Color(None, update=True)

    #: The default text color for even table rows.
    even_text_color = Color(None, update=True)

    #: The default text color for table rows.
    default_text_color = Color(None, update=True)

    #: The default background color for odd table rows.
    odd_bg_color = Color(None, update=True)

    #: The default background color for even table rows.
    even_bg_color = Color(None, update=True)

    #: The default background color for table rows.
    default_bg_color = Color(None, update=True)

    #: Horizontal alignment to use for a specified column.
    alignment = Enum("left", "center", "right")

    #: The Python format string to use for a specified column.
    format = Str("%s")

    #: Width of a specified column.
    width = Float(-1)

    #: Can the text value of each item be edited?
    can_edit = Bool(True)

    #: The value to be dragged for a specified row item.
    drag = Property()

    #: Can any arbitrary value be dropped onto the tabular view.
    can_drop = Bool(False)

    #: Specifies where a dropped item should be placed in the table relative to
    #: the item it is dropped on.
    dropped = Enum("after", "before")

    #: The font for a row item.
    font = Font(None)

    #: The text color for a row item.
    text_color = Property()

    #: The background color for a row item.
    bg_color = Property()

    #: The name of the default image to use for column items.
    image = Str(None, update=True)

    #: The text of a row/column item.
    text = Property()

    #: The content of a row/column item (may be any Python value).
    content = Property()

    #: The tooltip information for a row/column item.
    tooltip = Str()

    #: The context menu for a row/column item.
    menu = Any()

    #: The context menu for column header.
    column_menu = Any()

    #: List of optional delegated adapters.
    adapters = List(ITabularAdapter, update=True)

    # -- Traits Set by the Editor ---------------------------------------------

    #: The object whose trait is being edited.
    object = Instance(HasTraits)

    #: The name of the trait being edited.
    name = Str()

    #: The row index of the current item being adapted.
    row = Int()

    #: The column index of the current item being adapted.
    column = Int()

    #: The current column id being adapted (if any).
    column_id = Any()

    #: Current item being adapted.
    item = Any()

    #: The current value (if any).
    value = Any()

    # -- Private Trait Definitions --------------------------------------------

    #: Cache of attribute handlers.
    cache = Any({})

    #: Event fired when the cache is flushed.
    cache_flushed = Event(update=True)

    #: The mapping from column indices to column identifiers (defined by the
    #: :py:attr:`columns` trait).
    column_map = Property(depends_on="columns")

    #: The mapping from column indices to column labels (defined by the
    #: :py:attr:`columns` trait).
    label_map = Property(depends_on="columns")

    #: The name of the trait on a row item containing the value to use
    #: as a row label. If ``None``, the label will be the empty string.
    row_label_name = Either(None, Str)

    #: For each adapter, specifies the column indices the adapter handles.
    adapter_column_indices = Property(depends_on="adapters,columns")

    #: For each adapter, specifies the mapping from column index to column id.
    adapter_column_map = Property(depends_on="adapters,columns")

    # -------------------------------------------------------------------------
    # TabularAdapter interface
    # -------------------------------------------------------------------------

    def cleanup(self):
        """ Clean up the adapter to remove references to objects.
        """
        self.trait_setq(object=None, item=None, value=None)

    # -- Adapter methods that are sensitive to item type ----------------------

    def get_alignment(self, object, trait, column):
        """ Returns the alignment style to use for a specified column.

        The possible values that can be returned are: ``'left'``, ``'center'``
        or ``'right'``. All table items share the same alignment for a
        specified column.
        """
        return self._result_for("get_alignment", object, trait, 0, column)

    def get_width(self, object, trait, column):
        """ Returns the width to use for a specified column.

        If the value is <= 0, the column will have a *default* width, which is
        the same as specifying a width of 0.1.

        If the value is > 1.0, it is converted to an integer and the result is
        the width of the column in pixels. This is referred to as a
        *fixed width* column.

        If the value is a float such that 0.0 < value <= 1.0, it is treated as
        the *unnormalized fraction of the available space* that is to be
        assigned to the column. What this means requires a little explanation.

        To arrive at the size in pixels of the column at any given time, the
        editor adds together all of the *unnormalized fraction* values
        returned for all columns in the table to arrive at a total value. Each
        *unnormalized fraction* is then divided by the total to create a
        *normalized fraction*. Each column is then assigned an amount of space
        in pixels equal to the maximum of 30 or its *normalized fraction*
        multiplied by the *available space*. The *available space* is defined
        as the actual width of the table minus the width of all *fixed width*
        columns. Note that this calculation is performed each time the table is
        resized in the user interface, thus allowing columns of this type to
        increase or decrease their width dynamically, while leaving *fixed
        width* columns unchanged.
        """
        return self._result_for("get_width", object, trait, 0, column)

    def get_can_edit(self, object, trait, row):
        """ Returns whether the user can edit a specified row.

        A ``True`` result indicates that the value can be edited, while a
        ``False`` result indicates that it cannot.
        """
        return self._result_for("get_can_edit", object, trait, row, 0)

    def get_drag(self, object, trait, row):
        """ Returns the value to be *dragged* for a specified row.

        A result of ``None`` means that the item cannot be dragged. Note that
        the value returned does not have to be the actual row item. It can be
        any value that you want to drag in its place. In particular, if you
        want the drag target to receive a copy of the row item, you should
        return a copy or clone of the item in its place.

        Also note that if multiple items are being dragged, and this method
        returns ``None`` for any item in the set, no drag operation is
        performed.
        """
        return self._result_for("get_drag", object, trait, row, 0)

    def get_can_drop(self, object, trait, row, value):
        """ Returns whether the specified ``value`` can be dropped on the specified row.

        A value of ``True`` means the ``value`` can be dropped; and a value of
        ``False`` indicates that it cannot be dropped.

        The result is used to provide the user positive or negative drag
        feedback while dragging items over the table. ``value`` will always be
        a single value, even if multiple items are being dragged. The editor
        handles multiple drag items by making a separate call to
        :py:meth:`get_can_drop` for each item being dragged.
        """
        return self._result_for("get_can_drop", object, trait, row, 0, value)

    def get_dropped(self, object, trait, row, value):
        """ Returns how to handle a specified ``value`` being dropped on a specified row.

        The possible return values are:

        - ``'before'``: Insert the specified ``value`` before the dropped on item.
        - ``'after'``: Insert the specified ``value`` after the dropped on item.

        Note there is no result indicating *do not drop* since you will have
        already indicated that the ``object`` can be dropped by the result
        returned from a previous call to :py:meth:`get_can_drop`.
        """
        return self._result_for("get_dropped", object, trait, row, 0, value)

    def get_font(self, object, trait, row, column=0):
        """ Returns the font to use for displaying a specified row or cell.

        A result of ``None`` means use the default font; otherwise a toolkit
        font object should be returned. Note that all columns for the specified
        table row will use the font value returned.
        """
        return self._result_for("get_font", object, trait, row, column)

    def get_text_color(self, object, trait, row, column=0):
        """ Returns the text color to use for a specified row or cell.

        A result of ``None`` means use the default text color; otherwise a
        toolkit-compatible color should be returned. Note that all columns for
        the specified table row will use the text color value returned.
        """
        return self._result_for("get_text_color", object, trait, row, column)

    def get_bg_color(self, object, trait, row, column=0):
        """ Returns the background color to use for a specified row or cell.

        A result of ``None`` means use the default background color; otherwise
        a toolkit-compatible color should be returned. Note that all columns
        for the specified table row will use the background color value
        returned.
        """
        return self._result_for("get_bg_color", object, trait, row, column)

    def get_image(self, object, trait, row, column):
        """ Returns the image to display for a specified cell.

        A result of ``None`` means no image will be displayed in the specified
        table cell. Otherwise the result should either be the name of the
        image, or an :py:class:`~pyface.image_resource.ImageResource` object
        specifying the image to display.

        A name is allowed in the case where the image is specified in the
        :py:class:`~traitsui.editors.tabular_editor.TabularEditor`
        :py:attr:`~traitsui.editors.tabular_editor.TabularEditor.images` trait.
        In that case, the name should be the same as the string specified in
        the :py:class:`~pyface.image_resource.ImageResource` constructor.
        """
        return self._result_for("get_image", object, trait, row, column)

    def get_format(self, object, trait, row, column):
        """ Returns the Python formatting string to apply to the specified cell.

        The resulting of formatting with this string will be used as the text
        to display it in the table.

        The return can be any Python string containing exactly one old-style
        Python formatting sequence, such as ``'%.4f'`` or ``'(%5.2f)'``.
        """
        return self._result_for("get_format", object, trait, row, column)

    def get_text(self, object, trait, row, column):
        """ Returns a string containing the text to display for a specified cell.

        If the underlying data representation for a specified item is not a
        string, then it is your responsibility to convert it to one before
        returning it as the result.
        """
        return self._result_for("get_text", object, trait, row, column)

    def get_content(self, object, trait, row, column):
        """ Returns the content to display for a specified cell.
        """
        return self._result_for("get_content", object, trait, row, column)

    def set_text(self, object, trait, row, column, text):
        """ Sets the value for the specified cell.

        This method is called when the user completes an editing operation on a
        table cell.

        The string specified by ``text`` is the value that the user has
        entered in the table cell.  If the underlying data does not store the
        value as text, it is your responsibility to convert ``text`` to the
        correct representation used.
        """
        self._result_for("set_text", object, trait, row, column, text)

    def get_tooltip(self, object, trait, row, column):
        """ Returns a string containing the tooltip to display for a specified cell.

        You should return the empty string if you do not wish to display a
        tooltip.
        """
        return self._result_for("get_tooltip", object, trait, row, column)

    def get_menu(self, object, trait, row, column):
        """ Returns the context menu for a specified cell.
        """
        return self._result_for("get_menu", object, trait, row, column)

    def get_column_menu(self, object, trait, row, column):
        """ Returns the context menu for a specified column.
        """
        return self._result_for("get_column_menu", object, trait, row, column)

    # -- Adapter methods that are not sensitive to item type ------------------

    def get_item(self, object, trait, row):
        """ Returns the specified row item.

        The value returned should be the value that exists (or *logically*
        exists) at the specified ``row`` in your data. If your data is not
        really a list or array, then you can just use ``row`` as an integer
        *key* or *token* that can be used to retrieve a corresponding item. The
        value of ``row`` will always be in the range: 0 <= row <
        ``len(object, trait)`` (i.e. the result returned by the adapter
        :py:meth:`len` method).

        The default implementation assumes the trait defined by
        ``object.trait`` is a *sequence* and attempts to return the value at
        index ``row``. If an error occurs, it returns ``None`` instead. This
        definition should work correctly for lists, tuples and arrays, or any
        other object that is indexable, but will have to be overridden for all
        other cases.
        """
        try:
            return getattr(object, trait)[row]
        except:
            return None

    def len(self, object, trait):
        """ Returns the number of row items in the specified ``object.trait``.

        The result should be an integer greater than or equal to 0.

        The default implementation assumes the trait defined by
        ``object.trait`` is a *sequence* and attempts to return the result of
        calling ``len(object.trait)``. It will need to be overridden for any
        type of data which for which :py:func:`len` will not work.
        """
        # Sometimes, during shutdown, the object has been set to None.
        if object is None:
            return 0
        else:
            return len(getattr(object, trait))

    def get_default_value(self, object, trait):
        """ Returns a new default value for the specified ``object.trait`` list.

        This method is called when *insert* or *append* operations are allowed
        and the user requests that a new item be added to the table. The result
        should be a new instance of whatever underlying representation is being
        used for table items.

        The default implementation simply returns the value of the adapter's
        :py:attr:`default_value` trait.
        """
        return self.default_value

    def delete(self, object, trait, row):
        """ Deletes the specified row item.

        This method is only called if the *delete* operation is specified in
        the :py:class:`~traitsui.editors.tabular_editor.TabularEditor`
        :py:attr:`~traitsui.editors.tabular_editor.TabularEditor.operation`
        trait, and the user requests that the item be deleted from the table.

        The adapter can still choose not to delete the specified item if
        desired, although that may prove confusing to the user.

        The default implementation assumes the trait defined by
        ``object.trait`` is a mutable sequence and attempts to perform a
        ``del object.trait[row]`` operation.
        """
        del getattr(object, trait)[row]

    def insert(self, object, trait, row, value):
        """ Inserts ``value`` at the specified ``object.trait[row]`` index.

        The specified ``value`` can be:

        - An item being moved from one location in the data to another.
        - A new item created by a previous call to
          :py:meth:`~TabularAdapter.get_default_value`.
        - An item the adapter previously approved via a call to
          :py:meth:`~TabularAdapter.get_can_drop`.

        The adapter can still choose not to insert the item into the data,
        although that may prove confusing to the user.

        The default implementation assumes the trait defined by
        ``object.trait`` is a mutable sequence and attempts to perform an
        ``object.trait[row:row] = [value]`` operation.
        """
        getattr(object, trait)[row:row] = [value]

    def get_column(self, object, trait, index):
        """ Returns the column id corresponding to a specified column index.
        """
        self.object, self.name = object, trait
        return self.column_map[index]

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

    def _get_drag(self):
        return self.item

    def _get_text_color(self):
        if (self.row % 2) == 1:
            return self.even_text_color_ or self.default_text_color

        return self.odd_text_color or self.default_text_color_

    def _get_bg_color(self):
        if (self.row % 2) == 1:
            return self.even_bg_color_ or self.default_bg_color_

        return self.odd_bg_color or self.default_bg_color_

    def _get_text(self):
        return self.get_format(
            self.object, self.name, self.row, self.column) % self.get_content(
                self.object, self.name, self.row, self.column)

    def _set_text(self, value):
        if isinstance(self.column_id, int):
            self.item[self.column_id] = self.value
        else:
            # Convert value to the correct trait type.
            try:
                trait_handler = self.item.trait(self.column_id).handler
                setattr(
                    self.item,
                    self.column_id,
                    trait_handler.evaluate(self.value),
                )
            except:
                setattr(self.item, self.column_id, value)

    def _get_content(self):
        if isinstance(self.column_id, int):
            return self.item[self.column_id]

        return getattr(self.item, self.column_id)

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

    @cached_property
    def _get_column_dict(self):
        cols = {}
        for i, value in enumerate(self.columns):
            if isinstance(value, str):
                cols.update({value: value})
            else:
                cols.update({value[0]: value[1]})
        return cols

    @cached_property
    def _get_column_map(self):
        map = []
        for i, value in enumerate(self.columns):
            if isinstance(value, str):
                map.append(i)
            else:
                map.append(value[1])

        return map

    def get_label(self, section, obj=None):
        """Override this method if labels will vary from object to object."""
        return self.label_map[section]

    def get_row_label(self, section, obj=None):
        if self.row_label_name is None:
            return None
        rows = getattr(obj, self.name, None)
        if rows is None:
            return None
        item = rows[section]
        return getattr(item, self.row_label_name, None)

    @cached_property
    def _get_label_map(self):
        map = []
        for i, value in enumerate(self.columns):
            if isinstance(value, str):
                map.append(value)
            else:
                map.append(value[0])

        return map

    @cached_property
    def _get_adapter_column_indices(self):
        labels = self.label_map
        map = []
        for adapter in self.adapters:
            indices = []
            for label in adapter.columns:
                if not isinstance(label, str):
                    label = label[0]

                indices.append(labels.index(label))
            map.append(indices)
        return map

    @cached_property
    def _get_adapter_column_map(self):
        labels = self.label_map
        map = []
        for adapter in self.adapters:
            mapping = {}
            for label in adapter.columns:
                id = None
                if not isinstance(label, str):
                    label, id = label

                key = labels.index(label)
                if id is None:
                    id = key

                mapping[key] = id

            map.append(mapping)

        return map

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

    def _result_for(self, name, object, trait, row, column, value=None):
        """ Returns/Sets the value of the specified *name* attribute for the
            specified *object.trait[row].column* item.
        """
        self.object = object
        self.name = trait
        self.row = row
        self.column = column
        self.column_id = column_id = self.column_map[column]
        self.value = value
        self.item = item = self.get_item(object, trait, row)
        item_class = item.__class__
        key = "%s:%s:%d" % (item_class.__name__, name, column)
        handler = self.cache.get(key)
        if handler is not None:
            return handler()

        prefix = name[:4]
        trait_name = name[4:]

        for i, adapter in enumerate(self.adapters):
            if column in self.adapter_column_indices[i]:
                adapter.row = row
                adapter.item = item
                adapter.value = value
                adapter.column = column_id = self.adapter_column_map[i][column]
                if adapter.accepts:
                    get_name = "%s_%s" % (column_id, trait_name)
                    if adapter.trait(get_name) is not None:
                        if prefix == "get_":
                            handler = lambda: getattr(
                                adapter.trait_set(
                                    row=self.row,
                                    column=column_id,
                                    item=self.item,
                                ),
                                get_name,
                            )
                        else:
                            handler = lambda: setattr(
                                adapter.trait_set(
                                    row=self.row,
                                    column=column_id,
                                    item=self.item,
                                ),
                                get_name,
                                self.value,
                            )

                        if adapter.is_cacheable:
                            break

                        return handler()
        else:
            if item is not None and hasattr(item_class, "__mro__"):
                for klass in item_class.__mro__:
                    handler = self._get_handler_for(
                        "%s_%s_%s" % (klass.__name__, column_id, trait_name),
                        prefix,
                    ) or self._get_handler_for(
                        "%s_%s" % (klass.__name__, trait_name), prefix)
                    if handler is not None:
                        break

            if handler is None:
                handler = self._get_handler_for(
                    "%s_%s" % (column_id, trait_name),
                    prefix) or self._get_handler_for(trait_name, prefix)

        self.cache[key] = handler
        return handler()

    def _get_handler_for(self, name, prefix):
        """ Returns the handler for a specified trait name (or None if not
            found).
        """
        if self.trait(name) is not None:
            if prefix == "get_":
                return lambda: getattr(self, name)

            return lambda: setattr(self, name, self.value)

        return None

    @on_trait_change("columns,adapters.+update")
    def _flush_cache(self):
        """ Flushes the cache when the columns or any trait on any adapter
            changes.
        """
        self.cache = {}
        self.cache_flushed = True
Exemple #29
0
class TableFilter(HasPrivateTraits):
    """ Filter for items displayed in a table.
    """

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

    # UI name of this filter (so the user can identify it in the UI)
    name = Str('Default filter')

    # Default name that can be automatically overridden
    _name = Str('Default filter')

    # A user-readable description of what kind of object satisfies the filter
    desc = Str('All items')

    # A callable function that returns whether the passed object is allowed
    # by the filter
    allowed = Callable(lambda object: True, transient=True)

    # Is the filter a template (i.e., non-deletable, non-editable)?
    template = Bool(False)

    #-------------------------------------------------------------------------
    #  Class constants:
    #-------------------------------------------------------------------------

    # Traits that are ignored by the _anytrait_changed() handler
    ignored_traits = ['_name', 'template', 'desc']

    #-------------------------------------------------------------------------
    #  Traits view definitions:
    #-------------------------------------------------------------------------

    traits_view = View(
        'name{Filter name}',
        '_',
        Include('filter_view'),
        title='Edit Filter',
        width=0.2,
        buttons=[
            'OK', 'Cancel',
            Action(name='Help',
                   action='show_help',
                   defined_when="ui.view_elements.content['filter_view']"
                   ".help_id != ''")
        ])

    searchable_view = View(
        [[Include('search_view'), '|[]'], ['handler.status~', '|[]<>'],
         [
             'handler.find_next`Find the next matching item`',
             'handler.find_previous`Find the previous matching item`',
             'handler.select`Select all matching items`',
             'handler.OK`Exit search`', '-<>'
         ], '|<>'],
        title='Search for',
        kind='livemodal',
        width=0.25)

    search_view = Group(Include('filter_view'))

    filter_view = Group()

    #-------------------------------------------------------------------------
    #  Returns whether a specified object meets the filter/search criteria:
    #  (Should normally be overridden)
    #-------------------------------------------------------------------------

    def filter(self, object):
        """ Returns whether a specified object meets the filter or search
        criteria.
        """
        return self.allowed(object)

    #-------------------------------------------------------------------------
    #  Returns a user readable description of what kind of object will
    #  satisfy the filter:
    #  (Should normally be overridden):
    #-------------------------------------------------------------------------

    def description(self):
        """ Returns a user-readable description of what kind of object
        satisfies the filter.
        """
        return self.desc

    #-------------------------------------------------------------------------
    #  Edits the contents of the filter:
    #-------------------------------------------------------------------------

    def edit(self, object):
        """ Edits the contents of the filter.
        """
        return self.edit_traits(view=self.edit_view(object), kind='livemodal')

    def edit_view(self, object):
        """ Return a view to use for editing the filter.

        The ''object'' parameter is a sample object for the table that the
        filter will be applied to. It is supplied in case the filter needs to
        extract data or metadata from the object. If the table is empty, the
        ''object'' argument is None.
        """
        return None

    #-------------------------------------------------------------------------
    #  'object' interface:
    #-------------------------------------------------------------------------

    def __str__(self):
        return self.name

    #-------------------------------------------------------------------------
    #  Event handlers:
    #-------------------------------------------------------------------------

    def _anytrait_changed(self, name, old, new):
        if ((name not in self.ignored_traits)
                and ((self.name == self._name) or (self.name == ''))):
            self.name = self._name = self.description()
Exemple #30
0
class ThresholdOp(HasStrictTraits):
    """Apply a threshold to a cytometry experiment.
    
    Attributes
    ----------
    name : Str
        The operation name.  Used to name the new metadata field in the
        experiment that's created by apply()
        
    channel : Str
        The name of the channel to apply the threshold on.
        
    threshold : Float
        The value at which to threshold this channel.
        
    Examples
    --------
    >>> thresh = flow.ThresholdOp()
    >>> thresh.name = "Y2-A+"
    >>> thresh.channel = 'Y2-A'
    >>> thresh.threshold = 0.3
    >>> 
    >>> ex3 = thresh.apply(ex2)    
    
    Alternately, in an IPython notebook with `%matplotlib notebook`
    
    >>> h = flow.HistogramView()
    >>> h.channel = 'Y2-A'
    >>> h.huefacet = 'Dox'
    >>> ts = flow.ThresholdSelection(view = h)
    >>> ts.plot(ex2)
    >>> ts.interactive = True
    >>> # .... draw a threshold on the plot
    >>> thresh = flow.ThresholdOp(name = "Y2-A+",
    ...                           channel = "Y2-A",
    ...                           thresh.threshold = ts.threshold)
    >>> ex3 = thresh.apply(ex2)
    """

    # traits
    id = Constant('edu.mit.synbio.cytoflow.operations.threshold')
    friendly_id = Constant("Threshold")

    name = CStr()
    channel = Str()
    threshold = CFloat()

    def apply(self, experiment):
        """Applies the threshold to an experiment.
        
        Parameters
        ----------
        old_experiment : Experiment
            the experiment to which this op is applied
            
        Returns
        -------
            a new experiment, the same as old_experiment but with a new
            column the same as the operation name.  The bool is True if the
            event's measurement in self.channel is greater than self.threshold;
            it is False otherwise.
        """

        if not experiment:
            raise util.CytoflowOpError("No experiment specified")

        # make sure name got set!
        if not self.name:
            raise util.CytoflowOpError("You have to set the gate's name "
                                       "before applying it!")

        # make sure old_experiment doesn't already have a column named self.name
        if (self.name in experiment.data.columns):
            raise util.CytoflowOpError(
                "Experiment already contains a column {0}".format(self.name))

        if self.channel not in experiment.channels:
            raise util.CytoflowOpError(
                "{0} isn't a channel in the experiment".format(self.channel))

        gate = pd.Series(experiment[self.channel] > self.threshold)

        new_experiment = experiment.clone()
        new_experiment.add_condition(self.name, "bool", gate)
        new_experiment.history.append(self.clone_traits())
        return new_experiment

    def default_view(self, **kwargs):
        return ThresholdSelection(op=self, **kwargs)