~ubuntu-branches/ubuntu/precise/python-chaco/precise

« back to all changes in this revision

Viewing changes to enthought/chaco/log_mapper.py

  • Committer: Bazaar Package Importer
  • Author(s): Varun Hiremath
  • Date: 2008-12-29 02:34:05 UTC
  • Revision ID: james.westby@ubuntu.com-20081229023405-x7i4kp9mdxzmdnvu
Tags: upstream-3.0.1
ImportĀ upstreamĀ versionĀ 3.0.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
""" Defines the LogMapper and InvalidDataRangeException classes.
 
2
"""
 
3
# Major library imports
 
4
from numpy import array, isnan, log, log10, exp, zeros, sometrue,\
 
5
    floor, ceil
 
6
 
 
7
# Enthought library imports
 
8
from enthought.traits.api import Bool, Float
 
9
 
 
10
#Local relative imports
 
11
from base_1d_mapper import Base1DMapper
 
12
 
 
13
 
 
14
LOG_MINIMUM = 0.0
 
15
 
 
16
class InvalidDataRangeException(Exception):
 
17
    pass
 
18
 
 
19
class LogMapper(Base1DMapper):
 
20
    """ Defines a 1-D logarithmic scale mapping from a 1-D region in input
 
21
    space to a 1-D region in output space.
 
22
    """
 
23
    
 
24
    # The value to map when asked to map values <= LOG_MINIMUM to screen space.
 
25
    fill_value = Float(1.0)
 
26
    
 
27
    #------------------------------------------------------------------------
 
28
    # Private traits
 
29
    #------------------------------------------------------------------------
 
30
 
 
31
    _inter_scale = Float(0.0)
 
32
    _inter_offset = Float(0.0)
 
33
    _screen_scale = Float(0.0)
 
34
    _screen_offset = Float(0.0)
 
35
    _null_screen_range = Bool(False)
 
36
    _null_data_range = Bool(False)
 
37
 
 
38
    #------------------------------------------------------------------------
 
39
    # Public methods
 
40
    #------------------------------------------------------------------------
 
41
 
 
42
    def map_screen(self, data_array):
 
43
        """ map_screen(data_array) -> screen_array
 
44
 
 
45
        Overrides AbstractMapper. Maps values from data space to screen space.
 
46
        """
 
47
        #First convert to a [0,1] space, then to the screen space
 
48
        if not self._cache_valid:
 
49
            self._compute_scale()
 
50
        if self._inter_scale == 0.0:
 
51
            intermediate = data_array*0.0
 
52
        else:
 
53
            try:
 
54
                mask = (data_array <= LOG_MINIMUM) | isnan(data_array)
 
55
                if sometrue(mask):
 
56
                    data_array = array(data_array, copy=True, ndmin=1)
 
57
                    data_array[mask] = self.fill_value
 
58
                intermediate = (log(data_array) - self._inter_offset)/self._inter_scale
 
59
            except ValueError:
 
60
                intermediate = zeros(len(data_array))
 
61
 
 
62
        return intermediate * self._screen_scale + self._screen_offset
 
63
 
 
64
    def map_data(self, screen_val):
 
65
        """ map_data(screen_val) -> data_val
 
66
 
 
67
        Overrides Abstract Mapper. Maps values from screen space into data space.
 
68
        """
 
69
        if not self._cache_valid:
 
70
            self._compute_scale()
 
71
        if self._null_screen_range or self._null_data_range:
 
72
            return array([self.range.low])
 
73
        #First convert to a [0,1] space, then to the data space
 
74
        intermediate = (screen_val-self._screen_offset)/self._screen_scale
 
75
        return exp(self._inter_scale*intermediate + self._inter_offset)
 
76
 
 
77
    def map_data_array(self, screen_vals):
 
78
        return self.map_data(screen_vals)
 
79
        
 
80
    #------------------------------------------------------------------------
 
81
    # Private methods
 
82
    #------------------------------------------------------------------------
 
83
 
 
84
    def _get_safe_scale(self, range):
 
85
        orig_low = range.low
 
86
        orig_high = range.high
 
87
        if orig_low < LOG_MINIMUM:
 
88
            low = LOG_MINIMUM
 
89
        else:
 
90
            low = orig_low
 
91
        
 
92
        if orig_high < LOG_MINIMUM:
 
93
            high = LOG_MINIMUM
 
94
        else:
 
95
            high = orig_high
 
96
        
 
97
        if low == high:
 
98
            if low == LOG_MINIMUM:
 
99
                low = 1.0
 
100
                high = 10.0
 
101
            else:
 
102
                log_val = log10(low)
 
103
                low = pow(10, floor(log_val))
 
104
                if ceil(log_val) != floor(log_val):
 
105
                    high = pow(10, ceil(log_val))
 
106
                else:
 
107
                    high = pow(10, ceil(log_val) + 1)
 
108
        
 
109
        return (low, high)
 
110
 
 
111
    def _compute_scale(self):
 
112
        if self._cache_valid:
 
113
            return
 
114
        
 
115
        if self.range is None:
 
116
            self._cache_valid = False
 
117
            return
 
118
        
 
119
        screen_range = self.high_pos - self.low_pos 
 
120
        if screen_range == 0.0:
 
121
            self._null_screen_range = True
 
122
 
 
123
        # Get dataspace low and high from the range that are "safe" for a
 
124
        # logarithmic mapper, i.e. constrained to be between LOG_MINIMUM and inf.
 
125
        low, high = self._get_safe_scale(self.range)
 
126
        if high - low == 0:
 
127
            self._null_data_range = True
 
128
        else:
 
129
            if low == LOG_MINIMUM:
 
130
                self._inter_scale = log(high)
 
131
                self._inter_offset = 0.0
 
132
            else:
 
133
                self._inter_scale = log(high)-log(low)
 
134
                self._inter_offset = log(low)
 
135
            self._screen_scale = screen_range
 
136
            self._screen_offset = self.low_pos
 
137
        
 
138
        self._cache_valid = True
 
139
        return
 
140
 
 
141
# EOF