Commits

Miha Stajdohar  committed c40a176

Added network histogram, fixed browse doc networks.

  • Participants
  • Parent commits 18aa5e2

Comments (0)

Files changed (3)

File _network/readwrite.py

     if type(p) == str:
         if not os.path.isfile(p):
             path = Orange.data.io.find_file(os.path.split(p)[1])
-            #path = os.path.join(Orange.utils.environ.network_install_dir, \
-            #                    os.path.split(p)[1])
 
             if os.path.isfile(path):
                 return path

File _network/widgets/OWNxFile.py

         if inDemos:
             import os
             try:
-                import orngConfiguration
-                startfile = Orange.utils.environ.network_install_dir
+                import pkg_resources
+                startfile = pkg_resources.load_entry_point("Orange-Network", "orange.data.io.search_paths", "network")().next()[1]
             except:
                 startfile = ""
 
-            if not startfile or not os.path.exists(startfile):
-                try:
-                    import win32api, win32con
-                    t = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SOFTWARE\\Python\\PythonCore\\%i.%i\\PythonPath\\Orange" % sys.version_info[:2], 0, win32con.KEY_READ)
-                    t = win32api.RegQueryValueEx(t, "")[0]
-                    startfile = t[:t.find("orange")] + "orange\\doc\\networks"
-                except:
-                    startfile = ""
-
-            if not startfile or not os.path.exists(startfile):
-                d = OWGUI.__file__
-                if d[-8:] == "OWGUI.py":
-                    startfile = d[:-22] + "doc/networks"
-                elif d[-9:] == "OWGUI.pyc":
-                    startfile = d[:-23] + "doc/networks"
-
-            if not startfile or not os.path.exists(startfile):
-                d = os.getcwd()
-                if d[-12:] == "OrangeCanvas":
-                    startfile = d[:-12] + "doc/networks"
-                else:
-                    if d[-1] not in ["/", "\\"]:
-                        d += "/"
-                    startfile = d + "doc/networks"
+#            if not startfile or not os.path.exists(startfile):
+#                try:
+#                    import win32api, win32con
+#                    t = win32api.RegOpenKey(win32con.HKEY_LOCAL_MACHINE, "SOFTWARE\\Python\\PythonCore\\%i.%i\\PythonPath\\Orange" % sys.version_info[:2], 0, win32con.KEY_READ)
+#                    t = win32api.RegQueryValueEx(t, "")[0]
+#                    startfile = t[:t.find("orange")] + "orange\\doc\\networks"
+#                except:
+#                    startfile = ""
+#
+#            if not startfile or not os.path.exists(startfile):
+#                d = OWGUI.__file__
+#                if d[-8:] == "OWGUI.py":
+#                    startfile = d[:-22] + "doc/networks"
+#                elif d[-9:] == "OWGUI.pyc":
+#                    startfile = d[:-23] + "doc/networks"
+#
+#            if not startfile or not os.path.exists(startfile):
+#                d = os.getcwd()
+#                if d[-12:] == "OrangeCanvas":
+#                    startfile = d[:-12] + "doc/networks"
+#                else:
+#                    if d[-1] not in ["/", "\\"]:
+#                        d += "/"
+#                    startfile = d + "doc/networks"
 
             if not os.path.exists(startfile):
                 QMessageBox.information(None, "File", "Cannot find the directory with example networks", QMessageBox.Ok + QMessageBox.Default)

File _network/widgets/OWNxHist.py

+#
+# OWHist.py
+#
+# the base for network histograms
+
+import math
+import numpy
+
+import Orange
+import OWGUI
+
+from OWWidget import *
+from OWGraph import *
+from OWHist import *
+
+class OWNxHist():
+
+    def __init__(self, parent=None, type=0):
+        self.parent = parent
+
+        # set default settings
+        self.spinLowerThreshold = 0
+        self.spinLowerChecked = False
+        self.spinUpperThreshold = 0
+        self.spinUpperChecked = False
+        self.netOption = 0
+        self.dstWeight = 0
+        self.kNN = 0
+        self.andor = 0
+        self.matrix = None
+        self.excludeLimit = 2
+        self.percentil = 0
+
+        self.graph = None
+        self.graph_matrix = None
+
+    def addHistogramControls(self, parent=None):
+        if parent is None:
+            parent = self.controlArea
+
+        boxGeneral = OWGUI.widgetBox(parent, box="Distance boundaries")
+
+        ribg = OWGUI.widgetBox(boxGeneral, None, orientation="horizontal", addSpace=False)
+        OWGUI.lineEdit(ribg, self, "spinLowerThreshold", "Lower", orientation='horizontal', callback=self.changeLowerSpin, valueType=float, enterPlaceholder=True, controlWidth=100)
+        OWGUI.lineEdit(ribg, self, "spinUpperThreshold", "Upper    ", orientation='horizontal', callback=self.changeUpperSpin, valueType=float, enterPlaceholder=True, controlWidth=100)
+        ribg.layout().addStretch(1)
+        #ribg = OWGUI.radioButtonsInBox(boxGeneral, self, "andor", [], orientation='horizontal', callback = self.generateGraph)
+        #OWGUI.appendRadioButton(ribg, self, "andor", "OR", callback = self.generateGraph)
+        #b = OWGUI.appendRadioButton(ribg, self, "andor", "AND", callback = self.generateGraph)
+        #b.setEnabled(False)
+        #ribg.hide(False)
+
+        ribg = OWGUI.widgetBox(boxGeneral, None, orientation="horizontal", addSpace=False)
+        OWGUI.spin(ribg, self, "kNN", 0, 1000, 1, label="kNN   ", orientation='horizontal', callback=self.generateGraph, callbackOnReturn=1, controlWidth=100)
+        OWGUI.doubleSpin(ribg, self, "percentil", 0, 100, 0.1, label="Percentile", orientation='horizontal', callback=self.setPercentil, callbackOnReturn=1, controlWidth=100)
+        ribg.layout().addStretch(1)
+        # Options
+        self.attrColor = ""
+        ribg = OWGUI.radioButtonsInBox(parent, self, "netOption", [], "Options", callback=self.generateGraph)
+        OWGUI.appendRadioButton(ribg, self, "netOption", "All vertices", callback=self.generateGraph)
+        hb = OWGUI.widgetBox(ribg, None, orientation="horizontal", addSpace=False)
+        OWGUI.appendRadioButton(ribg, self, "netOption", "Large components only. Min nodes:", insertInto=hb, callback=self.generateGraph)
+        OWGUI.spin(hb, self, "excludeLimit", 2, 100, 1, callback=(lambda h=True: self.generateGraph(h)))
+        OWGUI.appendRadioButton(ribg, self, "netOption", "Largest connected component only", callback=self.generateGraph)
+        OWGUI.appendRadioButton(ribg, self, "netOption", "Connected component with vertex")
+        self.attribute = None
+        self.attributeCombo = OWGUI.comboBox(parent, self, "attribute", box="Filter attribute", orientation='horizontal')#, callback=self.setVertexColor)
+
+        ribg = OWGUI.radioButtonsInBox(parent, self, "dstWeight", [], "Distance -> Weight", callback=self.generateGraph)
+        hb = OWGUI.widgetBox(ribg, None, orientation="horizontal", addSpace=False)
+        OWGUI.appendRadioButton(ribg, self, "dstWeight", "Weight := distance", insertInto=hb, callback=self.generateGraph)
+        OWGUI.appendRadioButton(ribg, self, "dstWeight", "Weight := 1 - distance", insertInto=hb, callback=self.generateGraph)
+
+        self.label = ''
+        self.searchString = OWGUI.lineEdit(self.attributeCombo.box, self, "label", callback=self.setSearchStringTimer, callbackOnType=True)
+        self.searchStringTimer = QTimer(self)
+        self.connect(self.searchStringTimer, SIGNAL("timeout()"), self.generateGraph)
+
+        if str(self.netOption) != '3':
+            self.attributeCombo.box.setEnabled(False)
+
+    def setPercentil(self):
+        if self.matrix is None or self.percentil <= 0:
+            return
+
+        self.spinLowerThreshold = self.histogram.minValue
+        # flatten matrix, sort values and remove identities (self.matrix[i][i])
+        vals = sorted(sum(self.matrix, ()))[self.matrix.dim:]
+        ind = int(len(vals) * self.percentil / 100)
+        self.spinUpperThreshold = vals[ind]
+        self.generateGraph()
+
+    def enableAttributeSelection(self):
+        self.attributeCombo.box.setEnabled(True)
+
+    def setSearchStringTimer(self):
+        self.searchStringTimer.stop()
+        self.searchStringTimer.start(750)
+
+    def setMatrix(self, data):
+        if data == None:
+            self.matrix = None
+            self.histogram.setValues([])
+            self.attributeCombo.clear()
+            self.generateGraph()
+            return
+
+        if not hasattr(data, "items") or data.items is None:
+            setattr(data, "items", [i for i in range(data.dim)])
+
+        self.matrix = data
+        # draw histogram
+        data.matrixType = orange.SymMatrix.Symmetric
+        values = data.getValues()
+        #print "values:",values
+        self.histogram.setValues(values)
+
+        low = min(values)
+        upp = max(values)
+        self.spinLowerThreshold = self.spinUpperThreshold = math.floor(low - (0.03 * (upp - low)))
+
+        self.attributeCombo.clear()
+        vars = []
+
+        if hasattr(self.matrix, "items"):
+
+            if isinstance(self.matrix.items, orange.ExampleTable):
+                vars = list(self.matrix.items.domain.variables)
+
+                metas = self.matrix.items.domain.getmetas(0)
+                for i, var in metas.iteritems():
+                    vars.append(var)
+
+        self.icons = self.createAttributeIconDict()
+
+        for var in vars:
+            try:
+                if var.varType != 7: # if not Orange.feature.Python
+                    self.attributeCombo.addItem(self.icons[var.varType], unicode(var.name))
+            except:
+                print "Error adding", var, "to the attribute combo."
+
+        self.setPercentil()
+        self.generateGraph()
+
+    def changeLowerSpin(self):
+        self.percentil = 0
+
+        if self.spinLowerThreshold < self.histogram.minValue:
+            self.spinLowerThreshold = self.histogram.minValue
+        elif self.spinLowerThreshold > self.histogram.maxValue:
+            self.spinLowerThreshold = self.histogram.maxValue
+
+        if self.spinLowerThreshold >= self.spinUpperThreshold:
+            self.spinUpperThreshold = self.spinLowerThreshold
+
+        self.generateGraph()
+
+    def changeUpperSpin(self):
+        self.percentil = 0
+
+        if self.spinUpperThreshold < self.histogram.minValue:
+            self.spinUpperThreshold = self.histogram.minValue
+        elif self.spinUpperThreshold > self.histogram.maxValue:
+            self.spinUpperThreshold = self.histogram.maxValue
+
+        if self.spinUpperThreshold <= self.spinLowerThreshold:
+            self.spinLowerThreshold = self.spinUpperThreshold
+
+        self.generateGraph()
+
+    def generateGraph(self, N_changed=False):
+        self.searchStringTimer.stop()
+        self.attributeCombo.box.setEnabled(False)
+        self.error()
+        matrix = None
+        self.warning('')
+
+        if N_changed:
+            self.netOption = 1
+
+        if self.matrix == None:
+            if hasattr(self, "infoa"):
+                self.infoa.setText("No data loaded.")
+            if hasattr(self, "infob"):
+                self.infob.setText("")
+            if hasattr(self, "infoc"):
+                self.infoc.setText("")
+            self.pconnected = 0
+            self.nedges = 0
+            self.graph = None
+            if hasattr(self, "sendSignals"):
+                self.sendSignals()
+            return
+
+        #print len(self.histogram.yData), len(self.histogram.xData)
+        nEdgesEstimate = 2 * sum([self.histogram.yData[i] for i, e in enumerate(self.histogram.xData) if self.spinLowerThreshold <= e <= self.spinUpperThreshold])
+
+        if nEdgesEstimate > 200000:
+            self.graph = None
+            nedges = 0
+            n = 0
+            self.error('Estimated number of edges is too high (%d).' % nEdgesEstimate)
+        else:
+            graph = Orange.network.Graph()
+            graph.add_nodes_from(range(self.matrix.dim))
+            matrix = self.matrix
+
+            if hasattr(self.matrix, "items") and self.matrix.items is not None:
+                if type(self.matrix.items) == Orange.data.Table:
+                    graph.set_items(self.matrix.items)
+                else:
+                    data = [[str(x)] for x in self.matrix.items]
+                    items = Orange.data.Table(Orange.data.Domain(Orange.feature.String('label'), 0), data)
+                    graph.set_items(items)
+
+            # set the threshold
+            # set edges where distance is lower than threshold
+            self.warning(0)
+            if self.kNN >= self.matrix.dim:
+                self.warning(0, "kNN larger then supplied distance matrix dimension. Using k = %i" % (self.matrix.dim - 1))
+            #nedges = graph.fromDistanceMatrix(self.matrix, self.spinLowerThreshold, self.spinUpperThreshold, min(self.kNN, self.matrix.dim - 1), self.andor)
+            edge_list = Orange.network.GraphLayout().edges_from_distance_matrix(self.matrix, self.spinLowerThreshold, self.spinUpperThreshold, min(self.kNN, self.matrix.dim - 1))
+            if self.dstWeight == 1:
+                graph.add_edges_from(((u, v, {'weight':1 - d}) for u, v, d in edge_list))
+            else:
+                graph.add_edges_from(((u, v, {'weight':d}) for u, v, d in edge_list))
+
+            # exclude unconnected
+            if str(self.netOption) == '1':
+                components = [x for x in Orange.network.nx.algorithms.components.connected_components(graph) if len(x) >= self.excludeLimit]
+                if len(components) > 0:
+                    include = reduce(lambda x, y: x + y, components)
+                    if len(include) > 1:
+                        self.graph = graph.subgraph(include)
+                        matrix = self.matrix.getitems(include)
+                    else:
+                        self.graph = None
+                        matrix = None
+                else:
+                    self.graph = None
+                    matrix = None
+            # largest connected component only
+            elif str(self.netOption) == '2':
+                component = Orange.network.nx.algorithms.components.connected_components(graph)[0]
+                if len(component) > 1:
+                    self.graph = graph.subgraph(component)
+                    matrix = self.matrix.getitems(component)
+                else:
+                    self.graph = None
+                    matrix = None
+            # connected component with vertex by label
+            elif str(self.netOption) == '3':
+                self.attributeCombo.box.setEnabled(True)
+                self.graph = None
+                matrix = None
+                #print self.attributeCombo.currentText()
+                if self.attributeCombo.currentText() != '' and self.label != '':
+                    components = Orange.network.nx.algorithms.components.connected_components(graph)
+
+                    txt = self.label.lower()
+                    #print 'txt:',txt
+                    nodes = [i for i, values in enumerate(self.matrix.items) if txt in str(values[str(self.attributeCombo.currentText())]).lower()]
+                    #print "nodes:",nodes
+                    if len(nodes) > 0:
+                        vertices = []
+                        for component in components:
+                            for node in nodes:
+                                if node in component:
+                                    if len(component) > 0:
+                                        vertices.extend(component)
+
+                        if len(vertices) > 0:
+                            #print "n vertices:", len(vertices), "n set vertices:", len(set(vertices))
+                            vertices = list(set(vertices))
+                            self.graph = graph.subgraph(include)
+                            matrix = self.matrix.getitems(vertices)
+            else:
+                self.graph = graph
+
+        if matrix != None:
+            matrix.setattr("items", self.graph.items())
+        self.graph_matrix = matrix
+
+        if self.graph is None:
+            self.pconnected = 0
+            self.nedges = 0
+        else:
+            self.pconnected = self.graph.number_of_nodes()
+            self.nedges = self.graph.number_of_edges()
+        if hasattr(self, "infoa"):
+            self.infoa.setText("Matrix size: %d" % self.matrix.dim)
+        if hasattr(self, "infob"):
+            self.infob.setText("Graph nodes: %d (%3.1f%%)" % (self.pconnected,
+                self.pconnected / float(self.matrix.dim) * 100))
+        if hasattr(self, "infoc"):
+            self.infoc.setText("Graph edges: %d (%.2f edges/node)" % (
+                self.nedges, self.nedges / float(self.pconnected)
+                if self.pconnected else 0))
+
+        #print 'self.graph:',self.graph+
+        if hasattr(self, "sendSignals"):
+            self.sendSignals()
+
+        self.histogram.setBoundary(self.spinLowerThreshold, self.spinUpperThreshold)
+