#
source:
orange/Orange/OrangeWidgets/VisualizeQt/OWNxCanvas3D.py
@
11474:df0622184ee6

Revision 11474:df0622184ee6, 29.5 KB checked in by markotoplak, 12 months ago (diff) |
---|

Rev | Line | |
---|---|---|

[9079] | 1 | from plot.owplot3d import OWPlot3D, GL_FLOAT, GL_LINES, GL_POINTS, glEnable, GL_PROGRAM_POINT_SIZE |

2 | from plot.owopenglrenderer import VertexBuffer | |

[9047] | 3 | from PyQt4.QtCore import Qt |

[9064] | 4 | from PyQt4.QtGui import QVBoxLayout |

[9079] | 5 | from PyQt4 import QtOpenGL |

[10854] | 6 | from Orange import orangeqt |

[9045] | 7 | import Orange |

8 | import orange | |

9 | import numpy | |

10 | import math | |

[9079] | 11 | import os |

[9045] | 12 | |

13 | from orngScaleScatterPlotData import getVariableValueIndices | |

14 | ||

15 | class Node3D(orangeqt.Node3D): | |

[9079] | 16 | # TODO: __slot__ |

[9045] | 17 | def __init__(self, index, x=None, y=None, z=None): |

18 | orangeqt.Node3D.__init__(self, index, 0, Qt.blue, 5) | |

19 | if x is not None: | |

20 | self.set_x(x) | |

21 | if y is not None: | |

22 | self.set_y(y) | |

23 | if z is not None: | |

24 | self.set_z(z) | |

25 | ||

26 | class Edge3D(orangeqt.Edge3D): | |

27 | def __init__(self, u=None, v=None, weight=1, links_index=0, arrows=None, label=''): | |

28 | orangeqt.Edge3D.__init__(self, u, v) | |

29 | self.set_weight(weight) | |

30 | self.set_links_index(links_index) | |

31 | if arrows is not None: | |

32 | self.set_arrows(arrows) | |

33 | if label: | |

34 | self.set_label(label) | |

35 | ||

[9047] | 36 | class OWNxCanvas3D(orangeqt.Canvas3D): |

[9045] | 37 | def __init__(self, master, parent=None, name='None'): |

38 | orangeqt.Canvas3D.__init__(self, parent) | |

39 | ||

[9064] | 40 | layout = QVBoxLayout() |

[9047] | 41 | self.plot = OWPlot3D(self) |

[9064] | 42 | layout.addWidget(self.plot) |

43 | self.setLayout(layout) | |

[9056] | 44 | self.plot.initializeGL() |

[9064] | 45 | self.plot.before_draw_callback = self.draw_callback |

[9047] | 46 | self.plot.replot = self.plot.update |

47 | self.gui = self.plot.gui | |

48 | self.saveToFile = self.plot.save_to_file | |

49 | ||

[9045] | 50 | # A little workaround, since NetExplorer sometimes calls networkCurve directly |

51 | self.networkCurve = self | |

52 | ||

[9047] | 53 | self.Node3D = Node3D |

[9045] | 54 | self.replot = self.update |

[9047] | 55 | self.plot.animate_plot = False |

56 | self.plot.animate_points = False | |

57 | self.plot.antialias_plot = False | |

58 | self.plot.auto_adjust_performance = False | |

[9045] | 59 | |

60 | self.master = master | |

61 | self.parent = parent | |

62 | self.graph = None | |

63 | ||

64 | self.circles = [] | |

65 | self.freeze_neighbours = False | |

66 | self.labels_on_marked_only = 0 | |

67 | ||

68 | self.show_indices = False | |

69 | self.show_weights = False | |

70 | self.trim_label_words = 0 | |

71 | self.explore_distances = False | |

72 | self.show_component_distances = False | |

73 | ||

74 | self.show_component_attribute = None | |

75 | self.force_vectors = None | |

76 | self.font_size = 12 | |

77 | ||

78 | self.min_component_edge_width = 0 | |

79 | self.max_component_edge_width = 0 | |

80 | self.items_matrix = None | |

81 | ||

82 | self.items = None | |

83 | self.links = None | |

84 | self.edge_to_row = None | |

85 | ||

86 | self.node_label_attributes = [] | |

87 | self.edge_label_attributes = [] | |

88 | ||

89 | self.axis_margin = 0 | |

90 | self.title_margin = 0 | |

91 | self.graph_margin = 1 | |

92 | ||

[9079] | 93 | self._markers = [] |

94 | ||

[9064] | 95 | def draw_callback(self): |

[9079] | 96 | if not hasattr(self, '_edge_shader'): |

97 | self._edge_shader = QtOpenGL.QGLShaderProgram() | |

98 | self._edge_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Vertex, | |

99 | os.path.join(os.path.dirname(__file__), 'edge.vs')) | |

100 | self._edge_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Fragment, | |

101 | os.path.join(os.path.dirname(__file__), 'edge.fs')) | |

102 | ||

103 | self._edge_shader.bindAttributeLocation('position', 0) | |

104 | ||

105 | if not self._edge_shader.link(): | |

106 | print('Failed to link edge shader!') | |

107 | ||

108 | self._node_shader = QtOpenGL.QGLShaderProgram() | |

109 | self._node_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Vertex, | |

110 | os.path.join(os.path.dirname(__file__), 'node.vs')) | |

111 | self._node_shader.addShaderFromSourceFile(QtOpenGL.QGLShader.Fragment, | |

112 | os.path.join(os.path.dirname(__file__), 'node.fs')) | |

113 | ||

114 | self._node_shader.bindAttributeLocation('position', 0) | |

[9104] | 115 | self._node_shader.bindAttributeLocation('offset', 1) |

116 | self._node_shader.bindAttributeLocation('color', 2) | |

117 | self._node_shader.bindAttributeLocation('selected_marked', 3) | |

[9079] | 118 | |

119 | if not self._node_shader.link(): | |

120 | print('Failed to link node shader!') | |

121 | ||

122 | self._edge_shader.bind() | |

123 | self._edge_shader.setUniformValue('projection', self.plot.projection) | |

124 | self._edge_shader.setUniformValue('model', self.plot.model) | |

125 | self._edge_shader.setUniformValue('view', self.plot.view) | |

126 | self._edge_shader.setUniformValue('translation', self.plot.plot_translation) | |

127 | self._edge_shader.setUniformValue('scale', self.plot.plot_scale) | |

[9081] | 128 | orangeqt.Canvas3D.draw_edges(self) |

[9079] | 129 | self._edge_shader.release() |

130 | ||

131 | self._node_shader.bind() | |

132 | self._node_shader.setUniformValue('projection', self.plot.projection) | |

133 | self._node_shader.setUniformValue('model', self.plot.model) | |

134 | self._node_shader.setUniformValue('view', self.plot.view) | |

135 | self._node_shader.setUniformValue('translation', self.plot.plot_translation) | |

136 | self._node_shader.setUniformValue('scale', self.plot.plot_scale) | |

[9104] | 137 | self._node_shader.setUniformValue('mode', 0.) |

[9081] | 138 | orangeqt.Canvas3D.draw_nodes(self) |

[9079] | 139 | self._node_shader.release() |

[9064] | 140 | |

[9045] | 141 | def update_canvas(self): |

[9079] | 142 | self.update_component_keywords() |

[9045] | 143 | self.update() |

144 | ||

145 | def hide_selected_nodes(self): | |

146 | orangeqt.Canvas3D.hide_selected_nodes(self) | |

147 | self.draw_plot_items() | |

148 | ||

149 | def hide_unselected_nodes(self): | |

150 | orangeqt.Canvas3D.hide_unselected_nodes(self) | |

151 | self.draw_plot_items() | |

152 | ||

153 | def show_all_vertices(self): | |

154 | orangeqt.Canvas3D.show_all_vertices(self) | |

155 | self.draw_plot_items() | |

156 | ||

157 | def selected_nodes(self): | |

158 | return [node.index() for node in self.nodes().itervalues() if node.is_selected()] | |

159 | ||

160 | def not_selected_nodes(self): | |

161 | return [node.index() for node in self.nodes().itervalues() if not node.is_selected()] | |

162 | ||

163 | def marked_nodes(self): | |

164 | return [node.index() for node in self.nodes().itervalues() if node.is_marked()] | |

165 | ||

166 | def not_marked_nodes(self): | |

167 | return [node.index() for node in self.nodes().itervalues() if not node.is_marked()] | |

168 | ||

169 | def get_neighbors_upto(self, ndx, dist): | |

170 | newNeighbours = neighbours = set([ndx]) | |

171 | for d in range(dist): | |

172 | tNewNeighbours = set() | |

173 | for v in newNeighbours: | |

174 | tNewNeighbours |= set(self.graph.neighbors(v)) | |

175 | newNeighbours = tNewNeighbours - neighbours | |

176 | neighbours |= newNeighbours | |

177 | return neighbours | |

178 | ||

179 | def mark_on_selection_changed(self): | |

180 | toMark = set() | |

181 | for ndx in self.selected_nodes(): | |

182 | toMark |= self.get_neighbors_upto(ndx, self.mark_neighbors) | |

183 | ||

184 | orangeqt.Canvas3D.clear_node_marks(self) | |

185 | orangeqt.Canvas3D.set_node_marks(self, dict((i, True) for i in toMark)) | |

186 | ||

187 | def mark_on_focus_changed(self, node): | |

188 | orangeqt.Canvas3D.clear_node_marks(self) | |

189 | if node is not None: | |

190 | toMark = set(self.get_neighbors_upto(node.index(), self.mark_neighbors)) | |

191 | orangeqt.Canvas3D.set_node_marks(self, dict((i, True) for i in toMark)) | |

192 | ||

[9079] | 193 | def update_component_keywords(self): |

[9045] | 194 | if self.show_component_attribute == None or self.graph is None or self.items is None: |

195 | return | |

196 | ||

197 | if str(self.show_component_attribute) not in self.items.domain: | |

198 | self.show_component_attribute = None | |

199 | return | |

200 | ||

201 | components = Orange.network.nx.algorithms.components.connected_components(self.graph) | |

202 | nodes = self.nodes() | |

203 | ||

[9079] | 204 | self._markers = [] |

205 | ||

[9045] | 206 | for c in components: |

207 | if len(c) == 0: | |

208 | continue | |

209 | ||

210 | x1 = sum(nodes[n].x() for n in c) / len(c) | |

211 | y1 = sum(nodes[n].y() for n in c) / len(c) | |

[9079] | 212 | z1 = sum(nodes[n].z() for n in c) / len(c) |

[9045] | 213 | lbl = str(self.items[c[0]][str(self.show_component_attribute)]) |

214 | ||

[9079] | 215 | self._markers.append((lbl, x1, y1, z1)) |

[9045] | 216 | #self.add_marker(lbl, x1, y1, alignment=Qt.AlignCenter, size=self.font_size) |

217 | ||

218 | def get_color_indices(self, table, attribute, palette): | |

219 | colorIndices = {} | |

220 | colorIndex = None | |

221 | minValue = None | |

222 | maxValue = None | |

223 | ||

[9079] | 224 | if attribute[0] != "(" or attribute[-1] != ")": |

[9045] | 225 | i = 0 |

226 | for var in table.domain.variables: | |

227 | if var.name == attribute: | |

228 | colorIndex = i | |

229 | if var.varType == orange.VarTypes.Discrete: | |

230 | colorIndices = getVariableValueIndices(var, colorIndex) | |

231 | ||

232 | i += 1 | |

233 | metas = table.domain.getmetas() | |

234 | for i, var in metas.iteritems(): | |

235 | if var.name == attribute: | |

236 | colorIndex = i | |

237 | if var.varType == orange.VarTypes.Discrete: | |

238 | colorIndices = getVariableValueIndices(var, colorIndex) | |

239 | ||

240 | colorIndices['?'] = len(colorIndices) | |

241 | palette.setNumberOfColors(len(colorIndices)) | |

242 | ||

243 | if colorIndex != None and table.domain[colorIndex].varType == orange.VarTypes.Continuous: | |

244 | minValue = float(min([x[colorIndex].value for x in table if x[colorIndex].value != "?"] or [0.0])) | |

245 | maxValue = float(max([x[colorIndex].value for x in table if x[colorIndex].value != "?"] or [0.0])) | |

246 | ||

247 | return colorIndices, colorIndex, minValue, maxValue | |

248 | ||

[9056] | 249 | getColorIndeces = get_color_indices |

250 | ||

[9045] | 251 | def set_node_colors(self, attribute, nodes=None): |

252 | if self.graph is None: | |

253 | return | |

254 | ||

255 | colorIndices, colorIndex, minValue, maxValue = self.get_color_indices(self.items, attribute, self.discPalette) | |

256 | colors = {} | |

[9079] | 257 | |

[9045] | 258 | if nodes is None: |

259 | nodes = self.graph.nodes() | |

260 | ||

261 | if colorIndex is not None and self.items.domain[colorIndex].varType == orange.VarTypes.Continuous and minValue == maxValue: | |

262 | colors.update((node, self.discPalette[0]) for node in nodes) | |

[9079] | 263 | |

[9045] | 264 | elif colorIndex is not None and self.items.domain[colorIndex].varType == orange.VarTypes.Continuous: |

265 | colors.update((v, self.contPalette[(float(self.items[v][colorIndex].value) - minValue) / (maxValue - minValue)]) | |

266 | if str(self.items[v][colorIndex].value) != '?' else | |

267 | (v, self.discPalette[0]) for v in nodes) | |

268 | ||

269 | elif colorIndex is not None and self.items.domain[colorIndex].varType == orange.VarTypes.Discrete: | |

270 | colors.update((v, self.discPalette[colorIndices[self.items[v][colorIndex].value]]) for v in nodes) | |

[9079] | 271 | |

[9045] | 272 | else: |

273 | colors.update((node, self.discPalette[0]) for node in nodes) | |

[9079] | 274 | |

[9045] | 275 | orangeqt.Canvas3D.set_node_colors(self, colors) |

276 | self.update() | |

277 | ||

278 | def set_node_labels(self, attributes=None): | |

279 | if self.graph is None: | |

280 | return | |

281 | ||

282 | nodes = self.graph.nodes() | |

283 | ||

284 | if attributes is not None: | |

285 | self.node_label_attributes = attributes | |

[9079] | 286 | |

[9045] | 287 | label_attributes = [] |

288 | if self.items is not None and isinstance(self.items, orange.ExampleTable): | |

289 | label_attributes = [self.items.domain[att] for att in \ | |

290 | self.node_label_attributes if att in self.items.domain] | |

[9079] | 291 | |

[9045] | 292 | indices = [[] for u in nodes] |

293 | if self.show_indices: | |

294 | indices = [[str(u)] for u in nodes] | |

[9079] | 295 | |

[9045] | 296 | if self.trim_label_words > 0: |

[9056] | 297 | orangeqt.Canvas3D.set_node_labels(self, dict((node, |

[9045] | 298 | ', '.join(indices[i] + |

299 | [' '.join(str(self.items[node][att]).split(' ')[:min(self.trim_label_words,len(str(self.items[node][att]).split(' ')))]) | |

300 | for att in label_attributes])) for i, node in enumerate(nodes))) | |

301 | else: | |

[9056] | 302 | orangeqt.Canvas3D.set_node_labels(self, dict((node, ', '.join(indices[i]+\ |

[9045] | 303 | [str(self.items[node][att]) for att in \ |

304 | label_attributes])) for i, node in enumerate(nodes))) | |

305 | self.update() | |

306 | ||

307 | def set_edge_colors(self, attribute): | |

308 | if self.graph is None: | |

309 | return | |

310 | ||

311 | colorIndices, colorIndex, minValue, maxValue = self.getColorIndeces(self.links, attribute, self.discPalette) | |

312 | colors = [] | |

313 | ||

314 | if colorIndex is not None and self.links.domain[colorIndex].varType == orange.VarTypes.Continuous and minValue == maxValue: | |

[9056] | 315 | colors = [self.discEdgePalette[0] for edge in orangeqt.Canvas3D.edge_indices(self)] |

[9045] | 316 | |

317 | elif colorIndex is not None and self.links.domain[colorIndex].varType == orange.VarTypes.Continuous: | |

318 | colors = [self.contPalette[(float(self.links[edge.links_index()][colorIndex].value) - minValue) / (maxValue - minValue)] | |

319 | if str(self.links[edge.links_index()][colorIndex].value) != '?' else | |

[9056] | 320 | self.discPalette[0] for edge in orangeqt.Canvas3D.edges(self)] |

[9045] | 321 | |

322 | elif colorIndex is not None and self.links.domain[colorIndex].varType == orange.VarTypes.Discrete: | |

[9056] | 323 | colors = [self.discEdgePalette[colorIndices[self.links[edge.links_index()][colorIndex].value]] for edge in orangeqt.Canvas3D.edges(self)] |

[9045] | 324 | |

325 | else: | |

[9056] | 326 | colors = [self.discEdgePalette[0] for edge in orangeqt.Canvas3D.edge_indices(self)] |

[9045] | 327 | |

328 | orangeqt.Canvas3D.set_edge_colors(self, colors) | |

329 | self.update() | |

330 | ||

331 | def set_edge_labels(self, attributes=None): | |

332 | if self.graph is None: | |

333 | return | |

[9079] | 334 | |

[9045] | 335 | edges = self.edge_indices() |

336 | ||

337 | if attributes is not None: | |

338 | self.edge_label_attributes = attributes | |

[9079] | 339 | |

[9045] | 340 | label_attributes = [] |

341 | if self.links is not None and isinstance(self.links, orange.ExampleTable): | |

342 | label_attributes = [self.links.domain[att] for att in \ | |

343 | self.edge_label_attributes if att in self.links.domain] | |

[9079] | 344 | |

[9045] | 345 | weights = [[] for ex in edges] |

346 | if self.show_weights: | |

347 | weights = [["%.2f" % self.graph[u][v].get('weight', 1)] for u,v in edges] | |

[9079] | 348 | |

[9045] | 349 | orangeqt.Canvas3D.set_edge_labels(self, |

350 | [', '.join(weights[i] + [str(self.links[i][att]) for att in label_attributes]) for i,edge in enumerate(edges)]) | |

351 | ||

[9056] | 352 | self.update() |

[9045] | 353 | |

354 | def set_tooltip_attributes(self, attributes): | |

355 | if self.graph is None or self.items is None or \ | |

356 | not isinstance(self.items, orange.ExampleTable): | |

357 | return | |

358 | ||

359 | tooltip_attributes = [self.items.domain[att] for att in attributes if att in self.items.domain] | |

360 | orangeqt.Canvas3D.set_node_tooltips(self, | |

361 | dict((node, ', '.join(str(self.items[node][att]) for att in tooltip_attributes)) for node in self.graph)) | |

362 | ||

363 | def change_graph(self, newgraph): | |

364 | old_nodes = set(self.graph.nodes_iter()) | |

365 | new_nodes = set(newgraph.nodes_iter()) | |

366 | inter_nodes = old_nodes.intersection(new_nodes) | |

367 | remove_nodes = list(old_nodes.difference(inter_nodes)) | |

368 | add_nodes = list(new_nodes.difference(inter_nodes)) | |

369 | ||

370 | self.graph = newgraph | |

[9079] | 371 | |

[9045] | 372 | if len(remove_nodes) == 0 and len(add_nodes) == 0: |

373 | return False | |

[9079] | 374 | |

[9045] | 375 | current_nodes = self.nodes() |

376 | ||

377 | def closest_nodes_with_pos(nodes): | |

378 | neighbors = set() | |

379 | for n in nodes: | |

380 | neighbors |= set(self.graph.neighbors(n)) | |

381 | ||

382 | # checked all, none found | |

383 | if len(neighbors-nodes) == 0: | |

384 | return [] | |

[9079] | 385 | |

[9045] | 386 | inter = old_nodes.intersection(neighbors) |

387 | if len(inter) > 0: | |

388 | return inter | |

389 | else: | |

390 | print "in recursion" | |

391 | return closest_nodes_with_pos(neighbors) | |

392 | ||

393 | pos = dict((n, [numpy.average(c) for c in zip(*[(current_nodes[u].x(), current_nodes[u].y()) for u in closest_nodes_with_pos(set([n]))])]) for n in add_nodes) | |

394 | ||

395 | orangeqt.Canvas3D.remove_nodes(list(remove_nodes)) | |

396 | ||

397 | nodes = dict((v, self.Node3D(v, x=pos[v][0], y=pos[v][1])) for v in add_nodes) | |

398 | self.add_nodes(nodes) | |

399 | nodes = self.nodes() | |

400 | ||

401 | #add edges | |

402 | new_edges = self.graph.edges(add_nodes) | |

403 | ||

404 | if self.links is not None and len(self.links) > 0: | |

405 | links_indices = (self.edge_to_row[i + 1][j + 1] for (i, j) in new_edges) | |

406 | ||

407 | if self.graph.is_directed(): | |

408 | edges = [Edge3D(nodes[i], nodes[j], | |

409 | self.graph[i][j].get('weight', 1), links_index, arrows=Edge3D.ArrowV, \ | |

410 | ) for ((i, j), links_index) in \ | |

411 | zip(new_edges, links_indices)] | |

412 | else: | |

413 | edges = [Edge3D(nodes[i], nodes[j], | |

414 | self.graph[i][j].get('weight', 1), links_index) for \ | |

415 | ((i, j), links_index) in zip(new_edges, \ | |

416 | links_indices)] | |

417 | elif self.graph.is_directed(): | |

418 | edges = [Edge3D(nodes[i], nodes[j], self.graph[i][j].get('weight', 1), \ | |

419 | arrows=Edge3D.ArrowV) for (i, j) in new_edges] | |

420 | else: | |

421 | edges = [Edge3D(nodes[i], nodes[j], self.graph[i][j].get('weight', 1), \ | |

422 | ) for (i, j) in new_edges] | |

423 | ||

424 | self.add_edges(edges) | |

425 | return True | |

426 | ||

427 | def set_graph(self, graph, curve=None, items=None, links=None): | |

[9056] | 428 | # TODO: clear previous nodes and edges? |

[9045] | 429 | |

430 | if graph is None: | |

431 | self.graph = None | |

432 | self.items = None | |

433 | self.links = None | |

434 | xMin = -1.0 | |

435 | xMax = 1.0 | |

436 | yMin = -1.0 | |

437 | yMax = 1.0 | |

[9079] | 438 | zMin = -1.0 |

439 | zMax = 1.0 | |

440 | self._markers.append(('no network', (xMax - xMin) / 2, (yMax - yMin) / 2, (zMax - zMin) / 2)) | |

[9045] | 441 | self.update() |

442 | return | |

443 | ||

444 | self.graph = graph | |

445 | self.items = items if items is not None else self.graph.items() | |

446 | self.links = links if links is not None else self.graph.links() | |

447 | ||

[9056] | 448 | nodes = dict((v, self.Node3D(v)) for v in self.graph) |

449 | orangeqt.Canvas3D.set_nodes(self, nodes) | |

[9045] | 450 | |

451 | self.edge_to_row = {} | |

452 | if self.links is not None and len(self.links) > 0: | |

453 | for i, r in enumerate(self.links): | |

454 | u = int(r['u'].value) | |

455 | v = int(r['v'].value) | |

456 | if u - 1 in self.graph and v - 1 in self.graph: | |

457 | u_dict = self.edge_to_row.get(u, {}) | |

458 | v_dict = self.edge_to_row.get(v, {}) | |

459 | u_dict[v] = i | |

460 | v_dict[u] = i | |

461 | self.edge_to_row[u] = u_dict | |

462 | self.edge_to_row[v] = v_dict | |

463 | else: | |

464 | print('Could not find edge ' + str(u) + '-' + str(v)) | |

465 | ||

466 | if self.links is not None and len(self.links) > 0: | |

467 | links = self.links | |

468 | links_indices = (self.edge_to_row[i + 1][j + 1] for (i, j) in self.graph.edges()) | |

469 | ||

470 | if self.graph.is_directed(): | |

[9056] | 471 | edges = [Edge3D(nodes[i], nodes[j], |

[9045] | 472 | graph[i][j].get('weight', 1), links_index, arrows=Edge3D.ArrowV) for ((i, j), links_index) in zip(self.graph.edges(), links_indices)] |

473 | else: | |

[9056] | 474 | edges = [Edge3D(nodes[i], nodes[j], |

[9045] | 475 | graph[i][j].get('weight', 1), links_index) for ((i, j), links_index) in zip(self.graph.edges(), links_indices)] |

476 | elif self.graph.is_directed(): | |

[9056] | 477 | edges = [Edge3D(nodes[i], nodes[j], |

[9045] | 478 | graph[i][j].get('weight', 1), arrows=Edge3D.ArrowV) for (i, j) in self.graph.edges()] |

479 | else: | |

[9056] | 480 | edges = [Edge3D(nodes[i], nodes[j], |

[9045] | 481 | graph[i][j].get('weight', 1)) for (i, j) in self.graph.edges()] |

482 | ||

483 | self.set_edges(edges) | |

[9056] | 484 | self._nodes = nodes # Store references, so these objects are not destroyed |

485 | self._edges = edges | |

[9045] | 486 | self.update() |

487 | ||

488 | def update_animations(self, use_animations=None): | |

489 | orangeqt.Canvas3D.set_use_animations(self, self.use_animations) | |

490 | ||

491 | def clear_node_marks(self): | |

492 | orangeqt.Canvas3D.clear_node_marks(self) | |

493 | ||

494 | def set_node_marks(self, d): | |

495 | orangeqt.Canvas3D.set_node_marks(self, d) | |

496 | ||

497 | def set_node_coordinates(self, positions): | |

498 | orangeqt.Canvas3D.set_node_coordinates(self, positions) | |

499 | ||

500 | def random(self): | |

501 | orangeqt.Canvas3D.random(self) | |

502 | ||

503 | def circular(self, layout): | |

504 | orangeqt.Canvas3D.circular(self, layout) | |

505 | ||

506 | def set_labels_on_marked_only(self, labels_on_marked_only): | |

507 | orangeqt.Canvas3D.set_labels_on_marked_only(self, labels_on_marked_only) | |

508 | self.update() | |

509 | ||

510 | def set_show_component_distances(self): | |

511 | orangeqt.Canvas3D.set_show_component_distances(self.show_component_distances) | |

512 | self.update() | |

513 | ||

514 | def layout_fr(self, steps, weighted=False, smooth_cooling=False): | |

515 | orangeqt.Canvas3D.fr(self, steps, weighted, smooth_cooling) | |

516 | ||

517 | def set_node_sizes(self, values={}, min_size=0, max_size=0): | |

518 | orangeqt.Canvas3D.set_node_sizes(self, values, min_size, max_size) | |

519 | ||

520 | def fragviz_callback(self, a, b, mds, mds_refresh, components, progress_callback): | |

521 | """Refresh the UI when running MDS on network components.""" | |

522 | # TODO | |

523 | if not self.mdsStep % mds_refresh: | |

524 | rotationOnly = False | |

525 | component_props = [] | |

526 | x_mds = [] | |

527 | y_mds = [] | |

528 | phi = [None] * len(components) | |

529 | nodes = self.nodes() | |

530 | ||

531 | for i, component in enumerate(components): | |

532 | if len(mds.points) == len(components): # if average linkage before | |

533 | x_avg_mds = mds.points[i][0] | |

534 | y_avg_mds = mds.points[i][1] | |

535 | else: # if not average linkage before | |

536 | x = [mds.points[u][0] for u in component] | |

537 | y = [mds.points[u][1] for u in component] | |

538 | ||

539 | x_avg_mds = sum(x) / len(x) | |

540 | y_avg_mds = sum(y) / len(y) | |

541 | # compute rotation angle | |

542 | # c = [numpy.linalg.norm(numpy.cross(mds.points[u], \ | |

543 | # [nodes[u].x(), nodes[u].y()])) for u in component] | |

544 | # | |

545 | # n = [numpy.vdot([nodes[u].x(), nodes[u].y()], \ | |

546 | # [nodes[u].x(), nodes[u].y()]) for u in component] | |

547 | # phi[i] = sum(c) / sum(n) | |

548 | ||

549 | ||

550 | x = [nodes[i].x() for i in component] | |

551 | y = [nodes[i].y() for i in component] | |

552 | ||

553 | x_avg_graph = sum(x) / len(x) | |

554 | y_avg_graph = sum(y) / len(y) | |

555 | ||

556 | x_mds.append(x_avg_mds) | |

557 | y_mds.append(y_avg_mds) | |

558 | ||

559 | component_props.append((x_avg_graph, y_avg_graph, \ | |

560 | x_avg_mds, y_avg_mds, phi)) | |

561 | ||

562 | for i, component in enumerate(components): | |

563 | x_avg_graph, y_avg_graph, x_avg_mds, \ | |

564 | y_avg_mds, phi = component_props[i] | |

565 | ||

566 | # if phi[i]: # rotate vertices | |

567 | # #print "rotate", i, phi[i] | |

568 | # r = numpy.array([[numpy.cos(phi[i]), -numpy.sin(phi[i])], [numpy.sin(phi[i]), numpy.cos(phi[i])]]) #rotation matrix | |

569 | # c = [x_avg_graph, y_avg_graph] # center of mass in FR coordinate system | |

570 | # v = [numpy.dot(numpy.array([self.graph.coors[0][u], self.graph.coors[1][u]]) - c, r) + c for u in component] | |

571 | # self.graph.coors[0][component] = [u[0] for u in v] | |

572 | # self.graph.coors[1][component] = [u[1] for u in v] | |

573 | ||

574 | # translate vertices | |

575 | if not rotationOnly: | |

576 | self.set_node_coordinates(dict( | |

577 | (i, ((nodes[i].x() - x_avg_graph) + x_avg_mds, | |

578 | (nodes[i].y() - y_avg_graph) + y_avg_mds)) \ | |

579 | for i in component)) | |

580 | ||

581 | #if self.mdsType == MdsType.exactSimulation: | |

582 | # self.mds.points = [[self.graph.coors[0][i], \ | |

583 | # self.graph.coors[1][i]] \ | |

584 | # for i in range(len(self.graph.coors))] | |

585 | # self.mds.freshD = 0 | |

586 | ||

587 | self.update() | |

588 | qApp.processEvents() | |

589 | ||

590 | if progress_callback is not None: | |

591 | progress_callback(a, self.mdsStep) | |

592 | ||

593 | self.mdsStep += 1 | |

594 | return 0 if self.stopMDS else 1 | |

595 | ||

596 | def layout_fragviz(self, steps, distances, graph, progress_callback=None, opt_from_curr=False): | |

597 | """Position the network components according to similarities among them. | |

598 | """ | |

599 | if distances == None or graph == None or distances.dim != graph.number_of_nodes(): | |

600 | self.information('invalid or no distance matrix') | |

601 | return 1 | |

602 | ||

[9064] | 603 | #edges = self.edges() |

[9045] | 604 | nodes = self.nodes() |

605 | ||

606 | avgLinkage = True | |

[9064] | 607 | #rotationOnly = False |

[9045] | 608 | minStressDelta = 0 |

609 | mdsRefresh = int(steps / 20) | |

[9079] | 610 | |

[9045] | 611 | self.mdsStep = 1 |

612 | self.stopMDS = False | |

[9079] | 613 | |

[9045] | 614 | components = Orange.network.nx.algorithms.components.connected.connected_components(graph) |

615 | distances.matrixType = Orange.core.SymMatrix.Symmetric | |

[9079] | 616 | |

[9045] | 617 | # scale net coordinates |

618 | if avgLinkage: | |

619 | distances = distances.avgLinkage(components) | |

[9079] | 620 | |

[9045] | 621 | mds = Orange.projection.mds.MDS(distances) |

622 | mds.optimize(10, Orange.projection.mds.SgnRelStress, 0) | |

623 | rect = self.data_rect() | |

624 | w_fr = rect.width() | |

625 | h_fr = rect.height() | |

626 | d_fr = math.sqrt(w_fr**2 + h_fr**2) | |

[9079] | 627 | |

[9045] | 628 | x_mds = [mds.points[u][0] for u in range(len(mds.points))] |

629 | y_mds = [mds.points[u][1] for u in range(len(mds.points))] | |

630 | w_mds = max(x_mds) - min(x_mds) | |

631 | h_mds = max(y_mds) - min(y_mds) | |

632 | d_mds = math.sqrt(w_mds**2 + h_mds**2) | |

[9079] | 633 | |

[9045] | 634 | self.set_node_coordinates(dict( |

635 | (n, (nodes[n].x()*d_mds/d_fr, nodes[n].y()*d_mds/d_fr)) for n in nodes)) | |

[9079] | 636 | |

[9045] | 637 | self.update() |

638 | qApp.processEvents() | |

[9079] | 639 | |

[9045] | 640 | if opt_from_curr: |

641 | if avgLinkage: | |

642 | for u, c in enumerate(components): | |

643 | x = sum([nodes[n].x() for n in c]) / len(c) | |

644 | y = sum([nodes[n].y() for n in c]) / len(c) | |

645 | mds.points[u][0] = x | |

646 | mds.points[u][1] = y | |

647 | else: | |

648 | for i,u in enumerate(sorted(nodes.iterkeys())): | |

649 | mds.points[i][0] = nodes[u].x() | |

650 | mds.points[i][1] = nodes[u].y() | |

651 | else: | |

652 | mds.Torgerson() | |

653 | ||

654 | mds.optimize(steps, Orange.projection.mds.SgnRelStress, minStressDelta, | |

655 | progressCallback= | |

656 | lambda a, | |

657 | b=None, | |

658 | mds=mds, | |

659 | mdsRefresh=mdsRefresh, | |

660 | components=components, | |

661 | progress_callback=progress_callback: | |

662 | self.fragviz_callback(a, b, mds, mdsRefresh, components, progress_callback)) | |

[9081] | 663 | |

[9045] | 664 | self.mds_callback(mds.avgStress, 0, mds, mdsRefresh, components, progress_callback) |

[9081] | 665 | |

[9045] | 666 | if progress_callback != None: |

667 | progress_callback(mds.avgStress, self.mdsStep) | |

[9081] | 668 | |

[9045] | 669 | return 0 |

670 | ||

671 | def mds_callback(self, a, b, mds, mdsRefresh, progress_callback): | |

672 | """Refresh the UI when running MDS.""" | |

[9079] | 673 | |

[9045] | 674 | if not self.mdsStep % mdsRefresh: |

675 | self.set_node_coordinates(dict((u, (mds.points[u][0], \ | |

676 | mds.points[u][1])) for u in \ | |

677 | range(len(mds.points)))) | |

678 | self.update() | |

679 | qApp.processEvents() | |

[9079] | 680 | |

[9045] | 681 | if progress_callback is not None: |

[9079] | 682 | progress_callback(a, self.mdsStep) |

683 | ||

[9045] | 684 | self.mdsStep += 1 |

685 | return 0 if self.stopMDS else 1 | |

686 | ||

687 | def layout_mds(self, steps, distances, progress_callback=None, opt_from_curr=False): | |

688 | """Position the network components according to similarities among | |

689 | them. | |

690 | """ | |

691 | nodes = self.nodes() | |

[9079] | 692 | |

[9045] | 693 | if distances == None or distances.dim != len(nodes): |

694 | self.information('invalid or no distance matrix') | |

695 | return 1 | |

[9079] | 696 | |

[9045] | 697 | minStressDelta = 0 |

698 | mdsRefresh = int(steps / 20) | |

[9079] | 699 | |

[9045] | 700 | self.mdsStep = 1 |

701 | self.stopMDS = False | |

[9079] | 702 | |

[9045] | 703 | distances.matrixType = Orange.core.SymMatrix.Symmetric |

704 | mds = Orange.projection.mds.MDS(distances) | |

705 | mds.optimize(10, Orange.projection.mds.SgnRelStress, 0) | |

706 | rect = self.data_rect() | |

707 | w_fr = rect.width() | |

708 | h_fr = rect.height() | |

709 | d_fr = math.sqrt(w_fr**2 + h_fr**2) | |

[9079] | 710 | |

[9045] | 711 | x_mds = [mds.points[u][0] for u in range(len(mds.points))] |

712 | y_mds = [mds.points[u][1] for u in range(len(mds.points))] | |

713 | w_mds = max(x_mds) - min(x_mds) | |

714 | h_mds = max(y_mds) - min(y_mds) | |

715 | d_mds = math.sqrt(w_mds**2 + h_mds**2) | |

[9079] | 716 | |

[9045] | 717 | self.set_node_coordinates(dict( |

718 | (n, (nodes[n].x()*d_mds/d_fr, nodes[n].y()*d_mds/d_fr)) for n in nodes)) | |

[9079] | 719 | |

[9045] | 720 | self.update() |

721 | qApp.processEvents() | |

[9079] | 722 | |

[9045] | 723 | if opt_from_curr: |

724 | for i,u in enumerate(sorted(nodes.iterkeys())): | |

725 | mds.points[i][0] = nodes[u].x() | |

726 | mds.points[i][1] = nodes[u].y() | |

727 | else: | |

728 | mds.Torgerson() | |

729 | ||

730 | mds.optimize(steps, Orange.projection.mds.SgnRelStress, minStressDelta, | |

731 | progressCallback= | |

732 | lambda a, | |

733 | b=None, | |

734 | mds=mds, | |

735 | mdsRefresh=mdsRefresh, | |

736 | progress_callback=progress_callback: | |

737 | self.mds_callback(a, b, mds, mdsRefresh, progress_callback)) | |

[9079] | 738 | |

[9045] | 739 | self.mds_callback(mds.avgStress, 0, mds, mdsRefresh, progress_callback) |

[9079] | 740 | |

[9045] | 741 | if progress_callback != None: |

742 | progress_callback(mds.avgStress, self.mdsStep) | |

[9079] | 743 | |

[9045] | 744 | return 0 |

745 | ||

[9047] | 746 | def update(self): |

[9081] | 747 | orangeqt.Canvas3D.update(self) |

748 | self.plot.update() | |

[9079] | 749 |

**Note:**See TracBrowser for help on using the repository browser.