From: <lee...@us...> - 2009-08-08 02:07:11
|
Revision: 7423 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=7423&view=rev Author: leejjoon Date: 2009-08-08 02:06:56 +0000 (Sat, 08 Aug 2009) Log Message: ----------- BboxImage implemented and two examples added. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/image.py Added Paths: ----------- trunk/matplotlib/examples/pylab_examples/demo_bboximage.py trunk/matplotlib/examples/pylab_examples/demo_ribbon_box.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2009-08-08 01:46:44 UTC (rev 7422) +++ trunk/matplotlib/CHANGELOG 2009-08-08 02:06:56 UTC (rev 7423) @@ -1,3 +1,6 @@ +2009-08-07 BboxImage implemented. Two examples, demo_bboximage.py and + demo_ribbon_box.py added. - JJL + 2009-08-07 In an effort to simplify the backend API, all clipping rectangles and paths are now passed in using GraphicsContext objects, even on collections and images. Therefore: Added: trunk/matplotlib/examples/pylab_examples/demo_bboximage.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/demo_bboximage.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/demo_bboximage.py 2009-08-08 02:06:56 UTC (rev 7423) @@ -0,0 +1,62 @@ +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.image import BboxImage +from matplotlib.transforms import Bbox, TransformedBbox + +if __name__ == "__main__": + + fig = plt.figure(1) + ax = plt.subplot(121) + + txt = ax.text(0.5, 0.5, "test", size=30, ha="center", color="w") + kwargs = dict() + + bbox_image = BboxImage(txt.get_window_extent, + norm = None, + origin=None, + clip_on=False, + **kwargs + ) + a = np.arange(256).reshape(1,256)/256. + bbox_image.set_data(a) + ax.add_artist(bbox_image) + + + ax = plt.subplot(122) + a = np.linspace(0, 1, 256).reshape(1,-1) + a = np.vstack((a,a)) + + maps = sorted(m for m in plt.cm.datad if not m.endswith("_r")) + #nmaps = len(maps) + 1 + + #fig.subplots_adjust(top=0.99, bottom=0.01, left=0.2, right=0.99) + + ncol = 2 + nrow = len(maps)//ncol + 1 + + xpad_fraction = 0.3 + dx = 1./(ncol + xpad_fraction*(ncol-1)) + + ypad_fraction = 0.3 + dy = 1./(nrow + ypad_fraction*(nrow-1)) + + for i,m in enumerate(maps): + ix, iy = divmod(i, nrow) + #plt.figimage(a, 10, i*10, cmap=plt.get_cmap(m), origin='lower') + bbox0 = Bbox.from_bounds(ix*dx*(1+xpad_fraction), + 1.-iy*dy*(1+ypad_fraction)-dy, + dx, dy) + bbox = TransformedBbox(bbox0, ax.transAxes) + + bbox_image = BboxImage(bbox, + cmap = plt.get_cmap(m), + norm = None, + origin=None, + **kwargs + ) + + bbox_image.set_data(a) + ax.add_artist(bbox_image) + + plt.draw() + plt.show() Added: trunk/matplotlib/examples/pylab_examples/demo_ribbon_box.py =================================================================== --- trunk/matplotlib/examples/pylab_examples/demo_ribbon_box.py (rev 0) +++ trunk/matplotlib/examples/pylab_examples/demo_ribbon_box.py 2009-08-08 02:06:56 UTC (rev 7423) @@ -0,0 +1,140 @@ +import matplotlib.pyplot as plt +import numpy as np +from matplotlib.image import BboxImage + +from matplotlib._png import read_png +import matplotlib.colors +from matplotlib.cbook import get_sample_data + +class RibbonBox(object): + + original_image = read_png(get_sample_data("Minduka_Present_Blue_Pack.png", + asfileobj=False)) + cut_location = 70 + b_and_h = original_image[:,:,2] + color = original_image[:,:,2] - original_image[:,:,0] + alpha = original_image[:,:,3] + nx = original_image.shape[1] + + def __init__(self, color): + rgb = matplotlib.colors.colorConverter.to_rgb(color) + + im = np.empty(self.original_image.shape, + self.original_image.dtype) + + + im[:,:,:3] = self.b_and_h[:,:,np.newaxis] + im[:,:,:3] -= self.color[:,:,np.newaxis]*(1.-np.array(rgb)) + im[:,:,3] = self.alpha + + self.im = im + + + def get_stretched_image(self, stretch_factor): + stretch_factor = max(stretch_factor, 1) + ny, nx, nch = self.im.shape + ny2 = int(ny*stretch_factor) + + stretched_image = np.empty((ny2, nx, nch), + self.im.dtype) + cut = self.im[self.cut_location,:,:] + stretched_image[:,:,:] = cut + stretched_image[:self.cut_location,:,:] = \ + self.im[:self.cut_location,:,:] + stretched_image[-(ny-self.cut_location):,:,:] = \ + self.im[-(ny-self.cut_location):,:,:] + + self._cached_im = stretched_image + return stretched_image + + + +class RibbonBoxImage(BboxImage): + zorder = 1 + + def __init__(self, bbox, color, + cmap = None, + norm = None, + interpolation=None, + origin=None, + filternorm=1, + filterrad=4.0, + resample = False, + **kwargs + ): + + BboxImage.__init__(self, bbox, + cmap = None, + norm = None, + interpolation=None, + origin=None, + filternorm=1, + filterrad=4.0, + resample = False, + **kwargs + ) + + self._ribbonbox = RibbonBox(color) + self._cached_ny = None + + + def draw(self, renderer, *args, **kwargs): + + bbox = self.get_window_extent(renderer) + stretch_factor = bbox.height / bbox.width + + ny = int(stretch_factor*self._ribbonbox.nx) + if self._cached_ny != ny: + arr = self._ribbonbox.get_stretched_image(stretch_factor) + self.set_array(arr) + self._cached_ny = ny + + BboxImage.draw(self, renderer, *args, **kwargs) + + +if 1: + from matplotlib.transforms import Bbox, TransformedBbox + from matplotlib.ticker import ScalarFormatter + + fig = plt.gcf() + fig.clf() + ax = plt.subplot(111) + + years = np.arange(2004, 2009) + box_colors = [(0.8, 0.2, 0.2), + (0.2, 0.8, 0.2), + (0.2, 0.2, 0.8), + (0.7, 0.5, 0.8), + (0.3, 0.8, 0.7), + ] + heights = np.random.random(years.shape) * 7000 + 3000 + + fmt = ScalarFormatter(useOffset=False) + ax.xaxis.set_major_formatter(fmt) + + for year, h, bc in zip(years, heights, box_colors): + bbox0 = Bbox.from_extents(year-0.4, 0., year+0.4, h) + bbox = TransformedBbox(bbox0, ax.transData) + rb_patch = RibbonBoxImage(bbox, bc) + + ax.add_artist(rb_patch) + + ax.annotate(r"%d" % (int(h/100.)*100), + (year, h), va="bottom", ha="center") + + patch_gradient = BboxImage(ax.bbox, + interpolation="bicubic", + zorder=0.1, + ) + gradient = np.zeros((2, 2, 4), dtype=np.float) + gradient[:,:,:3] = [1, 1, 0.] + gradient[:,:,3] = [[0.1, 0.3],[0.3, 0.5]] # alpha channel + patch_gradient.set_array(gradient) + ax.add_artist(patch_gradient) + + + ax.set_xlim(years[0]-0.5, years[-1]+0.5) + ax.set_ylim(0, 10000) + + plt.show() + Modified: trunk/matplotlib/lib/matplotlib/image.py =================================================================== --- trunk/matplotlib/lib/matplotlib/image.py 2009-08-08 01:46:44 UTC (rev 7422) +++ trunk/matplotlib/lib/matplotlib/image.py 2009-08-08 02:06:56 UTC (rev 7423) @@ -24,6 +24,8 @@ # the image namespace: from matplotlib._image import * +from matplotlib.transforms import BboxBase + class AxesImage(martist.Artist, cm.ScalarMappable): zorder = 1 # map interpolation strings to module constants @@ -744,6 +746,149 @@ rows, cols, buffer = im.as_rgba_str() _png.write_png(buffer, cols, rows, fname) + +class BboxImage(AxesImage): + """ + The Image class whose size is determined by the given bbox. + """ + zorder = 1 + def __init__(self, bbox, + cmap = None, + norm = None, + interpolation=None, + origin=None, + filternorm=1, + filterrad=4.0, + resample = False, + **kwargs + ): + + """ + cmap is a colors.Colormap instance + norm is a colors.Normalize instance to map luminance to 0-1 + + kwargs are an optional list of Artist keyword args + """ + + AxesImage.__init__(self, ax=None, + cmap = cmap, + norm = norm, + interpolation=interpolation, + origin=origin, + filternorm=filternorm, + filterrad=filterrad, + resample = resample, + **kwargs + ) + + self.bbox = bbox + + def get_window_extent(self, renderer=None): + if renderer is None: + renderer = self.get_figure()._cachedRenderer + + if isinstance(self.bbox, BboxBase): + return self.bbox + elif callable(self.bbox): + return self.bbox(renderer) + else: + raise ValueError("unknown type of bbox") + + + def contains(self, mouseevent): + """Test whether the mouse event occured within the image. + """ + + if callable(self._contains): return self._contains(self,mouseevent) + + if not self.get_visible():# or self.get_figure()._renderer is None: + return False,{} + + x, y = mouseevent.x, mouseevent.y + inside = self.get_window_extent().contains(x, y) + + return inside,{} + + def get_size(self): + 'Get the numrows, numcols of the input image' + if self._A is None: + raise RuntimeError('You must first set the image array') + + return self._A.shape[:2] + + def make_image(self, renderer, magnification=1.0): + if self._A is None: + raise RuntimeError('You must first set the image array or the image attribute') + + if self._imcache is None: + if self._A.dtype == np.uint8 and len(self._A.shape) == 3: + im = _image.frombyte(self._A, 0) + im.is_grayscale = False + else: + if self._rgbacache is None: + x = self.to_rgba(self._A, self._alpha) + self._rgbacache = x + else: + x = self._rgbacache + im = _image.fromarray(x, 0) + if len(self._A.shape) == 2: + im.is_grayscale = self.cmap.is_gray() + else: + im.is_grayscale = False + self._imcache = im + + if self.origin=='upper': + im.flipud_in() + else: + im = self._imcache + + if 0: + fc = self.axes.patch.get_facecolor() + bg = mcolors.colorConverter.to_rgba(fc, 0) + im.set_bg( *bg) + + # image input dimensions + im.reset_matrix() + + im.set_interpolation(self._interpd[self._interpolation]) + + im.set_resample(self._resample) + + l, b, r, t = self.get_window_extent(renderer).extents #bbox.extents + widthDisplay = (round(r) + 0.5) - (round(l) - 0.5) + heightDisplay = (round(t) + 0.5) - (round(b) - 0.5) + widthDisplay *= magnification + heightDisplay *= magnification + #im.apply_translation(tx, ty) + + numrows, numcols = self._A.shape[:2] + + # resize viewport to display + rx = widthDisplay / numcols + ry = heightDisplay / numrows + #im.apply_scaling(rx*sx, ry*sy) + im.apply_scaling(rx, ry) + #im.resize(int(widthDisplay+0.5), int(heightDisplay+0.5), + # norm=self._filternorm, radius=self._filterrad) + im.resize(int(widthDisplay), int(heightDisplay), + norm=self._filternorm, radius=self._filterrad) + return im + + + @allow_rasterization + def draw(self, renderer, *args, **kwargs): + if not self.get_visible(): return + # todo: we should be able to do some cacheing here + image_mag = renderer.get_image_magnification() + im = self.make_image(renderer, image_mag) + l, b, r, t = self.get_window_extent(renderer).extents + gc = renderer.new_gc() + self._set_gc_clip(gc) + #gc.set_clip_path(self.get_clip_path()) + renderer.draw_image(gc, round(l), round(b), im) + + + def imread(fname): """ Return image file in *fname* as :class:`numpy.array`. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |