source: orange-bioinformatics/orangecontrib/bio/widgets/OWQualityControl.py @ 1874:b3e32cc5cf6f

Revision 1874:b3e32cc5cf6f, 24.7 KB checked in by Ales Erjavec <ales.erjavec@…>, 6 months ago (diff)

Added new style widget meta descriptions.

RevLine 
[1556]1"""
[1558]2<name>Quality Control</name>
[1562]3<description>Experiment quality control</description>
[1726]4<icon>icons/QualityControl.svg</icon>
[1556]5
6"""
7
[1632]8from __future__ import absolute_import, with_statement
9
[1556]10import sys
[1558]11from collections import defaultdict
12from contextlib import contextmanager
[1556]13from pprint import pprint
14
[1632]15import numpy
16
17import Orange
18from Orange.OrangeWidgets import OWGUI
19from Orange.OrangeWidgets.OWWidget import *
20from Orange.OrangeWidgets.OWItemModels import PyListModel, safe_text
21from Orange.OrangeWidgets.OWGraphics import GraphicsSimpleTextLayoutItem
22
23from .. import obiExperiments as exp
24
25from .OWGenotypeDistances import SetContextHandler
26
[1874]27NAME = "Quality Control"
28DESCRIPTION = "Experiment quality control"
29ICON = "icons/QualityControl.svg"
30PRIORITY = 5000
31
32INPUTS = [("Experiment Data", Orange.data.Table, "set_data")]
33OUTPUTS = []
34
35REPLACES = ["_bioinformatics.widgets.OWQualityControl.OWQualityControl"]
36
37
[1558]38DEBUG = False
[1556]39
[1558]40@contextmanager
[1560]41def widget_disable(widget):
42    """A context to disable the widget (enabled property) 
43    """
[1558]44    widget.setEnabled(False)
[1567]45    try:
46        yield
47    finally:
48        widget.setEnabled(True)
[1558]49   
[1566]50   
[1558]51@contextmanager
52def disable_updates(widget):
[1560]53    """
54    A context that sets '_disable_updates' member to True, and
55    then restores it.
56   
57    """
[1558]58    widget._disable_updates = True
[1567]59    try:
60        yield
61    finally:
62        widget._disable_updates = False
[1558]63
[1566]64
[1558]65def group_label(splits, groups):
[1560]66    """Return group label.
[1556]67    """
[1573]68    labels = ["%s=%s" % (split, group) \
[1556]69              for split, group in zip(splits, groups)]
70    return " | ".join(labels)
71
72
[1558]73def sort_label(sort, attr):
[1560]74    """Return within group sorted items label for attribute.
[1558]75    """
76    items = [(key, attr.attributes.get(key, "?")) \
77             for key in sort]
[1573]78    labels = ["%s=%s" % tuple(item) for item in items]
[1558]79    return " | ".join(labels)
80
[1566]81
[1558]82def float_if_posible(val):
[1560]83    """Return val as float if possible otherwise return the value unchanged.
84   
85    """
[1558]86    try:
87        return float(val)
88    except ValueError:
89        return val
[1561]90   
[1566]91   
[1561]92def experiment_description(feature):
[1562]93    """Return experiment description from ``feature.attributes``.
94    """
[1561]95    text = ""
96    if feature.attributes:
97        items = feature.attributes.items()
98        items = [(safe_text(key), safe_text(value)) for key, value in items]
99        labels = map("%s = %s".__mod__, items)
[1563]100        text += "<b>%s</b><br/>" % safe_text(feature.name)
[1561]101        text += "<br/>".join(labels)
102    return text
[1556]103
[1566]104
[1556]105class OWQualityControl(OWWidget):
[1558]106    contextHandlers = {"": SetContextHandler("")}
[1567]107    settingsList = ["selected_distance_index"]
[1558]108   
[1560]109    DISTANCE_FUNCTIONS = [("Distance from Pearson correlation",
110                           exp.dist_pcorr),
111                          ("Euclidean distance", 
112                           exp.dist_eucl),
113                          ("Distance from Spearman correlation", 
114                           exp.dist_spearman)]
[1556]115
116    def __init__(self, parent=None, signalManager=None,
117                 title="Quality Control"):
118        OWWidget.__init__(self, parent, signalManager, title,
119                          wantGraph=True)
120
121        self.inputs = [("Experiment Data", Orange.data.Table, self.set_data)]
122
[1558]123        ## Settings
[1556]124        self.selected_distance_index = 0
125
126        ## Attributes
127        self.data = None
128        self.distances = None
129        self.groups = None
[1558]130        self.unique_pos = None
[1566]131        self.base_group_index = 0
[1556]132
133        ## GUI
134        box = OWGUI.widgetBox(self.controlArea, "Info")
135        self.info_box = OWGUI.widgetLabel(box, "\n")
136
[1566]137        ## Separate By box
138        box = OWGUI.widgetBox(self.controlArea, "Separate By")
[1556]139        self.split_by_model = PyListModel()
140        self.split_by_view = QListView()
[1558]141        self.split_by_view.setSelectionMode(QListView.ExtendedSelection)
[1556]142        self.split_by_view.setModel(self.split_by_model)
143        box.layout().addWidget(self.split_by_view)
144
[1558]145        self.connect(self.split_by_view.selectionModel(),
146                     SIGNAL("selectionChanged(QItemSelection, QItemSelection)"),
147                     self.on_split_key_changed)
148
[1556]149        ## Sort By box
150        box = OWGUI.widgetBox(self.controlArea, "Sort By")
151        self.sort_by_model = PyListModel()
152        self.sort_by_view = QListView()
[1558]153        self.sort_by_view.setSelectionMode(QListView.ExtendedSelection)
[1556]154        self.sort_by_view.setModel(self.sort_by_model)
155        box.layout().addWidget(self.sort_by_view)
[1558]156       
157        self.connect(self.sort_by_view.selectionModel(),
158                     SIGNAL("selectionChanged(QItemSelection, QItemSelection)"),
159                     self.on_sort_key_changed)
[1556]160
161        ## Distance box
162        box = OWGUI.widgetBox(self.controlArea, "Distance Measure")
163        OWGUI.comboBox(box, self, "selected_distance_index",
[1558]164                       items=[t[0] for t in self.DISTANCE_FUNCTIONS],
165                       callback=self.on_distance_measure_changed)
[1556]166
[1558]167        self.connect(self.graphButton,
168                     SIGNAL("clicked()"),
169                     self.save_graph)
170       
[1556]171        self.scene = QGraphicsScene()
[1558]172        self.scene_view = QualityGraphicsView(self.scene)
173        self.scene_view.setRenderHints(QPainter.Antialiasing)
[1581]174        self.scene_view.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
[1556]175        self.mainArea.layout().addWidget(self.scene_view)
[1558]176       
177        self.connect(self.scene_view,
178                     SIGNAL("view_size_changed(QSize)"),
179                     self.on_view_resize)
[1556]180
[1558]181        self._disable_updates = False
[1561]182        self._cached_distances = {}
183        self._base_index_hints = {}
[1558]184        self.main_widget = None
185       
[1556]186        self.resize(800, 600)
187
188    def clear(self):
189        """Clear the widget state.
190        """
191        self.data = None
192        self.distances = None
193        self.groups = None
[1558]194        self.unique_pos = None
195       
196        with disable_updates(self):
197            self.split_by_model[:] = []
198            self.sort_by_model[:] = []
[1581]199       
200        self.main_widget = None
[1556]201        self.scene.clear()
[1558]202        self.info_box.setText("\n")
[1561]203        self._cached_distances = {}
[1556]204
205    def set_data(self, data=None):
206        """Set input experiment data.
207        """
[1564]208        self.clear()
[1566]209       
210        self.error(0)
211        self.warning(0)
212       
213        if data is not None:
214            keys = self.get_suitable_keys(data)
215            if not keys:
216                self.error(0, "Data has no suitable feature labels.")
217                data = None
218               
[1556]219        self.data = data
220
221    def handleNewSignals(self):
222        """Called after all signals have been set.
223        """
224        if self.data:
225            self.on_new_data()
226        else:
[1558]227            self.closeContext("")
[1556]228            self.clear()
229
230    def update_label_candidates(self):
231        """Update the label candidates selection GUI
232        (Group/Sort By views).
233       
234        """
[1558]235        keys = self.get_suitable_keys(self.data)
236        with disable_updates(self):
237            self.split_by_model[:] = keys
238            self.sort_by_model[:] = keys
239       
240    def get_suitable_keys(self, data):
[1560]241        """ Return suitable attr label keys from the data where
242        the key has at least two unique values in the data.
[1558]243       
244        """
245        attrs = [attr.attributes.items() for attr in data.domain.attributes]
246        attrs  = reduce(list.__add__, attrs, [])
247        # in case someone put non string values in attributes dict
248        attrs = [(str(key), str(value)) for key, value in attrs]
249        attrs = set(attrs)
250        values = defaultdict(set)
251        for key, value in attrs:
252            values[key].add(value)
253        keys = [key for key in values if len(values[key]) > 1]
254        return keys
[1556]255
256    def selected_split_by_labels(self):
257        """Return the current selected split labels.
258        """
[1558]259        sel_m = self.split_by_view.selectionModel()
260        indices = [r.row() for r in sel_m.selectedRows()]
261        return [self.sort_by_model[i] for i in indices]
[1556]262
263    def selected_sort_by_labels(self):
264        """Return the current selected sort labels
265        """
[1558]266        sel_m = self.sort_by_view.selectionModel()
267        indices = [r.row() for r in sel_m.selectedRows()]
268        return [self.sort_by_model[i] for i in indices]
[1556]269
270    def selected_distance(self):
271        """Return the selected distance function.
272        """
273        return self.DISTANCE_FUNCTIONS[self.selected_distance_index][1]
[1558]274   
[1561]275    def selected_base_group_index(self):
276        """Return the selected base group index
[1560]277        """
[1566]278        return self.base_group_index
[1561]279   
280    def selected_base_indices(self, base_group_index=None):
281        indices = []
282        for g, ind in self.groups:
283            if base_group_index is None:
284                label = group_label(self.selected_split_by_labels(), g)
[1563]285                ind = [i for i in ind if i is not None]
[1561]286                i = self._base_index_hints.get(label, ind[0] if ind else None)
287            else:
288                i = ind[base_group_index]
289            indices.append(i)
290        return indices
[1556]291
292    def on_new_data(self):
293        """We have new data and need to recompute all.
294        """
[1558]295        self.closeContext("")
296       
[1556]297        self.update_label_candidates()
[1573]298        self.info_box.setText("%s genes \n%s experiments" % (
[1558]299                                len(self.data), 
300                                len(self.data.domain.attributes)
301                                )
302                              )
303       
[1567]304        self.base_group_index = 0
305       
[1558]306        keys = self.get_suitable_keys(self.data)
307        self.openContext("", keys)
308       
309        ## Restore saved context
310        context = self.currentContexts[""]
[1560]311        split_by_labels = getattr(context, "split_by_labels", set())
[1558]312        sort_by_labels = getattr(context, "sort_by_labels", set())
313       
314        def select(model, selection_model, selected_items):
[1560]315            """Select items in a Qt item model view
316            """
[1558]317            all_items = list(model)
318            try:
319                indices = [all_items.index(item) for item in selected_items]
320            except:
321                indices = []
322            for ind in indices:
[1560]323                selection_model.select(model.index(ind), 
324                                       QItemSelectionModel.Select)
[1558]325               
326        with disable_updates(self):
327            select(self.split_by_view.model(),
328                   self.split_by_view.selectionModel(),
329                   split_by_labels)
330           
331            select(self.sort_by_view.model(),
332                   self.sort_by_view.selectionModel(),
333                   sort_by_labels)
[1567]334       
335        with widget_disable(self):
336            self.split_and_update()
[1558]337       
338    def on_split_key_changed(self, *args):
[1560]339        """Split key has changed
340        """
341        with widget_disable(self):
[1558]342            if not self._disable_updates:
[1566]343                self.base_group_index = 0
[1558]344                context = self.currentContexts[""]
345                context.split_by_labels = self.selected_split_by_labels()
346                self.split_and_update()
347   
348    def on_sort_key_changed(self, *args):
[1560]349        """Sort key has changed
350        """
351        with widget_disable(self):
[1558]352            if not self._disable_updates:
[1566]353                self.base_group_index = 0
[1558]354                context = self.currentContexts[""]
355                context.sort_by_labels = self.selected_sort_by_labels()
356                self.split_and_update()
357       
358    def on_distance_measure_changed(self):
[1560]359        """Distance measure has changed
360        """
[1581]361        if self.data is not None:
362            with widget_disable(self):
363                self.update_distances()
364                self.replot_experiments()
[1558]365       
366    def on_view_resize(self, size):
[1560]367        """The view with the quality plot has changed
368        """
[1558]369        if self.main_widget:
370            current = self.main_widget.size()
[1581]371            self.main_widget.resize(size.width() - 6, 
[1558]372                                    current.height())
373           
374            self.scene.setSceneRect(self.scene.itemsBoundingRect())
375       
376    def on_rug_item_clicked(self, item):
[1560]377        """An ``item`` in the quality plot has been clicked.
378        """
[1561]379        update = False
380        sort_by_labels = self.selected_sort_by_labels()
381        if sort_by_labels and item.in_group:
382            ## The item is part of the group
[1566]383            if item.group_index != self.base_group_index:
384                self.base_group_index = item.group_index
[1561]385                update = True
386           
387        else:
388            if sort_by_labels:
389                # If the user clicked on an background item it
390                # invalidates the sorted labels selection
391                with disable_updates(self):
392                    self.sort_by_view.selectionModel().clear()
393                    update = True
394                   
395            index = item.index
396            group = item.group
397            label = group_label(self.selected_split_by_labels(), group)
398           
399            if self._base_index_hints.get(label, 0) != index:
400                self._base_index_hints[label] = index
401                update = True
402           
403        if update:
[1567]404            with widget_disable(self):
405                self.split_and_update()
[1558]406       
[1556]407    def split_and_update(self):
408        """
409        Split the data based on the selected sort/split labels
410        and update the quality plot.
411       
412        """
[1561]413        split_labels = self.selected_split_by_labels()
414        sort_labels = self.selected_sort_by_labels()
[1566]415       
416        self.warning(0)
417        if not split_labels:
418            self.warning(0, "No separate by label selected.")
419           
[1558]420        self.groups, self.unique_pos = \
[1561]421                exp.separate_by(self.data, split_labels,
422                                consider=sort_labels,
[1558]423                                add_empty=True)
424       
425       
426        self.groups = sorted(self.groups.items(),
427                             key=lambda t: map(float_if_posible, t[0]))
428        self.unique_pos = sorted(self.unique_pos.items(),
429                                 key=lambda t: map(float_if_posible, t[0]))
[1556]430       
[1563]431       
[1558]432        if self.groups:
[1561]433            if sort_labels:
434                group_base = self.selected_base_group_index()
435                base_indices = self.selected_base_indices(group_base)
436            else:
437                base_indices = self.selected_base_indices()
438            self.update_distances(base_indices)
[1558]439            self.replot_experiments()
[1556]440
[1561]441    def get_cached_distances(self, measure):
442        if measure not in self._cached_distances:
443            attrs = self.data.domain.attributes
444            mat = Orange.misc.SymMatrix(len(attrs))
445            self._cached_distances[measure] = \
446                (mat, set(zip(range(len(attrs)), range(len(attrs)))))
447           
448        return self._cached_distances[measure]
[1566]449       
[1561]450    def get_cached_distance(self, measure, i, j):
451        matrix, computed = self.get_cached_distances(measure)
452        key = (i, j) if i < j else (j, i) 
453        if key in computed:
454            return matrix[i, j]
455        else:
456            return None
457       
458    def get_distance(self, measure, i, j):
459        d = self.get_cached_distance(measure, i, j)
460        if d is None:
461            vec_i = exp.linearize(self.data, [i])
462            vec_j = exp.linearize(self.data, [j])
463            d = distance(vec_i, vec_j)
464            mat, computed = self.get_cached_distances(measure)
465            mat[i, j] = d
466            key = key = (i, j) if i < j else (j, i)
467            computed.add(key)
468        return d
469   
470    def store_distance(self, measure, i, j, dist):
471        matrix, computed = self.get_cached_distances(measure)
472        key = key = (i, j) if i < j else (j, i)
473        matrix[i, j] = dist
474        computed.add(key)
475       
476    def update_distances(self, base_indices=()):
[1556]477        """Recompute the experiment distances.
478        """
479        distance = self.selected_distance()
[1561]480        if base_indices == ():
481            base_group_index = self.selected_base_group_index()
482            base_indices = [ind[base_group_index] \
483                            for _, ind in self.groups]
[1563]484           
[1561]485        assert(len(base_indices) == len(self.groups)) 
486       
[1556]487        base_distances = []
[1561]488        attributes = self.data.domain.attributes
[1558]489        pb = OWGUI.ProgressBar(self, len(self.groups) * \
[1561]490                               len(attributes))
491       
492        cached_distances, filled_set = self.get_cached_distances(distance)
493       
494        for (group, indices), base_index in zip(self.groups, base_indices):
[1556]495            # Base column of the group
[1561]496            if base_index is not None:
497                base_vec = exp.linearize(self.data, [base_index])
[1558]498                distances = []
[1561]499                # Compute the distances between base column
[1558]500                # and all the rest data columns.
[1561]501                for i in range(len(attributes)):
502                    if i == base_index:
[1558]503                        distances.append(0.0)
[1561]504                    elif self.get_cached_distance(distance, i, base_index) is not None:
505                        distances.append(self.get_cached_distance(distance, i, base_index))
[1558]506                    else:
507                        vec_i = exp.linearize(self.data, [i])
[1561]508                        dist = distance(base_vec, vec_i)
509                        self.store_distance(distance, i, base_index, dist)
510                        distances.append(dist)
[1558]511                    pb.advance()
512                   
513                base_distances.append(distances)
514            else:
515                base_distances.append(None)
[1561]516               
[1558]517        pb.finish()
[1556]518        self.distances = base_distances
519
520    def replot_experiments(self):
[1561]521        """Replot the whole quality plot.
[1556]522        """
523        self.scene.clear()
524        labels = []
[1562]525       
[1558]526        max_dist = numpy.max(filter(None, self.distances))
[1556]527        rug_widgets = []
[1558]528       
529        group_pen = QPen(QColor(0, 0, 0))
530        group_pen.setWidth(2)
531        group_pen.setCapStyle(Qt.RoundCap)
532        background_pen = QPen(QColor(0, 0, 250, 150))
533        background_pen.setWidth(1)
534        background_pen.setCapStyle(Qt.RoundCap)
535       
536        main_widget = QualityControlWidget()
537        layout = QGraphicsGridLayout()
538        split_by = self.selected_split_by_labels()
539        sort_by = self.selected_sort_by_labels()
540        attributes = self.data.domain.attributes
[1556]541        if self.data:
542            for (group, indices), dist_vec in zip(self.groups, self.distances):
543                indices_set = set(indices)
544                rug_items = []
[1558]545                if dist_vec is not None:
546                    for i, attr in enumerate(attributes):
547                        # Is this a within group distance or background
548                        in_group = i in indices_set
549                        if in_group:
550                            rug_item = ClickableRugItem(dist_vec[i] / max_dist,
551                                           1.0, self.on_rug_item_clicked)
552                            rug_item.setPen(group_pen)
[1561]553                            tooltip = experiment_description(attr)
[1558]554                            rug_item.setToolTip(tooltip)
[1561]555                            rug_item.group_index = indices.index(i)
[1581]556                            rug_item.setZValue(rug_item.zValue() + 1)
[1558]557                        else:
558                            rug_item = ClickableRugItem(dist_vec[i] / max_dist,
[1561]559                                           0.85, self.on_rug_item_clicked)
560                            rug_item.setPen(background_pen)
561                            tooltip = experiment_description(attr)
[1558]562                            rug_item.setToolTip(tooltip)
[1561]563                           
564                        rug_item.group = group
565                        rug_item.index = i
566                        rug_item.in_group = in_group
567                       
[1558]568                        rug_items.append(rug_item)
[1556]569                   
570                rug_widget = RugGraphicsWidget()
571                rug_widget.set_rug(rug_items)
[1558]572               
[1556]573                rug_widgets.append(rug_widget)
574               
[1558]575                label = group_label(self.selected_split_by_labels(), group)
[1562]576                label_item = QGraphicsSimpleTextItem(label, main_widget)
[1558]577                label_item = GraphicsSimpleTextLayoutItem(label_item)
578                label_item.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
579                labels.append(label_item)
580       
581        for i, (label, w) in enumerate(zip(labels, rug_widgets)):
582            layout.addItem(label, i, 0, Qt.AlignVCenter)
583            layout.addItem(w, i, 1)
584            layout.setRowMaximumHeight(i, 30)
[1556]585           
586        main_widget.setLayout(layout)
587        self.scene.addItem(main_widget)
[1558]588        main_widget.show()
589        self.main_widget = main_widget
590        self.rug_widgets = rug_widgets
591        self.labels = labels
592        self.on_view_resize(self.scene_view.size())
[1556]593       
[1558]594    def save_graph(self):
[1632]595        from Orange.OrangeWidgets.OWDlgs import OWChooseImageSizeDlg
[1558]596        dlg = OWChooseImageSizeDlg(self.scene, parent=self)
597        dlg.exec_()
[1556]598
599
600class RugGraphicsWidget(QGraphicsWidget):
601    def __init__(self, parent=None, rug=None):
602        QGraphicsWidget.__init__(self, parent)
603        self.rug_items = []
604        self.set_rug(rug)
[1558]605        self.setMaximumHeight(30)
606        self.setMinimumHeight(30)
607       
[1556]608    def clear(self):
609        """
610        Clear all rug items from this widget and remove them
611        from the scene.
612         
613        """
614        for item in self.rug_items:
615            item.setParent(None)
616            if self.scene() is not None:
617                self.scene().removeItem(item)
618
619    def set_rug(self, rug):
620        """
621        Set the rug items.
622       
623        ``rug`` must be a list of floats or already initialized
624        instances of RugItem. The widget takes ownership of all
625        items.
626         
627        """
628        rug = rug if rug is not None else []
629        self.clear()
630        self.add_rug(rug)
631
632    def add_rug(self, rug):
633        """
634        Add rug items.
635       
636        See :obj:`set_rug`
637       
638        """
639        items = []
640        for item in rug:
641            if isinstance(item, float):
642                item = RugItem(value=item)
643                items.append(item)
644            elif isinstance(item, RugItem):
645                items.append(item)
646
647        for item in items:
648            item.setParentItem(self)
649
650        self.rug_items.extend(items)
651
652        self.update_rug_geometry()
653       
654    def update_rug_geometry(self):
[1560]655        """Recompute the rug items positions within this widget.
656        """
[1556]657        size = self.size()
658        height = size.height()
659        width = size.width()
660       
661        for item in self.rug_items:
[1558]662            offset = (1.0 - item.height) * height / 2.0
[1556]663            item.setPos(width * item.value, 0)
[1558]664            item.setLine(0., offset, 0., height - offset)
[1556]665
666    def resizeEvent(self, event):
[1560]667        """Reimplemented from QGraphicsWidget
668        """
[1556]669        QGraphicsWidget.resizeEvent(self, event)
670        self.update_rug_geometry()
671
672    def setGeometry(self, geom):
[1560]673        """Reimplemented from QGraphicsWidget
674        """
[1556]675        QGraphicsWidget.setGeometry(self, geom)
676
677
678class RugItem(QGraphicsLineItem):
[1558]679    def __init__(self, value, height):
[1556]680        QGraphicsLineItem.__init__(self)
681        self.value = value
[1558]682        self.height = height
[1556]683
684    def set_height(self, height):
[1558]685        """Set the height of this item (in ratio of the rug height)
[1556]686        """
687        self.height = height
[1558]688       
689class ClickableRugItem(RugItem):
690    def __init__(self, value, height, on_pressed):
691        RugItem.__init__(self, value, height)
692        self.on_pressed = on_pressed
693        self.setAcceptedMouseButtons(Qt.LeftButton)
694        self.setAcceptHoverEvents(True)
695       
696    def mousePressEvent(self, event):
697        if event.button() == Qt.LeftButton and self.on_pressed:
698            self.on_pressed(self)
699           
700    def hoverEnterEvent(self, event):
701        pen = QPen(self.pen())
702        pen.setWidthF(3)
703        self.setPen(pen)
704        return RugItem.hoverEnterEvent(self, event)
705   
706    def hoverLeaveEvent(self, event):
707        pen = QPen(self.pen())
708        pen.setWidth(2)
709        self.setPen(pen)
710        return RugItem.hoverLeaveEvent(self, event)
[1556]711
712
[1558]713class QualityGraphicsView(QGraphicsView):
714    def resizeEvent(self, event):
715        QGraphicsView.resizeEvent(self, event)
716        self.emit(SIGNAL("view_size_changed(QSize)"),
717                  event.size())
[1556]718
[1558]719
720class QualityControlWidget(QGraphicsWidget):
721    if DEBUG:
722        def paint(self, painter, options, widget=0):
723            rect =  self.geometry()
724            rect.translate(-self.pos())
725            painter.drawRect(rect)
726           
[1556]727if __name__ == "__main__":
728    app = QApplication(sys.argv)
729    w = OWQualityControl()
[1558]730#    data = Orange.data.Table("doc:dicty-abc-sample.tab")
731    data = Orange.data.Table("doc:pipa.tab")
[1556]732
733    w.set_data(data)
734    w.show()
735    w.handleNewSignals()
736    app.exec_()
[1558]737    w.set_data(None)
738    w.handleNewSignals()
739    w.saveSettings()
Note: See TracBrowser for help on using the repository browser.