source: orange/orange/OrangeWidgets/Unsupervised/OWNxFile.py @ 8782:8da761589111

Revision 8782:8da761589111, 18.5 KB checked in by miha <miha.stajdohar@…>, 3 years ago (diff)

Build data table automatically from the network file.

Line 
1"""
2<name>Net File</name>
3<description>Reads data from a graf file (Pajek networks (.net) files and GML network files).</description>
4<icon>icons/NetworkFile.png</icon>
5<contact>Miha Stajdohar (miha.stajdohar(@at@)gmail.com)</contact> 
6<priority>6410</priority>
7"""
8
9import sys
10import string
11import os.path
12import user
13
14import Orange
15import OWGUI
16
17from OWWidget import *
18
19class OWNxFile(OWWidget):
20   
21    settingsList=["recentFiles", "recentDataFiles", "recentEdgesFiles", "auto_table"]
22   
23    def __init__(self,parent=None, signalManager = None):
24        OWWidget.__init__(self, parent, signalManager, "Nx File", wantMainArea=False)
25
26        self.inputs = []
27        self.outputs = [("Network", Orange.network.Graph), ("Items", Orange.data.Table)]
28   
29        #set default settings
30        self.recentFiles = ["(none)"]
31        self.recentDataFiles = ["(none)"]
32        self.recentEdgesFiles = ["(none)"]
33        self.auto_table = False
34       
35        self.domain = None
36        self.graph = None
37        self.auto_items = None
38       
39        #get settings from the ini file, if they exist
40        self.loadSettings()
41
42        #GUI
43        self.controlArea.layout().setMargin(4)
44        self.box = OWGUI.widgetBox(self.controlArea, box = "Graph File", orientation = "vertical")
45        hb = OWGUI.widgetBox(self.box, orientation = "horizontal")       
46        self.filecombo = OWGUI.comboBox(hb, self, "filename")
47        self.filecombo.setMinimumWidth(250)
48        button = OWGUI.button(hb, self, '...', callback = self.browseNetFile, disabled=0)
49        button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon))
50        button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
51        OWGUI.checkBox(self.box, self, "auto_table", "Build graph data table automatically", callback=lambda: self.selectNetFile(self.filecombo.currentIndex()))
52       
53        self.databox = OWGUI.widgetBox(self.controlArea, box = "Vertices Data File", orientation = "horizontal")
54        self.datacombo = OWGUI.comboBox(self.databox, self, "dataname")
55        self.datacombo.setMinimumWidth(250)
56        button = OWGUI.button(self.databox, self, '...', callback = self.browseDataFile, disabled=0)
57        button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon))
58        button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
59       
60        self.edgesbox = OWGUI.widgetBox(self.controlArea, box = "Edges Data File", orientation = "horizontal")
61        self.edgescombo = OWGUI.comboBox(self.edgesbox, self, "edgesname")
62        self.edgescombo.setMinimumWidth(250)
63        button = OWGUI.button(self.edgesbox, self, '...', callback = self.browseEdgesFile, disabled=0)
64        button.setIcon(self.style().standardIcon(QStyle.SP_DirOpenIcon))
65        button.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
66       
67        # info
68        box = OWGUI.widgetBox(self.controlArea, "Info")
69        self.infoa = OWGUI.widgetLabel(box, 'No data loaded.')
70        self.infob = OWGUI.widgetLabel(box, ' ')
71        self.infoc = OWGUI.widgetLabel(box, ' ')
72        self.infod = OWGUI.widgetLabel(box, ' ')
73
74        OWGUI.rubber(self.controlArea)
75        self.resize(150,100)
76        self.activateLoadedSettings()
77
78        # connecting GUI to code
79        self.connect(self.filecombo, SIGNAL('activated(int)'), self.selectNetFile)
80        self.connect(self.datacombo, SIGNAL('activated(int)'), self.selectDataFile)
81        self.connect(self.edgescombo, SIGNAL('activated(int)'), self.selectEdgesFile)
82       
83    # set the comboboxes
84    def setFileLists(self):
85        self.filecombo.clear()
86        if not self.recentFiles:
87            self.filecombo.addItem("(none)")
88        for file in self.recentFiles:
89            if file == "(none)":
90                self.filecombo.addItem("(none)")
91            else:
92                self.filecombo.addItem(os.path.split(file)[1])
93        self.filecombo.addItem("Browse documentation networks...")
94       
95        self.datacombo.clear()
96        if not self.recentDataFiles:
97            self.datacombo.addItem("(none)")
98        for file in self.recentDataFiles:
99            if file == "(none)":
100                self.datacombo.addItem("(none)")
101            else:
102                self.datacombo.addItem(os.path.split(file)[1])
103               
104        self.edgescombo.clear()
105        if not self.recentEdgesFiles:
106            self.edgescombo.addItem("(none)")
107        for file in self.recentEdgesFiles:
108            if file == "(none)":
109                self.edgescombo.addItem("(none)")
110            else:
111                self.edgescombo.addItem(os.path.split(file)[1])
112           
113        self.filecombo.updateGeometry()
114        self.datacombo.updateGeometry()
115        self.edgescombo.updateGeometry()
116     
117    def activateLoadedSettings(self):
118        # remove missing data set names
119        self.recentFiles = filter(os.path.exists, self.recentFiles)
120        self.recentDataFiles = filter(os.path.exists, self.recentDataFiles)
121        self.recentEdgesFiles = filter(os.path.exists, self.recentEdgesFiles)
122       
123        self.recentFiles.append("(none)")
124        self.recentDataFiles.append("(none)")
125        self.recentEdgesFiles.append("(none)")
126        self.setFileLists()
127       
128        if len(self.recentFiles) > 0 and os.path.exists(self.recentFiles[0]):
129            self.selectNetFile(0)
130
131        # if items not loaded with the network, load previous items
132        if len(self.recentDataFiles) > 1 and \
133            self.recentDataFiles[0] == 'none' and \
134                os.path.exists(self.recentDataFiles[1]):
135            self.selectDataFile(1)
136           
137        # if links not loaded with the network, load previous links   
138        if len(self.recentEdgesFiles) > 1 and \
139            self.recentEdgesFiles[0] == 'none' and \
140                os.path.exists(self.recentEdgesFiles[1]):
141            self.selectEdgesFile(1)
142       
143    # user selected a graph file from the combo box
144    def selectNetFile(self, n):
145        if n < len(self.recentFiles) :
146            name = self.recentFiles[n]
147            self.recentFiles.remove(name)
148            self.recentFiles.insert(0, name)
149        elif n:
150            self.browseNetFile(1)
151           
152        if len(self.recentFiles) > 0:
153            self.setFileLists() 
154            self.openFile(self.recentFiles[0])
155   
156    # user selected a data file from the combo box
157    def selectEdgesFile(self, n):
158        if n < len(self.recentEdgesFiles) :
159            name = self.recentEdgesFiles[n]
160            self.recentEdgesFiles.remove(name)
161            self.recentEdgesFiles.insert(0, name)
162
163        if len(self.recentEdgesFiles) > 0:
164            self.setFileLists()
165            self.addEdgesFile(self.recentEdgesFiles[0])
166   
167    def selectDataFile(self, n):
168        if n < len(self.recentDataFiles) :
169            name = self.recentDataFiles[n]
170            self.recentDataFiles.remove(name)
171            self.recentDataFiles.insert(0, name)
172
173        if len(self.recentDataFiles) > 0:
174            self.setFileLists()
175            self.addDataFile(self.recentDataFiles[0])
176           
177    def readingFailed(self, infoa='No data loaded', infob='', infoc='', infod=''):
178        self.graph = None
179        self.send("Network", None)
180        self.send("Items", None)
181        self.infoa.setText(infoa)
182        self.infob.setText(infob)
183        self.infoc.setText(infoc)           
184        self.infod.setText(infod)
185   
186    def openFile(self, fn):
187        """Read network from file."""
188       
189        # read network file
190        if fn == "(none)":
191            self.readingFailed()
192            return 
193       
194        fileExt = lower(os.path.splitext(fn)[1])
195        if not fileExt in (".net", ".gml", ".gpickle"):
196            self.readingFailed(infob='Network file type not supported')
197            return
198       
199        #try:
200        net = Orange.network.readwrite.read(fn, auto_table=self.auto_table)
201       
202        #except:
203        #    self.readingFailed(infob='Could not read file')
204        #    return
205       
206        if net == None:
207            self.readingFailed(infob='Error reading file')
208            return
209
210        if self.auto_table:
211            self.infoc.setText("Vertices data generated and added automatically")
212            self.auto_items = net.items()
213        else:
214            self.auto_items = None
215       
216        self.infoa.setText("%d nodes" % net.number_of_nodes())
217       
218        if net.is_directed():
219            self.infob.setText("Directed graph")
220        else:
221            self.infob.setText("Undirected graph")
222       
223        # make new data and send it
224        fName = os.path.split(fn)[1]
225        if "." in fName:
226            #data.name = string.join(string.split(fName, '.')[:-1], '.')
227            pass
228        else:
229            #data.name = fName
230            pass
231           
232        self.graph = net
233       
234        # Find items data file for selected network
235        items_candidate = os.path.splitext(fn)[0] + ".tab"
236        if os.path.exists(items_candidate):
237            self.readDataFile(items_candidate)
238            if items_candidate in self.recentDataFiles:
239                self.recentDataFiles.remove(items_candidate)
240            self.recentDataFiles.insert(0, items_candidate)
241        elif os.path.exists(os.path.splitext(fn)[0] + "_items.tab"):
242            items_candidate = os.path.splitext(fn)[0] + "_items.tab"
243            self.readDataFile(items_candidate)
244            if items_candidate in self.recentDataFiles:
245                self.recentDataFiles.remove(items_candidate)
246            self.recentDataFiles.insert(0, items_candidate)
247        else:
248            if '(none)' in self.recentDataFiles: 
249                self.recentDataFiles.remove('(none)')
250            self.recentDataFiles.insert(0, '(none)')
251       
252        # Find links data file for selected network
253        links_candidate = os.path.splitext(fn)[0] + "_links.tab" 
254        if os.path.exists(links_candidate):
255            self.readEdgesFile(links_candidate)
256            self.recentEdgesFiles.insert(0, links_candidate)
257        else:
258            if '(none)' in self.recentEdgesFiles: 
259                self.recentEdgesFiles.remove('(none)')
260            self.recentEdgesFiles.insert(0, '(none)')
261       
262        self.setFileLists()
263       
264        self.send("Network", self.graph)
265        if self.graph != None and self.graph.items() != None:
266            self.send("Items", self.graph.items())
267        else:
268            self.send("Items", None)
269       
270    def addDataFile(self, fn):
271        if fn == "(none)" or self.graph == None:
272           
273            if self.auto_items is not None:
274                self.infoc.setText("Vertices data generated and added automatically")
275                self.graph.set_items(self.auto_items)
276            else:
277                self.infoc.setText("No vertices data file specified")
278                self.graph.set_items(None)
279               
280            self.send("Network", self.graph)
281            self.send("Items", self.graph.items())
282            return
283         
284        self.readDataFile(fn)
285       
286        self.send("Network", self.graph)
287        self.send("Items", self.graph.items())
288       
289    def readDataFile(self, fn):
290        table = ExampleTable(fn)
291       
292        if len(table) != self.graph.number_of_nodes():
293            self.infoc.setText("Vertices data length does not match number of vertices")
294           
295            if '(none)' in self.recentDataFiles: 
296                self.recentDataFiles.remove('(none)')
297               
298            self.recentDataFiles.insert(0, '(none)')
299            self.setFileLists()
300            return
301       
302        items = self.graph.items()
303        if items is not None and \
304                'x' in items.domain and \
305                'y' in items.domain and \
306                len(self.graph.items()) == len(table) and \
307                'x' not in table.domain and 'y' not in table.domain:
308            xvar = items.domain['x']
309            yvar = items.domain['y']
310            tmp = Orange.data.Table(Orange.data.Domain([xvar, yvar], False), items)
311            table = Orange.data.Table([table, tmp])
312           
313        self.graph.set_items(table)
314        self.infoc.setText("Vertices data file added")
315       
316    def addEdgesFile(self, fn):
317        if fn == "(none)" or self.graph == None:
318            self.infod.setText("No edges data file specified")
319            #self.graph.setattr("links", None)
320            self.send("Network", self.graph)
321            self.send("Items", None)
322            return
323       
324        self.readEdgesFile(fn)
325       
326        self.send("Network", self.graph)
327        self.send("Items", self.graph.items())
328       
329    def readEdgesFile(self, fn):
330        table = ExampleTable(fn)
331        if self.graph.is_directed():
332            nEdges = len(self.graph.getEdges())
333        else:
334            nEdges = len(self.graph.getEdges()) / 2
335           
336        if len(table) != nEdges:
337            self.infod.setText("Edges data length does not match number of edges")
338           
339            if '(none)' in self.recentEdgesFiles: 
340                self.recentEdgesFiles.remove('(none)')
341               
342            self.recentEdgesFiles.insert(0, '(none)')
343            self.setFileLists()
344            return
345       
346        self.graph.set_links(table)
347        self.infod.setText("Edges data file added")
348       
349    def browseNetFile(self, inDemos=0):
350        """user pressed the '...' button to manually select a file to load"""
351       
352        "Display a FileDialog and select a file"
353        if inDemos:
354            import os
355            try:
356                import orngConfiguration
357                startfile = Orange.misc.environ.network_install_dir
358            except:
359                startfile = ""
360               
361            if not startfile or not os.path.exists(startfile):
362                try:
363                    import win32api, win32con
364                    t = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SOFTWARE\\Python\\PythonCore\\%i.%i\\PythonPath\\Orange" % sys.version_info[:2], 0, win32con.KEY_READ)
365                    t = win32api.RegQueryValueEx(t, "")[0]
366                    startfile = t[:t.find("orange")] + "orange\\doc\\networks"
367                except:
368                    startfile = ""
369
370            if not startfile or not os.path.exists(startfile):
371                d = OWGUI.__file__
372                if d[-8:] == "OWGUI.py":
373                    startfile = d[:-22] + "doc/networks"
374                elif d[-9:] == "OWGUI.pyc":
375                    startfile = d[:-23] + "doc/networks"
376
377            if not startfile or not os.path.exists(startfile):
378                d = os.getcwd()
379                if d[-12:] == "OrangeCanvas":
380                    startfile = d[:-12]+"doc/networks"
381                else:
382                    if d[-1] not in ["/", "\\"]:
383                        d+= "/"
384                    startfile = d+"doc/networks"
385
386            if not os.path.exists(startfile):
387                QMessageBox.information( None, "File", "Cannot find the directory with example networks", QMessageBox.Ok + QMessageBox.Default)
388                return
389        else:
390            if len(self.recentFiles) == 0 or self.recentFiles[0] == "(none)":
391                if sys.platform == "darwin":
392                    startfile = user.home
393                else:
394                    startfile = "."
395            else:
396                startfile = self.recentFiles[0]
397               
398        filename = str(QFileDialog.getOpenFileName(self, 'Open a Network File', startfile, "All network files (*.gpickle *.net *.gml)\nNetworkX graph as Python pickle (*.gpickle)\nPajek files (*.net)\nGML files (*.gml)\nAll files (*.*)"))
399       
400        if filename == "": return
401        if filename in self.recentFiles: self.recentFiles.remove(filename)
402        self.recentFiles.insert(0, filename)
403        self.setFileLists()
404        self.selectNetFile(0)
405       
406    def browseDataFile(self, inDemos=0):
407        if self.graph == None:
408            return
409       
410        #Display a FileDialog and select a file
411        if len(self.recentDataFiles) == 0 or self.recentDataFiles[0] == "(none)":
412            if len(self.recentFiles) == 0 or self.recentFiles[0] == "(none)":
413                if sys.platform == "darwin":
414                    startfile = user.home
415                else:
416                    startfile="."
417            else:
418                startfile = os.path.dirname(self.recentFiles[0])
419               
420        else:
421            startfile = self.recentDataFiles[0]
422               
423        filename = str(QFileDialog.getOpenFileName(self, 'Open a Vertices Data File', startfile, 'Data files (*.tab)\nAll files(*.*)'))
424   
425        if filename == "": return
426        if filename in self.recentDataFiles: self.recentDataFiles.remove(filename)
427        self.recentDataFiles.insert(0, filename)
428        self.setFileLists()
429        self.addDataFile(self.recentDataFiles[0])
430       
431    def browseEdgesFile(self, inDemos=0):
432        if self.graph == None:
433            return
434       
435        #Display a FileDialog and select a file
436        if len(self.recentEdgesFiles) == 0 or self.recentEdgesFiles[0] == "(none)":
437            if len(self.recentFiles) == 0 or self.recentFiles[0] == "(none)":
438                if sys.platform == "darwin":
439                    startfile = user.home
440                else:
441                    startfile="."
442            else:
443                startfile = os.path.dirname(self.recentFiles[0])
444               
445        else:
446            startfile = self.recentEdgesFiles[0]
447               
448        filename = str(QFileDialog.getOpenFileName(self, 'Open a Edges Data File', startfile, 'Data files (*.tab)\nAll files(*.*)'))
449   
450        if filename == "": return
451        if filename in self.recentEdgesFiles: self.recentEdgesFiles.remove(filename)
452        self.recentEdgesFiles.insert(0, filename)
453        self.setFileLists()
454        self.addEdgesFile(self.recentEdgesFiles[0])
455
456    def setInfo(self, info):
457        for (i, s) in enumerate(info):
458            self.info[i].setText(s)           
459
460    def sendReport(self):
461        self.reportSettings("Network file",
462                            [("File name", self.filecombo.currentText()),
463                             ("Vertices", self.graph.number_of_nodes()),
464                             hasattr(self.graph, "is_directed") and ("Directed", OWGUI.YesNo[self.graph.is_directed()])])
465        self.reportSettings("Vertices meta data", [("File name", self.datacombo.currentText())])
466        self.reportData(self.graph.items(), None)
467        self.reportSettings("Edges meta data", [("File name", self.edgescombo.currentText())])
468        self.reportData(self.graph.links(), None, None)
469       
470if __name__ == "__main__":
471    a=QApplication(sys.argv)
472    owf=OWNxFile()
473    owf.activateLoadedSettings()
474    owf.show() 
475    a.exec_()
476    owf.saveSettings()
Note: See TracBrowser for help on using the repository browser.