source: orange/Orange/OrangeWidgets/Unsupervised/OWDistanceFile.py @ 10466:b52f4c49e735

Revision 10466:b52f4c49e735, 10.1 KB checked in by Ales Erjavec <ales.erjavec@…>, 2 years ago (diff)

Added unicode filename support for the rest of save/load widget dialogs.

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