Changeset 11684:10858549f936 in orange


Ignore:
Timestamp:
09/03/13 14:54:34 (8 months ago)
Author:
Ales Erjavec <ales.erjavec@…>
Branch:
default
Message:

Refactor Rank widget. Allow adding extra score functions through entry points.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • Orange/OrangeWidgets/Data/OWRank.py

    r11666 r11684  
    66<priority>1102</priority> 
    77""" 
     8 
     9from collections import namedtuple 
     10from functools import partial 
     11 
     12import pkg_resources 
     13 
    814from OWWidget import * 
    9      
     15 
    1016import OWGUI 
    1117import orange 
    1218 
    13 from functools import partial 
     19from Orange.regression.earth import ScoreEarthImportance 
     20from orngSVM import MeasureAttribute_SVMWeights 
     21from orngEnsemble import MeasureAttribute_randomForests 
     22 
    1423 
    1524def _toPyObject(variant): 
     
    3948    """ 
    4049    return [[fill for j in range(shape[1])] for i in range(shape[0])] 
    41   
    42 from Orange.regression.earth import ScoreEarthImportance 
    43 from orngSVM import MeasureAttribute_SVMWeights 
    44 from orngEnsemble import MeasureAttribute_randomForests 
    45  
    46 MEASURE_PARAMS = {ScoreEarthImportance: \ 
    47                     [{"name": "t", 
    48                       "type": int, 
    49                       "display_name": "Num. models.", 
    50                       "range": range(1, 21), 
    51                       "default": 10, 
    52                       "doc": "Number of models to train for feature scoring." 
    53                       }, 
    54                      {"name": "terms", 
    55                       "type": int, 
    56                       "display_name": "Max. num of terms", 
    57                       "range": range(3, 200), 
    58                       "default": 10, 
    59                       "doc": "Maximum number of terms in the forward pass"  
    60                       }, 
    61                      {"name": "degree",  
    62                       "type": int, 
    63                       "display_name": "Max. term degree", 
    64                       "range": range(1, 4), 
    65                       "default": 2, 
    66                       "doc": "Maximum degree of terms included in the model."  
    67                      }, 
    68 #                     {"name": "score_what", 
    69 #                      "type": int, 
    70 #                      "display_name": "Score what", 
    71 #                      "range": range(0, 3), 
    72 #                      "display_role": ["Num. Subsets", "RSS", "GCV"] 
    73 #                      "default": 2, 
    74 #                      "doc": ""} 
    75                      ], 
    76                   orange.MeasureAttribute_relief: \ 
    77                      [{"name": "k", 
    78                        "type": int, 
    79                        "display_name": "Neighbours", 
    80                        "range": range(1, 21), 
    81                        "default": 10, 
    82                        "doc": "Number of neighbors to consider."}, 
    83                       {"name":"m", 
    84                        "type": int, 
    85                        "display_name": "Examples", 
    86                        "range": range(20, 101), 
    87                        "default": 20, 
    88                        "doc": ""} 
    89                       ], 
    90                   MeasureAttribute_randomForests:\ 
    91                      [{"name": "trees", 
    92                        "type": int, 
    93                        "display_name": "Num. of trees", 
    94                        "range": range(20, 101), 
    95                        "default": 100, 
    96                        "doc": "Number of trees in the random forest."} 
    97                       ] 
    98                   } 
    99  
    100  
    101 MEASURES = [("ReliefF", "ReliefF", orange.MeasureAttribute_relief), 
    102             ("Information Gain", "Inf. gain", orange.MeasureAttribute_info), 
    103             ("Gain Ratio", "Gain Ratio", orange.MeasureAttribute_gainRatio), 
    104             ("Gini Gain", "Gini", orange.MeasureAttribute_gini), 
    105             ("Log Odds Ratio", "log OR", orange.MeasureAttribute_logOddsRatio), 
    106             ("MSE", "MSE", orange.MeasureAttribute_MSE), 
    107             ("Earth Importance", "Earth imp.", ScoreEarthImportance), 
    108             ("Linear SVM Weights", "SVM weight", MeasureAttribute_SVMWeights), 
    109             ("Random Forests", "RF", MeasureAttribute_randomForests), 
    110             ] 
    111  
    112 MEASURES_HANDLES_CONTINUOUS = {"ReliefF": True, 
    113                                "Earth Importance": True, 
    114                                "Linear SVM Weights": True, 
    115                                "Random Forests": True, 
    116                                } 
    117  
    118 MEASURES_SUPPORTS_REGRESSION = {"ReliefF": True, 
    119                                 "MSE": True, 
    120                                 "Earth Importance": True, 
    121                                 "Random Forests": True, 
    122                                 } 
    123  
    124 MEASURES_SUPPORTS_CLASSIFICATION = {"MSE": False, 
    125                                     "Random Forests": True, 
    126                                     } 
    127  
    128 MEASURES_DEFAULT_SELECTED = dict([(mname, True) for mname, _, _ in MEASURES[:6]] + \ 
    129                                  [(mname, False) for mname, _, _ in MEASURES[6:]]) # The Earth imp. and SVM are not selected by default 
     50 
     51 
     52MEASURE_PARAMS = { 
     53    ScoreEarthImportance: [ 
     54        {"name": "t", 
     55         "type": int, 
     56         "display_name": "Num. models.", 
     57         "range": (1, 20), 
     58         "default": 10, 
     59         "doc": "Number of models to train for feature scoring."}, 
     60        {"name": "terms", 
     61         "type": int, 
     62         "display_name": "Max. num of terms", 
     63         "range": (3, 200), 
     64         "default": 10, 
     65         "doc": "Maximum number of terms in the forward pass"}, 
     66        {"name": "degree", 
     67         "type": int, 
     68         "display_name": "Max. term degree", 
     69         "range": (1, 3), 
     70         "default": 2, 
     71         "doc": "Maximum degree of terms included in the model."} 
     72    ], 
     73    orange.MeasureAttribute_relief: [ 
     74        {"name": "k", 
     75         "type": int, 
     76         "display_name": "Neighbours", 
     77         "range": (1, 20), 
     78         "default": 10, 
     79         "doc": "Number of neighbors to consider."}, 
     80        {"name":"m", 
     81         "type": int, 
     82         "display_name": "Examples", 
     83         "range": (20, 100), 
     84         "default": 20, 
     85         "doc": ""} 
     86        ], 
     87    MeasureAttribute_randomForests: [ 
     88        {"name": "trees", 
     89         "type": int, 
     90         "display_name": "Num. of trees", 
     91         "range": (20, 100), 
     92         "default": 100, 
     93         "doc": "Number of trees in the random forest."} 
     94        ] 
     95    } 
     96 
     97 
     98_score_meta = namedtuple( 
     99    "_score_meta", 
     100    ["name", 
     101     "shortname", 
     102     "score", 
     103     "params", 
     104     "supports_regression", 
     105     "supports_classification", 
     106     "handles_discrete", 
     107     "handles_continuous"] 
     108) 
     109 
     110 
     111class score_meta(_score_meta): 
     112    # Add sensible defaults to __new__ 
     113    def __new__(cls, name, shortname, score, params=None, 
     114                supports_regression=True, supports_classification=True, 
     115                handles_continuous=True, handles_discrete=True): 
     116        return _score_meta.__new__( 
     117            cls, name, shortname, score, params, 
     118            supports_regression, supports_classification, 
     119            handles_discrete, handles_continuous 
     120        ) 
     121 
     122 
     123# Default scores. 
     124SCORES = [ 
     125    score_meta( 
     126        "ReliefF", "ReliefF", orange.MeasureAttribute_relief, 
     127        params=MEASURE_PARAMS[orange.MeasureAttribute_relief], 
     128        handles_continuous=True, 
     129        handles_discrete=True), 
     130    score_meta( 
     131        "Information Gain", "Inf. gain", orange.MeasureAttribute_info, 
     132        params=None, 
     133        supports_regression=False, 
     134        supports_classification=True, 
     135        handles_continuous=False, 
     136        handles_discrete=True), 
     137    score_meta( 
     138        "Gain Ratio", "Gain Ratio", orange.MeasureAttribute_gainRatio, 
     139        params=None, 
     140        supports_regression=False, 
     141        handles_continuous=False, 
     142        handles_discrete=True), 
     143    score_meta( 
     144        "Gini Gain", "Gini", orange.MeasureAttribute_gini, 
     145        params=None, 
     146        supports_regression=False, 
     147        supports_classification=True, 
     148        handles_continuous=False), 
     149    score_meta( 
     150        "Log Odds Ratio", "log OR", orange.MeasureAttribute_logOddsRatio, 
     151        params=None, 
     152        supports_regression=False, 
     153        handles_continuous=False), 
     154    score_meta( 
     155        "MSE", "MSE", orange.MeasureAttribute_MSE, 
     156        params=None, 
     157        supports_classification=False, 
     158        handles_continuous=False), 
     159    score_meta( 
     160        "Linear SVM Weights", "SVM weight", MeasureAttribute_SVMWeights, 
     161        params=None), 
     162    score_meta( 
     163        "Random Forests", "RF", MeasureAttribute_randomForests, 
     164        params=MEASURE_PARAMS[MeasureAttribute_randomForests]), 
     165    score_meta( 
     166        "Earth Importance", "Earth imp.", ScoreEarthImportance, 
     167        params=MEASURE_PARAMS[ScoreEarthImportance], 
     168    ) 
     169] 
     170 
     171_DEFAULT_SELECTED = set(m.name for m in SCORES[:6]) 
    130172 
    131173 
     
    140182        self.doc = doc 
    141183 
    142 def supports_classification(name): 
    143     return MEASURES_SUPPORTS_CLASSIFICATION.get(name, True) 
    144  
    145 def supports_regression(name): 
    146     return MEASURES_SUPPORTS_REGRESSION.get(name, False) 
    147  
    148 def handles_continuous(name): 
    149     return MEASURES_HANDLES_CONTINUOUS.get(name, False) 
    150184 
    151185def measure_parameters(measure): 
    152     return [MethodParameter(**args) for args in MEASURE_PARAMS.get(measure, [])] 
     186    return [MethodParameter(**args) for args in (measure.params or [])] 
     187 
    153188 
    154189def param_attr_name(measure, param): 
    155     """ Name of the OWRank widget's member where the parameter is stored.  
     190    """Name of the OWRank widget's member where the parameter is stored. 
    156191    """ 
    157192    return "param_" + measure.__name__ + "_" + param.name 
    158          
     193 
     194 
     195def drop_exceptions(iterable, exceptions=(Exception,)): 
     196    iterable = iter(iterable) 
     197    while True: 
     198        try: 
     199            yield next(iterable) 
     200        except StopIteration: 
     201            raise 
     202        except BaseException as ex: 
     203            if not isinstance(ex, exceptions): 
     204                raise 
     205 
     206 
     207def load_ep_drop_exceptions(entry_point): 
     208    for ep in pkg_resources.iter_entry_points(entry_point): 
     209        try: 
     210            yield ep.load() 
     211        except Exception: 
     212            log = logging.getLogger(__name__) 
     213            log.debug("", exc_info=True) 
     214 
     215 
     216def all_measures(): 
     217    iter_ep = load_ep_drop_exceptions("orange.widgets.feature_score") 
     218    scores = [m for m in iter_ep if isinstance(m, score_meta)] 
     219    return SCORES + scores 
     220 
     221 
    159222class OWRank(OWWidget): 
    160     settingsList =  ["nDecimals", "nIntervals", "sortBy", "nSelected", "selectMethod", "autoApply", "showDistributions", "distColorRgb"] 
    161  
    162     def __init__(self,parent=None, signalManager = None): 
     223    settingsList = [ 
     224        "nDecimals", "nIntervals", "sortBy", "nSelected", 
     225        "selectMethod", "autoApply", "showDistributions", 
     226        "distColorRgb" 
     227    ] 
     228 
     229    def __init__(self, parent=None, signalManager=None): 
    163230        OWWidget.__init__(self, parent, signalManager, "Rank") 
    164231 
     
    173240        self.autoApply = True 
    174241        self.showDistributions = 1 
    175         self.distColorRgb = (220,220,220, 255) 
     242        self.distColorRgb = (220, 220, 220, 255) 
    176243        self.distColor = QColor(*self.distColorRgb) 
    177         self.minmax = {} 
    178         self.selectedMeasures = dict(MEASURES_DEFAULT_SELECTED) 
     244 
     245        self.all_measures = all_measures() 
     246 
     247        self.selectedMeasures = dict( 
     248            [(name, True) for name in _DEFAULT_SELECTED] + 
     249            [(m.name, False) 
     250             for m in self.all_measures[len(_DEFAULT_SELECTED):]] 
     251        ) 
     252 
    179253        self.data = None 
    180          
    181 #        self.measure_parameters = AttributeDict() 
    182 #        self.measure_parameters = {} 
    183          
     254 
    184255        self.methodParamAttrs = [] 
    185         for _, _, m in MEASURES: 
    186             params = measure_parameters(m) or [] 
     256        for m in self.all_measures: 
     257            params = measure_parameters(m) 
    187258            for p in params: 
    188                 setattr(self, param_attr_name(m, p), p.default) 
    189                 self.methodParamAttrs.append(param_attr_name(m, p)) 
     259                name_mangled = param_attr_name(m.score, p) 
     260                setattr(self, name_mangled, p.default) 
     261                self.methodParamAttrs.append(name_mangled) 
     262 
    190263        self.settingsList = self.settingsList + self.methodParamAttrs 
    191          
    192         self.loadSettings()  
    193  
    194         labelWidth = 80 
    195          
    196         self.discMeasures = [name for name, short, _ in MEASURES \ 
    197                              if supports_classification(name)] 
    198          
    199         self.contMeasures = [name for name, short, _ in MEASURES \ 
    200                              if supports_regression(name)] 
    201          
    202         self.discMeasuresShort = [short for name, short, _ in MEASURES \ 
    203                                   if supports_classification(name)] 
    204          
    205         self.contMeasuresShort = [short for name, short, _ in MEASURES \ 
    206                                   if supports_regression(name)] 
    207          
    208         self.discEstimators = [measure for name, _, measure in MEASURES \ 
    209                                if supports_classification(name)] 
    210          
    211         self.contEstimators = [measure for name, _, measure in MEASURES \ 
    212                                if supports_regression(name)] 
    213          
    214         self.discHandlesContinuous = map(handles_continuous, self.discMeasures) 
    215         self.contHandlesContinuous = map(handles_continuous, self.contMeasures) 
    216  
    217         # The stacked layout for Classification/Regression measures 
    218 #        self.stackedWidget = OWGUI.widgetBox(self.controlArea, margin=0, 
    219 #                                             addSpace=True) 
    220          
     264 
     265        self.loadSettings() 
     266 
     267        self.discMeasures = [m for m in self.all_measures 
     268                             if m.supports_classification] 
     269        self.contMeasures = [m for m in self.all_measures 
     270                             if m.supports_regression] 
     271 
    221272        self.stackedLayout = QStackedLayout() 
    222273        self.stackedLayout.setContentsMargins(0, 0, 0, 0) 
     
    224275                                             orientation=self.stackedLayout, 
    225276                                             addSpace=True) 
    226 #        self.stackedWidget.layout().addLayout(self.stackedLayout) 
     277 
    227278        # Discrete class scoring 
    228279        discreteBox = OWGUI.widgetBox(self.stackedWidget, "Scoring", 
     
    230281                                      addToLayout=False) 
    231282        self.stackedLayout.addWidget(discreteBox) 
    232          
     283 
    233284        # Continuous class scoring 
    234285        continuousBox = OWGUI.widgetBox(self.stackedWidget, "Scoring", 
     
    236287                                        addToLayout=False) 
    237288        self.stackedLayout.addWidget(continuousBox) 
    238          
    239         def measure_control(container, name, measure): 
    240             """ Construct UI control for measure. 
     289 
     290        def measure_control(container, measure): 
     291            """Construct UI control for `measure` (measure_meta instance). 
    241292            """ 
     293            name = measure.name 
    242294            params = measure_parameters(measure) 
    243295            if params: 
    244                 hbox = OWGUI.widgetBox(container, orientation = "horizontal") 
     296                hbox = OWGUI.widgetBox(container, orientation="horizontal") 
    245297                OWGUI.checkBox(hbox, self.selectedMeasures, name, name, 
    246                                callback=partial(self.measuresSelectionChanged, name), 
     298                               callback=partial(self.measuresSelectionChanged, 
     299                                                measure), 
    247300                               tooltip="Enable " + name) 
    248                 smallWidget = OWGUI.SmallWidgetLabel(hbox, pixmap=1, box=name + " Parameters", 
    249                                                      tooltip="Show " + name + "Parameters") 
     301 
     302                smallWidget = OWGUI.SmallWidgetLabel( 
     303                    hbox, pixmap=1, box=name + " Parameters", 
     304                    tooltip="Show " + name + "Parameters") 
     305 
    250306                for param in params: 
    251                     OWGUI.spin(smallWidget.widget, self, param_attr_name(measure, param), 
     307                    OWGUI.spin(smallWidget.widget, self, 
     308                               param_attr_name(measure.score, param), 
    252309                               param.range[0], param.range[-1], 
    253                                label=param.display_name,  
     310                               label=param.display_name, 
    254311                               tooltip=param.doc, 
    255                                callback=partial(self.measureParamChanged, name, param), 
     312                               callback=partial( 
     313                                    self.measureParamChanged, measure, param), 
    256314                               callbackOnReturn=True) 
    257                  
     315 
    258316                OWGUI.button(smallWidget.widget, self, "Load defaults", 
    259                              callback=partial(self.loadMeasureDefaults, name)) 
     317                             callback=partial(self.loadMeasureDefaults, 
     318                                              measure)) 
    260319            else: 
    261320                OWGUI.checkBox(container, self.selectedMeasures, name, name, 
    262                                callback=partial(self.measuresSelectionChanged, name), 
     321                               callback=partial(self.measuresSelectionChanged, 
     322                                                measure), 
    263323                               tooltip="Enable " + name) 
    264          
    265         for name, short_name, measure in MEASURES: 
    266             if supports_classification(name): 
    267                 measure_control(discreteBox, name, measure) 
    268                      
    269             if supports_regression(name): 
    270                 measure_control(continuousBox, name, measure) 
    271          
    272          
     324 
     325        for measure in self.all_measures: 
     326            if measure.supports_classification: 
     327                measure_control(discreteBox, measure) 
     328 
     329            if measure.supports_regression: 
     330                measure_control(continuousBox, measure) 
     331 
    273332        OWGUI.comboBox(discreteBox, self, "sortBy", label = "Sort by"+"  ", 
    274333                       items = ["No Sorting", "Attribute Name", "Number of Values"] + \ 
    275                                [name for name in self.discMeasures], 
     334                               [m.name for m in self.discMeasures], 
    276335                       orientation=0, valueType = int, 
    277336                       callback=self.sortingChanged) 
     
    279338        OWGUI.comboBox(continuousBox, self, "sortBy", label = "Sort by"+"  ", 
    280339                       items = ["No Sorting", "Attribute Name", "Number of Values"] + \ 
    281                                [name for name in self.contMeasures], 
     340                               [m.name for m in self.contMeasures], 
    282341                       orientation=0, valueType = int, 
    283342                       callback=self.sortingChanged) 
     
    348407         
    349408        self.discRanksModel = QStandardItemModel(self) 
    350         self.discRanksModel.setHorizontalHeaderLabels(["Attribute", "#"] + self.discMeasuresShort) 
     409        self.discRanksModel.setHorizontalHeaderLabels( 
     410            ["Attribute", "#"] + [m.shortname for m in self.discMeasures] 
     411        ) 
    351412        self.discRanksProxyModel = MySortProxyModel(self) 
    352413        self.discRanksProxyModel.setSourceModel(self.discRanksModel) 
     
    374435         
    375436        self.contRanksModel = QStandardItemModel(self) 
    376         self.contRanksModel.setHorizontalHeaderLabels(["Attribute", "#"] + self.contMeasuresShort) 
     437        self.contRanksModel.setHorizontalHeaderLabels( 
     438            ["Attribute", "#"] + [m.shortname for m in self.contMeasures] 
     439        ) 
    377440        self.contRanksProxyModel = MySortProxyModel(self) 
    378441        self.contRanksProxyModel.setSourceModel(self.contRanksModel) 
     
    409472        self.ranksViewStack.setCurrentIndex(index) 
    410473        self.stackedLayout.setCurrentIndex(index) 
    411          
     474 
    412475        if index == 0: 
    413476            self.ranksView = self.discRanksView 
     
    415478            self.ranksProxyModel = self.discRanksProxyModel 
    416479            self.measures = self.discMeasures 
    417             self.handlesContinuous = self.discHandlesContinuous 
    418             self.estimators = self.discEstimators 
    419480        else: 
    420481            self.ranksView = self.contRanksView 
     
    422483            self.ranksProxyModel = self.contRanksProxyModel 
    423484            self.measures = self.contMeasures 
    424             self.handlesContinuous = self.contHandlesContinuous 
    425             self.estimators = self.contEstimators 
    426              
     485 
    427486        self.updateVisibleScoreColumns() 
    428487             
     
    476535            return 
    477536         
    478         estimators = self.estimators 
     537#         estimators = self.estimators 
    479538        measures = self.measures 
    480         handlesContinous = self.handlesContinuous 
    481         self.warning(range(max(len(self.discEstimators), len(self.contEstimators)))) 
    482          
     539#         handlesContinous = self.handlesContinuous 
     540        # Invalidate all warnings 
     541        self.warning(range(max(len(self.discMeasures), 
     542                               len(self.contMeasures)))) 
     543 
    483544        if measuresMask is None: 
    484545            # Update all selected measures 
    485             measuresMask = [self.selectedMeasures.get(m) for m in measures] 
    486          
    487         for measure_index, (est, meas, mask) in enumerate(zip( 
    488                 estimators, measures, measuresMask)): 
     546            measuresMask = [self.selectedMeasures.get(m.name) 
     547                            for m in measures] 
     548 
     549        for measure_index, (meas, mask) in enumerate(zip(measures, measuresMask)): 
    489550            if not mask: 
    490551                continue 
    491             handles = MEASURES_HANDLES_CONTINUOUS.get(meas, False) 
    492             params = measure_parameters(est) 
    493             estimator = est() 
     552 
     553            params = measure_parameters(meas) 
     554            estimator = meas.score() 
    494555            if params: 
    495556                for p in params: 
    496557                    setattr(estimator, p.name, 
    497                             getattr(self, param_attr_name(est, p))) 
    498                      
    499             if not handles: 
     558                            getattr(self, param_attr_name(meas.score, p))) 
     559 
     560            if not meas.handles_continuous: 
    500561                data = self.getDiscretizedData() 
    501562                attr_map = data.attrDict 
     
    503564            else: 
    504565                attr_map, data = {}, self.data 
     566 
    505567            attr_scores = [] 
    506568            for i, attr in enumerate(data.domain.attributes): 
     
    511573                        s = estimator(attr, data) 
    512574                    except Exception, ex: 
    513                         self.warning(measure_index, "Error evaluating %r: %r" % (meas, str(ex))) 
     575                        self.warning(measure_index, "Error evaluating %r: %r" % (meas.name, str(ex))) 
    514576                        # TODO: store exception message (for widget info or item tooltip) 
    515                     if meas == "Log Odds Ratio" and s is not None: 
     577                    if meas.name == "Log Odds Ratio" and s is not None: 
    516578                        if s == -999999: 
    517579                            attr = u"-\u221E" 
     
    641703            self.discretizedData.setattr("attrDict", attrDict) 
    642704        return self.discretizedData 
    643          
     705 
    644706    def discretizationChanged(self): 
    645707        self.discretizedData = None 
    646         self.updateScores([not b for b in self.handlesContinuous]) 
     708        self.updateScores([not m.handles_continuous for m in self.measures]) 
    647709        self.autoSelection() 
    648          
    649     def measureParamChanged(self, name, param=None): 
    650         index = self.measures.index(name) 
    651         measure = self.estimators[index] 
     710 
     711    def measureParamChanged(self, measure, param=None): 
     712        index = self.measures.index(measure) 
    652713        mask = [i == index for i, _ in enumerate(self.measures)] 
    653714        self.updateScores(mask) 
    654715     
    655     def loadMeasureDefaults(self, name): 
    656         index = self.measures.index(name) 
    657         measure = self.estimators[index] 
     716    def loadMeasureDefaults(self, measure): 
     717#         index = self.measures.index(measure) 
     718#         measure = self.estimators[index] 
    658719        params = measure_parameters(measure) 
    659720        for i, p in enumerate(params): 
    660             setattr(self, param_attr_name(measure, p), p.default) 
    661         self.measureParamChanged(name) 
     721            setattr(self, param_attr_name(measure.score, p), p.default) 
     722        self.measureParamChanged(measure) 
    662723         
    663724    def autoSelection(self): 
     
    712773 
    713774    def setLogORTitle(self): 
    714         var =self.data.domain.classVar     
     775        var = self.data.domain.classVar 
    715776        if len(var.values) == 2: 
    716777            title = "log OR (for %r)" % var.values[1][:10] 
    717778        else: 
    718779            title = "log OR" 
    719         if "Log Odds Ratio" in self.discEstimators: 
    720             index = self.discMeasures.index("Log Odds Ratio") 
    721             item = PyStandardItem(title) 
    722             self.ranksModel.setHorizontalHeaderItem(index + 2, item) 
    723  
    724     def measuresSelectionChanged(self, name=None): 
    725         """ Measure selection has changed. Update column visibility. 
     780#         if "Log Odds Ratio" in self.discEstimators: 
     781#             index = self.discMeasures.index("Log Odds Ratio") 
     782        index = [m.name for m in self.discMeasures].index("Log Odds Ratio") 
     783 
     784        item = PyStandardItem(title) 
     785        self.ranksModel.setHorizontalHeaderItem(index + 2, item) 
     786 
     787    def measuresSelectionChanged(self, measure=None): 
     788        """Measure selection has changed. Update column visibility. 
    726789        """ 
    727         if name is None: 
     790        if measure is None: 
    728791            # Update all scores 
    729792            measuresMask = None 
    730793        else: 
    731794            # Update scores for shown column if they are not yet computed. 
    732             shown = self.selectedMeasures.get(name, False) 
    733             index = self.measures.index(name) 
     795            shown = self.selectedMeasures.get(measure.name, False) 
     796            index = self.measures.index(measure) 
    734797            if all(s is None for s in self.measure_scores[index]) and shown: 
    735                 measuresMask = [n == name for n in self.measures] 
     798                measuresMask = [m == measure for m in self.measures] 
    736799            else: 
    737800                measuresMask = [False] * len(self.measures) 
     
    744807        """ 
    745808        for i, measure in enumerate(self.measures): 
    746             shown = self.selectedMeasures.get(measure) 
     809            shown = self.selectedMeasures.get(measure.name) 
    747810            self.ranksView.setColumnHidden(i + 2, not shown) 
    748811 
Note: See TracChangeset for help on using the changeset viewer.