class OWGroupBy(OWWidget): contextHandlers = {"": DomainContextHandler("", ["hints"])} settingsList = [] def __init__(self, parent=None, signalManager=None, title="Group By"): OWWidget.__init__(self, parent, signalManager, title, wantMainArea=False) self.inputs = [("Data", Table, self.set_data)] self.outputs = [("Data", Table)] self.auto_commit = True self.hints = {} self.state_changed_flag = False self.loadSettings() ############# # Data Models ############# self.group_list = VariableListModel(parent=self, flags=Qt.ItemIsEnabled | Qt.ItemIsSelectable | \ Qt.ItemIsDragEnabled ) self.aggregate_list = VariableAggragateModel(parent=self, flags=Qt.ItemIsEnabled | Qt.ItemIsSelectable | \ Qt.ItemIsDragEnabled | \ Qt.ItemIsEditable) self.aggregate_delegate = AggregateDelegate() ##### # GUI ##### box = OWGUI.widgetBox(self.controlArea, "Group By Attributes") self.group_view = QListView() self.group_view.setSelectionMode(QListView.ExtendedSelection) self.group_view.setDragDropMode(QListView.DragDrop) self.group_view.setModel(self.group_list) # self.group_view.setDragDropOverwriteMode(True) self.group_view.setDefaultDropAction(Qt.MoveAction) self.group_view.viewport().setAcceptDrops(True) # self.group_view.setDropIndicatorShown(True) self.group_view.setToolTip("A set of attributes to group by (drag \ values to 'Aggregate Attributes' to remove them from this group).") box.layout().addWidget(self.group_view) box = OWGUI.widgetBox(self.controlArea, "Aggregate Attributes") self.aggregate_view = AggregateListView() self.aggregate_view.setSelectionMode(QListView.ExtendedSelection) self.aggregate_view.setDragDropMode(QListView.DragDrop) self.aggregate_view.setItemDelegate(self.aggregate_delegate) self.aggregate_view.setModel(self.aggregate_list) self.aggregate_view.setEditTriggers(QListView.DoubleClicked | QListView.EditKeyPressed) # self.aggregate_view.setDragDropOverwriteMode(False) self.aggregate_view.setDefaultDropAction(Qt.MoveAction) self.aggregate_view.viewport().setAcceptDrops(True) self.aggregate_view.setToolTip("Aggregated attributes.") box.layout().addWidget(self.aggregate_view) OWGUI.rubber(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Commit") cb = OWGUI.checkBox( box, self, "auto_commit", "Commit on input change.", tooltip="Send the data on output on change of input.", callback=self.commit_if) b = OWGUI.button(box, self, "Commit", callback=self.commit, tooltip="Send data on output.", autoDefault=True) # OWGUI.setStopper(self, b, cb, "state_changed_flag", # callback=self.commit) def set_data(self, data=None): """ Set the input data for the widget. """ self.update_hints() self.closeContext("") self.clear() if data is not None: self.init_with_data(data) self.openContext("", data) self.init_state_from_hints() self.commit_if() def init_with_data(self, data): """ Init widget state from data """ attrs = data.domain.variables + data.domain.get_metas().values() # self.group_list.set_items(attrs) self.all_attrs = attrs self.hints = dict([((a.name, a.varType), ("group_by", "First")) for a in attrs]) self.data = data def init_state_from_hints(self): """ Init the group and aggregate from hints (call after openContext) """ group = [] aggregate = [] aggregate_hint = {} for a in self.all_attrs: try: place, hint = self.hints.get((a.name, a.var_type), ("group_by", DEFAULT_METHOD)) except Exception: place, hint = ("group_by", DEFAULT_METHOD) if place == "group_by": group.append(a) else: aggregate.append(a) aggregate_hint[a] = hint self.group_list[:] = group self.aggregate_list[:] = aggregate for i, a in enumerate(group): self.group_list.setData(self.group_list.index(i), aggregate_hint[a], AggregateMethodRole) for i, a in enumerate(aggregate): self.aggregate_list.setData(self.aggregate_list.index(i), aggregate_hint[a], AggregateMethodRole) def update_hints(self): for i, var in enumerate(self.group_list): self.hints[var.name, var.var_type] = \ ("group_by", str(self.group_list.data( \ self.group_list.index(i), AggregateMethodRole).toPyObject())) for i, var in enumerate(self.aggregate_list): self.hints[var.name, var.var_type] = \ ("aggregate", str(self.aggregate_list.data( \ self.aggregate_list.index(i), AggregateMethodRole).toPyObject())) def clear(self): """ Clear the widget state. """ self.data = None self.group_list[:] = [] #clear() self.aggregate_list[:] = [] #.clear() self.all_attrs = [] self.hints = {} def get_aggregates_from_hints(self): aggregates = {} for i, v in enumerate(self.aggregate_list): _, hint = self.hints.get((v.name, v.var_type), ("", DEFAULT_METHOD)) aggregates[v] = hint.lower() return aggregates def commit_if(self): if self.auto_commit: self.commit() else: self.state_changed_flag = True def commit(self): self.update_hints() if self.data is not None: group = list(self.group_list) aggregates = self.get_aggregates_from_hints() print aggregates data = utils.group_by(self.data, group, attr_aggregate=aggregates) else: data = None self.send("Data", data) self.state_changed_flag = False
class OWGroupBy(OWWidget): contextHandlers = {"": DomainContextHandler("", ["hints"])} settingsList = [] def __init__(self, parent=None, signalManager=None, title="Group By"): OWWidget.__init__(self, parent, signalManager, title, wantMainArea=False) self.inputs = [("Data", Table, self.set_data)] self.outputs = [("Data", Table)] self.auto_commit = True self.hints = {} self.state_changed_flag = False self.loadSettings() ############# # Data Models ############# self.group_list = VariableListModel(parent=self, flags=Qt.ItemIsEnabled | Qt.ItemIsSelectable | \ Qt.ItemIsDragEnabled ) self.aggregate_list = VariableAggragateModel(parent=self, flags=Qt.ItemIsEnabled | Qt.ItemIsSelectable | \ Qt.ItemIsDragEnabled | \ Qt.ItemIsEditable) self.aggregate_delegate = AggregateDelegate() ##### # GUI ##### box = OWGUI.widgetBox(self.controlArea, "Group By Attributes") self.group_view = QListView() self.group_view.setSelectionMode(QListView.ExtendedSelection) self.group_view.setDragDropMode(QListView.DragDrop) self.group_view.setModel(self.group_list) # self.group_view.setDragDropOverwriteMode(True) self.group_view.setDefaultDropAction(Qt.MoveAction) self.group_view.viewport().setAcceptDrops(True) # self.group_view.setDropIndicatorShown(True) self.group_view.setToolTip("A set of attributes to group by (drag \ values to 'Aggregate Attributes' to remove them from this group).") box.layout().addWidget(self.group_view) box = OWGUI.widgetBox(self.controlArea, "Aggregate Attributes") self.aggregate_view = AggregateListView() self.aggregate_view.setSelectionMode(QListView.ExtendedSelection) self.aggregate_view.setDragDropMode(QListView.DragDrop) self.aggregate_view.setItemDelegate(self.aggregate_delegate) self.aggregate_view.setModel(self.aggregate_list) self.aggregate_view.setEditTriggers(QListView.DoubleClicked | QListView.EditKeyPressed) # self.aggregate_view.setDragDropOverwriteMode(False) self.aggregate_view.setDefaultDropAction(Qt.MoveAction) self.aggregate_view.viewport().setAcceptDrops(True) self.aggregate_view.setToolTip("Aggregated attributes.") box.layout().addWidget(self.aggregate_view) OWGUI.rubber(self.controlArea) box = OWGUI.widgetBox(self.controlArea, "Commit") cb = OWGUI.checkBox(box, self, "auto_commit", "Commit on input change.", tooltip="Send the data on output on change of input.", callback=self.commit_if ) b = OWGUI.button(box, self, "Commit", callback=self.commit, tooltip="Send data on output.", autoDefault=True) # OWGUI.setStopper(self, b, cb, "state_changed_flag", # callback=self.commit) def set_data(self, data=None): """ Set the input data for the widget. """ self.update_hints() self.closeContext("") self.clear() if data is not None: self.init_with_data(data) self.openContext("", data) self.init_state_from_hints() self.commit_if() def init_with_data(self, data): """ Init widget state from data """ attrs = data.domain.variables + data.domain.get_metas().values() # self.group_list.set_items(attrs) self.all_attrs = attrs self.hints = dict([((a.name, a.varType), ("group_by", "First")) for a in attrs]) self.data = data def init_state_from_hints(self): """ Init the group and aggregate from hints (call after openContext) """ group = [] aggregate = [] aggregate_hint = {} for a in self.all_attrs: try: place, hint = self.hints.get((a.name, a.var_type), ("group_by", DEFAULT_METHOD)) except Exception: place, hint = ("group_by", DEFAULT_METHOD) if place == "group_by": group.append(a) else: aggregate.append(a) aggregate_hint[a] = hint self.group_list[:] = group self.aggregate_list[:] = aggregate for i, a in enumerate(group): self.group_list.setData(self.group_list.index(i), aggregate_hint[a], AggregateMethodRole) for i, a in enumerate(aggregate): self.aggregate_list.setData(self.aggregate_list.index(i), aggregate_hint[a], AggregateMethodRole) def update_hints(self): for i, var in enumerate(self.group_list): self.hints[var.name, var.var_type] = \ ("group_by", str(self.group_list.data( \ self.group_list.index(i), AggregateMethodRole).toPyObject())) for i, var in enumerate(self.aggregate_list): self.hints[var.name, var.var_type] = \ ("aggregate", str(self.aggregate_list.data( \ self.aggregate_list.index(i), AggregateMethodRole).toPyObject())) def clear(self): """ Clear the widget state. """ self.data = None self.group_list[:] = [] #clear() self.aggregate_list[:] = [] #.clear() self.all_attrs = [] self.hints = {} def get_aggregates_from_hints(self): aggregates = {} for i, v in enumerate(self.aggregate_list): _, hint = self.hints.get((v.name, v.var_type), ("", DEFAULT_METHOD)) aggregates[v] = hint.lower() return aggregates def commit_if(self): if self.auto_commit: self.commit() else: self.state_changed_flag = True def commit(self): self.update_hints() if self.data is not None: group = list(self.group_list) aggregates = self.get_aggregates_from_hints() print aggregates data = utils.group_by(self.data, group, attr_aggregate=aggregates) else: data = None self.send("Data", data) self.state_changed_flag = False
class OWDataSort(OWWidget): contextHandlers = { "": DomainContextHandler( "", ["sortroles"] ) } settingsList = ["autoCommit"] def __init__(self, parent=None, signalManger=None, title="Data Sort"): super(OWDataSort, self).__init__(parent, signalManger, title, wantMainArea=False) #: Mapping (feature.name, feature.var_type) to (sort_index, sort_order) #: where sirt index is the position of the feature in the sortByModel #: and sort_order the Qt.SortOrder flag self.sortroles = {} self.autoCommit = False self._outputChanged = False box = OWGUI.widgetBox(self.controlArea, "Sort By Features") self.sortByView = QListView() self.sortByView.setItemDelegate(SortParamDelegate(self)) self.sortByView.setSelectionMode(QListView.ExtendedSelection) self.sortByView.setDragDropMode(QListView.DragDrop) self.sortByView.setDefaultDropAction(Qt.MoveAction) self.sortByView.viewport().setAcceptDrops(True) self.sortByModel = VariableListModel( flags=Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled | Qt.ItemIsEditable ) self.sortByView.setModel(self.sortByModel) box.layout().addWidget(self.sortByView) box = OWGUI.widgetBox(self.controlArea, "Unused Features") self.unusedView = QListView() self.unusedView.setSelectionMode(QListView.ExtendedSelection) self.unusedView.setDragDropMode(QListView.DragDrop) self.unusedView.setDefaultDropAction(Qt.MoveAction) self.unusedView.viewport().setAcceptDrops(True) self.unusedModel = VariableListModel( flags=Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled ) self.unusedView.setModel(self.unusedModel) box.layout().addWidget(self.unusedView) box = OWGUI.widgetBox(self.controlArea, "Output") cb = OWGUI.checkBox(box, self, "autoCommit", "Auto commit") b = OWGUI.button(box, self, "Commit", callback=self.commit) OWGUI.setStopper(self, b, cb, "_outputChanged", callback=self.commit) def setData(self, data): """ Set the input data. """ self._storeRoles() self.closeContext("") self.data = data if data is not None: self.openContext("", data) domain = data.domain features = (domain.variables + domain.class_vars + domain.get_metas().values()) sort_by = [] unused = [] for feat in features: hint = self.sortroles.get((feat.name, feat.var_type), None) if hint is not None: index, order = hint sort_by.append((feat, index, order)) else: unused.append(feat) sort_by = sorted(sort_by, key=itemgetter(1)) self.sortByModel[:] = [feat for feat, _, _ in sort_by] self.unusedModel[:] = unused # Restore the sort orders for i, (_, _, order) in enumerate(sort_by): index = self.sortByModel.index(i, 0) self.sortByModel.setData(index, order, SortOrderRole) self.commit() def _invalidate(self): if self.autoCommit: self.commit() else: self._outputChanged = True def _sortingParams(self): params = [] for i, feature in enumerate(self.sortByModel): index = self.sortByModel.index(i, 0) order = toSortOrder(index.data(SortOrderRole)) params.append((feature, order)) return params def commit(self): params = self._sortingParams() if self.data: instances = sorted(self.data, key=sort_key(params)) data = Orange.data.Table(self.data.domain, instances) else: data = self.data self.send("Data", data) def _storeRoles(self): """ Store the sorting roles back into the stored settings. """ roles = {} for i, feature in enumerate(self.sortByModel): index = self.sortByModel.index(i, 0) order = toSortOrder(index.data(SortOrderRole)) roles[(feature.name, feature.var_type)] = (i, int(order)) self.sortroles = roles def getSettings(self, *args, **kwargs): self._storeRoles() return OWWidget.getSettings(self, *args, **kwargs)
class OWDataGenerator(OWWidget): TOOLS = [ ("Brush", "Create multiple instances", BrushTool, icon_brush), ("Put", "Put individual instances", PutInstanceTool, icon_put), ("Select", "Select and move instances", SelectTool, icon_select), ("Lasso", "Select and move instances", LassoTool, icon_lasso), ("Jitter", "Jitter instances", JitterTool, icon_jitter), ("Magnet", "Move (drag) multiple instances", MagnetTool, icon_magnet), ("Zoom", "Zoom", ZoomTool, OWToolbars.dlg_zoom ) #"GenerateDataZoomTool.png") ] def __init__(self, parent=None, signalManager=None, name="Data Generator"): OWWidget.__init__(self, parent, signalManager, name, wantGraph=True) self.outputs = [("Example Table", ExampleTable)] self.addClassAsMeta = False self.attributes = [] self.cov = [] self.loadSettings() self.variablesModel = VariableListModel( [orange.FloatVariable(name) for name in ["X", "Y"]], self, flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) self.classVariable = orange.EnumVariable("Class label", values=["Class 1", "Class 2"], baseValue=0) w = OWGUI.widgetBox(self.controlArea, "Class Label") self.classValuesView = listView = QListView() listView.setSelectionMode(QListView.SingleSelection) self.classValuesModel = EnumVariableModel( self.classVariable, self, flags=Qt.ItemIsSelectable | Qt.ItemIsEnabled | Qt.ItemIsEditable) self.classValuesModel.wrap(self.classVariable.values) listView.setModel(self.classValuesModel) listView.selectionModel().select(self.classValuesModel.index(0), QItemSelectionModel.ClearAndSelect) self.connect( listView.selectionModel(), SIGNAL("selectionChanged(QItemSelection, QItemSelection)"), self.onClassLabelSelection) listView.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Maximum) w.layout().addWidget(listView) self.addClassLabel = addClassLabel = QAction("+", self) addClassLabel.pyqtConfigure( toolTip="Add class label") #, icon=QIcon(icon_put)) self.connect(addClassLabel, SIGNAL("triggered()"), self.addNewClassLabel) self.removeClassLabel = removeClassLabel = QAction("-", self) removeClassLabel.pyqtConfigure( toolTip="Remove class label") #, icon=QIcon(icon_remove)) self.connect(removeClassLabel, SIGNAL("triggered()"), self.removeSelectedClassLabel) actionsWidget = ModelActionsWidget([addClassLabel, removeClassLabel], self) actionsWidget.layout().addStretch(10) actionsWidget.layout().setSpacing(1) w.layout().addWidget(actionsWidget) toolbox = OWGUI.widgetBox(self.controlArea, "Tools", orientation=QGridLayout()) self.toolActions = QActionGroup(self) self.toolActions.setExclusive(True) for i, (name, tooltip, tool, icon) in enumerate(self.TOOLS): action = QAction(name, self) action.setToolTip(tooltip) action.setCheckable(True) if os.path.exists(icon): action.setIcon(QIcon(icon)) self.connect(action, SIGNAL("triggered()"), lambda tool=tool: self.onToolAction(tool)) button = QToolButton() button.setDefaultAction(action) button.setIconSize(QSize(24, 24)) button.setToolButtonStyle(Qt.ToolButtonTextUnderIcon) button.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Fixed) toolbox.layout().addWidget(button, i / 3, i % 3) self.toolActions.addAction(action) for column in range(3): toolbox.layout().setColumnMinimumWidth(column, 10) toolbox.layout().setColumnStretch(column, 1) self.optionsLayout = QStackedLayout() self.toolsStackCache = {} optionsbox = OWGUI.widgetBox(self.controlArea, "Options", orientation=self.optionsLayout) # OWGUI.checkBox(self.controlArea, self, "addClassAsMeta", "Add class ids as meta attributes") OWGUI.rubber(self.controlArea) OWGUI.button(self.controlArea, self, "Commit", callback=self.commit) self.graph = DataGeneratorGraph(self) self.graph.setAxisScale(QwtPlot.xBottom, 0.0, 1.0) self.graph.setAxisScale(QwtPlot.yLeft, 0.0, 1.0) self.graph.setAttribute(Qt.WA_Hover, True) self.mainArea.layout().addWidget(self.graph) self.currentOptionsWidget = None self.data = [] self.domain = None self.onDomainChanged() self.toolActions.actions()[0].trigger() self.resize(800, 600) def addNewClassLabel(self): i = 1 while True: newlabel = "Class %i" % i if newlabel not in self.classValuesModel: # self.classValuesModel.append(newlabel) break i += 1 values = list(self.classValuesModel) + [newlabel] newclass = orange.EnumVariable("Class label", values=values) newdomain = orange.Domain(self.graph.data.domain.attributes, newclass) newdata = orange.ExampleTable(newdomain) for ex in self.graph.data: newdata.append( orange.Example(newdomain, [ex[a] for a in ex.domain.attributes] + [str(ex.getclass())])) self.classVariable = newclass self.classValuesModel.wrap(self.classVariable.values) self.graph.data = newdata self.graph.updateGraph() newindex = self.classValuesModel.index(len(self.classValuesModel) - 1) self.classValuesView.selectionModel().select( newindex, QItemSelectionModel.ClearAndSelect) self.removeClassLabel.setEnabled(len(self.classValuesModel) > 1) def removeSelectedClassLabel(self): index = self.selectedClassLabelIndex() if index is not None and len(self.classValuesModel) > 1: label = self.classValuesModel[index] examples = [ ex for ex in self.graph.data if str(ex.getclass()) != label ] values = [val for val in self.classValuesModel if val != label] newclass = orange.EnumVariable("Class label", values=values) newdomain = orange.Domain(self.graph.data.domain.attributes, newclass) newdata = orange.ExampleTable(newdomain) for ex in examples: if ex[self.classVariable] != label and ex[ self.classVariable] in values: newdata.append( orange.Example(newdomain, [ex[a] for a in ex.domain.attributes] + [str(ex.getclass())])) self.classVariable = newclass self.classValuesModel.wrap(self.classVariable.values) self.graph.data = newdata self.graph.updateGraph() newindex = self.classValuesModel.index(max(0, index - 1)) self.classValuesView.selectionModel().select( newindex, QItemSelectionModel.ClearAndSelect) self.removeClassLabel.setEnabled(len(self.classValuesModel) > 1) def selectedClassLabelIndex(self): rows = [ i.row() for i in self.classValuesView.selectionModel().selectedRows() ] if rows: return rows[0] else: return None def onClassLabelSelection(self, selected, unselected): index = self.selectedClassLabelIndex() if index is not None: self.classVariable.baseValue = index def onAddFeature(self): self.variablesModel.append(orange.FloatVariable("New feature")) self.varListView.edit( self.variablesModel.index(len(self.variablesModel) - 1)) def onRemoveFeature(self): raise NotImplemented def onVariableSelectionChange(self, selected, deselected): self.selected def onToolAction(self, tool): self.setCurrentTool(tool) def setCurrentTool(self, tool): if tool not in self.toolsStackCache: newtool = tool(None, self) option = newtool.optionsWidget(newtool, self) self.optionsLayout.addWidget(option) self.connect(newtool, SIGNAL("dataChanged()"), self.graph.updateGraph) self.toolsStackCache[tool] = (newtool, option) self.currentTool, self.currentOptionsWidget = tool, option = self.toolsStackCache[ tool] self.optionsLayout.setCurrentWidget(option) self.currentTool.setGraph(self.graph) def onDomainChanged(self, *args): if self.variablesModel: self.domain = orange.Domain(list(self.variablesModel), self.classVariable) if self.data: self.data = orange.ExampleTable(self.domain, self.data) else: self.data = orange.ExampleTable(self.domain) self.graph.setData(self.data, 0, 1) def commit(self): if self.addClassAsMeta: domain = orange.Domain(self.graph.data.domain.attributes, None) domain.addmeta(orange.newmetaid(), self.graph.data.domain.classVar) data = orange.ExampleTable(domain, self.graph.data) else: data = self.graph.data self.send("Example Table", self.graph.data)