source: orange/Orange/OrangeWidgets/Data/OWMergeData.py @ 11096:cf7d2ae9d22b

Revision 11096:cf7d2ae9d22b, 11.3 KB checked in by Ales Erjavec <ales.erjavec@…>, 19 months ago (diff)

Added new svg icons for the widgets/categories.

Line 
1"""
2<name>Merge Data</name>
3<description>Merge datasets based on values of selected attributes.</description>
4<icon>icons/MergeData.svg</icon>
5<priority>1110</priority>
6<contact>Peter Juvan (peter.juvan@fri.uni-lj.si)</contact>
7"""
8import orange
9from OWWidget import *
10import OWGUI
11
12class OWMergeData(OWWidget):
13
14    contextHandlers = {"A": DomainContextHandler("A",
15                                [ContextField("varA")],
16                                syncWithGlobal=False,
17                                contextDataVersion=2),
18                       "B": DomainContextHandler("B",
19                                [ContextField("varB")],
20                                syncWithGlobal=False,
21                                contextDataVersion=2)}
22
23    def __init__(self, parent = None, signalManager = None, name = "Merge data"):
24        OWWidget.__init__(self, parent, signalManager, name, wantMainArea = 0)  #initialize base class
25
26        # set channels
27        self.inputs = [("Data A", ExampleTable, self.onDataAInput),
28                       ("Data B", ExampleTable, self.onDataBInput)]
29       
30        self.outputs = [("Merged Data A+B", ExampleTable),
31                        ("Merged Data B+A", ExampleTable)]
32
33        # data
34        self.dataA = None
35        self.dataB = None
36        self.varListA = []
37        self.varListB = []
38        self.varA = None
39        self.varB = None
40        self.lbAttrAItems = []
41        self.lbAttrBItems = []
42
43        # load settings
44        self.loadSettings()
45
46        # GUI
47        w = QWidget(self)
48        self.controlArea.layout().addWidget(w)
49        grid = QGridLayout()
50        grid.setMargin(0)
51        w.setLayout(grid)
52       
53        # attribute A
54        boxAttrA = OWGUI.widgetBox(self, 'Attribute A', orientation = "vertical", addToLayout=0)
55        grid.addWidget(boxAttrA, 0,0)
56        self.lbAttrA = OWGUI.listBox(boxAttrA, self, "lbAttrAItems", callback = self.lbAttrAChange)
57       
58        # attribute  B
59        boxAttrB = OWGUI.widgetBox(self, 'Attribute B', orientation = "vertical", addToLayout=0)
60        grid.addWidget(boxAttrB, 0,1)
61        self.lbAttrB = OWGUI.listBox(boxAttrB, self, "lbAttrBItems", callback = self.lbAttrBChange)
62
63        # info A
64        boxDataA = OWGUI.widgetBox(self, 'Data A', orientation = "vertical", addToLayout=0)
65        grid.addWidget(boxDataA, 1,0)
66        self.lblDataAExamples = OWGUI.widgetLabel(boxDataA, "num examples")
67        self.lblDataAAttributes = OWGUI.widgetLabel(boxDataA, "num attributes")
68
69        # info B
70        boxDataB = OWGUI.widgetBox(self, 'Data B', orientation = "vertical", addToLayout=0)
71        grid.addWidget(boxDataB, 1,1)
72        self.lblDataBExamples = OWGUI.widgetLabel(boxDataB, "num examples")
73        self.lblDataBAttributes = OWGUI.widgetLabel(boxDataB, "num attributes")
74
75        # icons
76        self.icons = self.createAttributeIconDict()
77
78        # resize
79        self.resize(400,500)
80
81
82    ############################################################################################################################################################
83    ## Data input and output management
84    ############################################################################################################################################################
85       
86    def inVarList(self, varList, var):
87        varList = [(v.name, v.varType) for v in varList]
88        if var in varList:
89            return True, varList.index(var)
90        else:
91            return False, -1
92       
93    def onDataAInput(self, data):
94        self.closeContext("A")
95        self.dataA = data
96        # update self.varListA and self.varA
97        if self.dataA:
98            self.varListA = list(self.dataA.domain.variables) + self.dataA.domain.getmetas().values()
99        else:
100            self.varListA = []
101           
102        # update info
103        self.updateInfoA()
104        # update attribute A listbox
105        self.lbAttrA.clear()
106        for var in self.varListA:
107            self.lbAttrA.addItem(QListWidgetItem(self.icons[var.varType], var.name))
108        if self.dataA:
109            self.openContext("A", self.dataA)
110        match, index = self.inVarList(self.varListA, self.varA)
111        if match:
112            var = self.varListA[index]
113            self.varA = (var.name, var.varType)
114            self.lbAttrA.setCurrentItem(self.lbAttrA.item(index))
115        else:
116            self.varA = None
117           
118        self.sendData()
119
120    def onDataBInput(self, data):
121        self.closeContext("B")
122        self.dataB = data
123        # update self.varListB and self.varB
124        if self.dataB:
125            self.varListB = list(self.dataB.domain.variables) + self.dataB.domain.getmetas().values()
126        else:
127            self.varListB = []
128       
129        # update info
130        self.updateInfoB()
131        # update attribute B listbox
132        self.lbAttrB.clear()
133        for var in self.varListB:
134            self.lbAttrB.addItem(QListWidgetItem(self.icons[var.varType], var.name))
135       
136        if self.dataB:
137            self.openContext("B", self.dataB)
138        match, index = self.inVarList(self.varListB, self.varB)
139        if match:
140            var = self.varListB[index]
141            self.varB = (var.name, var.varType)
142            self.lbAttrB.setCurrentItem(self.lbAttrB.item(index))
143        else:
144            self.varB = None
145           
146        self.sendData()
147
148
149    def updateInfoA(self):
150        """Updates data A info box.
151        """
152        if self.dataA:
153            self.lblDataAExamples.setText("%s example%s" % self._sp(self.dataA))
154            self.lblDataAAttributes.setText("%s attribute%s" % self._sp(self.varListA))
155        else:
156            self.lblDataAExamples.setText("No data on input A.")
157            self.lblDataAAttributes.setText("")
158
159
160    def updateInfoB(self):
161        """Updates data B info box.
162        """
163        if self.dataB:
164            self.lblDataBExamples.setText("%s example%s" % self._sp(self.dataB))
165            self.lblDataBAttributes.setText("%s attribute%s" % self._sp(self.varListB))
166        else:
167            self.lblDataBExamples.setText("No data on input B.")
168            self.lblDataBAttributes.setText("")
169
170    def sendData(self):
171        self.error(0)
172        if self.dataA and self.dataB and self.varA and self.varB:
173            try:
174                self.send("Merged Data A+B", self.merge(self.dataA, self.dataB, self.varA[0], self.varB[0]))
175                self.send("Merged Data B+A", self.merge(self.dataB, self.dataA, self.varB[0], self.varA[0]))
176            except orange.KernelException, ex:
177                self.error(0, "Cannot merge the two tables (%r)" % str(ex))
178        else:
179            self.send("Merged Data A+B", None)
180            self.send("Merged Data B+A", None)
181
182    ############################################################################################################################################################
183    ## Event handlers
184    ############################################################################################################################################################
185
186    def lbAttrAChange(self):
187        if self.dataA:
188            if self.lbAttrA.selectedItems() != []:
189                ind = self.lbAttrA.row(self.lbAttrA.selectedItems()[0])
190                var = self.varListA[ind]
191                self.varA = (var.name, var.varType)
192            else:
193                self.varA = None
194        else:
195            self.varA = None
196        self.sendData()
197
198
199    def lbAttrBChange(self):
200        if self.dataB:
201            if self.lbAttrB.selectedItems() != []:
202                ind = self.lbAttrB.row(self.lbAttrB.selectedItems()[0])
203                var = self.varListB[ind]
204                self.varB = (var.name, var.varType)
205            else:
206                self.varB = None
207        else:
208            self.varB = None
209        self.sendData()
210
211
212    ############################################################################################################################################################
213    ## Utility functions
214    ############################################################################################################################################################
215
216    def _sp(self, l, capitalize=True):
217        """Input: list; returns tuple (str(len(l)), "s"/"")
218        """
219        n = len(l)
220        if n == 0:
221            if capitalize:
222                return "No", "s"
223            else:
224                return "no", "s"
225        elif n == 1:
226            return str(n), ''
227        else:
228            return str(n), 's'
229
230    def merge(self, dataA, dataB, varA, varB):
231        """ Merge two tables
232        """
233       
234        val2idx = dict([(e[varB].native(), i) for i, e in reversed(list(enumerate(dataB)))])
235       
236        for key in ["?", "~", ""]:
237            if key in val2idx:
238                val2idx.pop(key)
239                 
240        metasA = dataA.domain.getmetas().items()
241        metasB = dataB.domain.getmetas().items()
242       
243        includedAttsB = [attrB for attrB in dataB.domain if attrB not in dataA.domain]
244        includedMetaB = [(mid, meta) for mid, meta in metasB if (mid, meta) not in metasA]
245        includedClassVarB = dataB.domain.classVar and dataB.domain.classVar not in dataA.domain
246       
247        reducedDomainB = orange.Domain(includedAttsB, includedClassVarB)
248        reducedDomainB.addmetas(dict(includedMetaB))
249       
250       
251        mergingB = orange.ExampleTable(reducedDomainB)
252       
253        for ex in dataA:
254            ind = val2idx.get(ex[varA].native(), None)
255            if ind is not None:
256                mergingB.append(orange.Example(reducedDomainB, dataB[ind]))
257               
258            else:
259                mergingB.append(orange.Example(reducedDomainB, ["?"] * len(reducedDomainB)))
260               
261        return orange.ExampleTable([dataA, mergingB])
262   
263if __name__=="__main__":
264    """
265    import sys
266    import OWDataTable, orngSignalManager
267    signalManager = orngSignalManager.SignalManager(0)
268    #data = orange.ExampleTable('dicty_800_genes_from_table07.tab')
269##    data = orange.ExampleTable(r'..\..\doc\datasets\adult_sample.tab')
270##    dataA = orange.ExampleTable(r'c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\sterolgene v.0 mouse probeRatios.tab')
271##    dataA = orange.ExampleTable(r'c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\Copy of sterolgene v.0 mouse probeRatios.tab')
272##    dataB = orange.ExampleTable(r'c:\Documents and Settings\peterjuv\My Documents\STEROLTALK\Sterolgene v.0 mouse\sterolgene v.0 mouse probeRatios.tab')
273    dataA = orange.ExampleTable(r'c:\Documents and Settings\peterjuv\My Documents\et1.tab')
274    dataB = orange.ExampleTable(r'c:\Documents and Settings\peterjuv\My Documents\et2.tab')
275    a=QApplication(sys.argv)
276    ow=OWMergeData()
277    a.setMainWidget(ow)
278    ow.show()
279    ow.onDataAInput(dataA)
280    ow.onDataBInput(dataB)
281    # data table
282    dt = OWDataTable.OWDataTable(signalManager = signalManager)
283    signalManager.addWidget(ow)
284    signalManager.addWidget(dt)
285    signalManager.setFreeze(1)
286    signalManager.addLink(ow, dt, 'Merged Examples A+B', 'Examples', 1)
287    signalManager.addLink(ow, dt, 'Merged Examples B+A', 'Examples', 1)
288    signalManager.setFreeze(0)
289    dt.show()
290    a.exec_()
291    """
292    import sys
293    a=QApplication(sys.argv)
294    ow=OWMergeData()
295    ow.show()
296    data = orange.ExampleTable("iris.tab")
297    ow.onDataAInput(data)
298    a.exec_()
Note: See TracBrowser for help on using the repository browser.