source: cows/trunk/cows/service/imps/data_reader_geoplot_backend/geoplot_slabs/geoplot_slab_base.py @ 5761

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

Added the ability to set background colours and some other options for the data renderer implementation.

Line 
1import logging
2import time
3
4import numpy
5
6from geoplot.utils import isRangeInLimits
7
8from cows.service.wms_iface import IwmsLayerSlab
9from cows.service.imps.image_import import Image
10from cows.service.imps.data_reader_geoplot_backend.slab_options_parser import SlabOptionsParser
11   
12log = logging.getLogger(__name__)
13
14class GeoplotSlabBase(IwmsLayerSlab):
15    """
16    A layer slab that implements the IwmsLayerSlab interface and uses geoplot
17    to render the required images.
18   
19    This is an abstract base class and should not be used directly.
20    """
21
22    """
23    contstructor
24   
25    @param netcdf: the netcdf variable that contains the data for this slab
26    @param title: the title of the variable that is to be used
27    @param crs: the coordinate refrence system the data is stored in
28    @param dimValues: the dimension values for this slab
29    @param transparent: indicates if the produced image should be transparent or
30        not.
31    @param bbox: the bounds of the data in lat/lon
32    @param renderOpts: the additional parameters recieved by the WMS, may include
33        some custom rendering options.
34    """
35    def __init__(self, variable, title, crs, dimValues, transparent, bgcolour, bbox, renderOpts):
36
37        self.title = title
38        self.crs = crs
39        self.dimValues = dimValues
40        self.renderOpts = renderOpts
41        self.bgcolour = bgcolour
42        self.transparent = transparent
43        self.bbox=bbox
44        self.variable = variable
45               
46        #log.debug("renderOpts = %s" % (renderOpts,))
47       
48        self.parser = SlabOptionsParser(self.renderingOptions, renderOpts)
49        self.ld = self._setupLayerDrawer()
50   
51    """
52    Creates the layer drawer object so that it can be used in getImage
53    """
54    def _setupLayerDrawer(self):
55        raise NotImplementedError()
56   
57    """
58    returns an image of the data constructed using the layer drawer
59   
60    @param bbox: the limits of the image requested
61    @param width: the width in px of the image
62    @param height: the height in px of the image
63    """
64    def getImage(self, bbox, width, height):
65        """
66        Create an image of a sub-bbox of a given size.
67
68        @ivar bbox: A bbox 4-tuple.
69        @ivar width: width in pixels.` 
70        @ivar height: height in pixels.
71        @return: A PIL Image object.
72
73        """
74        #log.debug("GetImage called with bbox=%s, width=%s, height = %s" % (bbox, width, height,))
75        xLimits = (bbox[0], bbox[2])
76        yLimits = (bbox[1], bbox[3])
77               
78        if self.variable.getAxisIds().sort() == ['latlitude','longitude'].sort():
79           
80            if not self._areBoundsInLimits(bbox, xLimits, yLimits):
81               
82                img = numpy.zeros((height,width,4), numpy.uint8)
83                pilImage = Image.fromarray(img, 'RGBA')
84               
85                log.debug("empty image used as no data found for id=%s (%sx%s), lon=%s, lat=%s " % \
86                  (self.variable.id, width, height, xLimits, yLimits))
87               
88                return pilImage
89                       
90        st = time.time()
91        im = self.ld.makeImage(xLimits, yLimits, width, height)
92       
93        log.debug("generated contour image id=%s (%sx%s, lon=%s, lat=%s in %.2fs" % \
94                  (self.variable.id, width, height, xLimits, yLimits,  time.time() - st,))
95       
96        return im
97
98    def _areBoundsInLimits(self, bbox, xLimits, yLimits):
99       
100        if self.variable.getAxisIds()[0] == 'longitude':
101            lonAx, latAx = self.variable.getAxisList()
102        else:
103            latAx, lonAx = self.variable.getAxisList()
104           
105        xRange = [ lonAx.getBounds().min(), lonAx.getBounds().max()]
106        yRange = [ latAx.getBounds().min(), latAx.getBounds().max()]
107#        log.debug("xLimits = %s" % (xLimits,))
108#        log.debug("yLimits = %s" % (yLimits,))
109#        log.debug("xRange = %s" % (xRange,))
110#        log.debug("yRange = %s" % (yRange,))
111       
112        xRange = self._fixLongitudeRange(xLimits, xRange)
113       
114        isInLimits = isRangeInLimits(xRange, xLimits) and \
115                     isRangeInLimits(yRange, yLimits)
116                     
117        return isInLimits
118   
119    def _fixLongitudeRange(self, xLimits, xRange):
120        """
121        Attemts to match the upper and lower bounds of the longiude range
122        to that of the xLimits (either -180,180 or 0,360)
123        """
124       
125        returnRange = xRange
126       
127        range_180to0 = False
128        range180to360 = False 
129             
130        #assuming the xLimits are given in range -180 to 180
131        for i in [0,1]:
132            if -180.0 <= xLimits[i] < 0.0:
133                range_180to0 = True
134           
135            elif 180 < xLimits[i] <= 360:
136                range180to360 = True
137       
138#        log.debug("range180to360 = %s, range_180to0 = %s" % (range180to360, range_180to0,))
139        assert not (range_180to0 and range180to360), "confusing bounds found on longitude range %s " % (xLimits,)
140       
141        if range_180to0:
142            #if the xRange is 0-360 need to adjust it
143            for x in returnRange:
144               
145                if x > 180.0:
146                    returnRange = [x - 180 for x in returnRange]
147                    break
148                   
149        if range180to360:
150            #if the range is -180-0 need to adjust it
151            for x in returnRange:
152                if x < 0.0:
153                    returnRange =  [x + 180 for x in returnRange]
154                    break
155               
156#        log.debug("returnRange = %s" % (returnRange,))
157        return returnRange
158       
Note: See TracBrowser for help on using the repository browser.