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

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@5945
Revision 5945, 6.3 KB checked in by pnorton, 11 years ago (diff)

Improved the csml_data_reader so that it no longer assumes the feature id is the variable name.

Improved the data reader layer so that it now gets the dataset name from the csml file.

Added some code to the geoplot slabs that is used for selecting a log scale.

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