Skip to content

Commit

Permalink
Scatterplot: Implement grouping of selections
Browse files Browse the repository at this point in the history
  • Loading branch information
janezd committed Mar 2, 2017
1 parent 9a5cdb6 commit 7079244
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 14 deletions.
4 changes: 2 additions & 2 deletions Orange/widgets/utils/annotated_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
ANNOTATED_DATA_FEATURE_NAME = "Selected"


def _get_next_name(names, name):
def get_next_name(names, name):
"""
Returns next 'possible' attribute name. The name should not be duplicated
and is generated using name parameter, appended by smallest possible index.
Expand Down Expand Up @@ -35,7 +35,7 @@ def create_annotated_table(data, selected_indices):
if data is None:
return None
names = [var.name for var in data.domain.variables + data.domain.metas]
name = _get_next_name(names, ANNOTATED_DATA_FEATURE_NAME)
name = get_next_name(names, ANNOTATED_DATA_FEATURE_NAME)
metas = data.domain.metas + (DiscreteVariable(name, ("No", "Yes")),)
domain = Domain(data.domain.attributes, data.domain.class_vars, metas)
annotated = np.zeros((len(data), 1))
Expand Down
34 changes: 30 additions & 4 deletions Orange/widgets/visualize/owscatterplot.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
from Orange.widgets.visualize.utils import VizRankDialogAttrPair
from Orange.widgets.widget import OWWidget, Default, AttributeList, Msg
from Orange.widgets.utils.annotated_data import (create_annotated_table,
ANNOTATED_DATA_SIGNAL_NAME)
ANNOTATED_DATA_SIGNAL_NAME,
get_next_name)


def font_resize(font, factor, minsize=None, maxsize=None):
Expand Down Expand Up @@ -463,19 +464,44 @@ def update_graph(self, reset_view=True, **_):
def selection_changed(self):
self.send_data()

@staticmethod
def create_groups_table(data, selection):
if data is None:
return None
names = [var.name for var in data.domain.variables + data.domain.metas]
name = get_next_name(names, "Selection group")
metas = data.domain.metas + (
DiscreteVariable(
name,
["G{}".format(i) for i in range(np.max(selection) + 1)]),
)
domain = Domain(data.domain.attributes, data.domain.class_vars, metas)
table = Table(
domain, data.X, data.Y,
metas=np.hstack((data.metas, selection.reshape(len(data), 1))))
table.attributes = data.attributes
return table

def send_data(self):
selected = None
selection = None
# TODO: Implement selection for sql data
graph = self.graph
if isinstance(self.data, SqlTable):
selected = self.data
elif self.data is not None:
selection = self.graph.get_selection()
selection = graph.get_selection()
if len(selection) > 0:
selected = self.data[selection]
print(graph.selection)
if graph.selection is not None and np.max(graph.selection) > 1:
annotated = self.create_groups_table(self.data, graph.selection)
else:
annotated = create_annotated_table(self.data, selection)
self.send("Selected Data", selected)
self.send(ANNOTATED_DATA_SIGNAL_NAME,
create_annotated_table(self.data, selection))
self.send(ANNOTATED_DATA_SIGNAL_NAME, annotated)



def send_features(self):
features = None
Expand Down
37 changes: 29 additions & 8 deletions Orange/widgets/visualize/owscatterplotgraph.py
Original file line number Diff line number Diff line change
Expand Up @@ -725,12 +725,24 @@ def make_pen(color, width):
p.setCosmetic(True)
return p

pens = [QPen(Qt.NoPen),
make_pen(QColor(255, 190, 0, 255), SELECTION_WIDTH + 1.)]
nopen = QPen(Qt.NoPen)
if self.selection is not None:
sels = np.max(self.selection)
if sels == 1:
pens = [nopen,
make_pen(QColor(255, 190, 0, 255),
SELECTION_WIDTH + 1.)]
else:
# Start with the first color so that the colors of the
# additional attribute in annotation (which start with 0,
# unselected) will match these colors
palette = ColorPaletteGenerator(number_of_colors=sels + 1)
pens = [nopen] + \
[make_pen(palette[i + 1], SELECTION_WIDTH + 1.)
for i in range(sels)]
pen = [pens[a] for a in self.selection[self.valid_data]]
else:
pen = [pens[0]] * self.n_points
pen = [nopen] * self.n_points
brush = [QBrush(QColor(255, 255, 255, 0))] * self.n_points
return pen, brush

Expand Down Expand Up @@ -1001,22 +1013,31 @@ def select(self, points):
keys = QApplication.keyboardModifiers()
if self.selection is None or not keys & (
Qt.ShiftModifier + Qt.ControlModifier + Qt.AltModifier):
self.selection = np.full(len(self.data), False, dtype=np.bool)
self.selection = np.zeros(len(self.data), dtype=np.uint8)
indices = [p.data() for p in points]
if keys & Qt.AltModifier:
self.selection[indices] = False
self.selection[indices] = 0
elif keys & Qt.ControlModifier:
self.selection[indices] = ~self.selection[indices]
elements = self.selection[indices]
max_sel = np.max(self.selection)
if max_sel <= 1:
self.selection[indices] = 1 - elements
else:
indices = np.array(indices, dtype=int)
to_unselect = indices[np.flatnonzero(elements)]
to_select = indices[np.flatnonzero(elements == 0)]
self.selection[to_unselect] = 0
self.selection[to_select] = max_sel + 1
else: # Handle shift and no modifiers
self.selection[indices] = True
self.selection[indices] = np.max(self.selection) + 1
self.update_colors(keep_colors=True)
if self.label_only_selected:
self.update_labels()
self.master.selection_changed()

def get_selection(self):
if self.selection is None:
return np.array([], dtype=int)
return np.array([], dtype=np.uint8)
else:
return np.flatnonzero(self.selection)

Expand Down

0 comments on commit 7079244

Please sign in to comment.