source: cows/branches/cows-vis/cows/service/imps/pywms/render_imp.py @ 5265

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows/branches/cows-vis/cows/service/imps/pywms/render_imp.py@5265
Revision 5265, 9.0 KB checked in by domlowe, 11 years ago (diff)

adding separate cowsclient pylons app

Line 
1# BSD Licence
2# Copyright (c) 2009, Science & Technology Facilities Council (STFC)
3# All rights reserved.
4#
5# See the LICENSE file in the source distribution of this software for
6# the full license text.
7
8"""
9Implementation of grid rendering classes.
10
11@author: Stephen Pascoe
12"""
13
14from view import GridRenderer
15import ImageColor, Image
16import numpy as N
17import logging
18from matplotlib import cm, colors
19
20logger = logging.getLogger(__name__)
21
22class ddcRGBARenderer(GridRenderer):
23    """Creates an RGBA PNG with a selectable matplotlib colour scale.
24    @todo: This shouldn't be called RgbaPNGRenderer because it produces PIL RGBA images, not just PNG.
25    """
26
27    mimeType = 'image/png'
28
29    def __init__(self, varmin, varmax):
30        self.setMinMax(varmin, varmax)
31       
32    def setMinMax(self, varmin, varmax):
33        self.varmin = varmin
34        self.varmax = varmax
35        self._norm = colors.normalize(varmin, varmax)
36       
37        logger.debug('Instantiating RgbaPNGRenderer with varmin=%s, varmax=%s'
38                     % (varmin, varmax))
39
40    def renderColourbar(self, width, height, cmap, isVertical=True):
41        a = N.arrayrange(0, 1.0, 1.0/256)
42        if isVertical:
43            a = a[-1::-1]
44            shape = (1, 256)
45        else:
46            shape = (256, 1)
47
48        cbar = (cmap(a) * 255).astype(byteTypecode).tostring()
49        img = Image.frombuffer("RGBA", shape, cbar, "raw", "RGBA", 0, 1)
50        img = img.resize((width, height))
51
52        return img
53
54    def renderGrid(self, grid, bbox, width, height, cmap):
55        cmap.set_bad('#ffffff', 0.0)
56
57        logger.info('grid %s, %s, %s, %s, %s, %s' %
58                    (grid.lon0, grid.lat0, grid.dlon, grid.dlat, grid.nlon, grid.nlat))
59
60        # Get a pixel = grid-box image for the grid
61        img = self._grid2Img(grid, cmap)
62
63        # Calculate the pixel-size of a grid box
64        pxPerDeg_lon = float(width) / (bbox[2] - bbox[0])
65        pxPerDeg_lat = float(height) / (bbox[3] - bbox[1])
66        pxPerGrid_x = grid.dlon * pxPerDeg_lon
67        pxPerGrid_y = grid.dlat * pxPerDeg_lat
68
69        # Scale Img to the right size
70        img = img.resize((pxPerGrid_x * grid.nlon, pxPerGrid_y * grid.nlat))
71
72        # We assume the grid points represent the centre of the grid boxes
73        # therefore we can calculate the upper-left position of the image
74
75        # Find top-left corner of grid
76        if grid.dlon > 0:
77            leftLon = grid.lon0
78        else:
79            leftLon = grid.lon0 + (grid.dlon * (grid.nlon - 1))
80        if grid.dlat > 0:
81            topLat = grid.lat0 + (grid.dlat * (grid.nlat - 1))
82        else:
83            topLat = grid.lat0
84
85        logger.info('top-left = %s lon, %s lat' % (leftLon, topLat))
86
87        # Find pixel position of top left centre grid box
88        cx = width * ((leftLon - bbox[0])/ (bbox[2] - bbox[0]))
89        cy = height * ((bbox[3] - topLat) / (bbox[3] - bbox[1]))
90
91        # Apply half width of grid box
92        ox = int(cx - pxPerGrid_x / 2)
93        oy = int(cy - pxPerGrid_y / 2)
94
95        # Paste the grid image into the tile image
96        tileImg = Image.new('RGBA', (width, height))
97        logger.info('Pasting image img%s into tileImg%s at (%s,%s)' % (tileImg.size, img.size, ox, oy))
98        tileImg.paste(img, (ox, oy))
99
100        return tileImg
101
102
103
104
105
106
107
108class RGBARenderer(GridRenderer):
109    """Creates an RGBA PNG with a selectable matplotlib colour scale.
110    """
111
112    mimeType = 'image/png'
113
114    def __init__(self, varmin, varmax):
115        self.varmin = varmin
116        self.varmax = varmax
117        self._norm = colors.normalize(varmin, varmax)
118
119    def renderColourbar(self, width, height, cmap, isVertical=True):
120        a = N.arrayrange(0, 1.0, 1.0/256)
121        if isVertical:
122            a = a[-1::-1]
123            shape = (1, 256)
124        else:
125            shape = (256, 1)
126
127        cbar = (cmap(a) * 255).astype('b').tostring()
128        img = Image.frombuffer("RGBA", shape, cbar, "raw", "RGBA", 0, 1)
129        img = img.resize((width, height))
130
131        return img
132
133    def DDCrenderGrid(self, grid, bbox, width, height, cmap):
134        cmap.set_bad('#ffffff', 0.0)
135
136        logger.info('grid %s, %s, %s, %s, %s, %s' %
137                    (grid.lon0, grid.lat0, grid.dlon, grid.dlat, grid.nlon, grid.nlat))
138
139        # Get a pixel = grid-box image for the grid
140        img = self._grid2Img(grid, cmap)
141
142        # Calculate the pixel-size of a grid box
143        pxPerDeg_lon = float(width) / (bbox[2] - bbox[0])
144        pxPerDeg_lat = float(height) / (bbox[3] - bbox[1])
145        pxPerGrid_x = grid.dlon * pxPerDeg_lon
146        pxPerGrid_y = grid.dlat * pxPerDeg_lat
147
148        # Scale Img to the right size
149        img = img.resize((pxPerGrid_x * grid.nlon, pxPerGrid_y * grid.nlat))
150
151        # We assume the grid points represent the centre of the grid boxes
152        # therefore we can calculate the upper-left position of the image
153
154        # Find top-left corner of grid
155        if grid.dlon > 0:
156            leftLon = grid.lon0
157        else:
158            leftLon = grid.lon0 + (grid.dlon * (grid.nlon - 1))
159        if grid.dlat > 0:
160            topLat = grid.lat0 + (grid.dlat * (grid.nlat - 1))
161        else:
162            topLat = grid.lat0
163
164        logger.info('top-left = %s lon, %s lat' % (leftLon, topLat))
165
166        # Find pixel position of top left centre grid box
167        cx = width * ((leftLon - bbox[0])/ (bbox[2] - bbox[0]))
168        cy = height * ((bbox[3] - topLat) / (bbox[3] - bbox[1]))
169
170        # Apply half width of grid box
171        ox = int(cx - pxPerGrid_x / 2)
172        oy = int(cy - pxPerGrid_y / 2)
173
174        # Paste the grid image into the tile image
175        tileImg = Image.new('RGBA', (width, height))
176        logger.info('Pasting image img%s into tileImg%s at (%s,%s)' % (tileImg.size, img.size, ox, oy))
177        tileImg.paste(img, (ox, oy))
178
179        return tileImg
180
181    def renderGrid(self, grid, bbox, width, height, cmap):
182        cmap.set_bad('#ffffff', 0.0)
183
184        logger.debug('grid %s, %s, %s, %s, %s, %s %s, %s' %
185                    (grid.x0, grid.y0, grid.dx, grid.dy, grid.nx, grid.ny,
186                     grid.ix, grid.iy))
187        logger.debug('bbox %s' % (bbox,))
188
189        # Get a pixel = grid-box image for the grid
190        img = self._grid2Img(grid, cmap)
191
192        # Calculate the pixel-size of a grid box
193        pxPerDeg_x = float(width) / (bbox[2] - bbox[0])
194        pxPerDeg_y = float(height) / (bbox[3] - bbox[1])
195        pxPerGrid_x = grid.dx * pxPerDeg_x
196        pxPerGrid_y = grid.dy * pxPerDeg_y
197
198        # Scale Img to the right size
199        img = img.resize(((abs(pxPerGrid_x * grid.nx),
200                           abs(pxPerGrid_y * grid.ny))))
201
202        #!NO: We assume the grid points represent the centre of the grid boxes
203        #!NO: therefore we can calculate the upper-left position of the image
204        # Adapted so that the grid points represent the lower left corner of grid boxes
205
206        # Find top-left corner of grid
207        if grid.dx > 0:
208            leftX = grid.x0
209        else:
210            leftX = grid.x0 + (grid.dx * (grid.nx - 1))
211        if grid.dy > 0:
212            topY = grid.y0 + (grid.dy * (grid.ny - 1))
213        else:
214            topY = grid.y0
215
216        logger.debug('top-left = %s x, %s y' % (leftX, topY))
217
218        # Find pixel position of top left centre grid box
219        cx = width * ((leftX - bbox[0])/ (bbox[2] - bbox[0]))
220        cy = height * ((bbox[3] - topY) / (bbox[3] - bbox[1]))
221        logger.debug('top-left centre pixel = %s x, %s y' % (cx, cy))
222
223        # Apply half width of grid box
224        ox = int(cx - pxPerGrid_x / 2)
225        oy = int(cy - pxPerGrid_y / 2)
226        #ox,oy = int(cx), int(cy-pxPerGrid_y)
227        logger.debug('Offset: %s x, %s y' % (ox, oy))
228
229
230        # Paste the grid image into the tile image
231        tileImg = Image.new('RGBA', (width, height))
232        logger.debug('Pasting image img%s into tileImg%s at (%s,%s)' % (img.size, tileImg.size, ox, oy))
233        tileImg.paste(img, (ox, oy))
234        return tileImg
235
236
237    def _grid2Img(self, grid, cmap):
238        """Returns the grid as an image where each pixel is one grid box.
239
240        """
241        a = self._norm(grid.value)
242        img_buf = (cmap(a) * 255).astype('b')
243
244        # This code assumes the axis ordering is either (y, x, time) or (x, y, time)
245        if min(grid.iy, grid.ix) != 0 and max(grid.iy, grid.ix) != 1:
246            raise ValueError("X and Y must be the first 2 dimensions!")
247
248        if grid.iy < grid.ix:
249            yxOrdering = True
250        else:
251            yxOrdering = False
252   
253        img = Image.frombuffer("RGBA", img_buf.shape[1::-1], img_buf.tostring(), "raw", "RGBA", 0, 1)
254        img.save('/tmp/raw1.png')
255
256        # Rotate if axis order is x, y
257        if not yxOrdering:
258            img = img.transpose(Image.ROTATE_90)
259
260        # Flip if x or y are ordered the wrong way
261        if grid.dy > 0:
262            logger.debug('Flipping y')
263            img = img.transpose(Image.FLIP_TOP_BOTTOM)
264        if grid.dx < 0:
265            logger.debug('Flipping x')
266            img = img.transpose(Image.FLIP_LEFT_RIGHT)
267
268
269        return img
270
271
272#---------------------------------------------------------------------------------
273
Note: See TracBrowser for help on using the repository browser.