source: orange/Orange/data/preprocess/scaling.py @ 11633:64a2f4b224ea

Revision 11633:64a2f4b224ea, 83.3 KB checked in by Ales Erjavec <ales.erjavec@…>, 9 months ago (diff)

Fixed 'ScaleLinProjData.create_projection_as_numeric_array' (again).

Two calls to jitter_array with the same seed resulted in jittering
applied only to the y=x direction.

Line 
1"""
2.. index:: data scaling
3
4.. index::
5   single: scaling
6
7**************************
8Data Scaling (``scaling``)
9**************************
10
11This module is a conglomerate of Orange 2.0 modules orngScaleData,
12orngScaleLinProjData, orngScaleLinProjData3D, orngScalePolyvizData and orngScaleScatterPlotData. The
13documentation is poor and has to be improved in the future.
14
15.. autoclass:: Orange.data.preprocess.scaling.ScaleData
16   :members:
17   :show-inheritance:
18
19.. autoclass:: Orange.data.preprocess.scaling.ScaleLinProjData
20   :members:
21   :show-inheritance:
22
23.. autoclass:: Orange.data.preprocess.scaling.ScaleLinProjData3D
24   :members:
25   :show-inheritance:
26
27.. autoclass:: Orange.data.preprocess.scaling.ScalePolyvizData
28   :members:
29   :show-inheritance:
30
31.. autoclass:: Orange.data.preprocess.scaling.ScaleScatterPlotData
32   :members:
33   :show-inheritance:
34
35.. autofunction:: get_variable_values_sorted
36
37.. autofunction:: get_variable_value_indices
38
39.. autofunction:: discretize_domain
40
41"""
42
43
44import sys
45import numpy
46import random
47import time
48try:
49    import numpy.ma as MA
50except:
51    import numpy.core.ma as MA
52from copy import copy
53from math import sqrt
54import math
55
56import Orange
57import Orange.core
58import Orange.data
59from Orange.data import preprocess
60
61from Orange.utils import caching
62
63import warnings
64
65from Orange.utils import deprecated_keywords, deprecated_members
66
67def get_variable_values_sorted(variable):
68    """
69    Return a list of sorted values for given attribute.
70   
71    EXPLANATION: if variable values have values 1, 2, 3, 4, ... then their
72    order in orange depends on when they appear first in the data. With this
73    function we get a sorted list of values.
74   
75    """
76    if variable.var_type == Orange.core.VarTypes.Continuous:
77        print "get_variable_values_sorted - attribute %s is a continuous variable" % variable
78        return []
79
80    values = list(variable.values)
81    int_values = []
82
83    # do all attribute values containt integers?
84    try:
85        int_values = [(int(val), val) for val in values]
86    except ValueError:
87        return values
88
89    # if all values were intergers, we first sort them ascendently
90    int_values.sort()
91    return [val[1] for val in int_values]
92
93@deprecated_keywords({"sortValuesForDiscreteAttrs":
94                      "sort_values_for_discrete_attrs"})
95def get_variable_value_indices(variable, sort_values_for_discrete_attrs=1):
96    """
97    Create a dictionary with given variable. Keys are variable values, values
98    are indices (transformed from string to int); in case all values are
99    integers, we also sort them.
100   
101    """
102    if variable.var_type == Orange.core.VarTypes.Continuous:
103        print "get_variable_value_indices - attribute %s is a continuous "\
104              "variable" % (str(variable))
105        return {}
106
107    if sort_values_for_discrete_attrs:
108        values = get_variable_values_sorted(variable)
109    else:
110        values = list(variable.values)
111    return dict([(values[i], i) for i in range(len(values))])
112
113
114@deprecated_keywords({"removeUnusedValues": "remove_unused_values",
115                      "numberOfIntervals": "number_of_intervals"})
116def discretize_domain(data, remove_unused_values = 1, number_of_intervals = 2):
117    """
118    Discretize the domain. If we have a class, remove the instances with missing
119    class value, discretize the continuous class into discrete class with two
120    values, discretize continuous attributes using entropy discretization (or
121    equiN if we don't have a class or class is continuous).
122    """
123    entro_disc = preprocess.EntropyDiscretization()
124    equi_disc  = preprocess.EquiNDiscretization(number_of_intervals=number_of_intervals)
125    disc_attrs = []
126
127    classname = (data and len(data) > 0 and data.domain.class_var and
128                 data.domain.class_var.name or None)
129
130    if not data or len(data) == 0:
131        return None
132
133    # if we have a continuous class we have to discretize it before we can
134    # discretize the attributes
135    if classname and data.domain.class_var.var_type == \
136                     Orange.core.VarTypes.Continuous:
137        try:
138            newclass = equi_disc(data.domain.class_var.name, data)
139            newclass.name = classname
140        except Orange.core.KernelException, ex:
141            warnings.warn("Could not discretize class variable '%s'. %s" %
142                          (data.domain.class_var.name, ex.message))
143            newclass = None
144            classname = None
145        new_domain = Orange.data.Domain(data.domain.attributes, newclass)
146        data = Orange.data.Table(new_domain, data)
147
148    for attr in data.domain.attributes:
149        try:
150            name = attr.name
151            if attr.var_type == Orange.core.VarTypes.Continuous:
152                # if continuous attribute then use entropy discretization
153                if data.domain.class_var and data.domain.class_var.var_type == \
154                   Orange.core.VarTypes.Discrete:
155                    new_attr = entro_disc(attr, data)
156                else:
157                    new_attr = equi_disc(attr, data)
158            else:
159                new_attr = attr
160            if remove_unused_values:
161                new_attr = preprocess.RemoveUnusedValues(new_attr, data)
162                if new_attr is None:
163                    raise Orange.core.KernelException, "No values"
164           
165            new_attr.name = name
166            disc_attrs.append(new_attr)
167        except Orange.core.KernelException, ex:
168            # if all values are missing, entropy discretization will throw an
169            # exception. in such cases ignore the attribute
170            warnings.warn("Could not discretize %s attribute. %s" %
171                          (attr.name, ex.message))
172
173    if classname: disc_attrs.append(data.domain.class_var)
174    d2 = data.translate(disc_attrs, True)
175    return d2
176
177
178class ScaleData:
179    def __init__(self):
180        self.raw_data = None           # input data
181        self.raw_subset_data = None
182        self.attribute_names = []    # list of attribute names from self.raw_data
183        self.attribute_name_index = {}  # dict with indices to attributes
184        self.attribute_flip_info = {}   # dictionary with attrName: 0/1 attribute is flipped or not
185       
186        self.data_has_class = False
187        self.data_has_continuous_class = False
188        self.data_has_discrete_class = False
189        self.data_class_name = None
190        self.data_domain = None
191        self.data_class_index = None
192        self.have_data = False
193        self.have_subset_data = False
194
195        self.jitter_size = 10
196        self.jitter_continuous = 0
197        self.jitter_seed = 0
198
199        self.attr_values = {}
200        self.domain_data_stat = []
201        self.original_data = self.original_subset_data = None    # input (nonscaled) data in a numpy array
202        self.scaled_data = self.scaled_subset_data = None        # scaled data to the interval 0-1
203        self.no_jittering_scaled_data = self.no_jittering_scaled_subset_data = None
204        self.valid_data_array = self.valid_subset_data_array = None
205
206    @deprecated_keywords({"subsetData": "subset_data"})
207    def merge_data_sets(self, data, subset_data):
208        """
209        Take examples from data and subset_data and merge them into one
210        dataset.
211       
212        """
213        if data == None and subset_data == None: None
214        if subset_data == None:
215            full_data = data
216        elif data == None:
217            full_data = subset_data
218        else:
219            full_data = Orange.data.Table(data)
220            full_data.extend(subset_data)
221        return full_data
222   
223    mergeDataSets = merge_data_sets
224
225    def rescale_data(self):
226        """
227        Force the existing data to be rescaled due to changes like
228        jitter_continuous, jitter_size, ...
229        """
230        self.set_data(self.raw_data, self.raw_subset_data, skipIfSame = 0)
231   
232    rescaleData = rescale_data
233
234    @deprecated_keywords({"subsetData": "subset_data",
235                          "sortValuesForDiscreteAttrs":
236                          "sort_values_for_discrete_attrs"})
237    def set_data(self, data, subset_data = None, **args):
238        if args.get("skipIfSame", 1):
239            if (((data == None and self.raw_data == None) or
240                (self.raw_data != None and data != None and
241                 self.raw_data.checksum() == data.checksum())) and
242                ((subset_data == None and self.raw_subset_data == None) or
243                 (self.raw_subset_data != None and subset_data != None and
244                  self.raw_subset_data.checksum() == subset_data.checksum()))):
245                    return
246
247        self.domain_data_stat = []
248        self.attr_values = {}
249        self.original_data = self.original_subset_data = None
250        self.scaled_data = self.scaled_subset_data = None
251        self.no_jittering_scaled_data = self.no_jittering_scaled_subset_data = None
252        self.valid_data_array = self.valid_subset_data_array = None
253
254        self.raw_data = None
255        self.raw_subset_data = None
256        self.have_data = False
257        self.have_subset_data = False
258        self.data_has_class = False
259        self.data_has_continuous_class = False
260        self.data_has_discrete_class = False
261        self.data_class_name = None
262        self.data_domain = None
263        self.data_class_index = None
264               
265        if data == None: return
266        full_data = self.merge_data_sets(data, subset_data)
267               
268        self.raw_data = data
269        self.raw_subset_data = subset_data
270
271        len_data = data and len(data) or 0
272
273        self.attribute_names = [attr.name for attr in full_data.domain]
274        self.attribute_name_index = dict([(full_data.domain[i].name, i)
275                                          for i in range(len(full_data.domain))])
276        self.attribute_flip_info = {}         # dict([(attr.name, 0) for attr in full_data.domain]) # reset the fliping information
277       
278        self.data_domain = full_data.domain
279        self.data_has_class = bool(full_data.domain.class_var)
280        self.data_has_continuous_class = bool(self.data_has_class and
281                                              full_data.domain.class_var.var_type == Orange.core.VarTypes.Continuous)
282        self.data_has_discrete_class = bool(self.data_has_class and
283                                            full_data.domain.class_var.var_type == Orange.core.VarTypes.Discrete)
284        self.data_class_name = self.data_has_class and full_data.domain.class_var.name
285        if self.data_has_class:
286            self.data_class_index = self.attribute_name_index[self.data_class_name]
287        self.have_data = bool(self.raw_data and len(self.raw_data) > 0)
288        self.have_subset_data = bool(self.raw_subset_data and
289                                     len(self.raw_subset_data) > 0)
290       
291        self.domain_data_stat = caching.getCached(full_data,
292                                          Orange.core.DomainBasicAttrStat,
293                                          (full_data,))
294
295        sort_values_for_discrete_attrs = args.get("sort_values_for_discrete_attrs",
296                                                  1)
297
298        for index in range(len(full_data.domain)):
299            attr = full_data.domain[index]
300            if attr.var_type == Orange.core.VarTypes.Discrete:
301                self.attr_values[attr.name] = [0, len(attr.values)]
302            elif attr.var_type == Orange.core.VarTypes.Continuous:
303                self.attr_values[attr.name] = [self.domain_data_stat[index].min,
304                                               self.domain_data_stat[index].max]
305       
306        # the original_data, no_jittering_scaled_data and validArray are arrays
307        # that we can cache so that other visualization widgets don't need to
308        # compute it. The scaled_data on the other hand has to be computed for
309        # each widget separately because of different
310        # jitter_continuous and jitter_size values
311        if caching.getCached(data, "visualizationData") and subset_data == None:
312            self.original_data, self.no_jittering_scaled_data, self.valid_data_array = caching.getCached(data,"visualizationData")
313            self.original_subset_data = self.no_jittering_scaled_subset_data = self.valid_subset_data_array = numpy.array([]).reshape([len(self.original_data), 0])
314        else:
315            no_jittering_data = full_data.toNumpyMA("ac")[0].T
316            valid_data_array = numpy.array(1-no_jittering_data.mask,
317                                           numpy.short)  # have to convert to int array, otherwise when we do some operations on this array we get overflow
318            no_jittering_data = numpy.array(MA.filled(no_jittering_data,
319                                                      Orange.core.Illegal_Float))
320            original_data = no_jittering_data.copy()
321           
322            for index in range(len(data.domain)):
323                attr = data.domain[index]
324                if attr.var_type == Orange.core.VarTypes.Discrete:
325                    # see if the values for discrete attributes have to be resorted
326                    variable_value_indices = get_variable_value_indices(data.domain[index],
327                                                                        sort_values_for_discrete_attrs)
328                    if 0 in [i == variable_value_indices[attr.values[i]]
329                             for i in range(len(attr.values))]:
330                        # make the array a contiguous, otherwise the putmask
331                        # function does not work
332                        line = no_jittering_data[index].copy()
333                        indices = [numpy.where(line == val, 1, 0)
334                                   for val in range(len(attr.values))]
335                        for i in range(len(attr.values)):
336                            numpy.putmask(line, indices[i],
337                                          variable_value_indices[attr.values[i]])
338                        no_jittering_data[index] = line   # save the changed array
339                        original_data[index] = line     # reorder also the values in the original data
340                    no_jittering_data[index] = ((no_jittering_data[index]*2.0 + 1.0)
341                                                / float(2*len(attr.values)))
342                   
343                elif attr.var_type == Orange.core.VarTypes.Continuous:
344                    diff = self.domain_data_stat[index].max - self.domain_data_stat[index].min or 1     # if all values are the same then prevent division by zero
345                    no_jittering_data[index] = (no_jittering_data[index] -
346                                                self.domain_data_stat[index].min) / diff
347
348            self.original_data = original_data[:,:len_data]; self.original_subset_data = original_data[:,len_data:]
349            self.no_jittering_scaled_data = no_jittering_data[:,:len_data]; self.no_jittering_scaled_subset_data = no_jittering_data[:,len_data:]
350            self.valid_data_array = valid_data_array[:,:len_data]; self.valid_subset_data_array = valid_data_array[:,len_data:]
351       
352        if data: caching.setCached(data, "visualizationData",
353                           (self.original_data, self.no_jittering_scaled_data,
354                            self.valid_data_array))
355        if subset_data: caching.setCached(subset_data, "visualizationData",
356                                  (self.original_subset_data,
357                                   self.no_jittering_scaled_subset_data,
358                                   self.valid_subset_data_array))
359           
360        # compute the scaled_data arrays
361        scaled_data = numpy.concatenate([self.no_jittering_scaled_data,
362                                         self.no_jittering_scaled_subset_data],
363                                         axis = 1)
364
365        # Random generators for jittering
366        random = numpy.random.RandomState(seed=self.jitter_seed)
367        rand_seeds = random.random_integers(0, sys.maxint - 1, size=len(data.domain))
368        for index, rseed in zip(range(len(data.domain)), rand_seeds):
369            # Need to use a different seed for each feature
370            random = numpy.random.RandomState(seed=rseed)
371            attr = data.domain[index]
372            if attr.var_type == Orange.core.VarTypes.Discrete:
373                scaled_data[index] += (self.jitter_size/(50.0*max(1,len(attr.values))))*\
374                                      (random.rand(len(full_data)) - 0.5)
375               
376            elif attr.var_type == Orange.core.VarTypes.Continuous and self.jitter_continuous:
377                scaled_data[index] += self.jitter_size/50.0 * (0.5 - random.rand(len(full_data)))
378                scaled_data[index] = numpy.absolute(scaled_data[index])       # fix values below zero
379                ind = numpy.where(scaled_data[index] > 1.0, 1, 0)     # fix values above 1
380                numpy.putmask(scaled_data[index], ind, 2.0 - numpy.compress(ind, scaled_data[index]))
381
382        if self.have_subset_data:
383            # Fix all subset instances which are also in the main data
384            # to have the same jittered values
385            ids_to_indices = dict((inst.id, i) \
386                                  for i, inst in enumerate(self.raw_data))
387
388            subset_ids_map = [[i, ids_to_indices[s.id]] \
389                               for i, s in enumerate(self.raw_subset_data)\
390                               if s.id in ids_to_indices]
391            if len(subset_ids_map):
392                subset_ids_map = numpy.array(subset_ids_map)
393                subset_ids_map[:, 0] += len_data
394                scaled_data[:, subset_ids_map[:, 0]] = \
395                        scaled_data[:, subset_ids_map[:, 1]]
396
397        self.scaled_data = scaled_data[:,:len_data]; self.scaled_subset_data = scaled_data[:,len_data:]
398   
399    setData = set_data
400
401    @deprecated_keywords({"example": "instance"})
402    def scale_example_value(self, instance, index):
403        """
404        Scale instance's value at index index to a range between 0 and 1 with
405        respect to self.raw_data.
406        """
407        if instance[index].isSpecial():
408            print "Warning: scaling instance with missing value"
409            return 0.5     #1e20
410        if instance.domain[index].var_type == Orange.core.VarTypes.Discrete:
411            d = get_variable_value_indices(instance.domain[index])
412            return (d[instance[index].value]*2 + 1) / float(2*len(d))
413        elif instance.domain[index].var_type == Orange.core.VarTypes.Continuous:
414            diff = self.domain_data_stat[index].max - self.domain_data_stat[index].min
415            if diff == 0: diff = 1          # if all values are the same then prevent division by zero
416            return (instance[index] - self.domain_data_stat[index].min) / diff
417
418    scaleExampleValue = scale_example_value
419
420    @deprecated_keywords({"attrName": "attr_name"})
421    def get_attribute_label(self, attr_name):
422        if self.attribute_flip_info.get(attr_name, 0) and self.data_domain[attr_name].var_type == Orange.core.VarTypes.Continuous:
423            return "-" + attr_name
424        return attr_name
425   
426    getAttributeLabel = get_attribute_label
427
428    @deprecated_keywords({"attrName": "attr_name"})
429    def flip_attribute(self, attr_name):
430        if attr_name not in self.attribute_names: return 0
431        if self.data_domain[attr_name].var_type == Orange.core.VarTypes.Discrete: return 0
432
433        index = self.attribute_name_index[attr_name]
434        self.attribute_flip_info[attr_name] = 1 - self.attribute_flip_info.get(attr_name, 0)
435        if self.data_domain[attr_name].var_type == Orange.core.VarTypes.Continuous:
436            self.attr_values[attr_name] = [-self.attr_values[attr_name][1], -self.attr_values[attr_name][0]]
437
438        self.scaled_data[index] = 1 - self.scaled_data[index]
439        self.scaled_subset_data[index] = 1 - self.scaled_subset_data[index]
440        self.no_jittering_scaled_data[index] = 1 - self.no_jittering_scaled_data[index]
441        self.no_jittering_scaled_subset_data[index] = 1 - self.no_jittering_scaled_subset_data[index]
442        return 1
443
444    flipAttribute = flip_attribute
445   
446    def get_min_max_val(self, attr):
447        if type(attr) == int:
448            attr = self.attribute_names[attr]
449        diff = self.attr_values[attr][1] - self.attr_values[attr][0]
450        return diff or 1.0
451
452    getMinMaxVal = get_min_max_val
453
454    @deprecated_keywords({"alsoClassIfExists": "also_class_if_exists"})
455    def get_valid_list(self, indices, also_class_if_exists = 1):
456        """
457        Get array of 0 and 1 of len = len(self.raw_data). If there is a missing
458        value at any attribute in indices return 0 for that instance.
459        """
460        if self.valid_data_array == None or len(self.valid_data_array) == 0:
461            return numpy.array([], numpy.bool)
462       
463        inds = indices[:]
464        if also_class_if_exists and self.data_has_class: 
465            inds.append(self.data_class_index) 
466        selected_array = self.valid_data_array.take(inds, axis = 0)
467        arr = numpy.add.reduce(selected_array)
468        return numpy.equal(arr, len(inds))
469   
470    getValidList = get_valid_list
471
472    @deprecated_keywords({"alsoClassIfExists": "also_class_if_exists"})
473    def get_valid_subset_list(self, indices, also_class_if_exists = 1):
474        """
475        Get array of 0 and 1 of len = len(self.raw_subset_data). if there is a
476        missing value at any attribute in indices return 0 for that instance.
477        """
478        if self.valid_subset_data_array == None or len(self.valid_subset_data_array) == 0:
479            return numpy.array([], numpy.bool)
480        inds = indices[:]
481        if also_class_if_exists and self.data_class_index: 
482            inds.append(self.data_class_index)
483        selected_array = self.valid_subset_data_array.take(inds, axis = 0)
484        arr = numpy.add.reduce(selected_array)
485        return numpy.equal(arr, len(inds))
486   
487    getValidSubsetList = get_valid_subset_list
488
489    def get_valid_indices(self, indices):
490        """
491        Get array with numbers that represent the instance indices that have a
492        valid data value.
493        """
494        valid_list = self.get_valid_list(indices)
495        return numpy.nonzero(valid_list)[0]
496   
497    getValidIndices = get_valid_indices
498
499    def get_valid_subset_indices(self, indices):
500        """
501        Get array with numbers that represent the instance indices that have a
502        valid data value.
503        """
504        valid_list = self.get_valid_subset_list(indices)
505        return numpy.nonzero(valid_list)[0]
506   
507    getValidSubsetIndices = get_valid_subset_indices
508
509    def rnd_correction(self, max):
510        """
511        Return a number from -max to max.
512        """
513        return (random.random() - 0.5)*2*max
514   
515    rndCorrection = rnd_correction
516
517ScaleData = deprecated_members({"rawData": "raw_data",
518                                "rawSubsetData": "raw_subset_data",
519                                "attributeNames": "attribute_names",
520                                "attributeNameIndex": "attribute_name_index",
521                                "attributeFlipInfo": "attribute_flip_info",
522                                "dataHasClass": "data_has_class",
523                                "dataHasContinuousClass": "data_has_continuous_class",
524                                "dataHasDiscreteClass": "data_has_discrete_class",
525                                "dataClassName": "data_class_name",
526                                "dataDomain": "data_domain",
527                                "dataClassIndex": "data_class_index",
528                                "haveData": "have_data",
529                                "haveSubsetData": "have_subset_data",
530                                "jitterSize": "jitter_size",
531                                "jitterContinuous": "jitter_continuous",
532                                "attrValues": "attr_values",
533                                "domainDataStat": "domain_data_stat",
534                                "originalData": "original_data",
535                                "originalSubsetData": "original_subset_data",
536                                "scaledData": "scaled_data",
537                                "scaledSubsetData": "scaled_subset_data",
538                                "noJitteringScaledData": "no_jittering_scaled_data",
539                                "noJitteringScaledSubsetData": "no_jittering_scaled_subset_data",
540                                "validDataArray": "valid_data_array",
541                                "validSubsetDataArray": "valid_subset_data_array",
542                                "mergeDataSets": "merge_data_sets",
543                                "rescaleData": "rescale_data",
544                                "setData": "set_data",
545                                "scaleExampleValue": "scale_example_value",
546                                "getAttributeLabel": "get_attribute_label",
547                                "flipAttribute": "flip_attribute",
548                                "getMinMaxVal": "get_min_max_val",
549                                "getValidList": "get_valid_list",
550                                "getValidSubsetList": "get_valid_subset_list",
551                                "getValidIndices": "get_valid_indices",
552                                "getValidSubsetIndices": "get_valid_subset_indices",
553                                "rndCorrection": "rnd_correction",
554                                })(ScaleData)
555
556
557def jitter_array(array, ratio=0.01, axis=0, rand_seed=None):
558    """
559    """
560    array = numpy.array(array)
561    shape = array.shape
562
563    if array.ndim == 1:
564        if axis != 0:
565            raise ValueError("Invalid axis")
566        array = array.reshape((-1, 1))
567
568    if array.ndim > 2:
569        raise ValueError("'array' must be at most 2 dimensional.")
570
571    axis_min = array.min(axis=axis)
572    axis_max = array.max(axis=axis)
573    axis_span = axis_max - axis_min
574
575    # roll axis to front
576    array = numpy.rollaxis(array, axis, 0)
577
578    random = numpy.random.RandomState(rand_seed)
579    for i, span in enumerate(axis_span):
580        array[:, i] += random.uniform(-ratio * span / 2, ratio * span / 2,
581                                      array.shape[0])
582
583    # roll axis back to its original position
584    array = numpy.rollaxis(array, 0, axis + 1)
585    array = array.reshape(shape)
586    return array
587
588
589class ScaleLinProjData(ScaleData):
590    def __init__(self):
591        ScaleData.__init__(self)
592        self.normalize_examples = 1
593        self.anchor_data =[]        # form: [(anchor1x, anchor1y, label1),(anchor2x, anchor2y, label2), ...]
594        self.last_attr_indices = None
595        self.anchor_dict = {}
596
597    @deprecated_keywords({"xAnchors": "xanchors", "yAnchors": "yanchors"})
598    def set_anchors(self, xanchors, yanchors, attributes):
599        if attributes:
600            if xanchors != None and yanchors != None:
601                self.anchor_data = [(xanchors[i], yanchors[i], attributes[i])
602                                    for i in range(len(attributes))]
603            else:
604                self.anchor_data = self.create_anchors(len(attributes), attributes)
605   
606    setAnchors = set_anchors
607
608    @deprecated_keywords({"numOfAttr": "num_of_attr"})
609    def create_anchors(self, num_of_attr, labels = None):
610        """
611        Create anchors around the circle.
612       
613        """
614        xanchors = self.create_xanchors(num_of_attr)
615        yanchors = self.create_yanchors(num_of_attr)
616        if labels:
617            return [(xanchors[i], yanchors[i], labels[i]) for i in range(num_of_attr)]
618        else:
619            return [(xanchors[i], yanchors[i]) for i in range(num_of_attr)]
620   
621    createAnchors = create_anchors
622
623    @deprecated_keywords({"numOfAttrs": "num_of_attrs"})
624    def create_xanchors(self, num_of_attrs):
625        if not self.anchor_dict.has_key(num_of_attrs):
626            self.anchor_dict[num_of_attrs] = (numpy.cos(numpy.arange(num_of_attrs)
627                                                        * 2*math.pi
628                                                        / float(num_of_attrs)),
629                                              numpy.sin(numpy.arange(num_of_attrs)
630                                                        * 2*math.pi
631                                                        / float(num_of_attrs)))
632        return self.anchor_dict[num_of_attrs][0]
633   
634    createXAnchors = create_xanchors
635
636    @deprecated_keywords({"numOfAttrs": "num_of_attrs"})
637    def create_yanchors(self, num_of_attrs):
638        if not self.anchor_dict.has_key(num_of_attrs):
639            self.anchor_dict[num_of_attrs] = (numpy.cos(numpy.arange(num_of_attrs)
640                                                        * 2*math.pi
641                                                        / float(num_of_attrs)),
642                                              numpy.sin(numpy.arange(num_of_attrs)
643                                                        * 2*math.pi
644                                                        / float(num_of_attrs)))
645        return self.anchor_dict[num_of_attrs][1]
646
647    createYAnchors = create_yanchors
648
649    @deprecated_keywords({"fileName": "filename", "attrList": "attrlist",
650                          "useAnchorData": "use_anchor_data"})
651    def save_projection_as_tab_data(self, filename, attrlist, use_anchor_data = 0):
652        """
653        Save projection (xattr, yattr, classval) into a filename filename.
654       
655        """
656        Orange.core.saveTabDelimited(filename,
657            self.create_projection_as_example_table([self.attribute_name_index[i]
658                                                     for i in attrlist],
659                                                    use_anchor_data = use_anchor_data))
660   
661    saveProjectionAsTabData = save_projection_as_tab_data
662
663    @deprecated_keywords({"attrIndices": "attr_indices",
664                          "settingsDict": "settings_dict",
665                          "useAnchorData": "use_anchor_data",
666                          "xAnchors": "xanchors",
667                          "yAnchors": "yanchors",
668                          "anchorRadius": "anchor_radius",
669                          "normalizeExample": "normalize_example"
670                          })
671    def get_projected_point_position(self, attr_indices, values, **settings_dict):
672        """
673        For attributes in attr_indices and values of these attributes in values
674        compute point positions. This function has more sense in radviz and
675        polyviz methods.
676   
677        """
678        # load the elements from the settings dict
679        use_anchor_data = settings_dict.get("use_anchor_data")
680        xanchors = settings_dict.get("x_anchors")
681        yanchors = settings_dict.get("y_anchors")
682        anchor_radius = settings_dict.get("anchor_radius")
683        normalize_example = settings_dict.get("normalize_example")
684
685        if attr_indices != self.last_attr_indices:
686            print "get_projected_point_position. Warning: Possible bug. The "+\
687                  "set of attributes is not the same as when computing the "+\
688                  "whole projection"
689
690        if xanchors != None and yanchors != None:
691            xanchors = numpy.array(xanchors)
692            yanchors = numpy.array(yanchors)
693            if anchor_radius == None: anchor_radius = numpy.sqrt(xanchors*xanchors +
694                                                                 yanchors*yanchors)
695        elif use_anchor_data and self.anchor_data:
696            xanchors = numpy.array([val[0] for val in self.anchor_data])
697            yanchors = numpy.array([val[1] for val in self.anchor_data])
698            if anchor_radius == None: anchor_radius = numpy.sqrt(xanchors*xanchors +
699                                                                 yanchors*yanchors)
700        else:
701            xanchors = self.create_xanchors(len(attr_indices))
702            yanchors = self.create_yanchors(len(attr_indices))
703            anchor_radius = numpy.ones(len(attr_indices), numpy.float)
704
705        if normalize_example == 1 or (normalize_example == None
706                                      and self.normalize_examples):
707            m = min(values); M = max(values)
708            if m < 0.0 or M > 1.0: 
709                # we have to do rescaling of values so that all the values will
710                # be in the 0-1 interval
711                #print "example values are not in the 0-1 interval"
712                values = [max(0.0, min(val, 1.0)) for val in values]
713                #m = min(m, 0.0); M = max(M, 1.0); diff = max(M-m, 1e-10)
714                #values = [(val-m) / float(diff) for val in values]
715
716            s = sum(numpy.array(values)*anchor_radius)
717            if s == 0: return [0.0, 0.0]
718            x = self.trueScaleFactor * numpy.dot(xanchors*anchor_radius,
719                                                 values) / float(s)
720            y = self.trueScaleFactor * numpy.dot(yanchors*anchor_radius,
721                                                 values) / float(s)
722        else:
723            x = self.trueScaleFactor * numpy.dot(xanchors, values)
724            y = self.trueScaleFactor * numpy.dot(yanchors, values)
725
726        return [x, y]
727   
728    getProjectedPointPosition = get_projected_point_position
729
730    @deprecated_keywords({"attrIndices": "attr_indices",
731                          "settingsDict": "settings_dict"})
732    def create_projection_as_example_table(self, attr_indices, **settings_dict):
733        """
734        Create the projection of attribute indices given in attr_indices and
735        create an example table with it.
736        """
737        if self.data_domain.class_var:
738            domain = settings_dict.get("domain") or \
739                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
740                                         Orange.feature.Continuous("yVar"),
741                                         Orange.feature.Discrete(self.data_domain.class_var.name,
742                                                                       values = get_variable_values_sorted(self.data_domain.class_var))])
743        else:
744            domain = settings_dict.get("domain") or \
745                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
746                                         Orange.feature.Continuous("yVar")])
747        data = self.create_projection_as_numeric_array(attr_indices,
748                                                       **settings_dict)
749        if data != None:
750            return Orange.data.Table(domain, data)
751        else:
752            return Orange.data.Table(domain)
753
754    createProjectionAsExampleTable = create_projection_as_example_table
755
756    @deprecated_keywords({"attrIndices": "attr_indices",
757                          "settingsDict": "settings_dict",
758                          "validData": "valid_data",
759                          "classList": "class_list",
760                          "XAnchors": "xanchors",
761                          "YAnchors": "yanchors",
762                          "scaleFactor": "scale_factor",
763                          "jitterSize": "jitter_size",
764                          "useAnchorData": "use_anchor_data",
765                          "removeMissingData": "remove_missing_data",
766                          "useSubsetData": "use_subset_data",
767                          })
768    def create_projection_as_numeric_array(self, attr_indices, **settings_dict):
769        # load the elements from the settings dict
770        valid_data = settings_dict.get("valid_data")
771        class_list = settings_dict.get("class_list")
772        sum_i     = settings_dict.get("sum_i")
773        xanchors = settings_dict.get("xanchors")
774        yanchors = settings_dict.get("yanchors")
775        scale_factor = settings_dict.get("scale_factor", 1.0)
776        normalize = settings_dict.get("normalize")
777        jitter_size = settings_dict.get("jitter_size", 0.0)
778        use_anchor_data = settings_dict.get("use_anchor_data", 0)
779        remove_missing_data = settings_dict.get("remove_missing_data", 1)
780        use_subset_data = settings_dict.get("use_subset_data", 0)        # use the data or subsetData?
781        #minmaxVals = settings_dict.get("minmaxVals", None)
782
783        # if we want to use anchor data we can get attr_indices from the anchor_data
784        if use_anchor_data and self.anchor_data:
785            attr_indices = [self.attribute_name_index[val[2]] for val in self.anchor_data]
786
787        if valid_data == None:
788            if use_subset_data: valid_data = self.get_valid_subset_list(attr_indices)
789            else:             valid_data = self.get_valid_list(attr_indices)
790        if sum(valid_data) == 0:
791            return None
792
793        if class_list == None and self.data_domain.class_var:
794            if use_subset_data: class_list = self.original_subset_data[self.data_class_index]
795            else:             class_list = self.original_data[self.data_class_index]
796
797        # if jitterSize is set below zero we use scaled_data that has already jittered data
798        if use_subset_data:
799            if jitter_size < 0.0: data = self.scaled_subset_data
800            else:                data = self.no_jittering_scaled_subset_data
801        else:
802            if jitter_size < 0.0: data = self.scaled_data
803            else:                data = self.no_jittering_scaled_data
804
805        selectedData = numpy.take(data, attr_indices, axis = 0)
806        if remove_missing_data:
807            selectedData = numpy.compress(valid_data, selectedData, axis = 1)
808            if class_list != None and len(class_list) != numpy.shape(selectedData)[1]:
809                class_list = numpy.compress(valid_data, class_list)
810
811        if use_anchor_data and self.anchor_data:
812            xanchors = numpy.array([val[0] for val in self.anchor_data])
813            yanchors = numpy.array([val[1] for val in self.anchor_data])
814            r = numpy.sqrt(xanchors*xanchors + yanchors*yanchors)     # compute the distance of each anchor from the center of the circle
815            if normalize == 1 or (normalize == None and self.normalize_examples):
816                xanchors *= r
817                yanchors *= r
818        elif (xanchors != None and yanchors != None):
819            xanchors = numpy.array(xanchors); yanchors = numpy.array(yanchors)
820            r = numpy.sqrt(xanchors*xanchors + yanchors*yanchors)     # compute the distance of each anchor from the center of the circle
821        else:
822            xanchors = self.create_xanchors(len(attr_indices))
823            yanchors = self.create_yanchors(len(attr_indices))
824            r = numpy.ones(len(xanchors), numpy.float)
825
826        x_positions = numpy.dot(xanchors, selectedData)
827        y_positions = numpy.dot(yanchors, selectedData)
828
829        if normalize == 1 or (normalize == None and self.normalize_examples):
830            if sum_i == None:
831                sum_i = self._getSum_i(selectedData, use_anchor_data, r)
832            x_positions /= sum_i
833            y_positions /= sum_i
834            self.trueScaleFactor = scale_factor
835        else:
836            if not remove_missing_data:
837                try:
838                    x_valid_data = numpy.compress(valid_data, x_positions)
839                    y_valid_data = numpy.compress(valid_data, y_positions)
840                except:
841                    print valid_data
842                    print x_positions
843                    print numpy.shape(valid_data)
844                    print numpy.shape(x_positions)
845            else:
846                x_valid_data = x_positions
847                y_valid_data = y_positions
848           
849            dist = math.sqrt(max(x_valid_data*x_valid_data + y_valid_data*y_valid_data)) or 1
850            self.trueScaleFactor = scale_factor / dist
851
852        self.unscaled_x_positions = numpy.array(x_positions)
853        self.unscaled_y_positions = numpy.array(y_positions)
854
855        if self.trueScaleFactor != 1.0:
856            x_positions *= self.trueScaleFactor
857            y_positions *= self.trueScaleFactor
858
859        if jitter_size > 0.0:
860            positions = numpy.vstack((x_positions, y_positions))
861            positions = jitter_array(positions, jitter_size / 100., axis=1,
862                                     rand_seed=self.jitter_seed)
863            x_positions, y_positions = numpy.vsplit(positions, 2)
864            x_positions = x_positions.ravel()
865            y_positions = y_positions.ravel()
866
867        self.last_attr_indices = attr_indices
868        if class_list != None:
869            return numpy.transpose(numpy.array((x_positions, y_positions, class_list)))
870        else:
871            return numpy.transpose(numpy.array((x_positions, y_positions)))
872
873    createProjectionAsNumericArray = create_projection_as_numeric_array
874   
875    @deprecated_keywords({"useAnchorData": "use_anchor_data",
876                          "anchorRadius": "anchor_radius"})
877    def _getsum_i(self, data, use_anchor_data = 0, anchor_radius = None):
878        """
879        Function to compute the sum of all values for each element in the data.
880        Used to normalize.
881       
882        """
883        if use_anchor_data:
884            if anchor_radius == None:
885                anchor_radius = numpy.sqrt([a[0]**2+a[1]**2 for a in self.anchor_data])
886            sum_i = numpy.add.reduce(numpy.transpose(numpy.transpose(data)*anchor_radius))
887        else:
888            sum_i = numpy.add.reduce(data)
889        if len(sum_i[numpy.nonzero(sum_i)]) < len(sum_i):    # test if there are zeros in sum_i
890            sum_i += numpy.where(sum_i == 0, 1.0, 0.0)
891        return sum_i
892   
893    _getSum_i = _getsum_i
894
895graph_deprecator = deprecated_members({"setData": "set_data",
896                                       "updateData": "update_data",
897                                       "scaleFactor": "scale_factor"})
898
899ScaleLinProjData = deprecated_members({"setAnchors": "set_anchors",
900                                       "createAnchors": "create_anchors",
901                                       "createXAnchors": "create_xanchors",
902                                       "createYAnchors": "create_yanchors",
903                                       "saveProjectionAsTabData": "save_projection_as_tab_data",
904                                       "getProjectedPointPosition":
905                                           "get_projected_point_position",
906                                       "createProjectionAsExampleTable":
907                                           "create_projection_as_example_table",
908                                       "createProjectionAsNumericArray":
909                                           "create_projection_as_numeric_array",
910                                       "_getSum_i": "_getsum_i",
911                                       "normalizeExamples": "normalize_examples",
912                                       "anchorData": "anchor_data",
913                                       "lastAttrIndices": "last_attr_indices",
914                                       "anchorDict": "anchor_dict"})(ScaleLinProjData)
915
916class ScaleLinProjData3D(ScaleData):
917    def __init__(self):
918        ScaleData.__init__(self)
919        self.normalize_examples = 1
920        self.anchor_data = []        # form: [(anchor1x, anchor1y, anchor1z, label1),(anchor2x, anchor2y, anchor2z, label2), ...]
921        self.last_attr_indices = None
922        self.anchor_dict = {}
923
924    @deprecated_keywords({"xAnchors": "xanchors", "yAnchors": "yanchors"})
925    def set_anchors(self, xanchors, yanchors, zanchors, attributes):
926        if attributes:
927            if xanchors != None and yanchors != None and zanchors != None:
928                self.anchor_data = [(xanchors[i], yanchors[i], zanchors[i], attributes[i])
929                                    for i in range(len(attributes))]
930            else:
931                self.anchor_data = self.create_anchors(len(attributes), attributes)
932
933    setAnchors = set_anchors
934
935    @deprecated_keywords({"numOfAttr": "num_of_attr"})
936    def create_anchors(self, num_of_attrs, labels=None):
937        """
938        Create anchors on the sphere.
939       
940        """
941        # Golden Section Spiral algorithm approximates even distribution of points on a sphere
942        # (read more here http://www.softimageblog.com/archives/115)
943        n = num_of_attrs
944        xanchors = []
945        yanchors = []
946        zanchors = []
947
948        inc = math.pi * (3 - math.sqrt(5))
949        off = 2. / n
950        for k in range(n):
951            y = k * off - 1 + (off / 2)
952            r = math.sqrt(1 - y*y)
953            phi = k * inc
954            xanchors.append(math.cos(phi)*r)
955            yanchors.append(y)
956            zanchors.append(math.sin(phi)*r)
957
958        self.anchor_dict[num_of_attrs] = [xanchors, yanchors, zanchors]
959 
960        if labels:
961            return [(xanchors[i], yanchors[i], zanchors[i], labels[i]) for i in range(num_of_attrs)]
962        else:
963            return [(xanchors[i], yanchors[i], zanchors[i]) for i in range(num_of_attrs)]
964
965    createAnchors = create_anchors
966
967    @deprecated_keywords({"numOfAttrs": "num_of_attrs"})
968    def create_xanchors(self, num_of_attrs):
969        if not self.anchor_dict.has_key(num_of_attrs):
970            self.create_anchors(num_of_attrs)
971        return self.anchor_dict[num_of_attrs][0]
972
973    createXAnchors = create_xanchors
974
975    @deprecated_keywords({"numOfAttrs": "num_of_attrs"})
976    def create_yanchors(self, num_of_attrs):
977        if not self.anchor_dict.has_key(num_of_attrs):
978            self.create_anchors(num_of_attrs)
979        return self.anchor_dict[num_of_attrs][1]
980
981    createYAnchors = create_yanchors
982
983    @deprecated_keywords({"numOfAttrs": "num_of_attrs"})
984    def create_zanchors(self, num_of_attrs):
985        if not self.anchor_dict.has_key(num_of_attrs):
986            self.create_anchors(num_of_attrs)
987        return self.anchor_dict[num_of_attrs][2]
988
989    createZAnchors = create_zanchors
990
991    @deprecated_keywords({"fileName": "filename", "attrList": "attrlist",
992                          "useAnchorData": "use_anchor_data"})
993    def save_projection_as_tab_data(self, filename, attrlist, use_anchor_data=0):
994        """
995        Save projection (xattr, yattr, zattr, classval) into a filename filename.
996       
997        """
998        Orange.core.saveTabDelimited(filename,
999            self.create_projection_as_example_table([self.attribute_name_index[i]
1000                                                     for i in attrlist],
1001                                                    use_anchor_data=use_anchor_data))
1002   
1003    saveProjectionAsTabData = save_projection_as_tab_data
1004
1005    @deprecated_keywords({"attrIndices": "attr_indices",
1006                          "settingsDict": "settings_dict",
1007                          "useAnchorData": "use_anchor_data",
1008                          "xAnchors": "xanchors",
1009                          "yAnchors": "yanchors",
1010                          "zAnchors": "zanchors",
1011                          "anchorRadius": "anchor_radius",
1012                          "normalizeExample": "normalize_example",
1013                          })
1014    def get_projected_point_position(self, attr_indices, values, **settings_dict):
1015        """
1016        For attributes in attr_indices and values of these attributes in values
1017        compute point positions. This function has more sense in radviz and
1018        polyviz methods.
1019   
1020        """
1021        # load the elements from the settings dict
1022        use_anchor_data = settings_dict.get("use_anchor_data")
1023        xanchors = settings_dict.get('xanchors')
1024        yanchors = settings_dict.get('yanchors')
1025        zanchors = settings_dict.get('zanchors')
1026        anchor_radius = settings_dict.get("anchor_radius")
1027        normalize_example = settings_dict.get("normalize_example")
1028
1029        if attr_indices != self.last_attr_indices:
1030            print "get_projected_point_position. Warning: Possible bug. The "+\
1031                  "set of attributes is not the same as when computing the "+\
1032                  "whole projection"
1033
1034        if xanchors != None and yanchors != None and zanchors != None:
1035            xanchors = numpy.array(xanchors)
1036            yanchors = numpy.array(yanchors)
1037            zanchors = numpy.array(zanchors)
1038            if anchor_radius == None: anchor_radius = numpy.sqrt(xanchors*xanchors +
1039                                                                 yanchors*yanchors +
1040                                                                 zanchors*zanchors)
1041        elif use_anchor_data and self.anchor_data:
1042            xanchors = numpy.array([val[0] for val in self.anchor_data])
1043            yanchors = numpy.array([val[1] for val in self.anchor_data])
1044            zanchors = numpy.array([val[2] for val in self.anchor_data])
1045            if anchor_radius == None: anchor_radius = numpy.sqrt(xanchors*xanchors +
1046                                                                 yanchors*yanchors +
1047                                                                 zanchors*zanchors)
1048        else:
1049            self.create_anchors(len(attr_indices))
1050            xanchors = numpy.array([val[0] for val in self.anchor_data])
1051            yanchors = numpy.array([val[1] for val in self.anchor_data])
1052            zanchors = numpy.array([val[2] for val in self.anchor_data])
1053            anchor_radius = numpy.ones(len(attr_indices), numpy.float)
1054
1055        if normalize_example == 1 or (normalize_example == None
1056                                      and self.normalize_examples):
1057            m = min(values); M = max(values)
1058            if m < 0.0 or M > 1.0: 
1059                # we have to do rescaling of values so that all the values will
1060                # be in the 0-1 interval
1061                #print "example values are not in the 0-1 interval"
1062                values = [max(0.0, min(val, 1.0)) for val in values]
1063                #m = min(m, 0.0); M = max(M, 1.0); diff = max(M-m, 1e-10)
1064                #values = [(val-m) / float(diff) for val in values]
1065
1066            s = sum(numpy.array(values)*anchor_radius)
1067            if s == 0: return [0.0, 0.0]
1068            x = self.true_scale_factor * numpy.dot(xanchors*anchor_radius,
1069                                                 values) / float(s)
1070            y = self.true_scale_factor * numpy.dot(yanchors*anchor_radius,
1071                                                 values) / float(s)
1072            z = self.true_scale_factor * numpy.dot(zanchors*anchor_radius,
1073                                                 values) / float(s)
1074        else:
1075            x = self.true_scale_factor * numpy.dot(xanchors, values)
1076            y = self.true_scale_factor * numpy.dot(yanchors, values)
1077            z = self.true_scale_factor * numpy.dot(zanchors, values)
1078
1079        return [x, y, z]
1080
1081    getProjectedPointPosition = get_projected_point_position
1082
1083    @deprecated_keywords({"attrIndices": "attr_indices",
1084                          "settingsDict": "settings_dict"})
1085    def create_projection_as_example_table(self, attr_indices, **settings_dict):
1086        """
1087        Create the projection of attribute indices given in attr_indices and
1088        create an example table with it.
1089        """
1090        if self.data_domain.class_var:
1091            domain = settings_dict.get("domain") or \
1092                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
1093                                         Orange.feature.Continuous("yVar"),
1094                                         Orange.feature.Continuous("zVar"),
1095                                         Orange.feature.Discrete(self.data_domain.class_var.name,
1096                                                                       values=get_variable_values_sorted(self.data_domain.class_var))])
1097        else:
1098            domain = settings_dict.get("domain") or \
1099                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
1100                                         Orange.feature.Continuous("yVar"),
1101                                         Orange.feature.Continuous("zVar")])
1102        data = self.create_projection_as_numeric_array(attr_indices,
1103                                                       **settings_dict)
1104        if data != None:
1105            return Orange.data.Table(domain, data)
1106        else:
1107            return Orange.data.Table(domain)
1108
1109    createProjectionAsExampleTable = create_projection_as_example_table
1110
1111    @deprecated_keywords({"attrIndices": "attr_indices",
1112                          "settingsDict": "settings_dict",
1113                          "validData": "valid_data",
1114                          "classList": "class_list",
1115                          "XAnchors": "xanchors",
1116                          "YAnchors": "yanchors",
1117                          "ZAnchors": "zanchors",
1118                          "scaleFactor": "scale_factor",
1119                          "jitterSize": "jitter_size",
1120                          "useAnchorData": "use_anchor_data",
1121                          "removeMissingData": "remove_missing_data",
1122                          "useSubsetData": "use_subset_data",
1123                          })
1124    def create_projection_as_numeric_array(self, attr_indices, **settings_dict):
1125        # load the elements from the settings dict
1126        valid_data = settings_dict.get("valid_data")
1127        class_list = settings_dict.get("class_list")
1128        sum_i     = settings_dict.get("sum_i")
1129        xanchors = settings_dict.get("xanchors")
1130        yanchors = settings_dict.get("yanchors")
1131        zanchors = settings_dict.get("zanchors")
1132        scale_factor = settings_dict.get("scale_factor", 1.0)
1133        normalize = settings_dict.get("normalize")
1134        jitter_size = settings_dict.get("jitter_size", 0.0)
1135        use_anchor_data = settings_dict.get("use_anchor_data", 0)
1136        remove_missing_data = settings_dict.get("remove_missing_data", 1)
1137        use_subset_data = settings_dict.get("use_subset_data", 0)        # use the data or subsetData?
1138        #minmaxVals = settings_dict.get("minmaxVals", None)
1139
1140        # if we want to use anchor data we can get attr_indices from the anchor_data
1141        if use_anchor_data and self.anchor_data:
1142            attr_indices = [self.attribute_name_index[val[3]] for val in self.anchor_data]
1143
1144        if valid_data == None:
1145            if use_subset_data: valid_data = self.get_valid_subset_list(attr_indices)
1146            else:             valid_data = self.get_valid_list(attr_indices)
1147        if sum(valid_data) == 0:
1148            return None
1149
1150        if class_list == None and self.data_domain.class_var:
1151            if use_subset_data: class_list = self.original_subset_data[self.data_class_index]
1152            else:             class_list = self.original_data[self.data_class_index]
1153
1154        # if jitterSize is set below zero we use scaled_data that has already jittered data
1155        if use_subset_data:
1156            if jitter_size < 0.0: data = self.scaled_subset_data
1157            else:                data = self.no_jittering_scaled_subset_data
1158        else:
1159            if jitter_size < 0.0: data = self.scaled_data
1160            else:                data = self.no_jittering_scaled_data
1161
1162        selected_data = numpy.take(data, attr_indices, axis=0)
1163        if remove_missing_data:
1164            selected_data = numpy.compress(valid_data, selected_data, axis=1)
1165            if class_list != None and len(class_list) != numpy.shape(selected_data)[1]:
1166                class_list = numpy.compress(valid_data, class_list)
1167
1168        if use_anchor_data and self.anchor_data:
1169            xanchors = numpy.array([val[0] for val in self.anchor_data])
1170            yanchors = numpy.array([val[1] for val in self.anchor_data])
1171            zanchors = numpy.array([val[2] for val in self.anchor_data])
1172            r = numpy.sqrt(xanchors*xanchors + yanchors*yanchors + zanchors*zanchors)     # compute the distance of each anchor from the center of the circle
1173            if normalize == 1 or (normalize == None and self.normalize_examples):
1174                xanchors *= r
1175                yanchors *= r
1176                zanchors *= r
1177        elif (xanchors != None and yanchors != None and zanchors != None):
1178            xanchors = numpy.array(xanchors)
1179            yanchors = numpy.array(yanchors)
1180            zanchors = numpy.array(zanchors)
1181            r = numpy.sqrt(xanchors*xanchors + yanchors*yanchors + zanchors*zanchors)     # compute the distance of each anchor from the center of the circle
1182        else:
1183            self.create_anchors(len(attr_indices))
1184            xanchors = numpy.array([val[0] for val in self.anchor_data])
1185            yanchors = numpy.array([val[1] for val in self.anchor_data])
1186            zanchors = numpy.array([val[2] for val in self.anchor_data])
1187            r = numpy.ones(len(xanchors), numpy.float)
1188
1189        x_positions = numpy.dot(xanchors, selected_data)
1190        y_positions = numpy.dot(yanchors, selected_data)
1191        z_positions = numpy.dot(zanchors, selected_data)
1192
1193        if normalize == 1 or (normalize == None and self.normalize_examples):
1194            if sum_i == None:
1195                sum_i = self._getSum_i(selected_data, use_anchor_data, r)
1196            x_positions /= sum_i
1197            y_positions /= sum_i
1198            z_positions /= sum_i
1199            self.true_scale_factor = scale_factor
1200        else:
1201            if not remove_missing_data:
1202                try:
1203                    x_valid_data = numpy.compress(valid_data, x_positions)
1204                    y_valid_data = numpy.compress(valid_data, y_positions)
1205                    z_valid_data = numpy.compress(valid_data, z_positions)
1206                except:
1207                    print valid_data
1208                    print x_positions
1209                    print numpy.shape(valid_data)
1210                    print numpy.shape(x_positions)
1211            else:
1212                x_valid_data = x_positions
1213                y_valid_data = y_positions
1214                z_valid_data = z_positions
1215
1216            dist = math.sqrt(max(x_valid_data*x_valid_data + y_valid_data*y_valid_data + z_valid_data*z_valid_data)) or 1
1217            self.true_scale_factor = scale_factor / dist
1218
1219        self.unscaled_x_positions = numpy.array(x_positions)
1220        self.unscaled_y_positions = numpy.array(y_positions)
1221        self.unscaled_z_positions = numpy.array(z_positions)
1222
1223        if self.true_scale_factor != 1.0:
1224            x_positions *= self.true_scale_factor
1225            y_positions *= self.true_scale_factor
1226            z_positions *= self.true_scale_factor
1227
1228        if jitter_size > 0.0:
1229            x_positions += numpy.random.uniform(-jitter_size, jitter_size, len(x_positions))
1230            y_positions += numpy.random.uniform(-jitter_size, jitter_size, len(y_positions))
1231            z_positions += numpy.random.uniform(-jitter_size, jitter_size, len(z_positions))
1232
1233        self.last_attr_indices = attr_indices
1234        if class_list != None:
1235            return numpy.transpose(numpy.array((x_positions, y_positions, z_positions, class_list)))
1236        else:
1237            return numpy.transpose(numpy.array((x_positions, y_positions, z_positions)))
1238
1239    createProjectionAsNumericArray = create_projection_as_numeric_array
1240
1241    @deprecated_keywords({"useAnchorData": "use_anchor_data",
1242                          "anchorRadius": "anchor_radius"})
1243    def _getsum_i(self, data, use_anchor_data=0, anchor_radius=None):
1244        """
1245        Function to compute the sum of all values for each element in the data.
1246        Used to normalize.
1247       
1248        """
1249        if use_anchor_data:
1250            if anchor_radius == None:
1251                anchor_radius = numpy.sqrt([a[0]**2+a[1]**2+a[2]**2 for a in self.anchor_data])
1252            sum_i = numpy.add.reduce(numpy.transpose(numpy.transpose(data)*anchor_radius))
1253        else:
1254            sum_i = numpy.add.reduce(data)
1255        if len(numpy.nonzero(sum_i)) < len(sum_i):    # test if there are zeros in sum_i
1256            sum_i += numpy.where(sum_i == 0, 1.0, 0.0)
1257        return sum_i
1258   
1259    _getSum_i = _getsum_i
1260
1261ScaleLinProjData3D = deprecated_members({"setAnchors": "set_anchors",
1262                                       "createAnchors": "create_anchors",
1263                                       "saveProjectionAsTabData": "save_projection_as_tab_data",
1264                                       "getProjectedPointPosition":
1265                                           "get_projected_point_position",
1266                                       "createProjectionAsExampleTable":
1267                                           "create_projection_as_example_table",
1268                                       "createProjectionAsNumericArray":
1269                                           "create_projection_as_numeric_array",
1270                                       "_getSum_i": "_getsum_i",
1271                                       "normalizeExamples": "normalize_examples",
1272                                       "anchorData": "anchor_data",
1273                                       "lastAttrIndices": "last_attr_indices",
1274                                       "anchorDict": "anchor_dict",
1275                                       "trueScaleFactor": "true_scale_factor"
1276                                      })(ScaleLinProjData3D)
1277
1278class ScalePolyvizData(ScaleLinProjData):
1279    def __init__(self):
1280        ScaleLinProjData.__init__(self)
1281        self.normalize_examples = 1
1282        self.anchor_data =[]        # form: [(anchor1x, anchor1y, label1),(anchor2x, anchor2y, label2), ...]
1283       
1284
1285    # attributeReverse, validData = None, classList = None, sum_i = None, XAnchors = None, YAnchors = None, domain = None, scaleFactor = 1.0, jitterSize = 0.0
1286    @deprecated_keywords({"attrIndices": "attr_indices",
1287                          "settingsDict": "settings_dict"})
1288    def create_projection_as_example_table(self, attr_list, **settings_dict):
1289        if self.data_domain.class_var:
1290            domain = settings_dict.get("domain") or \
1291                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
1292                                         Orange.feature.Continuous("yVar"),
1293                                         Orange.feature.Discrete(self.data_domain.class_var.name,
1294                                                                       values = get_variable_values_sorted(self.data_domain.class_var))])
1295        else:
1296            domain = settings_dict.get("domain") or \
1297                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
1298                                         Orange.feature.Continuous("yVar")])
1299        data = self.create_projection_as_numeric_array(attr_list, **settings_dict)
1300        if data != None:
1301            return Orange.data.Table(domain, data)
1302        else:
1303            return Orange.data.Table(domain)
1304   
1305    createProjectionAsExampleTable = create_projection_as_example_table
1306   
1307    @deprecated_keywords({"attrIndices": "attr_indices",
1308                          "settingsDict": "settings_dict",
1309                          "validData": "valid_data",
1310                          "classList": "class_list",
1311                          "XAnchors": "xanchors",
1312                          "YAnchors": "yanchors",
1313                          "scaleFactor": "scale_factor",
1314                          "jitterSize": "jitter_size",
1315                          "removeMissingData": "remove_missing_data",
1316                          })
1317    def create_projection_as_numeric_array(self, attr_indices, **settings_dict):
1318        # load the elements from the settings dict
1319        attribute_reverse = settings_dict.get("reverse", [0]*len(attr_indices))
1320        valid_data = settings_dict.get("valid_data")
1321        class_list = settings_dict.get("class_list")
1322        sum_i     = settings_dict.get("sum_i")
1323        xanchors  = settings_dict.get("xanchors")
1324        yanchors  = settings_dict.get("yanchors")
1325        scale_factor = settings_dict.get("scale_factor", 1.0)
1326        jitter_size  = settings_dict.get("jitter_size", 0.0)
1327        remove_missing_data = settings_dict.get("remove_missing_data", 1)
1328       
1329        if valid_data == None:
1330            valid_data = self.get_valid_list(attr_indices)
1331        if sum(valid_data) == 0:
1332            return None
1333
1334        if class_list == None and self.data_has_class:
1335            class_list = self.original_data[self.data_class_index]
1336
1337        if remove_missing_data:
1338            selected_data = numpy.compress(valid_data,
1339                                          numpy.take(self.no_jittering_scaled_data,
1340                                                     attr_indices, axis = 0),
1341                                                     axis = 1)
1342            if class_list != None and len(class_list) != numpy.shape(selected_data)[1]:
1343                class_list = numpy.compress(valid_data, class_list)
1344        else:
1345            selected_data = numpy.take(self.no_jittering_scaled_data,
1346                                      attr_indices, axis = 0)
1347       
1348        if sum_i == None:
1349            sum_i = self._getSum_i(selected_data)
1350
1351        if xanchors == None or yanchors == None:
1352            xanchors = self.create_xanchors(len(attr_indices))
1353            yanchors = self.create_yanchors(len(attr_indices))
1354
1355        xanchors = numpy.zeros(numpy.shape(selected_data), numpy.float)
1356        yanchors = numpy.zeros(numpy.shape(selected_data), numpy.float)
1357        length = len(attr_indices)
1358
1359        for i in range(length):
1360            if attribute_reverse[i]:
1361                xanchors[i] = selected_data[i] * xanchors[i] + (1-selected_data[i]) * xanchors[(i+1)%length]
1362                yanchors[i] = selected_data[i] * yanchors[i] + (1-selected_data[i]) * yanchors[(i+1)%length]
1363            else:
1364                xanchors[i] = (1-selected_data[i]) * xanchors[i] + selected_data[i] * xanchors[(i+1)%length]
1365                yanchors[i] = (1-selected_data[i]) * yanchors[i] + selected_data[i] * yanchors[(i+1)%length]
1366
1367        x_positions = numpy.sum(numpy.multiply(xanchors, selected_data), axis=0)/sum_i
1368        y_positions = numpy.sum(numpy.multiply(yanchors, selected_data), axis=0)/sum_i
1369        #x_positions = numpy.sum(numpy.transpose(xanchors* numpy.transpose(selectedData)), axis=0) / sum_i
1370        #y_positions = numpy.sum(numpy.transpose(yanchors* numpy.transpose(selectedData)), axis=0) / sum_i
1371
1372        if scale_factor != 1.0:
1373            x_positions = x_positions * scale_factor
1374            y_positions = y_positions * scale_factor
1375        if jitter_size > 0.0:
1376            x_positions += (numpy.random.random(len(x_positions))-0.5)*jitter_size
1377            y_positions += (numpy.random.random(len(y_positions))-0.5)*jitter_size
1378
1379        if class_list != None:
1380            return numpy.transpose(numpy.array((x_positions, y_positions, class_list)))
1381        else:
1382            return numpy.transpose(numpy.array((x_positions, y_positions)))
1383
1384    createProjectionAsNumericArray = create_projection_as_numeric_array
1385
1386    @deprecated_keywords({"attrIndices": "attr_indices",
1387                          "settingsDict": "settings_dict",
1388                          "useAnchorData": "use_anchor_data",
1389                          "XAnchors": "xanchors",
1390                          "YAnchors": "yanchors"})
1391    def get_projected_point_position(self, attr_indices, values, **settings_dict):
1392        # load the elements from the settings dict
1393        attribute_reverse = settings_dict.get("reverse", [0]*len(attr_indices))
1394        use_anchor_data = settings_dict.get("use_anchor_data")
1395        xanchors = settings_dict.get("xanchors")
1396        yanchors = settings_dict.get("yanchors")
1397   
1398        if xanchors != None and yanchors != None:
1399            xanchors = numpy.array(xanchors)
1400            yanchors = numpy.array(yanchors)
1401        elif use_anchor_data:
1402            xanchors = numpy.array([val[0] for val in self.anchor_data])
1403            yanchors = numpy.array([val[1] for val in self.anchor_data])
1404        else:
1405            xanchors = self.create_xanchors(len(attr_indices))
1406            yanchors = self.create_yanchors(len(attr_indices))
1407
1408        m = min(values); M = max(values)
1409        if m < 0.0 or M > 1.0:  # we have to do rescaling of values so that all
1410            # the values will be in the 0-1 interval
1411            values = [max(0.0, min(val, 1.0)) for val in values]
1412            #m = min(m, 0.0); M = max(M, 1.0); diff = max(M-m, 1e-10)
1413            #values = [(val-m) / float(diff) for val in values]
1414       
1415        s = sum(numpy.array(values))
1416        if s == 0: return [0.0, 0.0]
1417
1418        length = len(values)
1419        xanchors = numpy.zeros(length, numpy.float)
1420        yanchors = numpy.zeros(length, numpy.float)
1421        for i in range(length):
1422            if attribute_reverse[i]:
1423                xanchors[i] = values[i] * xanchors[i] + (1-values[i]) * xanchors[(i+1)%length]
1424                yanchors[i] = values[i] * yanchors[i] + (1-values[i]) * yanchors[(i+1)%length]
1425            else:
1426                xanchors[i] = (1-values[i]) * xanchors[i] + values[i] * xanchors[(i+1)%length]
1427                yanchors[i] = (1-values[i]) * yanchors[i] + values[i] * yanchors[(i+1)%length]
1428
1429        x_positions = numpy.sum(numpy.dot(xanchors, values), axis=0) / float(s)
1430        y_positions = numpy.sum(numpy.dot(yanchors, values), axis=0) / float(s)
1431        return [x, y]
1432   
1433    getProjectedPointPosition = get_projected_point_position
1434
1435ScalePolyvizData = deprecated_members({"createProjectionAsExampleTable":
1436                                           "create_projection_as_example_table",
1437                                       "createProjectionAsNumericArray":
1438                                           "create_projection_as_numeric_array",
1439                                       "getProjectedPointPosition":
1440                                           "get_projected_point_position"
1441                                       })(ScalePolyvizData)
1442
1443class ScaleScatterPlotData(ScaleData):
1444    def get_original_data(self, indices):
1445        data = self.original_data.take(indices, axis = 0)
1446        for i, ind in enumerate(indices):
1447            [minVal, maxVal] = self.attr_values[self.data_domain[ind].name]
1448            if self.data_domain[ind].varType == Orange.core.VarTypes.Discrete:
1449                data[i] += (self.jitter_size/50.0)*(numpy.random.random(len(self.raw_data)) - 0.5)
1450            elif self.data_domain[ind].varType == Orange.core.VarTypes.Continuous and self.jitter_continuous:
1451                data[i] += (self.jitter_size/(50.0*(maxVal-minVal or 1)))*(numpy.random.random(len(self.raw_data)) - 0.5)
1452        return data
1453   
1454    getOriginalData = get_original_data
1455   
1456    def get_original_subset_data(self, indices):
1457        data = self.original_subset_data.take(indices, axis = 0)
1458        for i, ind in enumerate(indices):
1459            [minVal, maxVal] = self.attr_values[self.raw_subset_data.domain[ind].name]
1460            if self.data_domain[ind].varType == Orange.core.VarTypes.Discrete:
1461                data[i] += (self.jitter_size/(50.0*max(1, maxVal)))*(numpy.random.random(len(self.raw_subset_data)) - 0.5)
1462            elif self.data_domain[ind].varType == Orange.core.VarTypes.Continuous and self.jitter_continuous:
1463                data[i] += (self.jitter_size/(50.0*(maxVal-minVal or 1)))*(numpy.random.random(len(self.raw_subset_data)) - 0.5)
1464        return data
1465
1466    getOriginalSubsetData = get_original_subset_data
1467
1468    @deprecated_keywords({"xAttr": "xattr", "yAttr": "yattr"})
1469    def get_xy_data_positions(self, xattr, yattr):
1470        """
1471        Create x-y projection of attributes in attrlist.
1472       
1473        """
1474        xattr_index, yattr_index = self.attribute_name_index[xattr], self.attribute_name_index[yattr]
1475
1476        xdata = self.scaled_data[xattr_index].copy()
1477        ydata = self.scaled_data[yattr_index].copy()
1478       
1479        if self.data_domain[xattr_index].varType == Orange.core.VarTypes.Discrete: xdata = ((xdata * 2*len(self.data_domain[xattr_index].values)) - 1.0) / 2.0
1480        else:  xdata = xdata * (self.attr_values[xattr][1] - self.attr_values[xattr][0]) + float(self.attr_values[xattr][0])
1481
1482        if self.data_domain[yattr_index].varType == Orange.core.VarTypes.Discrete: ydata = ((ydata * 2*len(self.data_domain[yattr_index].values)) - 1.0) / 2.0
1483        else:  ydata = ydata * (self.attr_values[yattr][1] - self.attr_values[yattr][0]) + float(self.attr_values[yattr][0])
1484        return (xdata, ydata)
1485   
1486    getXYDataPositions = get_xy_data_positions
1487   
1488    @deprecated_keywords({"xAttr": "xattr", "yAttr": "yattr"})
1489    def get_xy_subset_data_positions(self, xattr, yattr):
1490        """
1491        Create x-y projection of attributes in attr_list.
1492       
1493        """
1494        xattr_index, yattr_index = self.attribute_name_index[xattr], self.attribute_name_index[yattr]
1495
1496        xdata = self.scaled_subset_data[xattr_index].copy()
1497        ydata = self.scaled_subset_data[yattr_index].copy()
1498       
1499        if self.data_domain[xattr_index].varType == Orange.core.VarTypes.Discrete: xdata = ((xdata * 2*len(self.data_domain[xattr_index].values)) - 1.0) / 2.0
1500        else:  xdata = xdata * (self.attr_values[xattr][1] - self.attr_values[xattr][0]) + float(self.attr_values[xattr][0])
1501
1502        if self.data_domain[yattr_index].varType == Orange.core.VarTypes.Discrete: ydata = ((ydata * 2*len(self.data_domain[yattr_index].values)) - 1.0) / 2.0
1503        else:  ydata = ydata * (self.attr_values[yattr][1] - self.attr_values[yattr][0]) + float(self.attr_values[yattr][0])
1504        return (xdata, ydata)
1505   
1506    getXYSubsetDataPositions = get_xy_subset_data_positions
1507   
1508    @deprecated_keywords({"attrIndices": "attr_indices",
1509                          "settingsDict": "settings_dict"})
1510    def get_projected_point_position(self, attr_indices, values, **settings_dict):
1511        """
1512        For attributes in attr_indices and values of these attributes in values
1513        compute point positions this function has more sense in radviz and
1514        polyviz methods. settings_dict has to be because radviz and polyviz have
1515        this parameter.
1516        """
1517        return values
1518
1519    getProjectedPointPosition = get_projected_point_position
1520
1521    @deprecated_keywords({"attrIndices": "attr_indices",
1522                          "settingsDict": "settings_dict"})
1523    def create_projection_as_example_table(self, attr_indices, **settings_dict):
1524        """
1525        Create the projection of attribute indices given in attr_indices and
1526        create an example table with it.
1527       
1528        """
1529        if self.data_has_class:
1530            domain = settings_dict.get("domain") or \
1531                     Orange.data.Domain([Orange.feature.Continuous(self.data_domain[attr_indices[0]].name),
1532                                         Orange.feature.Continuous(self.data_domain[attr_indices[1]].name),
1533                                         Orange.feature.Discrete(self.data_domain.class_var.name,
1534                                                                       values = get_variable_values_sorted(self.data_domain.class_var))])
1535        else:
1536            domain = settings_dict.get("domain") or \
1537                     Orange.data.Domain([Orange.feature.Continuous(self.data_domain[attr_indices[0]].name),
1538                                         Orange.feature.Continuous(self.data_domain[attr_indices[1]].name)])
1539
1540        data = self.create_projection_as_numeric_array(attr_indices,
1541                                                       **settings_dict)
1542        if data != None:
1543            return Orange.data.Table(domain, data)
1544        else:
1545            return Orange.data.Table(domain)
1546
1547    createProjectionAsExampleTable = create_projection_as_example_table
1548
1549    @deprecated_keywords({"attrIndices": "attr_indices",
1550                          "settingsDict": "settings_dict"})
1551    def create_projection_as_example_table_3D(self, attr_indices, **settings_dict):
1552        """
1553        Create the projection of attribute indices given in attr_indices and
1554        create an example table with it.
1555       
1556        """
1557        if self.data_has_class:
1558            domain = settings_dict.get("domain") or \
1559                     Orange.data.Domain([Orange.feature.Continuous(self.data_domain[attr_indices[0]].name),
1560                                         Orange.feature.Continuous(self.data_domain[attr_indices[1]].name),
1561                                         Orange.feature.Continuous(self.data_domain[attr_indices[2]].name),
1562                                         Orange.feature.Discrete(self.data_domain.class_var.name,
1563                                                                       values = get_variable_values_sorted(self.data_domain.class_var))])
1564        else:
1565            domain = settings_dict.get("domain") or \
1566                     Orange.data.Domain([Orange.feature.Continuous(self.data_domain[attr_indices[0]].name),
1567                                         Orange.feature.Continuous(self.data_domain[attr_indices[1]].name),
1568                                         Orange.feature.Continuous(self.data_domain[attr_indices[2]].name)])
1569
1570        data = self.create_projection_as_numeric_array_3D(attr_indices,
1571                                                          **settings_dict)
1572        if data != None:
1573            return Orange.data.Table(domain, data)
1574        else:
1575            return Orange.data.Table(domain)
1576
1577    createProjectionAsExampleTable3D = create_projection_as_example_table_3D
1578
1579    @deprecated_keywords({"attrIndices": "attr_indices",
1580                          "settingsDict": "settings_dict",
1581                          "validData": "valid_data",
1582                          "classList": "class_list",
1583                          "jutterSize": "jitter_size"})
1584    def create_projection_as_numeric_array(self, attr_indices, **settings_dict):
1585        valid_data = settings_dict.get("valid_data")
1586        class_list = settings_dict.get("class_list")
1587        jitter_size = settings_dict.get("jitter_size", 0.0)
1588
1589        if valid_data == None:
1590            valid_data = self.get_valid_list(attr_indices)
1591        if sum(valid_data) == 0:
1592            return None
1593
1594        if class_list == None and self.data_has_class:
1595            class_list = self.original_data[self.data_class_index]
1596
1597        xarray = self.no_jittering_scaled_data[attr_indices[0]]
1598        yarray = self.no_jittering_scaled_data[attr_indices[1]]
1599        if jitter_size > 0.0:
1600            xarray += (numpy.random.random(len(xarray))-0.5)*jitter_size
1601            yarray += (numpy.random.random(len(yarray))-0.5)*jitter_size
1602        if class_list != None:
1603            data = numpy.compress(valid_data, numpy.array((xarray, yarray, class_list)), axis = 1)
1604        else:
1605            data = numpy.compress(valid_data, numpy.array((xarray, yarray)), axis = 1)
1606        data = numpy.transpose(data)
1607        return data
1608
1609    createProjectionAsNumericArray = create_projection_as_numeric_array
1610
1611    @deprecated_keywords({"attrIndices": "attr_indices",
1612                          "settingsDict": "settings_dict",
1613                          "validData": "valid_data",
1614                          "classList": "class_list",
1615                          "jutterSize": "jitter_size"})
1616    def create_projection_as_numeric_array_3D(self, attr_indices, **settings_dict):
1617        valid_data = settings_dict.get("valid_data")
1618        class_list = settings_dict.get("class_list")
1619        jitter_size = settings_dict.get("jitter_size", 0.0)
1620
1621        if valid_data == None:
1622            valid_data = self.get_valid_list(attr_indices)
1623        if sum(valid_data) == 0:
1624            return None
1625
1626        if class_list == None and self.data_has_class:
1627            class_list = self.original_data[self.data_class_index]
1628
1629        xarray = self.no_jittering_scaled_data[attr_indices[0]]
1630        yarray = self.no_jittering_scaled_data[attr_indices[1]]
1631        zarray = self.no_jittering_scaled_data[attr_indices[2]]
1632        if jitter_size > 0.0:
1633            xarray += (numpy.random.random(len(xarray))-0.5)*jitter_size
1634            yarray += (numpy.random.random(len(yarray))-0.5)*jitter_size
1635            zarray += (numpy.random.random(len(zarray))-0.5)*jitter_size
1636        if class_list != None:
1637            data = numpy.compress(valid_data, numpy.array((xarray, yarray, zarray, class_list)), axis = 1)
1638        else:
1639            data = numpy.compress(valid_data, numpy.array((xarray, yarray, zarray)), axis = 1)
1640        data = numpy.transpose(data)
1641        return data
1642
1643    createProjectionAsNumericArray3D = create_projection_as_numeric_array_3D
1644
1645    @deprecated_keywords({"attributeNameOrder": "attribute_name_order",
1646                          "addResultFunct": "add_result_funct"})
1647    def get_optimal_clusters(self, attribute_name_order, add_result_funct):
1648        if not self.data_has_class or self.data_has_continuous_class:
1649            return
1650       
1651        jitter_size = 0.001 * self.clusterOptimization.jitterDataBeforeTriangulation
1652        domain = Orange.data.Domain([Orange.feature.Continuous("xVar"),
1653                                     Orange.feature.Continuous("yVar"),
1654                                    self.data_domain.class_var])
1655
1656        # init again, in case that the attribute ordering took too much time
1657        self.scatterWidget.progressBarInit()
1658        start_time = time.time()
1659        count = len(attribute_name_order)*(len(attribute_name_order)-1)/2
1660        test_index = 0
1661
1662        for i in range(len(attribute_name_order)):
1663            for j in range(i):
1664                try:
1665                    attr1 = self.attribute_name_index[attribute_name_order[j]]
1666                    attr2 = self.attribute_name_index[attribute_name_order[i]]
1667                    test_index += 1
1668                    if self.clusterOptimization.isOptimizationCanceled():
1669                        secs = time.time() - start_time
1670                        self.clusterOptimization.setStatusBarText("Evaluation stopped (evaluated %d projections in %d min, %d sec)"
1671                                                                  % (test_index, secs/60, secs%60))
1672                        self.scatterWidget.progressBarFinished()
1673                        return
1674
1675                    data = self.create_projection_as_example_table([attr1, attr2],
1676                                                                   domain = domain,
1677                                                                   jitter_size = jitter_size)
1678                    graph, valuedict, closuredict, polygon_vertices_dict, enlarged_closure_dict, other_dict = self.clusterOptimization.evaluateClusters(data)
1679
1680                    all_value = 0.0
1681                    classes_dict = {}
1682                    for key in valuedict.keys():
1683                        add_result_funct(valuedict[key], closuredict[key],
1684                                         polygon_vertices_dict[key],
1685                                         [attribute_name_order[i],
1686                                          attribute_name_order[j]],
1687                                          int(graph.objects[polygon_vertices_dict[key][0]].getclass()),
1688                                          enlarged_closure_dict[key], other_dict[key])
1689                        classes_dict[key] = int(graph.objects[polygon_vertices_dict[key][0]].getclass())
1690                        all_value += valuedict[key]
1691                    add_result_funct(all_value, closuredict, polygon_vertices_dict,
1692                                     [attribute_name_order[i], attribute_name_order[j]],
1693                                     classes_dict, enlarged_closure_dict, other_dict)     # add all the clusters
1694                   
1695                    self.clusterOptimization.setStatusBarText("Evaluated %d projections..."
1696                                                              % (test_index))
1697                    self.scatterWidget.progressBarSet(100.0*test_index/float(count))
1698                    del data, graph, valuedict, closuredict, polygon_vertices_dict, enlarged_closure_dict, other_dict, classes_dict
1699                except:
1700                    type, val, traceback = sys.exc_info()
1701                    sys.excepthook(type, val, traceback)  # print the exception
1702       
1703        secs = time.time() - start_time
1704        self.clusterOptimization.setStatusBarText("Finished evaluation (evaluated %d projections in %d min, %d sec)" % (test_index, secs/60, secs%60))
1705        self.scatterWidget.progressBarFinished()
1706   
1707    getOptimalClusters = get_optimal_clusters
1708
1709ScaleScatterPlotData = deprecated_members({"getOriginalData": "get_original_data",
1710                                           "getOriginalSubsetData": "get_original_subset_data",
1711                                           "getXYDataPositions": "get_xy_data_positions",
1712                                           "getXYSubsetDataPositions": "get_xy_subset_data_positions",
1713                                           "getProjectedPointPosition": "get_projected_point_position",
1714                                           "createProjectionAsExampleTable": "create_projection_as_example_table",
1715                                           "createProjectionAsExampleTable3D": "create_projection_as_example_table_3D",
1716                                           "createProjectionAsNumericArray": "create_projection_as_numeric_array",
1717                                           "createProjectionAsNumericArray3D": "create_projection_as_numeric_array_3D",
1718                                           "getOptimalClusters": "get_optimal_clusters"
1719                                           })(ScaleScatterPlotData)
Note: See TracBrowser for help on using the repository browser.