The selection view now works. Functions can return a dataset.Selection object which will be stored in the selection list.
This commit is contained in:
parent
ae7a6a5a0e
commit
1b9aff1c5a
|
@ -319,7 +319,25 @@ def from_file(filepath):
|
||||||
|
|
||||||
return out_data
|
return out_data
|
||||||
|
|
||||||
class Selection:
|
class Selection(dict):
|
||||||
"""Handles selected identifiers along each dimension of a dataset"""
|
"""Handles selected identifiers along each dimension of a dataset"""
|
||||||
def __init__(self):
|
|
||||||
self.current_selection={}
|
def __init__(self, title='Unnamed Selecton'):
|
||||||
|
self.title = title
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
if not self.has_key(key):
|
||||||
|
return None
|
||||||
|
return dict.__getitem__(self, key)
|
||||||
|
|
||||||
|
def dims(self):
|
||||||
|
return self.keys()
|
||||||
|
|
||||||
|
def axis_len(self, axis):
|
||||||
|
if self._selection.has_key(axis):
|
||||||
|
return len(self._selection[axis])
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def select(self, axis, labels):
|
||||||
|
self[axis] = labels
|
||||||
|
|
||||||
|
|
|
@ -144,6 +144,9 @@ class FluentApp:
|
||||||
self.identifier_list.show()
|
self.identifier_list.show()
|
||||||
return self.identifier_list
|
return self.identifier_list
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
return self.widget_tree.get_widget(key)
|
||||||
|
|
||||||
# Event handlers.
|
# Event handlers.
|
||||||
# These methods are called by the gtk framework in response to events and
|
# These methods are called by the gtk framework in response to events and
|
||||||
# should not be called directly.
|
# should not be called directly.
|
||||||
|
@ -154,9 +157,6 @@ class FluentApp:
|
||||||
def on_multiple_view(self, *ignored):
|
def on_multiple_view(self, *ignored):
|
||||||
self['main_view'].goto_small()
|
self['main_view'].goto_small()
|
||||||
|
|
||||||
def __getitem__(self, key):
|
|
||||||
return self.widget_tree.get_widget(key)
|
|
||||||
|
|
||||||
def on_create_project(self, *rest):
|
def on_create_project(self, *rest):
|
||||||
d = dialogs.CreateProjectDruid(self)
|
d = dialogs.CreateProjectDruid(self)
|
||||||
d.run()
|
d.run()
|
||||||
|
|
|
@ -17,7 +17,8 @@ class Project:
|
||||||
self._dataset_observers = []
|
self._dataset_observers = []
|
||||||
self.current_data = []
|
self.current_data = []
|
||||||
self.datasets = []
|
self.datasets = []
|
||||||
self.sel_obj = dataset.Selection()
|
self.sel_obj = dataset.Selection('Current Selection')
|
||||||
|
self.selections = []
|
||||||
|
|
||||||
def add_selection_observer(self, observer):
|
def add_selection_observer(self, observer):
|
||||||
self._selection_observers.append(observer)
|
self._selection_observers.append(observer)
|
||||||
|
@ -39,12 +40,12 @@ class Project:
|
||||||
|
|
||||||
def set_selection(self, dim_name, selection):
|
def set_selection(self, dim_name, selection):
|
||||||
"""Sets a current selection and notify observers"""
|
"""Sets a current selection and notify observers"""
|
||||||
self.sel_obj.current_selection[dim_name] = set(selection)
|
self.sel_obj[dim_name] = set(selection)
|
||||||
self.notify_selection_listeners(dim_name)
|
self.notify_selection_listeners(dim_name)
|
||||||
|
|
||||||
def get_selection(self):
|
def get_selection(self):
|
||||||
"""Returns the current selection object"""
|
"""Returns the current selection object"""
|
||||||
return self.sel_obj.current_selection
|
return self.sel_obj
|
||||||
|
|
||||||
def get_data_iter(self, obj):
|
def get_data_iter(self, obj):
|
||||||
"""Retuns an iterator to data."""
|
"""Retuns an iterator to data."""
|
||||||
|
@ -84,6 +85,8 @@ class Project:
|
||||||
self.data_tree_insert(it, d.get_title(), d, "PaleGreen", "black")
|
self.data_tree_insert(it, d.get_title(), d, "PaleGreen", "black")
|
||||||
d.set_selection_listener(self.set_selection)
|
d.set_selection_listener(self.set_selection)
|
||||||
self._selection_observers.append(d)
|
self._selection_observers.append(d)
|
||||||
|
elif isinstance(d, dataset.Selection):
|
||||||
|
self.add_selection(d)
|
||||||
|
|
||||||
def data_tree_insert(self, parent, text, data, bgcolour,fontcolour,selected = 0):
|
def data_tree_insert(self, parent, text, data, bgcolour,fontcolour,selected = 0):
|
||||||
tree = self.data_tree
|
tree = self.data_tree
|
||||||
|
@ -103,9 +106,13 @@ class Project:
|
||||||
for dim_name in dataset.get_all_dims():
|
for dim_name in dataset.get_all_dims():
|
||||||
if dim_name not in self.dim_names:
|
if dim_name not in self.dim_names:
|
||||||
self.dim_names.append(dim_name)
|
self.dim_names.append(dim_name)
|
||||||
self.sel_obj.current_selection[dim_name] = set()
|
self.sel_obj[dim_name] = set()
|
||||||
self.notify_dataset_listeners()
|
self.notify_dataset_listeners()
|
||||||
|
|
||||||
|
def add_selection(self, selection):
|
||||||
|
"""Adds a new selection to the project."""
|
||||||
|
self.selections.append(selection)
|
||||||
|
self.notify_dataset_listeners()
|
||||||
|
|
||||||
def object_at(self, path):
|
def object_at(self, path):
|
||||||
"Returns the object at a given path in the tree."
|
"Returns the object at a given path in the tree."
|
||||||
|
|
|
@ -9,75 +9,145 @@ import gnome
|
||||||
import gnome.ui
|
import gnome.ui
|
||||||
import gobject
|
import gobject
|
||||||
|
|
||||||
|
class SimpleMenu(gtk.Menu):
|
||||||
|
def __init__(self):
|
||||||
|
gtk.Menu.__init__(self)
|
||||||
|
|
||||||
|
def add_simple_item(self, title, function):
|
||||||
|
item = gtk.MenuItem(title)
|
||||||
|
item.connect('activate', function)
|
||||||
|
self.append(item)
|
||||||
|
item.show()
|
||||||
|
|
||||||
class SelectionTree(gtk.TreeView):
|
class SelectionTree(gtk.TreeView):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.store = gtk.TreeStore(gobject.TYPE_STRING)
|
self.store = gtk.TreeStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)
|
||||||
gtk.TreeView.__init__(self, self.store)
|
gtk.TreeView.__init__(self, self.store)
|
||||||
|
|
||||||
renderer = gtk.CellRendererText()
|
renderer = gtk.CellRendererText()
|
||||||
sel_column = gtk.TreeViewColumn('Selection', renderer, text=0)
|
sel_column = gtk.TreeViewColumn('Selection', renderer, text=0)
|
||||||
self.insert_column(sel_column, 0)
|
self.insert_column(sel_column, 0)
|
||||||
|
|
||||||
self.connect('row-activated', self.on_row_activated)
|
self.connect('row-activated', self._on_row_activated)
|
||||||
|
|
||||||
self._identifier_list = None
|
self._identifier_list = None
|
||||||
self._dim_list = {}
|
self._dim_list = {}
|
||||||
|
|
||||||
# A mapping of selection names to selection lines.
|
# A mapping of selection names to selection lines.
|
||||||
self._selections = {}
|
self._selections = []
|
||||||
|
|
||||||
self.set_headers_visible(True)
|
self.set_headers_visible(True)
|
||||||
self._current_dim = None
|
self._current_dim = None
|
||||||
|
self._current_selection = None
|
||||||
|
|
||||||
|
# Set up context menu
|
||||||
|
self._menu = SimpleMenu()
|
||||||
|
self._menu.add_simple_item('Select', self._on_set_selection)
|
||||||
|
|
||||||
|
self.connect('popup_menu', self._on_popup_menu)
|
||||||
|
self.connect('button_press_event', self._on_button_press_event)
|
||||||
|
|
||||||
def set_identifier_list(self, identifier_list):
|
def set_identifier_list(self, identifier_list):
|
||||||
|
"""Dependency injection. Sets the widget that should be used to
|
||||||
|
display the selected identifiers."""
|
||||||
self._identifier_list = identifier_list
|
self._identifier_list = identifier_list
|
||||||
|
|
||||||
def set_project(self, project):
|
def set_project(self, project):
|
||||||
|
"""Dependency injection. Set the current project."""
|
||||||
self.project = project
|
self.project = project
|
||||||
project.add_selection_observer(self)
|
project.add_selection_observer(self)
|
||||||
project.add_dataset_observer(self)
|
project.add_dataset_observer(self)
|
||||||
self.update_dims(project.dim_names)
|
self.update_dims(project.dim_names)
|
||||||
|
self.add_selection(project.get_selection())
|
||||||
|
|
||||||
def selection_changed(self, selection):
|
def selection_changed(self, selection):
|
||||||
|
"""Callback on selection update"""
|
||||||
self.update_dims(selection.keys())
|
self.update_dims(selection.keys())
|
||||||
|
self.add_selection(selection)
|
||||||
self._update_current_dim()
|
self._update_current_dim()
|
||||||
|
|
||||||
|
def get_selection_iter(self, dimname, selection):
|
||||||
|
i = self._dim_list[dimname]
|
||||||
|
if not i:
|
||||||
|
return None
|
||||||
|
|
||||||
|
children = self.store.iter_children(i)
|
||||||
|
if not children:
|
||||||
|
return None
|
||||||
|
|
||||||
|
while children:
|
||||||
|
if self.store.get(children, 1)[0] == selection:
|
||||||
|
return self.store.get(children, 1)[0]
|
||||||
|
children = self.store.iter_next(children)
|
||||||
|
return None
|
||||||
|
|
||||||
def dataset_changed(self):
|
def dataset_changed(self):
|
||||||
|
"""Callback when new datasets are created"""
|
||||||
self.selection_changed(self.project.get_selection())
|
self.selection_changed(self.project.get_selection())
|
||||||
|
for sel in self.project.selections:
|
||||||
|
if not sel in self._selections:
|
||||||
|
self._selections.append(sel)
|
||||||
|
self.add_selection(sel)
|
||||||
|
|
||||||
def update_dims(self, dim_list):
|
def update_dims(self, dim_list):
|
||||||
|
"""Update the list of dimensions shown"""
|
||||||
for dim in dim_list:
|
for dim in dim_list:
|
||||||
if not self._dim_list.has_key(dim):
|
if not self._dim_list.has_key(dim):
|
||||||
d = self.store.insert_after(None, None, (dim,))
|
d = self.store.insert_after(None, None, (dim, None))
|
||||||
self._dim_list[dim] = d
|
self._dim_list[dim] = d
|
||||||
self.store.insert_before(d, None, ('current selection',))
|
|
||||||
|
|
||||||
def on_row_activated(self, treeview, path, column):
|
def add_selection(self, selection):
|
||||||
i = self.store.get_iter(path)
|
for dim in selection.dims():
|
||||||
p = self.store.iter_parent(i)
|
if not self.get_selection_iter(dim, selection):
|
||||||
self._current_dim = self.store.get_value(p, 0)
|
d = self._dim_list[dim]
|
||||||
self._update_current_dim()
|
i = self.store.insert_after(d, None, (selection.title, selection))
|
||||||
|
|
||||||
def _update_current_dim(self):
|
def _update_current_dim(self):
|
||||||
if not self._current_dim:
|
if not self._current_dim or not self._current_selection:
|
||||||
return
|
return
|
||||||
id_list = self.project.get_selection()[self._current_dim]
|
id_list = self._current_selection[self._current_dim]
|
||||||
self._identifier_list.set_identifiers(id_list)
|
self._identifier_list.set_identifiers(id_list)
|
||||||
|
|
||||||
|
# Callbacks
|
||||||
|
def _on_row_activated(self, treeview, path, column):
|
||||||
|
i = self.store.get_iter(path)
|
||||||
|
p = self.store.iter_parent(i)
|
||||||
|
if p == None:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self._current_dim = self.store.get_value(p, 0)
|
||||||
|
self._current_selection = self.store.get_value(i, 1)
|
||||||
|
self._update_current_dim()
|
||||||
|
|
||||||
|
def _on_set_selection(self, *rest):
|
||||||
|
if not self._current_selection:
|
||||||
|
return
|
||||||
|
self.project.set_selection(self._current_dim,
|
||||||
|
self._current_selection[self._current_dim])
|
||||||
|
|
||||||
|
def _on_button_press_event(self, widget, event):
|
||||||
|
if event.button == 3:
|
||||||
|
self._menu.popup(None, None, None, event.button, event.time)
|
||||||
|
|
||||||
|
def _on_popup_menu(self):
|
||||||
|
pass
|
||||||
|
|
||||||
class IdentifierList(gtk.TreeView):
|
class IdentifierList(gtk.TreeView):
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.store = gtk.ListStore(gobject.TYPE_STRING)
|
self.store = gtk.ListStore(gobject.TYPE_STRING)
|
||||||
gtk.TreeView.__init__(self, self.store)
|
gtk.TreeView.__init__(self, self.store)
|
||||||
|
self.set_headers_visible(True)
|
||||||
|
|
||||||
|
# Set up identifier column to show active identifiers
|
||||||
renderer = gtk.CellRendererText()
|
renderer = gtk.CellRendererText()
|
||||||
ids_column = gtk.TreeViewColumn('Identifiers', renderer, text=0)
|
ids_column = gtk.TreeViewColumn('Identifiers', renderer, text=0)
|
||||||
self.insert_column(ids_column, 0)
|
self.insert_column(ids_column, 0)
|
||||||
|
|
||||||
self.set_headers_visible(True)
|
|
||||||
|
|
||||||
def set_identifiers(self, identifiers):
|
def set_identifiers(self, identifiers):
|
||||||
|
"Show the list of identifier strings."
|
||||||
self.store.clear()
|
self.store.clear()
|
||||||
for e in identifiers:
|
for e in identifiers:
|
||||||
self.store.append((e,))
|
self.store.append((e,))
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ class TestWorkflow (workflow.Workflow):
|
||||||
load.add_function(CelFileImportFunction())
|
load.add_function(CelFileImportFunction())
|
||||||
load.add_function(TestDataFunction())
|
load.add_function(TestDataFunction())
|
||||||
load.add_function(DatasetLoadFunction())
|
load.add_function(DatasetLoadFunction())
|
||||||
|
load.add_function(SelectFunction())
|
||||||
self.add_stage(load)
|
self.add_stage(load)
|
||||||
|
|
||||||
preproc = workflow.Stage('preprocess', 'Preprocessing')
|
preproc = workflow.Stage('preprocess', 'Preprocessing')
|
||||||
|
@ -116,6 +117,17 @@ class TestDataFunction(workflow.Function):
|
||||||
ds_scatter = plots.ScatterMarkerPlot(ds, ds, 'rows_0', 'rows_0', '0_1', '0_2')
|
ds_scatter = plots.ScatterMarkerPlot(ds, ds, 'rows_0', 'rows_0', '0_1', '0_2')
|
||||||
return [X, ds, plots.SinePlot(), p, ds_plot, ds_scatter,p2]
|
return [X, ds, plots.SinePlot(), p, ds_plot, ds_scatter,p2]
|
||||||
|
|
||||||
|
class SelectFunction(workflow.Function):
|
||||||
|
def __init__(self):
|
||||||
|
workflow.Function.__init__(self, 'select', 'Select')
|
||||||
|
|
||||||
|
def run(self, data):
|
||||||
|
s = dataset.Selection('Arbitrary selection')
|
||||||
|
s.select('rows', ['0_1', '0_2'])
|
||||||
|
print s['rows']
|
||||||
|
print s.dims()
|
||||||
|
return [s]
|
||||||
|
|
||||||
class DatasetLog(workflow.Function):
|
class DatasetLog(workflow.Function):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
workflow.Function.__init__(self, 'log', 'Log')
|
workflow.Function.__init__(self, 'log', 'Log')
|
||||||
|
|
Reference in New Issue