source: orange/orange/OrangeWidgets/Prototypes/OWMissingValues.py @ 9546:2b6cc6f397fe

Revision 9546:2b6cc6f397fe, 7.6 KB checked in by ales_erjavec <ales.erjavec@…>, 2 years ago (diff)

Renamed widget channel names in line with the new naming rules/convention.
Added backwards compatibility in orngDoc loadDocument to enable loading of schemas saved before the change.

Line 
1"""<name>Missing Values</name>
2<description>Helps remove features with too many missing values</description>
3<icon>icons/MissingValues.png</icon>
4<priority>30</priority>
5<contact>Janez Demsar (janez.demsar@fri.uni-lj.si)</contact>"""
6
7from OWWidget import *
8from OWGUI import *
9from math import log
10
11class PropBarItem(QItemDelegate):
12    _colors = [QColor(255, 255, 153), QColor(255, 102,51)]
13   
14    def paint(self, painter, option, index):
15        col = index.column()
16        if col == 1:
17            try:
18                text = index.data(Qt.DisplayRole).toString()
19                prop = float(str(text).split()[1][1:-2])/100
20                row = index.row()
21                painter.save()
22                self.drawBackground(painter, option, index)
23                painter.fillRect(option.rect.adjusted(1, 1, -option.rect.width()*(1-prop), -1), self._colors[self.parent().check[row]])
24                self.drawDisplay(painter, option, option.rect, text)
25                painter.restore()
26                return
27            except:
28                pass
29        return QItemDelegate.paint(self, painter, option, index)
30 
31       
32class OWMissingValues(OWWidget):
33    contextHandlers = {"": PerfectDomainContextHandler("", ["check"])}
34
35    def __init__(self,parent=None, signalManager = None):
36        OWWidget.__init__(self, parent, signalManager, "Compare Examples", noReport=True)
37        self.inputs = [("Data", ExampleTable, self.setData, Default)]
38        self.outputs = [("Data", ExampleTable, Default), ("Selected Data", ExampleTable)]
39       
40        self.check = []
41        self.resize(520, 560)
42        self.loadSettings()
43        self.controlArea.setFixedSize(0, 0)
44        self.pushing = False
45        self.table = OWGUI.table(self.mainArea, rows = 0, columns = 0, selectionMode = QTableWidget.SingleSelection)
46        self.table.setColumnCount(3)
47        self.table.setHorizontalHeaderLabels(["Feature", "Instances with missing value", "Data increase if removed"])
48        self.table.verticalHeader().hide()
49        self.table.setItemDelegate(PropBarItem(self))
50        self.connect(self.table, SIGNAL("itemChanged(QTableWidgetItem *)"), self.checksChanged)
51        self.connect(self.table, SIGNAL("itemSelectionChanged()"), self.sendSelected)
52
53        b = OWGUI.widgetBox(self.mainArea, orientation=0)
54        b1 = OWGUI.widgetBox(b)
55        OWGUI.button(b1, self, "Select All", self.selectAll, width=150, debuggingEnabled=0)
56        self.reportButton = OWGUI.button(b1, self, "&Report", self.reportAndFinish, width=150, debuggingEnabled=0)
57        self.reportButton.setAutoDefault(0)
58        b1 = OWGUI.widgetBox(b, "Info", orientation=0)
59        self.lbInput = OWGUI.label(b1, self, "")
60        OWGUI.separator(b1, 16)
61        self.lbOutput = OWGUI.label(b1, self, "")
62
63    def setData(self, data):
64        self.closeContext()
65        self.data = data
66        if data:
67            self.check = [1]*len(data.domain)
68            self.openContext("", data)
69           
70            self.pushing = True
71            self.table.setRowCount(len(data.domain))
72
73            filt_all_unk = orange.Filter_isDefined(domain=data.domain, negate=1)
74            self.notMissing = len(data.filterref(filt_all_unk))
75            self.lbInput.setText("Input: %i instances\nWith missing data: %i (%.2f%%)" % (len(data), self.notMissing, self.notMissing*100./(len(data) or 1)))
76
77            filt_all_unk.check = [0]*len(data.domain)
78            for row, var in enumerate(data.domain):
79                it = QTableWidgetItem(" "+var.name)
80                it.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
81                it.setCheckState(Qt.Checked if self.check[row] else Qt.Unchecked)
82                self.table.setItem(row, 0, it)
83               
84                filt_all_unk.check[row] = 1
85                miss = len(data.filterref(filt_all_unk))
86                filt_all_unk.check[row] = 0
87                it = QTableWidgetItem(("%i (%.2f%%)" % (miss, miss*100./len(data))) if miss else "-")
88                it.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
89                it.setTextAlignment(Qt.AlignRight)
90                self.table.setItem(row, 1, it)
91
92                it = QTableWidgetItem()
93                it.setTextAlignment(Qt.AlignRight)
94                self.table.setItem(row, 2, it)
95            self.table.resizeColumnsToContents()
96            self.table.resizeRowsToContents()
97        else:
98            self.table.setRowCount(0)
99            self.lbInput.setText("")
100            self.lbOutput.setText("")
101        self.pushing = False
102        self.table.clearSelection()
103        self.checksChanged(None)
104
105    def selectAll(self):
106        for row in range(len(self.data.domain)):
107            self.table.item(row, 0).setCheckState(Qt.Checked)
108        self.checksChanged(None)
109       
110    def checksChanged(self, item=None):
111        if self.pushing or item and item.column():
112            return
113        self.missingReport = []
114        if self.data:
115            data = self.data
116            filt_unk = orange.Filter_isDefined(domain = data.domain)
117            self.check = [self.table.item(i, 0).checkState()==Qt.Checked for i in range(len(data.domain))]
118            filt_unk.check = self.check
119            dataout = data.filterref(filt_unk)
120            totOut = len(dataout)
121            percOut = len(dataout)*100./(len(self.data) or 1)
122            self.lbOutput.setText("Output: %i (%.2f%%) instances\nRemoved: %i (%.2f%%)" % 
123                                  (totOut, percOut, len(self.data)-totOut, 100-percOut))
124            variables = []
125            for i, checked in enumerate(self.check):
126                it = self.table.item(i, 2)
127                if checked:
128                    filt_unk.check[i] = 0
129                    datatest = data.filterref(filt_unk)
130                    filt_unk.check[i] = 1
131                    miss = len(datatest) - len(dataout)
132                    txt = "%i" % miss if miss else "-"
133                    it.setText(txt)
134                    it.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled)
135                    var = self.data.domain[i]
136                    self.missingReport.append((var.name, txt))
137                    variables.append(var)
138                else:
139                    it.setText("(removed)")
140                    it.setFlags(Qt.NoItemFlags)
141                # this is ridiculous, but triggering an update by calling update doesn't work
142                it = self.table.item(i, 1)
143                tt = it.text()
144                it.setText(str(tt).strip() + " "*(tt and tt[-1]!=" "))
145            self.dataout = orange.ExampleTable(orange.Domain(variables), dataout)
146        else:
147            self.dataout = None
148        self.send("Data", self.dataout)
149           
150    def sendSelected(self):
151        toSend = None
152        if self.data:
153            selection = self.table.selectedItems()
154            if len(selection)==1 and selection[0].column():
155                row = selection[0].row()
156                data = self.data
157                filt_unk = orange.Filter_isDefined(domain = data.domain)
158                if selection[0].column()==2:
159                    filt_unk.check = [i!=row and self.table.item(i, 0).checkState()==Qt.Checked for i in range(len(data.domain))]
160                    data = data.filterref(filt_unk)
161                filt_unk.negate=1
162                filt_unk.check = [i==row for i in range(len(data.domain))]
163                toSend = data.filterref(filt_unk)
164        self.send("Selected Data", toSend)
165
166    def sendReport(self):
167        import OWReport
168        self.reportData(self.data, "Original data")
169        self.reportData(self.dataout, "Output data")
170        self.reportSection("Missing values by features")
171        self.reportRaw(OWReport.reportTable(self.table))
Note: See TracBrowser for help on using the repository browser.