~ubuntu-branches/ubuntu/gutsy/matplotlib/gutsy

« back to all changes in this revision

Viewing changes to lib/matplotlib/colorbar.py

  • Committer: Bazaar Package Importer
  • Author(s): Michael Bienia
  • Date: 2007-07-31 23:04:56 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20070731230456-lfmr0h69yh1i37w1
Tags: 0.90.1-2ubuntu1
* Merge from Debian unstable. Remaining changes:
  + debian/rules:
    - Check only the files for the python version which just got installed
      (fixes FTBFS).
    - Modify Maintainer value to match DebianMaintainerField spec.

Show diffs side-by-side

added added

removed removed

Lines of Context:
35
35
                              new image axes
36
36
        shrink      = 1.0; fraction by which to shrink the colorbar
37
37
        aspect      = 20; ratio of long to short dimensions
 
38
 
38
39
'''
39
40
 
40
41
colormap_kw_doc = '''
55
56
                If true, draw lines at color boundaries.
56
57
 
57
58
        The following will probably be useful only in the context of
58
 
        indexed colors (that is, when the mappable has norm=no_norm()),
 
59
        indexed colors (that is, when the mappable has norm=NoNorm()),
59
60
        or other unusual circumstances.
60
61
 
61
62
        boundaries=None or a sequence
92
93
 
93
94
If mappable is a ContourSet, its extend kwarg is included automatically.
94
95
 
 
96
Note that the shrink kwarg provides a simple way to keep
 
97
a vertical colorbar, for example, from being taller than
 
98
the axes of the mappable to which the colorbar is attached;
 
99
but it is a manual method requiring some trial and error.
 
100
If the colorbar is too tall (or a horizontal colorbar is
 
101
too wide) use a smaller value of shrink.
 
102
 
 
103
For more precise control, you can manually specify the
 
104
positions of the axes objects in which the mappable and
 
105
the colorbar are drawn.  In this case, do not use any of the
 
106
axes properties kwargs.
95
107
''' % (make_axes_kw_doc, colormap_kw_doc)
96
108
 
97
109
 
106
118
 
107
119
    def __init__(self, ax, cmap=None,
108
120
                           norm=None,
 
121
                           alpha=1.0,
109
122
                           values=None,
110
123
                           boundaries=None,
111
124
                           orientation='vertical',
118
131
                           ):
119
132
        self.ax = ax
120
133
        if cmap is None: cmap = cm.get_cmap()
121
 
        if norm is None: norm = colors.normalize()
 
134
        if norm is None: norm = colors.Normalize()
 
135
        self.alpha = alpha
122
136
        cm.ScalarMappable.__init__(self, cmap=cmap, norm=norm)
123
137
        self.values = values
124
138
        self.boundaries = boundaries
131
145
        self.solids = None
132
146
        self.lines = None
133
147
        if iterable(ticks):
134
 
            self.locator = ticker.FixedLocator(ticks, nbins=10)
 
148
            self.locator = ticker.FixedLocator(ticks, nbins=len(ticks))
135
149
        else:
136
150
            self.locator = ticks    # Handle default in _ticker()
137
151
        if format is None:
138
 
            self.formatter = ticker.ScalarFormatter()
 
152
            if isinstance(self.norm, colors.LogNorm):
 
153
                self.formatter = ticker.LogFormatter()
 
154
            else:
 
155
                self.formatter = ticker.ScalarFormatter()
139
156
        elif is_string_like(format):
140
157
            self.formatter = ticker.FormatStrFormatter(format)
141
158
        else:
225
242
 
226
243
    def _add_solids(self, X, Y, C):
227
244
        '''
228
 
        Draw the colors using pcolormesh; optionally add separators.
 
245
        Draw the colors using pcolor; optionally add separators.
229
246
        '''
 
247
        ## Change to pcolormesh if/when it is fixed to handle alpha
 
248
        ## correctly.
230
249
        if self.orientation == 'vertical':
231
250
            args = (X, Y, C)
232
251
        else:
233
252
            args = (nx.transpose(Y), nx.transpose(X), nx.transpose(C))
234
 
        kw = {'cmap':self.cmap, 'norm':self.norm, 'shading':'flat'}
 
253
        kw = {'cmap':self.cmap, 'norm':self.norm,
 
254
                    'shading':'flat', 'alpha':self.alpha}
235
255
        col = self.ax.pcolor(*args, **kw)
236
 
        self.add_observer(col)
 
256
        #self.add_observer(col) # We should observe, not be observed...
237
257
        self.solids = col
238
258
        if self.drawedges:
239
259
            self.dividers = LineCollection(self._edges(X,Y),
247
267
        Draw lines on the colorbar.
248
268
        '''
249
269
        N = len(levels)
250
 
        y = self._locate(levels)
 
270
        dummy, y = self._locate(levels)
 
271
        if len(y) <> N:
 
272
            raise ValueError("levels are outside colorbar range")
251
273
        x = nx.array([0.0, 1.0])
252
274
        X, Y = meshgrid(x,y)
253
275
        if self.orientation == 'vertical':
269
291
        formatter = self.formatter
270
292
        if locator is None:
271
293
            if self.boundaries is None:
272
 
                if isinstance(self.norm, colors.no_norm):
 
294
                if isinstance(self.norm, colors.NoNorm):
273
295
                    nv = len(self._values)
274
296
                    base = 1 + int(nv/10)
275
297
                    locator = ticker.IndexLocator(base=base, offset=0)
 
298
                elif isinstance(self.norm, colors.LogNorm):
 
299
                    locator = ticker.LogLocator()
276
300
                else:
277
301
                    locator = ticker.MaxNLocator()
278
302
            else:
279
303
                b = self._boundaries[self._inside]
280
304
                locator = ticker.FixedLocator(b, nbins=10)
281
 
        if isinstance(self.norm, colors.no_norm):
 
305
        if isinstance(self.norm, colors.NoNorm):
282
306
            intv = Interval(Value(self._values[0]), Value(self._values[-1]))
283
307
        else:
284
308
            intv = Interval(Value(self.vmin), Value(self.vmax))
287
311
        formatter.set_view_interval(intv)
288
312
        formatter.set_data_interval(intv)
289
313
        b = nx.array(locator())
290
 
        eps = 0.001 * (self.vmax - self.vmin)
291
 
        b = nx.compress((b >= self.vmin-eps) & (b <= self.vmax+eps), b)
292
 
        ticks = self._locate(b)
 
314
        b, ticks = self._locate(b)
293
315
        formatter.set_locs(b)
294
316
        ticklabels = [formatter(t) for t in b]
295
317
        offset_string = formatter.get_offset()
308
330
            if self.values is None:
309
331
                self._values = 0.5*(self._boundaries[:-1]
310
332
                                        + self._boundaries[1:])
311
 
                if isinstance(self.norm, colors.no_norm):
 
333
                if isinstance(self.norm, colors.NoNorm):
312
334
                    self._values = (self._values + 0.00001).astype(nx.Int16)
313
335
                return
314
336
            self._values = nx.array(self.values)
324
346
                return
325
347
            self._boundaries = nx.array(self.boundaries)
326
348
            return
327
 
        if isinstance(self.norm, colors.no_norm):
 
349
        if isinstance(self.norm, colors.NoNorm):
328
350
            b = nx.arange(self.norm.vmin, self.norm.vmax + 2) - 0.5
329
351
        else:
330
 
            dv = self.norm.vmax - self.norm.vmin
331
 
            b = self.norm.vmin + dv * self._uniform_y(self.cmap.N+1)
 
352
            b = self.norm.inverse(self._uniform_y(self.cmap.N+1))
332
353
        self._process_values(b)
333
354
 
334
355
    def _find_range(self):
393
414
        if self.extend in ('both', 'max'):
394
415
            y[-1] = 1.05
395
416
        yi = y[self._inside]
396
 
        norm = colors.normalize(yi[0], yi[-1])
 
417
        norm = colors.Normalize(yi[0], yi[-1])
397
418
        y[self._inside] = norm(yi)
398
419
        return y
399
420
 
419
440
 
420
441
    def _locate(self, x):
421
442
        '''
422
 
        Return the colorbar data coordinate(s) corresponding to the color
423
 
        value(s) in scalar or array x.
424
 
        Used for tick positioning.
 
443
        Given a possible set of color data values, return the ones
 
444
        within range, together with their corresponding colorbar
 
445
        data coordinates.
425
446
        '''
426
 
        b = self._boundaries
 
447
        if isinstance(self.norm, colors.NoNorm):
 
448
            b = self._boundaries
 
449
            xn = x
 
450
            xout = x
 
451
        else:
 
452
            # Do calculations using normalized coordinates so
 
453
            # as to make the interpolation more accurate.
 
454
            b = self.norm(self._boundaries, clip=False).filled()
 
455
            # We do our own clipping so that we can allow a tiny
 
456
            # bit of slop in the end point ticks to allow for
 
457
            # floating point errors.
 
458
            xn = self.norm(x, clip=False).filled()
 
459
            in_cond = (xn > -0.001) & (xn < 1.001)
 
460
            xn = nx.compress(in_cond, xn)
 
461
            xout = nx.compress(in_cond, x)
 
462
        # The rest is linear interpolation with clipping.
427
463
        y = self._y
428
464
        N = len(b)
429
 
        ii = nx.minimum(nx.searchsorted(b, x), N-1)
430
 
        isscalar = False
431
 
        if not iterable(ii):
432
 
            isscalar = True
433
 
            ii = nx.array((ii,))
 
465
        ii = nx.minimum(nx.searchsorted(b, xn), N-1)
434
466
        i0 = nx.maximum(ii - 1, 0)
435
 
        #db = b[ii] - b[i0]
 
467
        #db = b[ii] - b[i0]  (does not work with Numeric)
436
468
        db = nx.take(b, ii) - nx.take(b, i0)
437
469
        db = nx.where(i0==ii, 1.0, db)
438
470
        #dy = y[ii] - y[i0]
439
471
        dy = nx.take(y, ii) - nx.take(y, i0)
440
 
        z = nx.take(y, i0) + (x-nx.take(b,i0))*dy/db
441
 
        if isscalar:
442
 
            z = z[0]
443
 
        return z
 
472
        z = nx.take(y, i0) + (xn-nx.take(b,i0))*dy/db
 
473
        return xout, z
 
474
 
 
475
    def set_alpha(self, alpha):
 
476
        self.alpha = alpha
444
477
 
445
478
class Colorbar(ColorbarBase):
446
479
    def __init__(self, ax, mappable, **kw):
447
 
        mappable.autoscale() # Ensure mappable.norm.vmin, vmax
 
480
        mappable.autoscale_None() # Ensure mappable.norm.vmin, vmax
448
481
                             # are set when colorbar is called,
449
482
                             # even if mappable.draw has not yet
450
483
                             # been called.  This will not change
451
484
                             # vmin, vmax if they are already set.
452
485
        self.mappable = mappable
 
486
        kw['cmap'] = mappable.cmap
 
487
        kw['norm'] = mappable.norm
 
488
        kw['alpha'] = mappable.get_alpha()
453
489
        if isinstance(mappable, ContourSet):
454
490
            CS = mappable
455
 
            kw['cmap'] = CS.cmap
456
 
            kw['norm'] = CS.norm
457
491
            kw['boundaries'] = CS._levels
458
492
            kw['values'] = CS.cvalues
459
493
            kw['extend'] = CS.extend
460
494
            #kw['ticks'] = CS._levels
461
 
            kw.setdefault('ticks', CS.levels)
 
495
            kw.setdefault('ticks', ticker.FixedLocator(CS.levels, nbins=10))
462
496
            kw['filled'] = CS.filled
463
497
            ColorbarBase.__init__(self, ax, **kw)
464
498
            if not CS.filled:
465
499
                self.add_lines(CS)
466
500
        else:
467
 
            kw['cmap'] = mappable.cmap
468
 
            kw['norm'] = mappable.norm
469
501
            ColorbarBase.__init__(self, ax, **kw)
470
502
 
471
503
 
477
509
            raise ValueError('add_lines is only for a ContourSet of lines')
478
510
        tcolors = [c[0] for c in CS.tcolors]
479
511
        tlinewidths = [t[0] for t in CS.tlinewidths]
 
512
        # The following was an attempt to get the colorbar lines
 
513
        # to follow subsequent changes in the contour lines,
 
514
        # but more work is needed: specifically, a careful
 
515
        # look at event sequences, and at how
 
516
        # to make one object track another automatically.
 
517
        #tcolors = [col.get_colors()[0] for col in CS.collections]
 
518
        #tlinewidths = [col.get_linewidth()[0] for lw in CS.collections]
 
519
        #print 'tlinewidths:', tlinewidths
480
520
        ColorbarBase.add_lines(self, CS.levels, tcolors, tlinewidths)
481
521
 
482
522
    def notify(self, mappable):
485
525
        is changed.
486
526
        '''
487
527
        cm.ScalarMappable.notify(self, mappable)
488
 
        if self.vmin != self.norm.vmin or self.vmax != self.norm.vmax:
489
 
            self.ax.cla()
490
 
            self.draw_all()
 
528
        self.ax.cla()
 
529
        self.draw_all()
 
530
        #if self.vmin != self.norm.vmin or self.vmax != self.norm.vmax:
 
531
        #    self.ax.cla()
 
532
        #    self.draw_all()
491
533
        if isinstance(self.mappable, ContourSet):
492
534
            CS = self.mappable
493
 
            if self.lines is not None:
494
 
                tcolors = [c[0] for c in CS.tcolors]
495
 
                self.lines.set_color(tcolors)
 
535
            if not CS.filled:
 
536
                self.add_lines(CS)
 
537
            #if self.lines is not None:
 
538
            #    tcolors = [c[0] for c in CS.tcolors]
 
539
            #    self.lines.set_color(tcolors)
496
540
        #Fixme? Recalculate boundaries, ticks if vmin, vmax have changed.
497
 
 
 
541
        #Fixme: Some refactoring may be needed; we should not
 
542
        # be recalculating everything if there was a simple alpha
 
543
        # change.
498
544
 
499
545
def make_axes(parent, **kw):
500
546
    orientation = kw.setdefault('orientation', 'vertical')