source: orange/Orange/OrangeWidgets/OWNxHist.py @ 10511:5ad28922ee4a

Revision 10511:5ad28922ee4a, 12.4 KB checked in by miha, 2 years ago (diff)

Fixed a bug if matrix.items was None.

Line 
1#
2# OWHist.py
3#
4# the base for network histograms
5
6import math
7import numpy
8
9import Orange
10import OWGUI
11
12from OWWidget import *
13from OWGraph import *
14from OWHist import *
15
16class OWNxHist():
17
18    def __init__(self, parent=None, type=0):
19        self.parent = parent
20
21    def addHistogramControls(self, parent=None):
22        # set default settings
23        self.spinLowerThreshold = 0
24        self.spinLowerChecked = False
25        self.spinUpperThreshold = 0
26        self.spinUpperChecked = False
27        self.netOption = 0
28        self.dstWeight = 0
29        self.kNN = 0
30        self.andor = 0
31        self.matrix = None
32        self.excludeLimit = 1
33        self.percentil = 0
34
35        if parent is None:
36            parent = self.controlArea
37
38        boxGeneral = OWGUI.widgetBox(parent, box="Distance boundaries")
39
40        ribg = OWGUI.widgetBox(boxGeneral, None, orientation="horizontal", addSpace=False)
41        OWGUI.lineEdit(ribg, self, "spinLowerThreshold", "Lower", orientation='horizontal', callback=self.changeLowerSpin, valueType=float, enterPlaceholder=True, controlWidth=100)
42        OWGUI.lineEdit(ribg, self, "spinUpperThreshold", "Upper    ", orientation='horizontal', callback=self.changeUpperSpin, valueType=float, enterPlaceholder=True, controlWidth=100)
43        ribg.layout().addStretch(1)
44        #ribg = OWGUI.radioButtonsInBox(boxGeneral, self, "andor", [], orientation='horizontal', callback = self.generateGraph)
45        #OWGUI.appendRadioButton(ribg, self, "andor", "OR", callback = self.generateGraph)
46        #b = OWGUI.appendRadioButton(ribg, self, "andor", "AND", callback = self.generateGraph)
47        #b.setEnabled(False)
48        #ribg.hide(False)
49
50        ribg = OWGUI.widgetBox(boxGeneral, None, orientation="horizontal", addSpace=False)
51        OWGUI.spin(ribg, self, "kNN", 0, 1000, 1, label="kNN   ", orientation='horizontal', callback=self.generateGraph, callbackOnReturn=1, controlWidth=100)
52        OWGUI.doubleSpin(ribg, self, "percentil", 0, 100, 0.1, label="Percentile", orientation='horizontal', callback=self.setPercentil, callbackOnReturn=1, controlWidth=100)
53        ribg.layout().addStretch(1)
54        # Options
55        self.attrColor = ""
56        ribg = OWGUI.radioButtonsInBox(parent, self, "netOption", [], "Options", callback=self.generateGraph)
57        OWGUI.appendRadioButton(ribg, self, "netOption", "All vertices", callback=self.generateGraph)
58        hb = OWGUI.widgetBox(ribg, None, orientation="horizontal", addSpace=False)
59        OWGUI.appendRadioButton(ribg, self, "netOption", "Large components only. Min nodes:", insertInto=hb, callback=self.generateGraph)
60        OWGUI.spin(hb, self, "excludeLimit", 1, 100, 1, callback=(lambda h=True: self.generateGraph(h)))
61        OWGUI.appendRadioButton(ribg, self, "netOption", "Largest connected component only", callback=self.generateGraph)
62        OWGUI.appendRadioButton(ribg, self, "netOption", "Connected component with vertex")
63        self.attribute = None
64        self.attributeCombo = OWGUI.comboBox(parent, self, "attribute", box="Filter attribute", orientation='horizontal')#, callback=self.setVertexColor)
65
66        ribg = OWGUI.radioButtonsInBox(parent, self, "dstWeight", [], "Distance -> Weight", callback=self.generateGraph)
67        hb = OWGUI.widgetBox(ribg, None, orientation="horizontal", addSpace=False)
68        OWGUI.appendRadioButton(ribg, self, "dstWeight", "Weight := distance", insertInto=hb, callback=self.generateGraph)
69        OWGUI.appendRadioButton(ribg, self, "dstWeight", "Weight := 1 - distance", insertInto=hb, callback=self.generateGraph)
70
71        self.label = ''
72        self.searchString = OWGUI.lineEdit(self.attributeCombo.box, self, "label", callback=self.setSearchStringTimer, callbackOnType=True)
73        self.searchStringTimer = QTimer(self)
74        self.connect(self.searchStringTimer, SIGNAL("timeout()"), self.generateGraph)
75
76        if str(self.netOption) != '3':
77            self.attributeCombo.box.setEnabled(False)
78
79    def setPercentil(self):
80        self.spinLowerThreshold = self.histogram.minValue
81        # flatten matrix, sort values and remove identities (self.matrix[i][i])
82        vals = sorted(sum(self.matrix, ()))[self.matrix.dim:]
83        ind = int(len(vals) * self.percentil / 100)
84        self.spinUpperThreshold = vals[ind]
85        self.generateGraph()
86
87    def enableAttributeSelection(self):
88        self.attributeCombo.box.setEnabled(True)
89
90    def setSearchStringTimer(self):
91        self.searchStringTimer.stop()
92        self.searchStringTimer.start(750)
93
94    def setMatrix(self, data):
95        if data == None: return
96
97        if not hasattr(data, "items") or data.items is None:
98            setattr(data, "items", [i for i in range(data.dim)])
99
100        self.matrix = data
101        # draw histogram
102        data.matrixType = orange.SymMatrix.Symmetric
103        values = data.getValues()
104        #print "values:",values
105        self.histogram.setValues(values)
106
107        low = min(values)
108        upp = max(values)
109        self.spinLowerThreshold = self.spinUpperThreshold = math.floor(low - (0.03 * (upp - low)))
110        self.generateGraph()
111        self.attributeCombo.clear()
112        vars = []
113        if (self.matrix != None):
114            if hasattr(self.matrix, "items"):
115
116                if isinstance(self.matrix.items, orange.ExampleTable):
117                    vars = list(self.matrix.items.domain.variables)
118
119                    metas = self.matrix.items.domain.getmetas(0)
120                    for i, var in metas.iteritems():
121                        vars.append(var)
122
123        self.icons = self.createAttributeIconDict()
124
125        for var in vars:
126            try:
127                self.attributeCombo.addItem(self.icons[var.varType], unicode(var.name))
128            except:
129                print "error adding ", var, " to the attribute combo"
130
131    def changeLowerSpin(self):
132        self.percentil = 0
133
134        if self.spinLowerThreshold < self.histogram.minValue:
135            self.spinLowerThreshold = self.histogram.minValue
136        elif self.spinLowerThreshold > self.histogram.maxValue:
137            self.spinLowerThreshold = self.histogram.maxValue
138
139        if self.spinLowerThreshold >= self.spinUpperThreshold:
140            self.spinUpperThreshold = self.spinLowerThreshold
141
142        self.generateGraph()
143
144    def changeUpperSpin(self):
145        self.percentil = 0
146
147        if self.spinUpperThreshold < self.histogram.minValue:
148            self.spinUpperThreshold = self.histogram.minValue
149        elif self.spinUpperThreshold > self.histogram.maxValue:
150            self.spinUpperThreshold = self.histogram.maxValue
151
152        if self.spinUpperThreshold <= self.spinLowerThreshold:
153            self.spinLowerThreshold = self.spinUpperThreshold
154
155        self.generateGraph()
156
157    def generateGraph(self, N_changed=False):
158        self.searchStringTimer.stop()
159        self.attributeCombo.box.setEnabled(False)
160        self.error()
161        matrix = None
162        self.warning('')
163
164        if N_changed:
165            self.netOption = 1
166
167        if self.matrix == None:
168            self.infoa.setText("No data loaded.")
169            self.infob.setText("")
170            return
171
172        #print len(self.histogram.yData), len(self.histogram.xData)
173        nEdgesEstimate = 2 * sum([self.histogram.yData[i] for i, e in enumerate(self.histogram.xData) if self.spinLowerThreshold <= e <= self.spinUpperThreshold])
174
175        if nEdgesEstimate > 200000:
176            self.graph = None
177            nedges = 0
178            n = 0
179            self.error('Estimated number of edges is too high (%d).' % nEdgesEstimate)
180        else:
181            graph = Orange.network.Graph()
182            graph.add_nodes_from(range(self.matrix.dim))
183            matrix = self.matrix
184
185            if hasattr(self.matrix, "items") and self.matrix.items is not None:
186                if type(self.matrix.items) == Orange.data.Table:
187                    graph.set_items(self.matrix.items)
188                else:
189                    data = [[str(x)] for x in self.matrix.items]
190                    items = Orange.data.Table(Orange.data.Domain(Orange.feature.String('label'), 0), data)
191                    graph.set_items(items)
192
193            # set the threshold
194            # set edges where distance is lower than threshold
195            self.warning(0)
196            if self.kNN >= self.matrix.dim:
197                self.warning(0, "kNN larger then supplied distance matrix dimension. Using k = %i" % (self.matrix.dim - 1))
198            #nedges = graph.fromDistanceMatrix(self.matrix, self.spinLowerThreshold, self.spinUpperThreshold, min(self.kNN, self.matrix.dim - 1), self.andor)
199            edge_list = Orange.network.GraphLayout().edges_from_distance_matrix(self.matrix, self.spinLowerThreshold, self.spinUpperThreshold, min(self.kNN, self.matrix.dim - 1))
200            if self.dstWeight == 1:
201                graph.add_edges_from(((u, v, {'weight':1 - d}) for u, v, d in edge_list))
202            else:
203                graph.add_edges_from(((u, v, {'weight':d}) for u, v, d in edge_list))
204
205            # exclude unconnected
206            if str(self.netOption) == '1':
207                components = [x for x in Orange.network.nx.algorithms.components.connected_components(graph) if len(x) > self.excludeLimit]
208                if len(components) > 0:
209                    include = reduce(lambda x, y: x + y, components)
210                    if len(include) > 1:
211                        self.graph = graph.subgraph(include)
212                        matrix = self.matrix.getitems(include)
213                    else:
214                        self.graph = None
215                        matrix = None
216                else:
217                    self.graph = None
218                    matrix = None
219            # largest connected component only
220            elif str(self.netOption) == '2':
221                component = Orange.network.nx.algorithms.components.connected_components(graph)[0]
222                if len(component) > 1:
223                    self.graph = graph.subgraph(component)
224                    matrix = self.matrix.getitems(component)
225                else:
226                    self.graph = None
227                    matrix = None
228            # connected component with vertex by label
229            elif str(self.netOption) == '3':
230                self.attributeCombo.box.setEnabled(True)
231                self.graph = None
232                matrix = None
233                #print self.attributeCombo.currentText()
234                if self.attributeCombo.currentText() != '' and self.label != '':
235                    components = Orange.network.nx.algorithms.components.connected_components(graph)
236
237                    txt = self.label.lower()
238                    #print 'txt:',txt
239                    nodes = [i for i, values in enumerate(self.matrix.items) if txt in str(values[str(self.attributeCombo.currentText())]).lower()]
240                    #print "nodes:",nodes
241                    if len(nodes) > 0:
242                        vertices = []
243                        for component in components:
244                            for node in nodes:
245                                if node in component:
246                                    if len(component) > 0:
247                                        vertices.extend(component)
248
249                        if len(vertices) > 0:
250                            #print "n vertices:", len(vertices), "n set vertices:", len(set(vertices))
251                            vertices = list(set(vertices))
252                            self.graph = graph.subgraph(include)
253                            matrix = self.matrix.getitems(vertices)
254            else:
255                self.graph = graph
256
257        if matrix != None:
258            matrix.items = self.graph.items()
259        self.graph_matrix = matrix
260
261        if self.graph is None:
262            self.pconnected = 0
263            self.nedges = 0
264        else:
265            self.pconnected = self.graph.number_of_nodes()
266            self.nedges = self.graph.number_of_edges()
267        if hasattr(self, "infoa"):
268            self.infoa.setText("Matrix size: %d" % self.matrix.dim)
269        if hasattr(self, "infob"):
270            self.infob.setText("Graph nodes: %d (%3.1f%%)" % (self.pconnected,
271                self.pconnected / float(self.matrix.dim) * 100))
272        if hasattr(self, "infoc"):
273            self.infoc.setText("Graph edges: %d (%.2f edges/node)" % (
274                self.nedges, self.nedges / float(self.pconnected)
275                if self.pconnected else 0))
276
277        #print 'self.graph:',self.graph+
278        if hasattr(self, "sendSignals"):
279            self.sendSignals()
280
281        self.histogram.setBoundary(self.spinLowerThreshold, self.spinUpperThreshold)
282
Note: See TracBrowser for help on using the repository browser.