source: cows/trunk/cows/service/imps/data_reader_geoplot_backend/data_reader_geoplot_wms_layer_slab.py @ 5684

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows/trunk/cows/service/imps/data_reader_geoplot_backend/data_reader_geoplot_wms_layer_slab.py@5684
Revision 5684, 6.7 KB checked in by pnorton, 11 years ago (diff)

Fixed a problem in the masking of the landtype_common variable from the modis_file_reader. The index 0 data was bing masked along with the cases where all the indicies are 0.0.

Also made some small improvements to the geoplot layers.

Line 
1import logging
2import time
3
4from cows.service.imps.data_reader_geoplot_backend.data_reader_geoplot_render_options_parser import DRGeoplotRenderOptionsParser
5
6import numpy
7from geoplot.utils import isRangeInLimits
8from geoplot.layer_drawer_contour import LayerDrawerContour
9from geoplot.layer_drawer_grid import LayerDrawerGrid
10
11from cows.service.wms_iface import IwmsLayerSlab
12import Image
13
14log = logging.getLogger(__name__)
15
16
17class STYLES:
18    CONTOUR = 'contour'
19    GRID = 'grid'
20    DEFAULT = GRID
21   
22    @staticmethod
23    def all():
24        return [STYLES.CONTOUR, STYLES.GRID]
25
26class DRGeoplotWmsLayerSlab(IwmsLayerSlab):
27    """
28    A layer slab that implements the IwmsLayerSlab interface and uses geoplot
29    to render the required images.
30   
31    This is an abstract base class and should not be used directly.
32    """
33
34    def __init__(self, variable, title, style, crs, dimValues, transparent, bbox, renderOpts):
35        """
36        contstructor
37       
38        @param netcdf: the netcdf variable that contains the data for this slab
39        @param title: the title of the variable that is to be used
40        @param crs: the coordinate refrence system the data is stored in
41        @param dimValues: the dimension values for this slab
42        @param transparent: indicates if the produced image should be transparent or
43            not.
44        @param bbox: the bounds of the data in lat/lon
45        @param renderOpts: the additional parameters recieved by the WMS, may include
46            some custom rendering options.
47        """
48
49        self.title = title
50       
51        if style == None or style == "":
52            style = STYLES.DEFAULT
53           
54        assert style in STYLES.all(), "Style %s not recognised" % (style,)
55       
56        self.style = style
57       
58        self.crs = crs
59        self.dimValues = dimValues
60        self.renderOpts = renderOpts
61        self.transparent = transparent
62        self.bbox=bbox
63        self.variable = variable
64       
65        self.minval = variable.min()
66        self.maxval = variable.max()
67       
68        #log.debug("renderOpts = %s" % (renderOpts,))
69       
70        self.parser = DRGeoplotRenderOptionsParser(renderOpts, self.minval, self.maxval)
71        self.ld = self._setupLayerDrawer()
72   
73    def _setupLayerDrawer(self):
74        """
75        Creates the layer drawer object so that it can be used in getImage
76        """
77       
78        cmapRange = (self.parser.getOption('cmap_min'), self.parser.getOption('cmap_max'))
79       
80        kwargs = {
81            'cmapRange':cmapRange,
82            'transparent':self.transparent,
83            'cmap':self.parser.getOption('cmap'),
84        }
85       
86        if self.style == STYLES.CONTOUR:
87           
88            ld = LayerDrawerContour(self.variable, 
89                             labelInterval= self.parser.getOption('contour_label_interval'),
90                             numLines = self.parser.getOption('num_contour_lines'),
91                             fontSize = self.parser.getOption('contour_font_size'),
92                             **kwargs)
93           
94        elif self.style == STYLES.GRID:
95           
96            ld = LayerDrawerGrid(self.variable, 
97                     showGridLines=self.parser.getOption('show_grid_lines'), 
98                     **kwargs)
99       
100        return ld
101       
102    def getImage(self, bbox, width, height):
103        """
104        returns an image of the data constructed using the layer drawer
105       
106        @param bbox: the limits of the image requested
107        @param width: the width in px of the image
108        @param height: the height in px of the image
109        """
110        xLimits = (bbox[0], bbox[2])
111        yLimits = (bbox[1], bbox[3])
112               
113        if self.variable.getAxisIds().sort() == ['latlitude','longitude'].sort():
114           
115            if not self._areBoundsInLimits(bbox, xLimits, yLimits):
116               
117                img = numpy.zeros((height,width,4), numpy.uint8)
118                pilImage = Image.fromarray(img, 'RGBA')
119               
120                log.debug("empty image used as no data found for id=%s (%sx%s), lon=%s, lat=%s " % \
121                  (self.variable.id, width, height, xLimits, yLimits))
122               
123                return pilImage
124                       
125        st = time.time()
126        im = self.ld.makeImage(xLimits, yLimits, width, height)
127       
128        log.debug("generated contour image id=%s (%sx%s, lon=%s, lat=%s in %.2fs" % \
129                  (self.variable.id, width, height, xLimits, yLimits,  time.time() - st,))
130       
131        return im
132
133   
134
135    def _areBoundsInLimits(self, bbox, xLimits, yLimits):
136       
137        if self.variable.getAxisIds()[0] == 'longitude':
138            lonAx, latAx = self.variable.getAxisList()
139        else:
140            latAx, lonAx = self.variable.getAxisList()
141           
142        xRange = [ lonAx.getBounds().min(), lonAx.getBounds().max()]
143        yRange = [ latAx.getBounds().min(), latAx.getBounds().max()]
144#        log.debug("xLimits = %s" % (xLimits,))
145#        log.debug("yLimits = %s" % (yLimits,))
146#        log.debug("xRange = %s" % (xRange,))
147#        log.debug("yRange = %s" % (yRange,))
148       
149        xRange = self._fixLongitudeRange(xLimits, xRange)
150       
151        isInLimits = isRangeInLimits(xRange, xLimits) and \
152                     isRangeInLimits(yRange, yLimits)
153                     
154        return isInLimits
155   
156    def _fixLongitudeRange(self, xLimits, xRange):
157        """
158        Attemts to match the upper and lower bounds of the longiude range
159        to that of the xLimits (either -180,180 or 0,360)
160        """
161       
162        returnRange = xRange
163       
164        range_180to0 = False
165        range180to360 = False 
166             
167        #assuming the xLimits are given in range -180 to 180
168        for i in [0,1]:
169            if -180.0 <= xLimits[i] < 0.0:
170                range_180to0 = True
171           
172            elif 180 < xLimits[i] <= 360:
173                range180to360 = True
174       
175#        log.debug("range180to360 = %s, range_180to0 = %s" % (range180to360, range_180to0,))
176        assert not (range_180to0 and range180to360), "confusing bounds found on longitude range %s " % (xLimits,)
177       
178        if range_180to0:
179            #if the xRange is 0-360 need to adjust it
180            for x in returnRange:
181               
182                if x > 180.0:
183                    returnRange = [x - 180 for x in returnRange]
184                    break
185                   
186        if range180to360:
187            #if the range is -180-0 need to adjust it
188            for x in returnRange:
189                if x < 0.0:
190                    returnRange =  [x + 180 for x in returnRange]
191                    break
192               
193#        log.debug("returnRange = %s" % (returnRange,))
194        return returnRange
195       
Note: See TracBrowser for help on using the repository browser.