def _restore_selection(self, state): # type: (SelectionState) -> bool """ Restore the (manual) node selection state. Return True if successful; False otherwise. """ linkmatrix = self.linkmatrix if self.selection_method == 0 and self.root: selected, linksaved = state linkstruct = np.array(linksaved, dtype=float) selected = set(selected) # type: Set[Tuple[int]] if not selected: return False if linkmatrix.shape[0] != linkstruct.shape[0]: return False # check that the linkage matrix structure matches. Use isclose for # the height column to account for inexact floating point math # (e.g. summation order in different ?gemm implementations for # euclidean distances, ...) if np.any(linkstruct[:, :2] != linkmatrix[:, :2]) or \ not np.all(np.isclose(linkstruct[:, 2], linkstruct[:, 2])): return False selection = [] indices = np.array([n.value.index for n in leaves(self.root)], dtype=int) # mapping from ranges to display (pruned) nodes mapping = { node.value.range: node for node in postorder(self._displayed_root) } for node in postorder(self.root): # type: Tree r = tuple(indices[node.value.first:node.value.last]) if r in selected: if node.value.range not in mapping: # the node was pruned from display and cannot be # selected break selection.append(mapping[node.value.range]) selected.remove(r) if not selected: break # found all, nothing more to do if selection and selected: # Could not restore all selected nodes (only partial match) return False self._set_selected_nodes(selection) return True return False
def set_root(self, root): """ Set the root cluster. :param root: Root cluster. :type root: :class:`Orange.clustering.hierarchical.HierarchicalCluster` """ self.clear() self.root_cluster = root self.dendrogram_items = {} self.cluster_parent = {} self.selected_items = {} if root: items = [] for cluster in hierarchical.postorder(self.root_cluster): item = DendrogramItem(cluster, parent=self, orientation=self.orientation) for branch in cluster.branches or []: branch_item = self.dendrogram_items[branch] self.cluster_parent[branch] = cluster items.append(GraphicsRectLayoutItem(item)) self.dendrogram_items[cluster] = item self.layout().setDendrogram(root, items) self.resize(self.layout().sizeHint(Qt.PreferredSize)) self.layout().activate() self.emit(SIGNAL("dendrogramLayoutChanged()"))
def setRoot(self, root): # type: (Tree) -> None """ Set the root cluster tree node for display. Parameters ---------- root : Tree The tree root node. """ self.clear() self._root = root if root is not None: foreground = self.palette().color(QPalette.Foreground) pen = make_pen(foreground, width=1, cosmetic=True, join_style=Qt.MiterJoin) for node in postorder(root): item = DendrogramWidget.ClusterGraphicsItem(self._itemgroup) item.setAcceptHoverEvents(True) item.setPen(pen) item.node = node for branch in node.branches: assert branch in self._items self._cluster_parent[branch] = node self._items[node] = item self._relayout() self._rescale() self.updateGeometry()
def test_pre_post_order(self): tree = hierarchical.Tree root = tree("A", (tree("B"), tree("C"))) self.assertEqual([n.value for n in hierarchical.postorder(root)], ["B", "C", "A"]) self.assertEqual([n.value for n in hierarchical.preorder(root)], ["A", "B", "C"])
def _relayout(self): if self._root is None: return scale = self._height_scale_factor() base = scale * self._root.value.height self._layout = dendrogram_path(self._root, self.orientation, scaleh=scale) for node_geom in postorder(self._layout): node, geom = node_geom.value item = self._items[node] item.element = geom # the untransformed source path item.sourcePath = path_toQtPath(geom) r = item.sourcePath.boundingRect() if self.orientation == Left: r.setRight(base) elif self.orientation == Right: r.setLeft(0) elif self.orientation == Top: r.setBottom(base) else: r.setTop(0) hitarea = QPainterPath() hitarea.addRect(r) item.sourceAreaShape = hitarea item.setGeometryData(item.sourcePath, item.sourceAreaShape) item.setZValue(-node.value.height)
def _relayout(self): if not self._root: return self._layout = dendrogram_path(self._root, self.orientation) for node_geom in postorder(self._layout): node, geom = node_geom.value item = self._items[node] item.element = geom item.setPath(Path_toQtPath(geom)) item.setZValue(-node.value.height) item.setPen(QPen(Qt.blue)) r = item.boundingRect() base = self._root.value.height if self.orientation == Left: r.setRight(base) elif self.orientation == Right: r.setLeft(0) elif self.orientation == Top: r.setBottom(base) else: r.setTop(0) item.setRect(r)
def dendrogram_layout(tree, expand_leaves=False): coords = [] cluster_geometry = {} leaf_idx = 0 for node in postorder(tree): cluster = node.value if node.is_leaf: if expand_leaves: start, end = float(cluster.first), float(cluster.last - 1) else: start = end = leaf_idx leaf_idx += 1 center = (start + end) / 2.0 cluster_geometry[node] = (start, center, end) coords.append((node, (start, center, end))) else: left = node.left right = node.right left_center = cluster_geometry[left][1] right_center = cluster_geometry[right][1] start, end = left_center, right_center center = (start + end) / 2.0 cluster_geometry[node] = (start, center, end) coords.append((node, (start, center, end))) return coords
def set_root(self, root): """Set the root cluster. :param Tree root: Root tree. """ self.clear() self._root = root if root: pen = make_pen(Qt.blue, width=1, cosmetic=True, join_style=Qt.MiterJoin) for node in postorder(root): item = DendrogramWidget.ClusterGraphicsItem(self._itemgroup) item.setAcceptHoverEvents(True) item.setPen(pen) item.node = node item.installSceneEventFilter(self) for branch in node.branches: assert branch in self._items self._cluster_parent[branch] = node self._items[node] = item self.updateGeometry() self._relayout() self._rescale()
def set_color(item: DendrogramWidget.ClusterGraphicsItem, color: QColor): def branches(item): return [self._items[ch] for ch in item.node.branches] for it in postorder(item, branches): it.setPen(update_pen(it.pen(), brush=color))
def _set_hover_item(self, item): """Set the currently highlighted item.""" if self._highlighted_item is item: return def branches(item): return [self._items[ch] for ch in item.node.branches] if self._highlighted_item: pen = make_pen(Qt.blue, width=1, cosmetic=True) for it in postorder(self._highlighted_item, branches): it.setPen(pen) self._highlighted_item = item if item: hpen = make_pen(Qt.blue, width=2, cosmetic=True) for it in postorder(item, branches): it.setPen(hpen)
def leaf_items(self): """ Iterate over the dendrogram leaf items (instances of :class:`DendrogramItem`). """ if self.root_cluster: clusters = hierarchical.postorder(self.root_cluster) else: clusters = [] for cluster in clusters: if not cluster.branches: yield self.dendrogram_items[cluster]
def test_order(self): post = list(hierarchical.postorder(self.cluster)) seen = set() for n in post: self.assertTrue(all(ch in seen for ch in n.branches)) seen.add(n) pre = list(hierarchical.preorder(self.cluster)) seen = set() for n in pre: self.assertTrue(all(ch not in seen for ch in n.branches)) seen.add(n)
def _save_selection(self): # Save the current manual node selection state selection_state = None if self.selection_method == 0 and self.root: assert self.linkmatrix is not None linkmat = [(int(_0), int(_1), _2) for _0, _1, _2 in self.linkmatrix[:, :3].tolist()] nodes_ = self.dendrogram.selected_nodes() # match the display (pruned) nodes back (by ranges) mapping = {node.value.range: node for node in postorder(self.root)} nodes = [mapping[node.value.range] for node in nodes_] indices = [tuple(node.value.index for node in leaves(node)) for node in nodes] if nodes: selection_state = (indices, linkmat) return selection_state
def set_root(self, root): """ Set the root cluster. :param root: Root cluster. :type root: :class:`Orange.clustering.hierarchical.HierarchicalCluster` """ self.clear() self.root_cluster = root self.dendrogram_items = {} self.cluster_parent = {} if root: items = [] for cluster in hierarchical.postorder(self.root_cluster): item = RadialDendrogramItem(cluster) for branch in cluster.branches or []: branch_item = self.dendrogram_items[branch] self.cluster_parent[branch] = cluster items.append(GraphicsRectLayoutItem(item)) self.dendrogram_items[cluster] = item self.layout().setDendrogram(root, items) self.layout().activate()
def _rescale(self): if self._root is None: return scale = self._height_scale_factor() base = scale * self._root.value.height crect = self.contentsRect() leaf_count = len(list(leaves(self._root))) if self.orientation in [Left, Right]: drect = QSizeF(base, leaf_count) else: drect = QSizeF(leaf_count, base) eps = np.finfo(np.float64).eps if abs(drect.width()) < eps: sx = 1.0 else: sx = crect.width() / drect.width() if abs(drect.height()) < eps: sy = 1.0 else: sy = crect.height() / drect.height() transform = QTransform().scale(sx, sy) self._transform = transform self._itemgroup.setPos(crect.topLeft()) self._itemgroup.setGeometry(crect) for node_geom in postorder(self._layout): node, _ = node_geom.value item = self._items[node] item.setGeometryData(transform.map(item.sourcePath), transform.map(item.sourceAreaShape)) self._selection_items = None self._update_selection_items()
def test_order(self): post = hier.postorder(self.cluster) pre = hier.preorder(self.cluster)
def set_pen(item, pen): def branches(item): return [self._items[ch] for ch in item.node.branches] for it in postorder(item, branches): it.setPen(pen)