Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Orange/widgets/visualize/owpythagorastree.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ def __init__(self):
box_plot, self, 'show_legend', label='Show legend',
callback=self.update_show_legend)

gui.button(self.controlArea, self, label="Redraw", callback=self.redraw)

# Stretch to fit the rest of the unsused area
gui.rubber(self.controlArea)

Expand Down Expand Up @@ -224,6 +226,10 @@ def update_size_calc(self):
self._update_log_scale_slider()
self.invalidate_tree()

def redraw(self):
self.tree_adapter.shuffle_children()
self.invalidate_tree()

def invalidate_tree(self):
"""When the tree needs to be completely recalculated."""
if self.model is not None:
Expand Down
11 changes: 9 additions & 2 deletions Orange/widgets/visualize/pythagorastreeviewer.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,17 +137,19 @@ def set_tree(self, tree_adapter, weight_adjustment=lambda x: x,
"""
self.clear_tree()
self.tree_adapter = tree_adapter
self.weight_adjustment = weight_adjustment

if self.tree_adapter is not None:
self.root = self._calculate_tree(self.tree_adapter, weight_adjustment)
self.root = self._calculate_tree(self.tree_adapter, self.weight_adjustment)
self.set_depth_limit(tree_adapter.max_depth)
self.target_class_changed(target_class_index)
self._draw_tree(self.root)

def set_size_calc(self, weight_adjustment):
"""Set the weight adjustment on the tree. Redraws the whole tree."""
# Since we have to redraw the whole tree anyways, just call `set_tree`
self.set_tree(self.tree_adapter, weight_adjustment,
self.weight_adjustment = weight_adjustment
self.set_tree(self.tree_adapter, self.weight_adjustment,
self._target_class_index)

def set_depth_limit(self, depth):
Expand Down Expand Up @@ -467,6 +469,11 @@ def _propagate_to_parents(self, graphics_item, fnc, other_fnc):
# propagate up the tree
self._propagate_to_parents(parent, fnc, other_fnc)

def mouseDoubleClickEvent(self, event):
self.tree_node.tree.reverse_children(self.tree_node.label)
p = self.parentWidget()
p.set_tree(p.tree_adapter, p.weight_adjustment, self.tree_node.target_class_index)

def selection_changed(self):
"""Handle selection changed."""
self.any_selected = len(self.scene().selectedItems()) > 0
Expand Down
10 changes: 10 additions & 0 deletions Orange/widgets/visualize/utils/tree/skltreeadapter.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Tree adapter class for sklearn trees."""
from collections import OrderedDict
import random

import numpy as np
from Orange.widgets.visualize.utils.tree.treeadapter import BaseTreeAdapter
Expand Down Expand Up @@ -63,6 +64,15 @@ def __left_child(self, node):
def __right_child(self, node):
return self._tree.children_right[node]

def reverse_children(self, node):
self._tree.children_left[node], self._tree.children_right[node] = \
self._tree.children_right[node], self._tree.children_left[node]

def shuffle_children(self):
for i in range(self.num_nodes):
if random.randrange(2) == 0:
self.reverse_children(i)

@memoize_method(maxsize=1024)
def get_distribution(self, node):
value = self._tree.value[node]
Expand Down
26 changes: 26 additions & 0 deletions Orange/widgets/visualize/utils/tree/treeadapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from abc import ABCMeta, abstractmethod
from functools import reduce
from operator import add
import random


class BaseTreeAdapter(metaclass=ABCMeta):
Expand Down Expand Up @@ -117,6 +118,20 @@ def children(self, node):
"""
pass

def reverse_children(self, node):
"""Reverse children of a given node.

Parameters
----------
node : object
"""
pass

def shuffle_children(self):
"""Randomly shuffle node's children in the entire tree.
"""
pass

@abstractmethod
def get_distribution(self, node):
"""Get the distribution of types for a given node.
Expand Down Expand Up @@ -295,6 +310,17 @@ def is_leaf(self, node):
def children(self, node):
return [child for child in node.children if child is not None]

def reverse_children(self, node):
node.children = node.children[::-1]

def shuffle_children(self):
def _shuffle_children(node):
if node and node.children:
random.shuffle(node.children)
for c in node.children:
_shuffle_children(c)
_shuffle_children(self.root)

def get_distribution(self, node):
return [node.value]

Expand Down