Changeset 3590:777de4aed8d1 in orange


Ignore:
Timestamp:
04/26/07 02:10:18 (7 years ago)
Author:
janezd <janez.demsar@…>
Branch:
default
Convert:
0398af6e942b54f1629aff9885a05738a3cd6394
Message:
  • multiple attributes can now be added
File:
1 edited

Legend:

Unmodified
Added
Removed
  • orange/OrangeWidgets/Prototypes/OWFeatureConstructor.py

    r3587 r3590  
    1010import OWGUI, math, re 
    1111 
    12 re_identifier = re.compile(r'((?<=\W)[a-zA-Z_]\w*(?=(\Z|\W)))|("[^"]+")') 
    13  
    14 def identifier_replacer(id): 
    15     id = id.group() 
    16     if id in math.__dict__: 
     12re_identifier = re.compile(r'([a-zA-Z_]\w*)|("[^"]+")') 
     13 
     14class IdentifierReplacer: 
     15    def __init__(self, reinserted, attributes): 
     16        self.reinserted = reinserted 
     17        self.attributes = attributes 
     18         
     19    def __call__(self, id): 
     20        id = id.group() 
     21        if id in self.reinserted: 
     22            return "(%s)" % self.reinserted[id] 
     23        if (id[0] == id[-1] == '"') and (id[1:-1] in self.attributes): 
     24            return "_ex[%s]" % id 
     25        if id in self.attributes: 
     26            return "_ex['%s']" % id 
    1727        return id 
    18     if id[0] == id[-1] == '"': 
    19         return "_ex[%s]" % id 
    20     else: 
    21         return "_ex['%s']" % id 
     28 
    2229 
    2330class AttrComputer: 
     
    3138            return "?" 
    3239         
     40 
    3341class OWFeatureConstructor(OWWidget): 
    3442    def __init__(self,parent=None, signalManager = None): 
     
    3947 
    4048        self.expression = self.attrname = "" 
     49        self.selectedDef = [] 
     50        self.defLabels = [] 
    4151        self.data = None 
    42         OWGUI.lineEdit(self.controlArea, self, "attrname", "Attribute name") 
     52        self.definitions = [] 
     53         
     54        self.selectedAttr = 0 
     55        self.selectedFunc = 0 
     56         
     57        hb = OWGUI.widgetBox(self.controlArea, None, "horizontal") 
     58         
     59        vb = OWGUI.widgetBox(hb, None, "vertical") 
     60        self.leAttrName = OWGUI.lineEdit(vb, self, "attrname", "New attribute") 
     61        OWGUI.rubber(vb) 
     62         
     63        OWGUI.separator(hb, 8, 8) 
     64         
     65        vb = OWGUI.widgetBox(hb, None, "vertical") 
     66        self.leExpression = OWGUI.lineEdit(vb, self, "expression", "Expression") 
     67        hhb = OWGUI.widgetBox(vb, None, "horizontal") 
     68        self.cbAttrs = OWGUI.comboBox(hhb, self, "selectedAttr", items = ["(all attributes)"], callback = self.attrListSelected) 
     69        self.cbFuncs = OWGUI.comboBox(hhb, self, "selectedFunc", items = ["(all functions)"] + [m for m in math.__dict__.keys() if m[:2]!="__"], callback = self.funcListSelected) 
     70         
     71        OWGUI.separator(hb, 8, 8) 
     72        OWGUI.button(hb, self, "Clear", callback = self.clearLineEdits) 
     73         
     74        OWGUI.separator(self.controlArea, 12, 12) 
     75 
     76        hb = OWGUI.widgetBox(self.controlArea, None, "horizontal") 
     77        OWGUI.button(hb, self, "Add", callback = self.addAttr) 
     78        OWGUI.button(hb, self, "Update", callback = self.updateAttr) 
     79        OWGUI.button(hb, self, "Remove", callback = self.removeAttr) 
     80        OWGUI.button(hb, self, "Remove All", callback = self.removeAllAttr) 
     81         
    4382        OWGUI.separator(self.controlArea) 
    44         OWGUI.lineEdit(self.controlArea, self, "expression", "Expression") 
     83        self.lbDefinitions = OWGUI.listBox(self.controlArea, self, "selectedDef", "defLabels", callback=self.selectAttr) 
     84        self.lbDefinitions.setFixedHeight(160) 
     85 
    4586        OWGUI.separator(self.controlArea) 
    4687        OWGUI.button(self.controlArea, self, "Apply", callback = self.apply) 
     88 
     89        self.definitions = [("x", '"petal length"+2'), ("z", "x+2"), ("u", "x+z"), ("zz", '"petal length"**3+"sepal length"')] 
     90        self.loadDefinitions() 
    4791        self.adjustSize() 
     92 
     93 
     94    def loadDefinitions(self): 
     95        self.defLabels = ["%s := %s" % t for t in self.definitions] 
     96        self.selectedDef = [] 
    4897 
    4998    def setData(self, data): 
    5099        if not self.data or self.data.domain != data.domain: 
    51             self.expression = self.attrname = "" 
     100            self.clearLineEdits() 
    52101        self.data = data 
    53  
     102        self.cbAttrs.clear() 
     103        self.cbAttrs.insertItem("(all attributes)") 
     104        if self.data: 
     105            for attr in self.data.domain: 
     106                self.cbAttrs.insertItem(attr.name) 
     107         
     108         
     109    def clearLineEdits(self): 
     110        self.expression = self.attrname = "" 
     111         
     112    def addAttr(self): 
     113        if not self.attrname: 
     114            self.leAttrName.setFocus() 
     115            return 
     116        if not self.expression: 
     117            self.leExpression.setFocus() 
     118            return 
     119        self.defLabels = self.defLabels + ["%s := %s" % (self.attrname, self.expression)] 
     120        self.definitions.append((self.attrname, self.expression)) 
     121        self.expression = self.attrname = "" 
     122         
     123    def removeAttr(self): 
     124        if self.selectedDef: 
     125            selected = self.selectedDef[0] 
     126            if 0 <= selected < self.lbDefinitions.count(): 
     127                self.defLabels = self.defLabels[:selected] + self.defLabels[selected+1:] 
     128                del self.definitions[selected] 
     129 
     130    def removeAllAttr(self): 
     131        self.defLabels = [] 
     132        self.definitions = [] 
     133        self.clearLineEdits() 
     134         
     135    def updateAttr(self): 
     136        selected = self.selectedDef[0] 
     137        if 0 <= selected < self.lbDefinitions.count(): 
     138            self.defLabels = self.defLabels[:selected] + ["%s := %s" % (self.attrname, self.expression)] + self.defLabels[selected+1:] 
     139            self.definitions[selected] = (self.attrname, self.expression) 
     140     
     141    def selectAttr(self): 
     142        selected = self.selectedDef[0] 
     143        if 0 <= selected < self.lbDefinitions.count(): 
     144            self.attrname, self.expression = self.definitions[selected] 
     145        else: 
     146            self.attrname = self.expression = "" 
     147         
     148    def insertIntoExpression(self, what): 
     149        if self.leExpression.hasMarkedText(): 
     150            self.leExpression.delChar() 
     151         
     152        cp = self.leExpression.cursorPosition() 
     153        self.expression = self.expression[:cp] + what + self.expression[cp:] 
     154        self.leExpression.setFocus() 
     155     
     156    def attrListSelected(self): 
     157        if self.selectedAttr: 
     158            attr = str(self.cbAttrs.text(self.selectedAttr)) 
     159            mo = re_identifier.match(attr) 
     160            if not mo or mo.span()[1] != len(attr): 
     161                attr = '"%s"' % attr 
     162             
     163            self.insertIntoExpression(attr) 
     164            self.selectedAttr = 0 
     165         
     166    def funcListSelected(self): 
     167        if self.selectedFunc: 
     168            func = str(self.cbFuncs.text(self.selectedFunc)) 
     169            if func in ["atan2", "fmod", "ldexp", "log", "pow"]: 
     170                self.insertIntoExpression(func + "(,)") 
     171                self.leExpression.cursorLeft(False, 2) 
     172            elif func == "pi": 
     173                self.insertIntoExpression(func) 
     174            else: 
     175                self.insertIntoExpression(func + "()") 
     176                self.leExpression.cursorLeft(False) 
     177             
     178            self.selectedFunc = 0 
     179         
     180     
    54181    def apply(self): 
    55182        if not self.data: 
     
    58185 
    59186        oldDomain = self.data.domain 
    60          
    61         if self.attrname: 
    62             attrname = self.attrname 
    63         else: 
    64             t = 1 
    65             while "T%04i" % t in oldDomain: 
    66                 t += 1 
    67             attrname = "T%04i" % t 
    68  
    69         exp = re_identifier.sub(identifier_replacer, " "+self.expression) 
    70         newattr = orange.FloatVariable(str(attrname), getValueFrom = AttrComputer(exp)) 
    71  
    72         newDomain = orange.Domain(oldDomain.attributes + [newattr], oldDomain.classVar) 
     187 
     188        names = [d[0] for d in self.definitions] 
     189        unknown = [[name, exp, set([id[0] or id[1] for id in re_identifier.findall(exp) if id[0] in names or id[1][1:-1] in names])] for name, exp in self.definitions] 
     190        reinserted = {} 
     191        replacer = IdentifierReplacer(reinserted, [n.name for n in oldDomain]) 
     192        while unknown: 
     193            solved = set() 
     194            for i, (name, exp, unk_attrs) in enumerate(unknown): 
     195                if not unk_attrs: 
     196                    reinserted[name] = re_identifier.sub(replacer, exp) 
     197                    del unknown[i] 
     198                    solved.add(name) 
     199            if not solved: 
     200                self.error(1, "Circular attribute definitions (%s)" % ", ".join([x[0] for x in unknown])) 
     201                self.send("Examples", None) 
     202                return 
     203            for name, exp, unk_attrs in unknown: 
     204                unk_attrs -= solved 
     205 
     206        self.error(1) 
     207 
     208        newDomain = orange.Domain(oldDomain.attributes + [orange.FloatVariable(str(attrname), getValueFrom = AttrComputer(reinserted[attrname])) for attrname in names], oldDomain.classVar) 
    73209        newDomain.addmetas(oldDomain.getmetas()) 
    74          
    75210        self.send("Examples", orange.ExampleTable(newDomain, self.data)) 
    76  
Note: See TracChangeset for help on using the changeset viewer.