1- from itertools import chain
2-
31import numpy as np
42from scipy .stats .distributions import chi2
53
64from PyQt4 .QtCore import Qt , QSize
75from PyQt4 .QtGui import (
86 QGraphicsScene , QColor , QPen , QBrush , QSizePolicy , QGraphicsLineItem )
97
10- from Orange .data import Table , filter
8+ from Orange .data import Table , filter , Variable
119from Orange .data .sql .table import SqlTable , LARGE_TABLE , DEFAULT_SAMPLE_TIME
1210from Orange .preprocess import Discretize
1311from Orange .preprocess .discretize import EqualFreq
1412from Orange .statistics .contingency import get_contingency
1513from Orange .widgets import gui
1614from Orange .widgets .settings import DomainContextHandler , ContextSetting
1715from Orange .widgets .utils import to_html as to_html
18- from Orange .widgets .utils .itemmodels import VariableListModel
16+ from Orange .widgets .utils .itemmodels import DomainModel
1917from Orange .widgets .visualize .utils import (
2018 CanvasText , CanvasRectangle , ViewWithPress , VizRankDialogAttrPair )
2119from Orange .widgets .widget import OWWidget , Default , AttributeList
@@ -48,7 +46,8 @@ def initialize(self):
4846 self .attrs = self .master .attrs
4947
5048 def compute_score (self , state ):
51- return ChiSqStats (self .master .discrete_data , * state ).p
49+ return ChiSqStats (self .master .discrete_data ,
50+ * (self .attrs [i ].name for i in state )).p
5251
5352
5453class OWSieveDiagram (OWWidget ):
@@ -67,8 +66,8 @@ class OWSieveDiagram(OWWidget):
6766 want_control_area = False
6867
6968 settingsHandler = DomainContextHandler ()
70- attrX = ContextSetting ("" , exclude_metas = False )
71- attrY = ContextSetting ("" , exclude_metas = False )
69+ attr_x = ContextSetting (None , exclude_metas = False )
70+ attr_y = ContextSetting (None , exclude_metas = False )
7271 selection = ContextSetting (set ())
7372
7473 def __init__ (self ):
@@ -82,16 +81,15 @@ def __init__(self):
8281 self .selection = set ()
8382
8483 self .attr_box = gui .hBox (self .mainArea )
85- model = VariableListModel ()
86- model .wrap (self .attrs )
84+ self .domain_model = DomainModel ()
8785 combo_args = dict (
8886 widget = self .attr_box , master = self , contentsLength = 12 ,
8987 callback = self .update_attr , sendSelectedValue = True , valueType = str ,
90- model = model )
88+ model = self . domain_model )
9189 fixed_size = (QSizePolicy .Fixed , QSizePolicy .Fixed )
92- self .attrXCombo = gui .comboBox (value = "attrX " , ** combo_args )
90+ self .attr_x_combo = gui .comboBox (value = "attr_x " , ** combo_args )
9391 gui .widgetLabel (self .attr_box , "\u2715 " , sizePolicy = fixed_size )
94- self .attrYCombo = gui .comboBox (value = "attrY " , ** combo_args )
92+ self .attr_y_combo = gui .comboBox (value = "attr_y " , ** combo_args )
9593 self .vizrank , self .vizrank_button = SieveRank .add_vizrank (
9694 self .attr_box , self , "Score Combinations" , self .set_attr )
9795 self .vizrank_button .setSizePolicy (* fixed_size )
@@ -121,7 +119,7 @@ def showEvent(self, event):
121119 def set_data (self , data ):
122120 """
123121 Discretize continuous attributes, and put all attributes and discrete
124- metas into self.attrs, which is used as a model for combos .
122+ metas into self.attrs.
125123
126124 Select the first two attributes unless context overrides this.
127125 Method `resolve_shown_attributes` is called to use the attributes from
@@ -142,24 +140,22 @@ def set_data(self, data):
142140 self .selection = set ()
143141 if self .data is None :
144142 self .attrs [:] = []
143+ self .domain_model .set_domain (None )
145144 else :
145+ self .domain_model .set_domain (data .domain )
146146 if any (attr .is_continuous for attr in data .domain ):
147147 discretizer = Discretize (
148148 method = EqualFreq (n = 4 ),
149149 discretize_classes = True , discretize_metas = True )
150150 self .discrete_data = discretizer (data )
151151 else :
152152 self .discrete_data = self .data
153- self .attrs [:] = [
154- var for var in chain (
155- self .discrete_data .domain ,
156- (var for var in self .data .domain .metas if var .is_discrete ))
157- ]
153+ self .attrs = [x for x in self .domain_model if isinstance (x , Variable )]
158154 if self .attrs :
159- self .attrX = self .attrs [0 ]. name
160- self .attrY = self .attrs [len (self .attrs ) > 1 ]. name
155+ self .attr_x = self .attrs [0 ]
156+ self .attr_y = self .attrs [len (self .attrs ) > 1 ]
161157 else :
162- self .attrX = self .attrY = None
158+ self .attr_x = self .attr_y = None
163159 self .areas = []
164160 self .selection = set ()
165161 self .openContext (self .data )
@@ -173,7 +169,7 @@ def set_data(self, data):
173169 len (self .data .domain .attributes ) > 1 )
174170
175171 def set_attr (self , attr_x , attr_y ):
176- self .attrX , self .attrY = attr_x . name , attr_y . name
172+ self .attr_x , self .attr_y = attr_x , attr_y
177173 self .update_attr ()
178174
179175 def update_attr (self ):
@@ -205,15 +201,15 @@ def resolve_shown_attributes(self):
205201 self .attr_box .setEnabled (True )
206202 if not self .input_features : # None or empty
207203 return
208- features = [f for f in self .input_features if f in self .attrs ]
204+ features = [f for f in self .input_features if f in self .domain_model ]
209205 if not features :
210206 self .warning (
211207 "Features from the input signal are not present in the data" )
212208 return
213- old_attrs = self .attrX , self .attrY
214- self .attrX , self .attrY = [f . name for f in (features * 2 )[:2 ]]
209+ old_attrs = self .attr_x , self .attr_y
210+ self .attr_x , self .attr_y = [f for f in (features * 2 )[:2 ]]
215211 self .attr_box .setEnabled (False )
216- if (self .attrX , self .attrY ) != old_attrs :
212+ if (self .attr_x , self .attr_y ) != old_attrs :
217213 self .selection = set ()
218214 self .update_graph ()
219215
@@ -254,8 +250,8 @@ def update_selection(self):
254250 val_x , val_y = area .value_pair
255251 filts .append (
256252 filter .Values ([
257- filter .FilterDiscrete (self .attrX , [val_x ]),
258- filter .FilterDiscrete (self .attrY , [val_y ])
253+ filter .FilterDiscrete (self .attr_x . name , [val_x ]),
254+ filter .FilterDiscrete (self .attr_y . name , [val_y ])
259255 ]))
260256 else :
261257 width = 1
@@ -344,22 +340,22 @@ def make_tooltip():
344340 """Create the tooltip. The function uses local variables from
345341 the enclosing scope."""
346342 # pylint: disable=undefined-loop-variable
347- def _oper (attr_name , txt ):
348- if self .data .domain [attr_name ] is ddomain [attr_name ]:
343+ def _oper (attr , txt ):
344+ if self .data .domain [attr . name ] is ddomain [attr . name ]:
349345 return "="
350346 return " " if txt [0 ] in "<≥" else " in "
351347
352348 return (
353- "<b>{attrX }{xeq}{xval_name}</b>: {obs_x}/{n} ({p_x:.0f} %)" .
354- format (attrX = to_html (attr_x ),
349+ "<b>{attr_x }{xeq}{xval_name}</b>: {obs_x}/{n} ({p_x:.0f} %)" .
350+ format (attr_x = to_html (attr_x . name ),
355351 xeq = _oper (attr_x , xval_name ),
356352 xval_name = to_html (xval_name ),
357353 obs_x = fmt (chi .probs_x [x ] * n ),
358354 n = int (n ),
359355 p_x = 100 * chi .probs_x [x ]) +
360356 "<br/>" +
361- "<b>{attrY }{yeq}{yval_name}</b>: {obs_y}/{n} ({p_y:.0f} %)" .
362- format (attrY = to_html (attr_y ),
357+ "<b>{attr_y }{yeq}{yval_name}</b>: {obs_y}/{n} ({p_y:.0f} %)" .
358+ format (attr_y = to_html (attr_y . name ),
363359 yeq = _oper (attr_y , yval_name ),
364360 yval_name = to_html (yval_name ),
365361 obs_y = fmt (chi .probs_y [y ] * n ),
@@ -377,19 +373,19 @@ def _oper(attr_name, txt):
377373 for item in self .canvas .items ():
378374 self .canvas .removeItem (item )
379375 if self .data is None or len (self .data ) == 0 or \
380- self .attrX is None or self .attrY is None :
376+ self .attr_x is None or self .attr_y is None :
381377 return
382378
383379 ddomain = self .discrete_data .domain
384- attr_x , attr_y = self .attrX , self .attrY
385- disc_x , disc_y = ddomain [attr_x ], ddomain [attr_y ]
380+ attr_x , attr_y = self .attr_x , self .attr_y
381+ disc_x , disc_y = ddomain [attr_x . name ], ddomain [attr_y . name ]
386382 view = self .canvasView
387383
388- chi = ChiSqStats (self .discrete_data , attr_x , attr_y )
384+ chi = ChiSqStats (self .discrete_data , disc_x , disc_y )
389385 n = chi .n
390386 max_ylabel_w = max ((width (val ) for val in disc_y .values ), default = 0 )
391387 max_ylabel_w = min (max_ylabel_w , 200 )
392- x_off = width (attr_x ) + max_ylabel_w
388+ x_off = width (attr_x . name ) + max_ylabel_w
393389 y_off = 15
394390 square_size = min (view .width () - x_off - 35 , view .height () - y_off - 50 )
395391 square_size = max (square_size , 10 )
@@ -431,9 +427,9 @@ def _oper(attr_name, txt):
431427 curr_x += width
432428
433429 bottom = y_off + square_size + max_xlabel_h
434- text (attr_y , 0 , y_off + square_size / 2 ,
430+ text (attr_y . name , 0 , y_off + square_size / 2 ,
435431 Qt .AlignLeft | Qt .AlignVCenter , bold = True , vertical = True )
436- text (attr_x , x_off + square_size / 2 , bottom ,
432+ text (attr_x . name , x_off + square_size / 2 , bottom ,
437433 Qt .AlignHCenter | Qt .AlignTop , bold = True )
438434 xl = text ("χ²={:.2f}, p={:.3f}" .format (chi .chisq , chi .p ),
439435 0 , bottom )
@@ -442,7 +438,7 @@ def _oper(attr_name, txt):
442438
443439 def get_widget_name_extension (self ):
444440 if self .data is not None :
445- return "{} vs {}" .format (self .attrX , self .attrY )
441+ return "{} vs {}" .format (self .attr_x . name , self .attr_y . name )
446442
447443 def send_report (self ):
448444 self .report_plot ()
0 commit comments