Commits

Aleš Erjavec committed 73d51aa

Added rectangle point selection.

Comments (0)

Files changed (1)

_differentiation/widgets/OWDifferentiationScale.py

 
 from __future__ import absolute_import
 
-import os, sys
-import random
+import os
+import sys
+
 from collections import defaultdict
 from operator import itemgetter, add
 
 class OWDifferentiationScale(OWWidget):
     settingsList = ["auto_commit", "merge"]
 
-    def __init__(self, parent=None, signalManager=None, title="Differentiation Scale"):
-        OWWidget.__init__(self, parent, signalManager, title, wantGraph=True)
+    def __init__(self, parent=None, signalManager=None,
+                 title="Differentiation Scale"):
+        OWWidget.__init__(self, parent, signalManager, title,
+                          wantGraph=True)
 
-        self.inputs = [("Gene Expression Samples", Orange.data.Table, self.set_data),
-                       ("Additional Expression Samples", Orange.data.Table, self.set_additional_data)]
+        self.inputs = [("Gene Expression Samples", Orange.data.Table,
+                        self.set_data),
+                       ("Additional Expression Samples", Orange.data.Table,
+                        self.set_additional_data)]
+
         self.outputs = [("Selected Time Points", Orange.data.Table),
                         ("Additional Selected Time Points", Orange.data.Table),
                         ("Informative genes", Orange.data.Table),
         box = OWGUI.widgetBox(self.controlArea, "Info")
         self.info_label = OWGUI.widgetLabel(box, "No data on input")
         self.info_label.setWordWrap(True)
-        self.info_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
+        self.info_label.setSizePolicy(QSizePolicy.Expanding,
+                                      QSizePolicy.Expanding)
 
         OWGUI.rubber(self.controlArea)
 
 
         self.connect(self.graphButton, SIGNAL("pressed()"), self.save_graph)
 
-        self.scene = QGraphicsScene()
+        self.scene = DiffScaleScene()
         self.scene_view = DiffScaleView(self.scene, self.mainArea)
         self.scene_view.setRenderHint(QPainter.Antialiasing)
         self.scene_view.setMinimumWidth(300)
+
         self.mainArea.layout().addWidget(self.scene_view)
-        self.connect(self.scene, SIGNAL("selectionChanged()"), self.on_selection_changed)
-        self.connect(self.scene_view, SIGNAL("view_resized(QSize)"), lambda size: self.on_view_resized())
+        self.connect(self.scene, SIGNAL("selectionChanged()"),
+                     self.on_selection_changed)
+        self.connect(self.scene_view, SIGNAL("view_resized(QSize)"),
+                     self.on_view_resized)
 
         self.data = None
         self.additional_data = None
         """
         self.selected_time_samples = [], []
 
-    def set_data(self, data = None):
+    def set_data(self, data=None):
         """ Set the data for the widget.
         """
         self.clear()
 
             info_text = """\
 Data with {0} genes
-and {1} samples on input.\n""".format(len(self.data),
-                 len(self.data.domain.attributes))
+and {1} samples on input.\n""".format(
+                len(self.data),
+                len(self.data.domain.attributes)
+                )
+
             if self.additional_data is not None:
                 info_text += """\
 Additional data with {0} genes
-and  {1} samples on input.""".format(len(self.additional_data),
-                                                    len(self.additional_data.domain.attributes))
+and  {1} samples on input.""".format(
+                len(self.additional_data),
+                len(self.additional_data.domain.attributes)
+                )
+
             self.info_label.setText(info_text)
         else:
             self.send("Selected Time Points", None)
         """ Run difscale.get_projections with the current inputs.
         """
         self.error()
-#        try:
-#            attr_set = list(set(a.attributes['time'] for a in data.domain.attributes))
-#            self.time_points = difscale.conv(attr_set, ticks=False)
-#        except KeyError, ex:
-#            self.error("Could not extract time data")
-#            self.clear()
-#            return
 
         try:
             (self.projections1, self.labels1,
 
             labels = self.labels1 + self.labels2
 
-            samples = [(attr, self.data) for attr in self.data.domain.attributes] + \
-                      ([(attr, self.additional_data) for attr in self.additional_data.domain.attributes] \
-                       if self.additional_data is not None else [])
+            samples = [(attr, self.data) \
+                       for attr in self.data.domain.attributes]
+            if self.additional_data is not None:
+                samples += [(attr, self.additional_data) \
+                            for attr in self.additional_data.domain.attributes]
 
             # TODO: handle samples with the same projection
             # the point_layout should return the proj to sample mapping instead
-            proj_to_sample = dict([((label, proj), sample) for label, proj, sample \
-                                   in zip(labels, projections, samples)])
+            proj_to_sample = dict([((label, proj), sample) \
+                                   for label, proj, sample \
+                                   in zip(labels, projections, samples)]
+                                  )
             self.proj_to_sample = proj_to_sample
 
             time_points = point_layout(labels, projections)
             self.time_points = time_points
-            level_height = 20
+
             all_points = numpy.array(reduce(add, [p for _, p in time_points], []))
             self.all_points = all_points
 
-#            all_points[:, 1] *= -level_height
-            self.time_samples = [] # samples for time label (same order as in self.time_points)
+            # samples for time label (same order as in self.time_points)
+            self.time_samples = []
 
             point_i = 0
             for label, points, in time_points:
             rects = []
             ticks = []
             axis_label_items = []
-            labels = [(center, label) for center, (label, _) in zip(centers, self.time_samples)]
+            labels = [(center, label) for center, (label, _) in \
+                      zip(centers, self.time_samples)]
             labels = sorted(labels, key=lambda (c, l): c[0])
             for center, label in labels:
                 x, y = center
                 ticks.append(QPointF(x - w / 2.0, 4.0))
                 axis_label_items.append(item)
 
-#            rects = SA_axis_label_layout(ticks, rects, max_time=0.5,
-#                                         x_factor=scene_size_hint.width() / 50.0,
-#                                         y_factor=10,
-#                                         random=random.Random(0))
-
             rects = greedy_scale_label_layout(ticks, rects, spacing=5)
 
-            for (tick, label), rect, item in zip(labels, rects, axis_label_items):
+            for (tick, label), rect, item in zip(labels, rects,
+                                                 axis_label_items):
                 x, y = tick
                 self.scene.addLine(x, -2, x, 2)
                 if rect.top() - item.pos().y() > 5:
                     self.scene.addLine(x, 2, rect.center().x(), 14.0)
                 if rect.top() - item.pos().y() > 15:
-                    self.scene.addLine(rect.center().x(), 14.0, rect.center().x(), rect.top())
-#                item.setPos(rect.topLeft())
+                    self.scene.addLine(rect.center().x(), 14.0,
+                                       rect.center().x(), rect.top())
 
-#                text = QGraphicsSimpleTextItem(label)
-#            for tick, rect, item in zip(ticks, rects, axis_label_items):
                 item.setPos(rect.topLeft())
                 self.scene.addItem(item)
-#                w = text.boundingRect().width()
-#                text.setPos(x - w / 2.0, 4)
-                # Need to compute axis label layout.
-#                self.scene.addItem(text)
 
-            self.scene.setSceneRect(self.scene.itemsBoundingRect().adjusted(-10, -10, 10, 10))
+            rect = self.scene.itemsBoundingRect()
+            self.scene.setSceneRect(rect.adjusted(-10, -10, 10, 10))
 
-    def on_view_resized(self):
+    def on_view_resized(self, *args):
         self.update_graph()
 
     def on_selection_changed(self):
                 selected_attrs2.append(attr)
 
         self.selected_time_samples = selected_attrs1, selected_attrs2
-        print self.selected_time_samples
         self.commit_if()
 
     def commit_if(self):
         self.emit(SIGNAL("view_resized(QSize)"), event.size())
 
 
+class DiffScaleScene(QGraphicsScene):
+    def __init__(self, *args):
+        QGraphicsScene.__init__(self, *args)
+        self._selection_rect = None
+
+    def mousePressEvent(self, event):
+        item = self.itemAt(event.scenePos())
+        if not item and event.modifiers() & Qt.ControlModifier:
+            # Default implementation clears selection on ctrl press on
+            # an empty spot.
+            return
+        else:
+            # Let the default implementation handle it
+            return QGraphicsScene.mousePressEvent(self, event)
+
+    def mouseMoveEvent(self, event):
+        if event.buttons() & Qt.LeftButton:
+            if not self._selection_rect:
+                self._selection_rect = QGraphicsRectItem(scene=self)
+                self._selection_rect.setPen(
+                    QPen(QBrush(QColor(51, 153, 255, 192)),
+                         0.4, Qt.SolidLine, Qt.RoundCap)
+                )
+                self._selection_rect.setBrush(
+                    QBrush(QColor(168, 202, 236, 192))
+                )
+                self._selection_rect.setZValue(-100)
+
+            down = event.buttonDownScenePos(Qt.LeftButton)
+            rect = QRectF(down, event.scenePos()).normalized()
+            self._selection_rect.setRect(rect)
+            self._selection_rect.show()
+            if not event.modifiers() & Qt.ControlModifier:
+                self.clearSelection()
+
+            items = self.items(self._selection_rect.rect(),
+                               Qt.IntersectsItemShape,
+                               Qt.AscendingOrder)
+
+            for item in items:
+                if isinstance(item, GraphicsTimePoint) and \
+                        item.flags() & GraphicsTimePoint.ItemIsSelectable:
+                    item.setSelected(True)
+
+        return QGraphicsScene.mouseMoveEvent(self, event)
+
+    def mouseReleaseEvent(self, event):
+        if self._selection_rect:
+            self._selection_rect.hide()
+            self._selection_rect.setRect(QRectF())
+            self.removeItem(self._selection_rect)
+            self._selection_rect = None
+        return QGraphicsScene.mouseReleaseEvent(self, event)
+
+
 def point_layout(labels, points, label_size_hints=None):
     groups = defaultdict(list)
     for label, point in zip(labels, points):