source: orange/orange/OrangeWidgets/Unsupervised/OWDistanceFile.py @ 9273:9c33029c1c40

Revision 9273:9c33029c1c40, 10.1 KB checked in by ales_erjavec <ales.erjavec@…>, 2 years ago (diff)

More fixes to reporting.

Line 
1"""
2<name>Distance File</name>
3<description>Loads a distance matrix from a file</description>
4<contact>Janez Demsar</contact>
5<icon>icons/DistanceFile.png</icon>
6<priority>1100</priority>
7"""
8
9from OWWidget import *
10import OWGUI
11import orange
12import exceptions
13import os.path
14import pickle
15
16def readMatrix(fn, progress=None):
17    msg = None
18    matrix = labels = data = None
19   
20    if type(fn) != file and (os.path.splitext(fn)[1] == '.pkl' or os.path.splitext(fn)[1] == '.sym'):
21        pkl_file = open(fn, 'rb')
22        matrix = pickle.load(pkl_file)
23        data = None
24        if hasattr(matrix, 'items'):
25            items = matrix.items
26            if isinstance(items, orange.ExampleTable):
27                data = items
28            elif isinstance(items, list) or hasattr(item, "__iter__"):
29                labels = items
30        pkl_file.close()
31    elif type(fn) != file and os.path.splitext(fn)[1] == '.npy':
32        import numpy
33        nmatrix = numpy.load(fn)
34        matrix = orange.SymMatrix(len(nmatrix))
35        milestones = orngMisc.progressBarMilestones(matrix.dim, 100)
36        for i in range(len(nmatrix)):
37            for j in range(i+1):
38                matrix[j,i] = nmatrix[i,j]
39               
40            if progress and i in milestones:
41                progress.advance()
42        #labels = [""] * len(nmatrix)
43    else:   
44        if type(fn) == file:
45            fle = fn
46        else:
47            fle = open(fn)
48        while 1:
49            lne = fle.readline().strip()
50            if lne:
51                break
52        spl = lne.split()
53        try:
54            dim = int(spl[0])
55        except IndexError:
56            raise ValueError("Matrix dimension expected in the first line.")
57       
58        #print dim
59        labeled = len(spl) > 1 and spl[1] in ["labelled", "labeled"]
60        matrix = orange.SymMatrix(dim)
61        data = None
62       
63        milestones = orngMisc.progressBarMilestones(dim, 100)     
64        if labeled:
65            labels = []
66        else:
67            labels = [""] * dim
68        for li, lne in enumerate(fle):
69            if li > dim:
70                if not li.strip():
71                    continue
72                raise ValueError("File to long")
73           
74            spl = lne.split("\t")
75            if labeled:
76                labels.append(spl[0].strip())
77                spl = spl[1:]
78            if len(spl) > dim:
79                raise ValueError("Line %i too long" % li+2)
80           
81            for lj, s in enumerate(spl):
82                if s:
83                    try:
84                        matrix[li, lj] = float(s)
85                    except ValueError:
86                        raise ValueError("Invalid number in line %i, column %i" % (li+2, lj))
87                   
88            if li in milestones:
89                if progress:
90                    progress.advance()
91    if progress:
92        progress.finish()
93
94    return matrix, labels, data
95
96class OWDistanceFile(OWWidget):
97    settingsList = ["recentFiles", "invertDistances", "normalizeMethod", "invertMethod"]
98
99    def __init__(self, parent=None, signalManager=None, name="Distance File", inputItems=True):
100        self.callbackDeposit = [] # deposit for OWGUI callback functions
101        OWWidget.__init__(self, parent, signalManager, name, wantMainArea = 0, resizingEnabled = 1)
102       
103        if inputItems: 
104            self.inputs = [("Examples", ExampleTable, self.getExamples, Default)]
105           
106        self.outputs = [("Distance Matrix", orange.SymMatrix)]
107
108        self.recentFiles=[]
109        self.fileIndex = 0
110        self.takeAttributeNames = False
111        self.data = None
112        self.matrix = None
113        self.invertDistances = 0
114        self.normalizeMethod = 0
115        self.invertMethod = 0
116        self.loadSettings()
117        self.labels = None
118       
119       
120        self.dataFileBox = OWGUI.widgetBox(self.controlArea, "Data File", addSpace=True)
121        hbox = OWGUI.widgetBox(self.dataFileBox, orientation = 0)
122        self.filecombo = OWGUI.comboBox(hbox, self, "fileIndex", callback = self.loadFile)
123        self.filecombo.setMinimumWidth(250)
124        button = OWGUI.button(hbox, self, '...', callback = self.browseFile)
125        button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon))
126        button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
127       
128        if inputItems: 
129            self.rbInput = OWGUI.radioButtonsInBox(self.controlArea, self,
130                            "takeAttributeNames", ["Use examples as items", 
131                            "Use attribute names"], "Items from input data", 
132                            callback = self.relabel)
133           
134            self.rbInput.setDisabled(True)
135    #
136#        Moved to SymMatrixTransform widget
137#
138#        ribg = OWGUI.radioButtonsInBox(self.controlArea, self, "normalizeMethod", [], "Normalize method", callback = self.setNormalizeMode)
139#        OWGUI.appendRadioButton(ribg, self, "normalizeMethod", "None", callback = self.setNormalizeMode)
140#        OWGUI.appendRadioButton(ribg, self, "normalizeMethod", "To interval [0,1]", callback = self.setNormalizeMode)
141#        OWGUI.appendRadioButton(ribg, self, "normalizeMethod", "Sigmoid function: 1 / (1 + e^x)", callback = self.setNormalizeMode)
142#       
143#        ribg = OWGUI.radioButtonsInBox(self.controlArea, self, "invertMethod", [], "Invert method", callback = self.setInvertMode)
144#        OWGUI.appendRadioButton(ribg, self, "invertMethod", "None", callback = self.setInvertMode)
145#        OWGUI.appendRadioButton(ribg, self, "invertMethod", "-X", callback = self.setInvertMode)
146#        OWGUI.appendRadioButton(ribg, self, "invertMethod", "1 - X", callback = self.setInvertMode)
147#        OWGUI.appendRadioButton(ribg, self, "invertMethod", "Max - X", callback = self.setInvertMode)
148#        OWGUI.appendRadioButton(ribg, self, "invertMethod", "1 / X", callback = self.setInvertMode)
149       
150        OWGUI.rubber(self.controlArea)
151       
152        self.adjustSize()
153
154        if self.recentFiles:
155            self.loadFile()
156
157    def setNormalizeMode(self):
158        self.relabel()
159   
160    def setInvertMode(self):
161        self.relabel()
162               
163    def browseFile(self):
164        if self.recentFiles:
165            lastPath = os.path.split(self.recentFiles[0])[0]
166        else:
167            lastPath = "."
168        fn = str(QFileDialog.getOpenFileName(self, "Open Distance Matrix File", 
169                                             lastPath, "Distance matrix (*.*)"))
170        fn = os.path.abspath(fn)
171        if fn in self.recentFiles: # if already in list, remove it
172            self.recentFiles.remove(fn)
173        self.recentFiles.insert(0, fn)
174        self.fileIndex = 0
175        self.loadFile()
176
177    def loadFile(self):
178        if self.fileIndex:
179            fn = self.recentFiles[self.fileIndex]
180            self.recentFiles.remove(fn)
181            self.recentFiles.insert(0, fn)
182            self.fileIndex = 0
183        else:
184            fn = self.recentFiles[0]
185
186        self.filecombo.clear()
187        for file in self.recentFiles:
188            self.filecombo.addItem(os.path.split(file)[1])
189        #self.filecombo.updateGeometry()
190
191        self.matrix = None
192        self.labels = None
193        self.data = None
194        pb = OWGUI.ProgressBar(self, 100)
195       
196        self.error()
197        try:
198            self.matrix, self.labels, self.data = readMatrix(fn, pb)
199        except Exception, ex:
200            self.error("Error while reading the file: '%s'" % str(ex))
201            return
202        self.relabel()
203           
204    def relabel(self):
205        #print 'relabel'
206        self.error()
207        matrix = self.matrix
208        if matrix is not None and self.data is not None:
209            if self.takeAttributeNames:
210                domain = self.data.domain
211                if matrix.dim == len(domain.attributes):
212                    matrix.setattr("items", domain.attributes)
213                elif matrix.dim == len(domain.variables):
214                    matrix.setattr("items", domain.variables)
215                else:
216                    self.error("The number of attributes doesn't match the matrix dimension")
217
218            else:
219                if matrix.dim == len(self.data):
220                    matrix.setattr("items", self.data)
221                else:
222                    self.error("The number of examples doesn't match the matrix dimension")
223        elif matrix and self.labels:
224            lbl = orange.StringVariable('label')
225            self.data = orange.ExampleTable(orange.Domain([lbl]), 
226                                            [[str(l)] for l in self.labels])
227            for e, label in zip(self.data, self.labels):
228                e.name = label
229            matrix.setattr("items", self.data)
230       
231        if self.data == None and self.labels == None:
232            matrix.setattr("items", [str(i) for i in range(matrix.dim)])
233       
234        self.matrix.matrixType = orange.SymMatrix.Symmetric
235        self.send("Distance Matrix", self.matrix)
236
237    def getExamples(self, data):
238        self.data = data
239        self.rbInput.setDisabled(data is None)
240        self.relabel()
241
242    def sendReport(self):
243        if self.data:
244            if self.takeAttributeNames:
245                attrs = self.data.domain.attributes if len(self.data.domain.attributes) == self.matrix.dim else self.data.domain.variables
246                labels = "Attribute names (%s%s) from the input signal" % (", ".join(x.name for x in list(attrs)[:5]), " ..." if len(attrs)>5 else "")
247            else:
248                labels = "Examples form the input signal"
249        elif self.labels:
250            labels = "Labels from the file (%s%s)" % (", ".join(self.labels[:5]), " ..." if len(self.labels)>5 else "")
251        else:
252            labels = "None" 
253           
254        if self.matrix is not None:
255            self.reportSettings("File",
256                                [("File name", self.recentFiles[self.fileIndex or 0]),
257                                 ("Matrix dimension", self.matrix.dim),
258                                 ("Labels", labels)])
259        else:
260            self.reportSettings("File", [])
261        if self.data:
262            self.reportData(self.data, "Examples")
263       
264if __name__=="__main__":
265    a = QApplication(sys.argv)
266    ow = OWDistanceFile()
267    ow.show()
268    a.exec_()
269    ow.saveSettings()
Note: See TracBrowser for help on using the repository browser.