📄 owselectdata.py
字号:
"""
<name>Select Data</name>
<description>Selects instances from the data set based on conditions over attributes.</description>
<icon>icons/SelectData.png</icon>
<priority>1150</priority>
<contact>Peter Juvan (peter.juvan@fri.uni-lj.si)</contact>
"""
import orange
from OWWidget import *
from qttable import *
import OWGUI
class OWSelectData(OWWidget):
# loadedConditions and loadedVarNames saved the last conditions, but they failed to show
# in the table when they are reloaded!
# I removed them; we shall have the context settings doing that some day
settingsList = ["updateOnChange", "purgeAttributes", "purgeClasses"]#, "loadedConditions", "loadedVarNames"]
def __init__(self, parent = None, signalManager = None, name = "Select data"):
OWWidget.__init__(self, parent, signalManager, name) #initialize base class
# set channels
self.inputs = [("Examples", ExampleTable, self.onDataInput)]
self.outputs = [("Matching Examples", ExampleTable, Default), ("Non-Matching Examples", ExampleTable), ("Matching Classified Examples", ExampleTableWithClass, Default), ("Non-Matching Classified Examples", ExampleTableWithClass)]
# manually set member variables
self.name2var = {} # key: variable name, item: orange.Variable
self.Conditions = []
# handled member variables
self.currentVar = None
self.NegateCondition = False
self.currentOperatorDict = {orange.VarTypes.Continuous:Operator(Operator.operatorsC[0], orange.VarTypes.Continuous),
orange.VarTypes.Discrete:Operator(Operator.operatorsD[0],orange.VarTypes.Discrete),
orange.VarTypes.String:Operator(Operator.operatorsS[0], orange.VarTypes.String)}
self.Num1 = 0.0
self.Num2 = 0.0
self.Str1 = ""
self.Str2 = ""
self.currentVals = []
self.CaseSensitive = False
self.updateOnChange = True
self.purgeAttributes = True
self.purgeClasses = True
self.oldPurgeClasses = True
# load settings
self.loadedVarNames = []
self.loadedConditions = []
self.loadSettings()
# GUI
self.mainArea.setFixedWidth(0)
ca=QFrame(self.controlArea)
ca.adjustSize()
gl=QGridLayout(ca,4,3,5)
# attribute condition box
boxAttrCond = QVGroupBox('Attribute Condition', ca)
gl.addMultiCellWidget(boxAttrCond, 0,0,0,2)
frmAttrCond = QFrame(boxAttrCond)
frmAttrCond.adjustSize()
glac=QGridLayout(frmAttrCond,1,3,5)
glac.setColStretch(0,2)
glac.setColStretch(1,1)
glac.setColStretch(2,2)
# attributes
boxAttr = QVGroupBox(frmAttrCond)
glac.addWidget(boxAttr,0,0)
boxAttr.setTitle('Attribute')
self.lbAttr = QListBox(boxAttr, 'SelAttr')
self.connect(self.lbAttr, SIGNAL('selectionChanged()'), self.lbAttrChange)
sbox = QHBox(boxAttr)
QLabel("Search: ", sbox)
self.leSelect = QLineEdit(sbox)
self.connect(self.leSelect, SIGNAL('textChanged(const QString &)'), self.setLbAttr)
# operators
boxOper = QVGroupBox('Operator', frmAttrCond)
# operators 0: empty
self.lbOperatosNone = QListBox(boxOper, 'SelAttr')
# operators 1: discrete
self.lbOperatorsD = QListBox(boxOper, 'SelAttr')
self.lbOperatorsD.hide()
self.connect(self.lbOperatorsD, SIGNAL('selectionChanged()'), self.lbOperatorsChange)
for op in Operator.operatorsD + [Operator.operatorDef]:
self.lbOperatorsD.insertItem(op)
# operators 2: continuous
self.lbOperatorsC = QListBox(boxOper, 'SelAttr')
self.lbOperatorsC.hide()
self.connect(self.lbOperatorsC, SIGNAL('selectionChanged()'), self.lbOperatorsChange)
for op in Operator.operatorsC + [Operator.operatorDef]:
self.lbOperatorsC.insertItem(op)
# operators 6: string
self.lbOperatorsS = QListBox(boxOper, 'SelAttr')
self.lbOperatorsS.hide()
self.connect(self.lbOperatorsS, SIGNAL('selectionChanged()'), self.lbOperatorsChange)
for op in Operator.operatorsS + [Operator.operatorDef]:
self.lbOperatorsS.insertItem(op)
self.lbOperatorsDict = {0: self.lbOperatosNone,
orange.VarTypes.Continuous: self.lbOperatorsC,
orange.VarTypes.Discrete: self.lbOperatorsD,
orange.VarTypes.String: self.lbOperatorsS}
# NOT checkbox
glac.addWidget(boxOper,0,1)
self.cbNot = OWGUI.checkBox(boxOper, self, "NegateCondition", "NOT")
# values
self.valuesStack = QWidgetStack(frmAttrCond)
glac.addWidget(self.valuesStack,0,2)
# values 0: empty
boxVal = QVGroupBox("Values", None)
self.valuesStack.addWidget(boxVal, 0)
# values 2: continuous between num and num
boxVal = QVGroupBox("Values", None)
self.valuesStack.addWidget(boxVal, orange.VarTypes.Continuous)
self.leNum1 = OWGUI.lineEdit(boxVal, self, "Num1")
self.lblAndCon = OWGUI.widgetLabel(boxVal, "and")
self.leNum2 = OWGUI.lineEdit(boxVal, self, "Num2")
boxAttrStat = QVGroupBox("Statistics", boxVal)
self.lblMin = QLabel("Min: ", boxAttrStat)
self.lblAvg = QLabel("Avg: ", boxAttrStat)
self.lblMax = QLabel("Max: ", boxAttrStat)
self.lblDefined = QLabel("Defined for ---- examples", boxAttrStat)
# values 1: discrete
boxVal = QVGroupBox("Values", None)
self.valuesStack.addWidget(boxVal, orange.VarTypes.Discrete)
self.lbVals = QListBox(boxVal)
self.connect(self.lbVals , SIGNAL('selectionChanged()'), self.lbValsChange)
# values 6: string between str and str
boxVal = QVGroupBox("Values", None)
self.valuesStack.addWidget(boxVal, orange.VarTypes.String)
self.leStr1 = OWGUI.lineEdit(boxVal, self, "Str1")
self.lblAndStr = OWGUI.widgetLabel(boxVal, "and")
self.leStr2 = OWGUI.lineEdit(boxVal, self, "Str2")
self.cbCaseSensitive = OWGUI.checkBox(boxVal, self, "CaseSensitive", "Case sensitive")
# buttons Add, Update, Remove, Disjunction, Up, Down
self.boxButtons = QHBox(ca)
gl.addMultiCellWidget(self.boxButtons, 1,1,0,2)
self.btnNew = OWGUI.button(self.boxButtons, self, "Add", self.OnNewCondition)
self.btnUpdate = OWGUI.button(self.boxButtons, self, "Update", self.OnUpdateCondition)
self.btnRemove = OWGUI.button(self.boxButtons, self, "Remove", self.OnRemoveCondition)
self.btnOR = OWGUI.button(self.boxButtons, self, "OR", self.OnDisjunction)
self.btnMoveUp = OWGUI.button(self.boxButtons, self, "Move Up", self.btnMoveUpClicked)
self.btnMoveDown = OWGUI.button(self.boxButtons, self, "Move Down", self.btnMoveDownClicked)
self.btnRemove.setEnabled(False)
self.btnUpdate.setEnabled(False)
self.btnMoveUp.setEnabled(False)
self.btnMoveDown.setEnabled(False)
# data selection criteria
boxCriteria = QVGroupBox(ca)
boxCriteria.setTitle('Data Selection Criteria')
gl.addMultiCellWidget(boxCriteria, 2,2,0,2)
self.criteriaTable = QTable(boxCriteria)
self.criteriaTable.setShowGrid(False)
self.criteriaTable.setSelectionMode(QTable.NoSelection)
self.criteriaTable.setNumCols(2)
self.criteriaTable.verticalHeader().setClickEnabled(False)
self.criteriaTable.verticalHeader().setResizeEnabled(False,-1)
hheader=self.criteriaTable.horizontalHeader()
hheader.setClickEnabled(False)
hheader.setLabel(0, "Active ")
hheader.setLabel(1, "Condition")
self.connect(self.criteriaTable, SIGNAL('currentChanged(int, int)'), self.currentCriteriaChange)
self.criteriaTable.adjustColumn(0)
self.criteriaTable.setColumnWidth(1, 360)
# data in
boxDataIn = QVGroupBox(ca)
boxDataIn.setTitle('Data In')
gl.addWidget(boxDataIn, 3,0)
self.dataInExamplesLabel = OWGUI.widgetLabel(boxDataIn, "num examples")
self.dataInAttributesLabel = OWGUI.widgetLabel(boxDataIn, "num attributes")
# data out
boxDataOut = QVGroupBox(ca)
boxDataOut.setTitle('Data Out')
gl.addWidget(boxDataOut, 3,1)
self.dataOutExamplesLabel = OWGUI.widgetLabel(boxDataOut, "num examples")
self.dataOutAttributesLabel = OWGUI.widgetLabel(boxDataOut, "num attributes")
# update
boxSettings = QVGroupBox(ca)
boxSettings.setTitle('Update')
gl.addWidget(boxSettings, 3,2)
OWGUI.checkBox(boxSettings, self, "purgeAttributes", "Remove unused values/attributes", box=None, callback=self.OnPurgeChange)
self.purgeClassesCB = OWGUI.checkBox(OWGUI.indentedBox(boxSettings), self, "purgeClasses", "Remove unused classes", callback=self.OnPurgeChange)
OWGUI.checkBox(boxSettings, self, "updateOnChange", "Update on any change", box=None)
btnUpdate = OWGUI.button(boxSettings, self, "Update", self.setOutput)
# icons
self.icons = self.createAttributeIconDict()
self.onDataInput(None)
self.lbOperatorsD.setCurrentItem(0)
self.lbOperatorsC.setCurrentItem(0)
self.lbOperatorsS.setCurrentItem(0)
self.resize(500,661)
############################################################################################################################################################
## Data input and output management ########################################################################################################################
############################################################################################################################################################
def onDataInput(self, data):
"""Loads stored conditions (if we have a similar domain), updates list boxes and data in info, sends out data.
"""
self.data = data
self.bas = orange.DomainBasicAttrStat(data)
if self.data:
# set self.name2var
optmetas = self.data.domain.getmetas(True).values()
optmetas.sort(lambda x,y: cmp(x.name, y.name))
self.varList = self.data.domain.variables.native() + self.data.domain.getmetas(False).values() + optmetas
varNames = []
for v in self.varList:
self.name2var[v.name] = v
varNames.append(v.name)
if varNames == self.loadedVarNames:
if self.Conditions == []:
self.Conditions = self.loadedConditions
else:
self.loadedVarNames = varNames
# clear conditions and criteria table
self.Conditions = []
for row in range(self.criteriaTable.numRows()-1,-1,-1):
self.criteriaTable.clearCellWidget(row,0)
self.criteriaTable.clearCell(row,1)
self.criteriaTable.hideRow(row)
self.criteriaTable.setNumRows(0)
self.setLbAttr()
self.criteriaTable.setCurrentCell(-1,1)
self.boxButtons.setEnabled(True)
else:
self.name2var = {}
self.varList = []
self.Conditions = []
self.lbAttr.clear()
self.leSelect.clear()
self.currentVar = None
for row in range(self.criteriaTable.numRows()-1,-1,-1):
self.criteriaTable.clearCellWidget(row,0)
self.criteriaTable.clearCell(row,1)
self.criteriaTable.hideRow(row)
self.criteriaTable.setNumRows(0)
self.criteriaTable.setCurrentCell(-1,1)
self.boxButtons.setEnabled(False)
# update operators, values and info, and send out data
self.updateOperatorStack()
self.updateValuesStack()
self.updateInfoIn(self.data)
self.setOutput()
def setLbAttr(self, filter=None):
# update attribute listbox
self.lbAttr.clear()
if not filter:
for v in self.varList:
self.lbAttr.insertItem(self.icons[v.varType], v.name)
else:
flen = len(filter)
for v in self.varList:
if v.name[:flen] == filter:
self.lbAttr.insertItem(self.icons[v.varType], v.name)
if self.lbAttr.count():
self.lbAttr.setSelected(0,True)
else:
self.lbAttrChange()
def setOutput(self):
"""Sends out data, updates data out info.
"""
matchingOutput = self.data
nonMatchingOutput = None
hasClass = False
if self.data:
hasClass = bool(self.data.domain.classVar)
filterList = self.getFilterList(self.data.domain, self.Conditions, enabledOnly=True)
if len(filterList)>0:
filter = orange.Filter_disjunction([orange.Filter_conjunction(l) for l in filterList])
else:
filter = orange.Filter_conjunction([]) # a filter that does nothing
matchingOutput = filter(self.data)
matchingOutput.name = self.data.name
## print "len(matchingOutput)", len(matchingOutput)
nonMatchingOutput = filter(self.data, negate=1)
nonMatchingOutput.name = self.data.name
## print "len(nonMatchingOutput)", len(nonMatchingOutput)
if self.purgeAttributes or self.purgeClasses:
remover = orange.RemoveUnusedValues(removeOneValued=True)
newDomain = remover(matchingOutput, 0, True, self.purgeClasses)
if newDomain != matchingOutput.domain:
matchingOutput = orange.ExampleTable(newDomain, matchingOutput)
newDomain = remover(nonMatchingOutput, 0, True, self.purgeClasses)
if newDomain != nonMatchingOutput.domain:
nonmatchingOutput = orange.ExampleTable(newDomain, nonMatchingOutput)
self.send("Matching Examples", matchingOutput)
self.send("Non-Matching Examples", nonMatchingOutput)
if hasClass:
self.send("Matching Classified Examples", matchingOutput)
self.send("Non-Matching Classified Examples", nonMatchingOutput)
else:
self.send("Matching Classified Examples", None)
self.send("Non-Matching Classified Examples", None)
self.updateInfoOut(matchingOutput)
def getFilterList(self, domain, conditions, enabledOnly):
"""Returns list of lists of orange filters, e.g. [[f1,f2],[f3]].
OR is always enabled (with no respect to cond.enabled)
"""
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -