source: orange/Orange/data/preprocess/scaling.py @ 11632:85aaadf66c89

Revision 11632:85aaadf66c89, 83.2 KB checked in by Ales Erjavec <ales.erjavec@…>, 9 months ago (diff)

Fixed 'ScaleLinProjData.create_projection_as_numeric_array' point jittering.

Use data points span ratio to deterimine the amount of jittering to apply.

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=0):
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            x_positions = jitter_array(x_positions, jitter_size / 100.,
861                                       rand_seed=self.jitter_seed)
862            y_positions = jitter_array(y_positions, jitter_size / 100.,
863                                       rand_seed=self.jitter_seed)
864
865        self.last_attr_indices = attr_indices
866        if class_list != None:
867            return numpy.transpose(numpy.array((x_positions, y_positions, class_list)))
868        else:
869            return numpy.transpose(numpy.array((x_positions, y_positions)))
870
871    createProjectionAsNumericArray = create_projection_as_numeric_array
872   
873    @deprecated_keywords({"useAnchorData": "use_anchor_data",
874                          "anchorRadius": "anchor_radius"})
875    def _getsum_i(self, data, use_anchor_data = 0, anchor_radius = None):
876        """
877        Function to compute the sum of all values for each element in the data.
878        Used to normalize.
879       
880        """
881        if use_anchor_data:
882            if anchor_radius == None:
883                anchor_radius = numpy.sqrt([a[0]**2+a[1]**2 for a in self.anchor_data])
884            sum_i = numpy.add.reduce(numpy.transpose(numpy.transpose(data)*anchor_radius))
885        else:
886            sum_i = numpy.add.reduce(data)
887        if len(sum_i[numpy.nonzero(sum_i)]) < len(sum_i):    # test if there are zeros in sum_i
888            sum_i += numpy.where(sum_i == 0, 1.0, 0.0)
889        return sum_i
890   
891    _getSum_i = _getsum_i
892
893graph_deprecator = deprecated_members({"setData": "set_data",
894                                       "updateData": "update_data",
895                                       "scaleFactor": "scale_factor"})
896
897ScaleLinProjData = deprecated_members({"setAnchors": "set_anchors",
898                                       "createAnchors": "create_anchors",
899                                       "createXAnchors": "create_xanchors",
900                                       "createYAnchors": "create_yanchors",
901                                       "saveProjectionAsTabData": "save_projection_as_tab_data",
902                                       "getProjectedPointPosition":
903                                           "get_projected_point_position",
904                                       "createProjectionAsExampleTable":
905                                           "create_projection_as_example_table",
906                                       "createProjectionAsNumericArray":
907                                           "create_projection_as_numeric_array",
908                                       "_getSum_i": "_getsum_i",
909                                       "normalizeExamples": "normalize_examples",
910                                       "anchorData": "anchor_data",
911                                       "lastAttrIndices": "last_attr_indices",
912                                       "anchorDict": "anchor_dict"})(ScaleLinProjData)
913
914class ScaleLinProjData3D(ScaleData):
915    def __init__(self):
916        ScaleData.__init__(self)
917        self.normalize_examples = 1
918        self.anchor_data = []        # form: [(anchor1x, anchor1y, anchor1z, label1),(anchor2x, anchor2y, anchor2z, label2), ...]
919        self.last_attr_indices = None
920        self.anchor_dict = {}
921
922    @deprecated_keywords({"xAnchors": "xanchors", "yAnchors": "yanchors"})
923    def set_anchors(self, xanchors, yanchors, zanchors, attributes):
924        if attributes:
925            if xanchors != None and yanchors != None and zanchors != None:
926                self.anchor_data = [(xanchors[i], yanchors[i], zanchors[i], attributes[i])
927                                    for i in range(len(attributes))]
928            else:
929                self.anchor_data = self.create_anchors(len(attributes), attributes)
930
931    setAnchors = set_anchors
932
933    @deprecated_keywords({"numOfAttr": "num_of_attr"})
934    def create_anchors(self, num_of_attrs, labels=None):
935        """
936        Create anchors on the sphere.
937       
938        """
939        # Golden Section Spiral algorithm approximates even distribution of points on a sphere
940        # (read more here http://www.softimageblog.com/archives/115)
941        n = num_of_attrs
942        xanchors = []
943        yanchors = []
944        zanchors = []
945
946        inc = math.pi * (3 - math.sqrt(5))
947        off = 2. / n
948        for k in range(n):
949            y = k * off - 1 + (off / 2)
950            r = math.sqrt(1 - y*y)
951            phi = k * inc
952            xanchors.append(math.cos(phi)*r)
953            yanchors.append(y)
954            zanchors.append(math.sin(phi)*r)
955
956        self.anchor_dict[num_of_attrs] = [xanchors, yanchors, zanchors]
957 
958        if labels:
959            return [(xanchors[i], yanchors[i], zanchors[i], labels[i]) for i in range(num_of_attrs)]
960        else:
961            return [(xanchors[i], yanchors[i], zanchors[i]) for i in range(num_of_attrs)]
962
963    createAnchors = create_anchors
964
965    @deprecated_keywords({"numOfAttrs": "num_of_attrs"})
966    def create_xanchors(self, num_of_attrs):
967        if not self.anchor_dict.has_key(num_of_attrs):
968            self.create_anchors(num_of_attrs)
969        return self.anchor_dict[num_of_attrs][0]
970
971    createXAnchors = create_xanchors
972
973    @deprecated_keywords({"numOfAttrs": "num_of_attrs"})
974    def create_yanchors(self, num_of_attrs):
975        if not self.anchor_dict.has_key(num_of_attrs):
976            self.create_anchors(num_of_attrs)
977        return self.anchor_dict[num_of_attrs][1]
978
979    createYAnchors = create_yanchors
980
981    @deprecated_keywords({"numOfAttrs": "num_of_attrs"})
982    def create_zanchors(self, num_of_attrs):
983        if not self.anchor_dict.has_key(num_of_attrs):
984            self.create_anchors(num_of_attrs)
985        return self.anchor_dict[num_of_attrs][2]
986
987    createZAnchors = create_zanchors
988
989    @deprecated_keywords({"fileName": "filename", "attrList": "attrlist",
990                          "useAnchorData": "use_anchor_data"})
991    def save_projection_as_tab_data(self, filename, attrlist, use_anchor_data=0):
992        """
993        Save projection (xattr, yattr, zattr, classval) into a filename filename.
994       
995        """
996        Orange.core.saveTabDelimited(filename,
997            self.create_projection_as_example_table([self.attribute_name_index[i]
998                                                     for i in attrlist],
999                                                    use_anchor_data=use_anchor_data))
1000   
1001    saveProjectionAsTabData = save_projection_as_tab_data
1002
1003    @deprecated_keywords({"attrIndices": "attr_indices",
1004                          "settingsDict": "settings_dict",
1005                          "useAnchorData": "use_anchor_data",
1006                          "xAnchors": "xanchors",
1007                          "yAnchors": "yanchors",
1008                          "zAnchors": "zanchors",
1009                          "anchorRadius": "anchor_radius",
1010                          "normalizeExample": "normalize_example",
1011                          })
1012    def get_projected_point_position(self, attr_indices, values, **settings_dict):
1013        """
1014        For attributes in attr_indices and values of these attributes in values
1015        compute point positions. This function has more sense in radviz and
1016        polyviz methods.
1017   
1018        """
1019        # load the elements from the settings dict
1020        use_anchor_data = settings_dict.get("use_anchor_data")
1021        xanchors = settings_dict.get('xanchors')
1022        yanchors = settings_dict.get('yanchors')
1023        zanchors = settings_dict.get('zanchors')
1024        anchor_radius = settings_dict.get("anchor_radius")
1025        normalize_example = settings_dict.get("normalize_example")
1026
1027        if attr_indices != self.last_attr_indices:
1028            print "get_projected_point_position. Warning: Possible bug. The "+\
1029                  "set of attributes is not the same as when computing the "+\
1030                  "whole projection"
1031
1032        if xanchors != None and yanchors != None and zanchors != None:
1033            xanchors = numpy.array(xanchors)
1034            yanchors = numpy.array(yanchors)
1035            zanchors = numpy.array(zanchors)
1036            if anchor_radius == None: anchor_radius = numpy.sqrt(xanchors*xanchors +
1037                                                                 yanchors*yanchors +
1038                                                                 zanchors*zanchors)
1039        elif use_anchor_data and self.anchor_data:
1040            xanchors = numpy.array([val[0] for val in self.anchor_data])
1041            yanchors = numpy.array([val[1] for val in self.anchor_data])
1042            zanchors = numpy.array([val[2] for val in self.anchor_data])
1043            if anchor_radius == None: anchor_radius = numpy.sqrt(xanchors*xanchors +
1044                                                                 yanchors*yanchors +
1045                                                                 zanchors*zanchors)
1046        else:
1047            self.create_anchors(len(attr_indices))
1048            xanchors = numpy.array([val[0] for val in self.anchor_data])
1049            yanchors = numpy.array([val[1] for val in self.anchor_data])
1050            zanchors = numpy.array([val[2] for val in self.anchor_data])
1051            anchor_radius = numpy.ones(len(attr_indices), numpy.float)
1052
1053        if normalize_example == 1 or (normalize_example == None
1054                                      and self.normalize_examples):
1055            m = min(values); M = max(values)
1056            if m < 0.0 or M > 1.0: 
1057                # we have to do rescaling of values so that all the values will
1058                # be in the 0-1 interval
1059                #print "example values are not in the 0-1 interval"
1060                values = [max(0.0, min(val, 1.0)) for val in values]
1061                #m = min(m, 0.0); M = max(M, 1.0); diff = max(M-m, 1e-10)
1062                #values = [(val-m) / float(diff) for val in values]
1063
1064            s = sum(numpy.array(values)*anchor_radius)
1065            if s == 0: return [0.0, 0.0]
1066            x = self.true_scale_factor * numpy.dot(xanchors*anchor_radius,
1067                                                 values) / float(s)
1068            y = self.true_scale_factor * numpy.dot(yanchors*anchor_radius,
1069                                                 values) / float(s)
1070            z = self.true_scale_factor * numpy.dot(zanchors*anchor_radius,
1071                                                 values) / float(s)
1072        else:
1073            x = self.true_scale_factor * numpy.dot(xanchors, values)
1074            y = self.true_scale_factor * numpy.dot(yanchors, values)
1075            z = self.true_scale_factor * numpy.dot(zanchors, values)
1076
1077        return [x, y, z]
1078
1079    getProjectedPointPosition = get_projected_point_position
1080
1081    @deprecated_keywords({"attrIndices": "attr_indices",
1082                          "settingsDict": "settings_dict"})
1083    def create_projection_as_example_table(self, attr_indices, **settings_dict):
1084        """
1085        Create the projection of attribute indices given in attr_indices and
1086        create an example table with it.
1087        """
1088        if self.data_domain.class_var:
1089            domain = settings_dict.get("domain") or \
1090                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
1091                                         Orange.feature.Continuous("yVar"),
1092                                         Orange.feature.Continuous("zVar"),
1093                                         Orange.feature.Discrete(self.data_domain.class_var.name,
1094                                                                       values=get_variable_values_sorted(self.data_domain.class_var))])
1095        else:
1096            domain = settings_dict.get("domain") or \
1097                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
1098                                         Orange.feature.Continuous("yVar"),
1099                                         Orange.feature.Continuous("zVar")])
1100        data = self.create_projection_as_numeric_array(attr_indices,
1101                                                       **settings_dict)
1102        if data != None:
1103            return Orange.data.Table(domain, data)
1104        else:
1105            return Orange.data.Table(domain)
1106
1107    createProjectionAsExampleTable = create_projection_as_example_table
1108
1109    @deprecated_keywords({"attrIndices": "attr_indices",
1110                          "settingsDict": "settings_dict",
1111                          "validData": "valid_data",
1112                          "classList": "class_list",
1113                          "XAnchors": "xanchors",
1114                          "YAnchors": "yanchors",
1115                          "ZAnchors": "zanchors",
1116                          "scaleFactor": "scale_factor",
1117                          "jitterSize": "jitter_size",
1118                          "useAnchorData": "use_anchor_data",
1119                          "removeMissingData": "remove_missing_data",
1120                          "useSubsetData": "use_subset_data",
1121                          })
1122    def create_projection_as_numeric_array(self, attr_indices, **settings_dict):
1123        # load the elements from the settings dict
1124        valid_data = settings_dict.get("valid_data")
1125        class_list = settings_dict.get("class_list")
1126        sum_i     = settings_dict.get("sum_i")
1127        xanchors = settings_dict.get("xanchors")
1128        yanchors = settings_dict.get("yanchors")
1129        zanchors = settings_dict.get("zanchors")
1130        scale_factor = settings_dict.get("scale_factor", 1.0)
1131        normalize = settings_dict.get("normalize")
1132        jitter_size = settings_dict.get("jitter_size", 0.0)
1133        use_anchor_data = settings_dict.get("use_anchor_data", 0)
1134        remove_missing_data = settings_dict.get("remove_missing_data", 1)
1135        use_subset_data = settings_dict.get("use_subset_data", 0)        # use the data or subsetData?
1136        #minmaxVals = settings_dict.get("minmaxVals", None)
1137
1138        # if we want to use anchor data we can get attr_indices from the anchor_data
1139        if use_anchor_data and self.anchor_data:
1140            attr_indices = [self.attribute_name_index[val[3]] for val in self.anchor_data]
1141
1142        if valid_data == None:
1143            if use_subset_data: valid_data = self.get_valid_subset_list(attr_indices)
1144            else:             valid_data = self.get_valid_list(attr_indices)
1145        if sum(valid_data) == 0:
1146            return None
1147
1148        if class_list == None and self.data_domain.class_var:
1149            if use_subset_data: class_list = self.original_subset_data[self.data_class_index]
1150            else:             class_list = self.original_data[self.data_class_index]
1151
1152        # if jitterSize is set below zero we use scaled_data that has already jittered data
1153        if use_subset_data:
1154            if jitter_size < 0.0: data = self.scaled_subset_data
1155            else:                data = self.no_jittering_scaled_subset_data
1156        else:
1157            if jitter_size < 0.0: data = self.scaled_data
1158            else:                data = self.no_jittering_scaled_data
1159
1160        selected_data = numpy.take(data, attr_indices, axis=0)
1161        if remove_missing_data:
1162            selected_data = numpy.compress(valid_data, selected_data, axis=1)
1163            if class_list != None and len(class_list) != numpy.shape(selected_data)[1]:
1164                class_list = numpy.compress(valid_data, class_list)
1165
1166        if use_anchor_data and self.anchor_data:
1167            xanchors = numpy.array([val[0] for val in self.anchor_data])
1168            yanchors = numpy.array([val[1] for val in self.anchor_data])
1169            zanchors = numpy.array([val[2] for val in self.anchor_data])
1170            r = numpy.sqrt(xanchors*xanchors + yanchors*yanchors + zanchors*zanchors)     # compute the distance of each anchor from the center of the circle
1171            if normalize == 1 or (normalize == None and self.normalize_examples):
1172                xanchors *= r
1173                yanchors *= r
1174                zanchors *= r
1175        elif (xanchors != None and yanchors != None and zanchors != None):
1176            xanchors = numpy.array(xanchors)
1177            yanchors = numpy.array(yanchors)
1178            zanchors = numpy.array(zanchors)
1179            r = numpy.sqrt(xanchors*xanchors + yanchors*yanchors + zanchors*zanchors)     # compute the distance of each anchor from the center of the circle
1180        else:
1181            self.create_anchors(len(attr_indices))
1182            xanchors = numpy.array([val[0] for val in self.anchor_data])
1183            yanchors = numpy.array([val[1] for val in self.anchor_data])
1184            zanchors = numpy.array([val[2] for val in self.anchor_data])
1185            r = numpy.ones(len(xanchors), numpy.float)
1186
1187        x_positions = numpy.dot(xanchors, selected_data)
1188        y_positions = numpy.dot(yanchors, selected_data)
1189        z_positions = numpy.dot(zanchors, selected_data)
1190
1191        if normalize == 1 or (normalize == None and self.normalize_examples):
1192            if sum_i == None:
1193                sum_i = self._getSum_i(selected_data, use_anchor_data, r)
1194            x_positions /= sum_i
1195            y_positions /= sum_i
1196            z_positions /= sum_i
1197            self.true_scale_factor = scale_factor
1198        else:
1199            if not remove_missing_data:
1200                try:
1201                    x_valid_data = numpy.compress(valid_data, x_positions)
1202                    y_valid_data = numpy.compress(valid_data, y_positions)
1203                    z_valid_data = numpy.compress(valid_data, z_positions)
1204                except:
1205                    print valid_data
1206                    print x_positions
1207                    print numpy.shape(valid_data)
1208                    print numpy.shape(x_positions)
1209            else:
1210                x_valid_data = x_positions
1211                y_valid_data = y_positions
1212                z_valid_data = z_positions
1213
1214            dist = math.sqrt(max(x_valid_data*x_valid_data + y_valid_data*y_valid_data + z_valid_data*z_valid_data)) or 1
1215            self.true_scale_factor = scale_factor / dist
1216
1217        self.unscaled_x_positions = numpy.array(x_positions)
1218        self.unscaled_y_positions = numpy.array(y_positions)
1219        self.unscaled_z_positions = numpy.array(z_positions)
1220
1221        if self.true_scale_factor != 1.0:
1222            x_positions *= self.true_scale_factor
1223            y_positions *= self.true_scale_factor
1224            z_positions *= self.true_scale_factor
1225
1226        if jitter_size > 0.0:
1227            x_positions += numpy.random.uniform(-jitter_size, jitter_size, len(x_positions))
1228            y_positions += numpy.random.uniform(-jitter_size, jitter_size, len(y_positions))
1229            z_positions += numpy.random.uniform(-jitter_size, jitter_size, len(z_positions))
1230
1231        self.last_attr_indices = attr_indices
1232        if class_list != None:
1233            return numpy.transpose(numpy.array((x_positions, y_positions, z_positions, class_list)))
1234        else:
1235            return numpy.transpose(numpy.array((x_positions, y_positions, z_positions)))
1236
1237    createProjectionAsNumericArray = create_projection_as_numeric_array
1238
1239    @deprecated_keywords({"useAnchorData": "use_anchor_data",
1240                          "anchorRadius": "anchor_radius"})
1241    def _getsum_i(self, data, use_anchor_data=0, anchor_radius=None):
1242        """
1243        Function to compute the sum of all values for each element in the data.
1244        Used to normalize.
1245       
1246        """
1247        if use_anchor_data:
1248            if anchor_radius == None:
1249                anchor_radius = numpy.sqrt([a[0]**2+a[1]**2+a[2]**2 for a in self.anchor_data])
1250            sum_i = numpy.add.reduce(numpy.transpose(numpy.transpose(data)*anchor_radius))
1251        else:
1252            sum_i = numpy.add.reduce(data)
1253        if len(numpy.nonzero(sum_i)) < len(sum_i):    # test if there are zeros in sum_i
1254            sum_i += numpy.where(sum_i == 0, 1.0, 0.0)
1255        return sum_i
1256   
1257    _getSum_i = _getsum_i
1258
1259ScaleLinProjData3D = deprecated_members({"setAnchors": "set_anchors",
1260                                       "createAnchors": "create_anchors",
1261                                       "saveProjectionAsTabData": "save_projection_as_tab_data",
1262                                       "getProjectedPointPosition":
1263                                           "get_projected_point_position",
1264                                       "createProjectionAsExampleTable":
1265                                           "create_projection_as_example_table",
1266                                       "createProjectionAsNumericArray":
1267                                           "create_projection_as_numeric_array",
1268                                       "_getSum_i": "_getsum_i",
1269                                       "normalizeExamples": "normalize_examples",
1270                                       "anchorData": "anchor_data",
1271                                       "lastAttrIndices": "last_attr_indices",
1272                                       "anchorDict": "anchor_dict",
1273                                       "trueScaleFactor": "true_scale_factor"
1274                                      })(ScaleLinProjData3D)
1275
1276class ScalePolyvizData(ScaleLinProjData):
1277    def __init__(self):
1278        ScaleLinProjData.__init__(self)
1279        self.normalize_examples = 1
1280        self.anchor_data =[]        # form: [(anchor1x, anchor1y, label1),(anchor2x, anchor2y, label2), ...]
1281       
1282
1283    # attributeReverse, validData = None, classList = None, sum_i = None, XAnchors = None, YAnchors = None, domain = None, scaleFactor = 1.0, jitterSize = 0.0
1284    @deprecated_keywords({"attrIndices": "attr_indices",
1285                          "settingsDict": "settings_dict"})
1286    def create_projection_as_example_table(self, attr_list, **settings_dict):
1287        if self.data_domain.class_var:
1288            domain = settings_dict.get("domain") or \
1289                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
1290                                         Orange.feature.Continuous("yVar"),
1291                                         Orange.feature.Discrete(self.data_domain.class_var.name,
1292                                                                       values = get_variable_values_sorted(self.data_domain.class_var))])
1293        else:
1294            domain = settings_dict.get("domain") or \
1295                     Orange.data.Domain([Orange.feature.Continuous("xVar"),
1296                                         Orange.feature.Continuous("yVar")])
1297        data = self.create_projection_as_numeric_array(attr_list, **settings_dict)
1298        if data != None:
1299            return Orange.data.Table(domain, data)
1300        else:
1301            return Orange.data.Table(domain)
1302   
1303    createProjectionAsExampleTable = create_projection_as_example_table
1304   
1305    @deprecated_keywords({"attrIndices": "attr_indices",
1306                          "settingsDict": "settings_dict",
1307                          "validData": "valid_data",
1308                          "classList": "class_list",
1309                          "XAnchors": "xanchors",
1310                          "YAnchors": "yanchors",
1311                          "scaleFactor": "scale_factor",
1312                          "jitterSize": "jitter_size",
1313                          "removeMissingData": "remove_missing_data",
1314                          })
1315    def create_projection_as_numeric_array(self, attr_indices, **settings_dict):
1316        # load the elements from the settings dict
1317        attribute_reverse = settings_dict.get("reverse", [0]*len(attr_indices))
1318        valid_data = settings_dict.get("valid_data")
1319        class_list = settings_dict.get("class_list")
1320        sum_i     = settings_dict.get("sum_i")
1321        xanchors  = settings_dict.get("xanchors")
1322        yanchors  = settings_dict.get("yanchors")
1323        scale_factor = settings_dict.get("scale_factor", 1.0)
1324        jitter_size  = settings_dict.get("jitter_size", 0.0)
1325        remove_missing_data = settings_dict.get("remove_missing_data", 1)
1326       
1327        if valid_data == None:
1328            valid_data = self.get_valid_list(attr_indices)
1329        if sum(valid_data) == 0:
1330            return None
1331
1332        if class_list == None and self.data_has_class:
1333            class_list = self.original_data[self.data_class_index]
1334
1335        if remove_missing_data:
1336            selected_data = numpy.compress(valid_data,
1337                                          numpy.take(self.no_jittering_scaled_data,
1338                                                     attr_indices, axis = 0),
1339                                                     axis = 1)
1340            if class_list != None and len(class_list) != numpy.shape(selected_data)[1]:
1341                class_list = numpy.compress(valid_data, class_list)
1342        else:
1343            selected_data = numpy.take(self.no_jittering_scaled_data,
1344                                      attr_indices, axis = 0)
1345       
1346        if sum_i == None:
1347            sum_i = self._getSum_i(selected_data)
1348
1349        if xanchors == None or yanchors == None:
1350            xanchors = self.create_xanchors(len(attr_indices))
1351            yanchors = self.create_yanchors(len(attr_indices))
1352
1353        xanchors = numpy.zeros(numpy.shape(selected_data), numpy.float)
1354        yanchors = numpy.zeros(numpy.shape(selected_data), numpy.float)
1355        length = len(attr_indices)
1356
1357        for i in range(length):
1358            if attribute_reverse[i]:
1359                xanchors[i] = selected_data[i] * xanchors[i] + (1-selected_data[i]) * xanchors[(i+1)%length]
1360                yanchors[i] = selected_data[i] * yanchors[i] + (1-selected_data[i]) * yanchors[(i+1)%length]
1361            else:
1362                xanchors[i] = (1-selected_data[i]) * xanchors[i] + selected_data[i] * xanchors[(i+1)%length]
1363                yanchors[i] = (1-selected_data[i]) * yanchors[i] + selected_data[i] * yanchors[(i+1)%length]
1364
1365        x_positions = numpy.sum(numpy.multiply(xanchors, selected_data), axis=0)/sum_i
1366        y_positions = numpy.sum(numpy.multiply(yanchors, selected_data), axis=0)/sum_i
1367        #x_positions = numpy.sum(numpy.transpose(xanchors* numpy.transpose(selectedData)), axis=0) / sum_i
1368        #y_positions = numpy.sum(numpy.transpose(yanchors* numpy.transpose(selectedData)), axis=0) / sum_i
1369
1370        if scale_factor != 1.0:
1371            x_positions = x_positions * scale_factor
1372            y_positions = y_positions * scale_factor
1373        if jitter_size > 0.0:
1374            x_positions += (numpy.random.random(len(x_positions))-0.5)*jitter_size
1375            y_positions += (numpy.random.random(len(y_positions))-0.5)*jitter_size
1376
1377        if class_list != None:
1378            return numpy.transpose(numpy.array((x_positions, y_positions, class_list)))
1379        else:
1380            return numpy.transpose(numpy.array((x_positions, y_positions)))
1381
1382    createProjectionAsNumericArray = create_projection_as_numeric_array
1383
1384    @deprecated_keywords({"attrIndices": "attr_indices",
1385                          "settingsDict": "settings_dict",
1386                          "useAnchorData": "use_anchor_data",
1387                          "XAnchors": "xanchors",
1388                          "YAnchors": "yanchors"})
1389    def get_projected_point_position(self, attr_indices, values, **settings_dict):
1390        # load the elements from the settings dict
1391        attribute_reverse = settings_dict.get("reverse", [0]*len(attr_indices))
1392        use_anchor_data = settings_dict.get("use_anchor_data")
1393        xanchors = settings_dict.get("xanchors")
1394        yanchors = settings_dict.get("yanchors")
1395   
1396        if xanchors != None and yanchors != None:
1397            xanchors = numpy.array(xanchors)
1398            yanchors = numpy.array(yanchors)
1399        elif use_anchor_data:
1400            xanchors = numpy.array([val[0] for val in self.anchor_data])
1401            yanchors = numpy.array([val[1] for val in self.anchor_data])
1402        else:
1403            xanchors = self.create_xanchors(len(attr_indices))
1404            yanchors = self.create_yanchors(len(attr_indices))
1405
1406        m = min(values); M = max(values)
1407        if m < 0.0 or M > 1.0:  # we have to do rescaling of values so that all
1408            # the values will be in the 0-1 interval
1409            values = [max(0.0, min(val, 1.0)) for val in values]
1410            #m = min(m, 0.0); M = max(M, 1.0); diff = max(M-m, 1e-10)
1411            #values = [(val-m) / float(diff) for val in values]
1412       
1413        s = sum(numpy.array(values))
1414        if s == 0: return [0.0, 0.0]
1415
1416        length = len(values)
1417        xanchors = numpy.zeros(length, numpy.float)
1418        yanchors = numpy.zeros(length, numpy.float)
1419        for i in range(length):
1420            if attribute_reverse[i]:
1421                xanchors[i] = values[i] * xanchors[i] + (1-values[i]) * xanchors[(i+1)%length]
1422                yanchors[i] = values[i] * yanchors[i] + (1-values[i]) * yanchors[(i+1)%length]
1423            else:
1424                xanchors[i] = (1-values[i]) * xanchors[i] + values[i] * xanchors[(i+1)%length]
1425                yanchors[i] = (1-values[i]) * yanchors[i] + values[i] * yanchors[(i+1)%length]
1426
1427        x_positions = numpy.sum(numpy.dot(xanchors, values), axis=0) / float(s)
1428        y_positions = numpy.sum(numpy.dot(yanchors, values), axis=0) / float(s)
1429        return [x, y]
1430   
1431    getProjectedPointPosition = get_projected_point_position
1432
1433ScalePolyvizData = deprecated_members({"createProjectionAsExampleTable":
1434                                           "create_projection_as_example_table",
1435                                       "createProjectionAsNumericArray":
1436                                           "create_projection_as_numeric_array",
1437                                       "getProjectedPointPosition":
1438                                           "get_projected_point_position"
1439                                       })(ScalePolyvizData)
1440
1441class ScaleScatterPlotData(ScaleData):
1442    def get_original_data(self, indices):
1443        data = self.original_data.take(indices, axis = 0)
1444        for i, ind in enumerate(indices):
1445            [minVal, maxVal] = self.attr_values[self.data_domain[ind].name]
1446            if self.data_domain[ind].varType == Orange.core.VarTypes.Discrete:
1447                data[i] += (self.jitter_size/50.0)*(numpy.random.random(len(self.raw_data)) - 0.5)
1448            elif self.data_domain[ind].varType == Orange.core.VarTypes.Continuous and self.jitter_continuous:
1449                data[i] += (self.jitter_size/(50.0*(maxVal-minVal or 1)))*(numpy.random.random(len(self.raw_data)) - 0.5)
1450        return data
1451   
1452    getOriginalData = get_original_data
1453   
1454    def get_original_subset_data(self, indices):
1455        data = self.original_subset_data.take(indices, axis = 0)
1456        for i, ind in enumerate(indices):
1457            [minVal, maxVal] = self.attr_values[self.raw_subset_data.domain[ind].name]
1458            if self.data_domain[ind].varType == Orange.core.VarTypes.Discrete:
1459                data[i] += (self.jitter_size/(50.0*max(1, maxVal)))*(numpy.random.random(len(self.raw_subset_data)) - 0.5)
1460            elif self.data_domain[ind].varType == Orange.core.VarTypes.Continuous and self.jitter_continuous:
1461                data[i] += (self.jitter_size/(50.0*(maxVal-minVal or 1)))*(numpy.random.random(len(self.raw_subset_data)) - 0.5)
1462        return data
1463
1464    getOriginalSubsetData = get_original_subset_data
1465
1466    @deprecated_keywords({"xAttr": "xattr", "yAttr": "yattr"})
1467    def get_xy_data_positions(self, xattr, yattr):
1468        """
1469        Create x-y projection of attributes in attrlist.
1470       
1471        """
1472        xattr_index, yattr_index = self.attribute_name_index[xattr], self.attribute_name_index[yattr]
1473
1474        xdata = self.scaled_data[xattr_index].copy()
1475        ydata = self.scaled_data[yattr_index].copy()
1476       
1477        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
1478        else:  xdata = xdata * (self.attr_values[xattr][1] - self.attr_values[xattr][0]) + float(self.attr_values[xattr][0])
1479
1480        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
1481        else:  ydata = ydata * (self.attr_values[yattr][1] - self.attr_values[yattr][0]) + float(self.attr_values[yattr][0])
1482        return (xdata, ydata)
1483   
1484    getXYDataPositions = get_xy_data_positions
1485   
1486    @deprecated_keywords({"xAttr": "xattr", "yAttr": "yattr"})
1487    def get_xy_subset_data_positions(self, xattr, yattr):
1488        """
1489        Create x-y projection of attributes in attr_list.
1490       
1491        """
1492        xattr_index, yattr_index = self.attribute_name_index[xattr], self.attribute_name_index[yattr]
1493
1494        xdata = self.scaled_subset_data[xattr_index].copy()
1495        ydata = self.scaled_subset_data[yattr_index].copy()
1496       
1497        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
1498        else:  xdata = xdata * (self.attr_values[xattr][1] - self.attr_values[xattr][0]) + float(self.attr_values[xattr][0])
1499
1500        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
1501        else:  ydata = ydata * (self.attr_values[yattr][1] - self.attr_values[yattr][0]) + float(self.attr_values[yattr][0])
1502        return (xdata, ydata)
1503   
1504    getXYSubsetDataPositions = get_xy_subset_data_positions
1505   
1506    @deprecated_keywords({"attrIndices": "attr_indices",
1507                          "settingsDict": "settings_dict"})
1508    def get_projected_point_position(self, attr_indices, values, **settings_dict):
1509        """
1510        For attributes in attr_indices and values of these attributes in values
1511        compute point positions this function has more sense in radviz and
1512        polyviz methods. settings_dict has to be because radviz and polyviz have
1513        this parameter.
1514        """
1515        return values
1516
1517    getProjectedPointPosition = get_projected_point_position
1518
1519    @deprecated_keywords({"attrIndices": "attr_indices",
1520                          "settingsDict": "settings_dict"})
1521    def create_projection_as_example_table(self, attr_indices, **settings_dict):
1522        """
1523        Create the projection of attribute indices given in attr_indices and
1524        create an example table with it.
1525       
1526        """
1527        if self.data_has_class:
1528            domain = settings_dict.get("domain") or \
1529                     Orange.data.Domain([Orange.feature.Continuous(self.data_domain[attr_indices[0]].name),
1530                                         Orange.feature.Continuous(self.data_domain[attr_indices[1]].name),
1531                                         Orange.feature.Discrete(self.data_domain.class_var.name,
1532                                                                       values = get_variable_values_sorted(self.data_domain.class_var))])
1533        else:
1534            domain = settings_dict.get("domain") or \
1535                     Orange.data.Domain([Orange.feature.Continuous(self.data_domain[attr_indices[0]].name),
1536                                         Orange.feature.Continuous(self.data_domain[attr_indices[1]].name)])
1537
1538        data = self.create_projection_as_numeric_array(attr_indices,
1539                                                       **settings_dict)
1540        if data != None:
1541            return Orange.data.Table(domain, data)
1542        else:
1543            return Orange.data.Table(domain)
1544
1545    createProjectionAsExampleTable = create_projection_as_example_table
1546
1547    @deprecated_keywords({"attrIndices": "attr_indices",
1548                          "settingsDict": "settings_dict"})
1549    def create_projection_as_example_table_3D(self, attr_indices, **settings_dict):
1550        """
1551        Create the projection of attribute indices given in attr_indices and
1552        create an example table with it.
1553       
1554        """
1555        if self.data_has_class:
1556            domain = settings_dict.get("domain") or \
1557                     Orange.data.Domain([Orange.feature.Continuous(self.data_domain[attr_indices[0]].name),
1558                                         Orange.feature.Continuous(self.data_domain[attr_indices[1]].name),
1559                                         Orange.feature.Continuous(self.data_domain[attr_indices[2]].name),
1560                                         Orange.feature.Discrete(self.data_domain.class_var.name,
1561                                                                       values = get_variable_values_sorted(self.data_domain.class_var))])
1562        else:
1563            domain = settings_dict.get("domain") or \
1564                     Orange.data.Domain([Orange.feature.Continuous(self.data_domain[attr_indices[0]].name),
1565                                         Orange.feature.Continuous(self.data_domain[attr_indices[1]].name),
1566                                         Orange.feature.Continuous(self.data_domain[attr_indices[2]].name)])
1567
1568        data = self.create_projection_as_numeric_array_3D(attr_indices,
1569                                                          **settings_dict)
1570        if data != None:
1571            return Orange.data.Table(domain, data)
1572        else:
1573            return Orange.data.Table(domain)
1574
1575    createProjectionAsExampleTable3D = create_projection_as_example_table_3D
1576
1577    @deprecated_keywords({"attrIndices": "attr_indices",
1578                          "settingsDict": "settings_dict",
1579                          "validData": "valid_data",
1580                          "classList": "class_list",
1581                          "jutterSize": "jitter_size"})
1582    def create_projection_as_numeric_array(self, attr_indices, **settings_dict):
1583        valid_data = settings_dict.get("valid_data")
1584        class_list = settings_dict.get("class_list")
1585        jitter_size = settings_dict.get("jitter_size", 0.0)
1586
1587        if valid_data == None:
1588            valid_data = self.get_valid_list(attr_indices)
1589        if sum(valid_data) == 0:
1590            return None
1591
1592        if class_list == None and self.data_has_class:
1593            class_list = self.original_data[self.data_class_index]
1594
1595        xarray = self.no_jittering_scaled_data[attr_indices[0]]
1596        yarray = self.no_jittering_scaled_data[attr_indices[1]]
1597        if jitter_size > 0.0:
1598            xarray += (numpy.random.random(len(xarray))-0.5)*jitter_size
1599            yarray += (numpy.random.random(len(yarray))-0.5)*jitter_size
1600        if class_list != None:
1601            data = numpy.compress(valid_data, numpy.array((xarray, yarray, class_list)), axis = 1)
1602        else:
1603            data = numpy.compress(valid_data, numpy.array((xarray, yarray)), axis = 1)
1604        data = numpy.transpose(data)
1605        return data
1606
1607    createProjectionAsNumericArray = create_projection_as_numeric_array
1608
1609    @deprecated_keywords({"attrIndices": "attr_indices",
1610                          "settingsDict": "settings_dict",
1611                          "validData": "valid_data",
1612                          "classList": "class_list",
1613                          "jutterSize": "jitter_size"})
1614    def create_projection_as_numeric_array_3D(self, attr_indices, **settings_dict):
1615        valid_data = settings_dict.get("valid_data")
1616        class_list = settings_dict.get("class_list")
1617        jitter_size = settings_dict.get("jitter_size", 0.0)
1618
1619        if valid_data == None:
1620            valid_data = self.get_valid_list(attr_indices)
1621        if sum(valid_data) == 0:
1622            return None
1623
1624        if class_list == None and self.data_has_class:
1625            class_list = self.original_data[self.data_class_index]
1626
1627        xarray = self.no_jittering_scaled_data[attr_indices[0]]
1628        yarray = self.no_jittering_scaled_data[attr_indices[1]]
1629        zarray = self.no_jittering_scaled_data[attr_indices[2]]
1630        if jitter_size > 0.0:
1631            xarray += (numpy.random.random(len(xarray))-0.5)*jitter_size
1632            yarray += (numpy.random.random(len(yarray))-0.5)*jitter_size
1633            zarray += (numpy.random.random(len(zarray))-0.5)*jitter_size
1634        if class_list != None:
1635            data = numpy.compress(valid_data, numpy.array((xarray, yarray, zarray, class_list)), axis = 1)
1636        else:
1637            data = numpy.compress(valid_data, numpy.array((xarray, yarray, zarray)), axis = 1)
1638        data = numpy.transpose(data)
1639        return data
1640
1641    createProjectionAsNumericArray3D = create_projection_as_numeric_array_3D
1642
1643    @deprecated_keywords({"attributeNameOrder": "attribute_name_order",
1644                          "addResultFunct": "add_result_funct"})
1645    def get_optimal_clusters(self, attribute_name_order, add_result_funct):
1646        if not self.data_has_class or self.data_has_continuous_class:
1647            return
1648       
1649        jitter_size = 0.001 * self.clusterOptimization.jitterDataBeforeTriangulation
1650        domain = Orange.data.Domain([Orange.feature.Continuous("xVar"),
1651                                     Orange.feature.Continuous("yVar"),
1652                                    self.data_domain.class_var])
1653
1654        # init again, in case that the attribute ordering took too much time
1655        self.scatterWidget.progressBarInit()
1656        start_time = time.time()
1657        count = len(attribute_name_order)*(len(attribute_name_order)-1)/2
1658        test_index = 0
1659
1660        for i in range(len(attribute_name_order)):
1661            for j in range(i):
1662                try:
1663                    attr1 = self.attribute_name_index[attribute_name_order[j]]
1664                    attr2 = self.attribute_name_index[attribute_name_order[i]]
1665                    test_index += 1
1666                    if self.clusterOptimization.isOptimizationCanceled():
1667                        secs = time.time() - start_time
1668                        self.clusterOptimization.setStatusBarText("Evaluation stopped (evaluated %d projections in %d min, %d sec)"
1669                                                                  % (test_index, secs/60, secs%60))
1670                        self.scatterWidget.progressBarFinished()
1671                        return
1672
1673                    data = self.create_projection_as_example_table([attr1, attr2],
1674                                                                   domain = domain,
1675                                                                   jitter_size = jitter_size)
1676                    graph, valuedict, closuredict, polygon_vertices_dict, enlarged_closure_dict, other_dict = self.clusterOptimization.evaluateClusters(data)
1677
1678                    all_value = 0.0
1679                    classes_dict = {}
1680                    for key in valuedict.keys():
1681                        add_result_funct(valuedict[key], closuredict[key],
1682                                         polygon_vertices_dict[key],
1683                                         [attribute_name_order[i],
1684                                          attribute_name_order[j]],
1685                                          int(graph.objects[polygon_vertices_dict[key][0]].getclass()),
1686                                          enlarged_closure_dict[key], other_dict[key])
1687                        classes_dict[key] = int(graph.objects[polygon_vertices_dict[key][0]].getclass())
1688                        all_value += valuedict[key]
1689                    add_result_funct(all_value, closuredict, polygon_vertices_dict,
1690                                     [attribute_name_order[i], attribute_name_order[j]],
1691                                     classes_dict, enlarged_closure_dict, other_dict)     # add all the clusters
1692                   
1693                    self.clusterOptimization.setStatusBarText("Evaluated %d projections..."
1694                                                              % (test_index))
1695                    self.scatterWidget.progressBarSet(100.0*test_index/float(count))
1696                    del data, graph, valuedict, closuredict, polygon_vertices_dict, enlarged_closure_dict, other_dict, classes_dict
1697                except:
1698                    type, val, traceback = sys.exc_info()
1699                    sys.excepthook(type, val, traceback)  # print the exception
1700       
1701        secs = time.time() - start_time
1702        self.clusterOptimization.setStatusBarText("Finished evaluation (evaluated %d projections in %d min, %d sec)" % (test_index, secs/60, secs%60))
1703        self.scatterWidget.progressBarFinished()
1704   
1705    getOptimalClusters = get_optimal_clusters
1706
1707ScaleScatterPlotData = deprecated_members({"getOriginalData": "get_original_data",
1708                                           "getOriginalSubsetData": "get_original_subset_data",
1709                                           "getXYDataPositions": "get_xy_data_positions",
1710                                           "getXYSubsetDataPositions": "get_xy_subset_data_positions",
1711                                           "getProjectedPointPosition": "get_projected_point_position",
1712                                           "createProjectionAsExampleTable": "create_projection_as_example_table",
1713                                           "createProjectionAsExampleTable3D": "create_projection_as_example_table_3D",
1714                                           "createProjectionAsNumericArray": "create_projection_as_numeric_array",
1715                                           "createProjectionAsNumericArray3D": "create_projection_as_numeric_array_3D",
1716                                           "getOptimalClusters": "get_optimal_clusters"
1717                                           })(ScaleScatterPlotData)
Note: See TracBrowser for help on using the repository browser.