source: cows/trunk/cows/service/imps/data_reader_geoplot_backend/data_reader_geoplot_wms_layer.py @ 5693

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

Fixed a problem with the getLegend code trying to use the old parser object.

Line 
1'''
2Created on 9 Jun 2009
3
4@author: pnorton
5'''
6
7import logging
8
9import time
10import os
11import csml
12import cdms2 as cdms
13
14from cows.service.imps.csmlbackend.config import config
15from cows.service.wms_iface import IwmsLayer
16
17log = logging.getLogger(__name__)
18
19import geoplot.colour_bar
20
21from cows.model.wms import Style, LegendURL, FormattedURL, MetadataURL
22from cows.xml.iso19115_subset import OnlineResource
23
24from routes import url_for
25
26from cows.service.imps.data_reader_geoplot_backend.geoplot_slabs.geoplot_slab_contour import GeoplotSlabContour
27from cows.service.imps.data_reader_geoplot_backend.geoplot_slabs.geoplot_slab_grid import GeoplotSlabGrid
28from cows.service.imps.data_reader_geoplot_backend.slab_options_parser import SlabOptionsParser
29
30
31class DRGeoplotWmsLayer(IwmsLayer):
32
33    slab_classes = [GeoplotSlabGrid, GeoplotSlabContour]
34    default_slab_class = GeoplotSlabGrid
35   
36    EnableDisplayOptions = False
37   
38    def __init__(self, name, title, abstract, dimensions, units, crss, boundingBox, dataReader):
39        self.featureInfoFormats=None #NotImplemented
40        self.title=title
41        self.abstract=abstract
42        self.dimensions=dimensions
43        self.units=units
44        self.crss=crss
45        self.legendSize=(630,80)
46       
47        # dummy values, will need to be set when the data is opened
48        self._minval = None
49        self._maxval = None 
50       
51        self.name = name
52        self.dataReader = dataReader
53       
54        self.styles = self._buildStyles()
55        self.metadataURLs = self._buildMetadataURL()
56       
57        bb = boundingBox
58           
59        #convert 0 - 360 to -180, 180 as per common WMS convention
60        if abs(bb[2]-bb[0]) >= 359 and abs(bb[2]-bb[0]) < 361:
61            bb[0], bb[2]=-180, 180
62           
63        self.wgs84BBox = bb
64        self.featureInfoFormats = ['text/html']
65       
66        try:
67            self.wgs84BBox = self.getBBox('EPSG:4326')
68        except:
69            raise ValueError("Layer must provide a bounding box in EPSG:4326 "
70                             "coordinates for compatibility with WMS-1.3.0")
71           
72        self.featureinfofilecache={} #used for caching netcdf file in getFeatureInfo
73   
74    def getBBox(self, crs):
75        """
76        @return: A 4-typle of the bounding box in the given coordinate
77            reference system.
78        """
79        #bb= self._feature.getCSMLBoundingBox().getBox()
80        #convert 0 - 360 to -180, 180 as per common WMS convention
81        #if abs(bb[2]-bb[0]) >= 359 and abs(bb[2]-bb[0]) < 361:
82        #    bb[0], bb[2]=-180, 180
83        #self.wgs84BBox = bb
84        return self.wgs84BBox
85        #raise NotImplementedError
86       
87    def getSlab(self, crs, style, dimValues, transparent, bgcolor, 
88                    additionalParams={}):
89        """
90        Creates a slab of the layer in a particular CRS and set of
91        dimensions.
92
93        @param crs: The coordinate reference system.
94        @param dimValues: A mapping of dimension names to dimension values
95            as specified in the IDimension.extent
96        @param renderOpts: A generic mapping object for passing rendering
97            options
98        @return: An object implementing ILayerSlab
99        #create netcdf for whole lat/lon for given dimValues, use to init slab
100        """
101        log.debug("additionalParams = %s" % (additionalParams,))
102        log.debug("bgcolor = %s" % (bgcolor,))
103        log.debug("transparent = %s" % (transparent,))
104        log.debug("dimValues = %s" % (dimValues,))
105       
106        st = time.time()
107        netcdfVar = self.dataReader.getNetcdfVar(self.name, dimValues)
108        log.debug("got netcdf in %ss" % (time.time() - st,))
109       
110        slabClass = self._getSlabClass(style)
111       
112        bbox=self.getBBox(crs)
113       
114        slab = slabClass(netcdfVar, self.title, crs, dimValues, transparent, bbox, additionalParams)
115               
116        return slab
117 
118    def getCacheKey(self, crs, style, dimValues, transparent, bgcolor, 
119                    additionalParams={}): 
120        """
121        Create a unique key for use in caching a slab.
122
123        The intention here is that most of the work should be done when
124        instantiating an ILayerSlab object.  These can be cached by the
125        server for future use.  The server will first call getCacheKey()
126        for the slab creation arguments and if the key is in it's cache
127        it will use a pre-generated ILayerSlab object.
128
129        """
130
131        dimList = list(dimValues.items())
132        dimList.sort()
133
134        #set the default style if none provided
135        s = self._getActualStyle(style)
136           
137        return '%s:%s:%s:%s:%s:%s:%s' % (self.name, crs, s, dimList,
138                                      transparent, bgcolor, additionalParams)
139
140    def _getActualStyle(self, style=None):
141        actualStyle = None
142       
143        if style == 'default' or style == '' or style is None:
144            actualStyle = DRGeoplotWmsLayer.default_slab_class.style
145        else:
146            actualStyle = style
147       
148        if actualStyle not in [x.style for x in DRGeoplotWmsLayer.slab_classes]:
149             Exception("No slab class found for style = %s"  % (style,))
150             
151        return actualStyle
152   
153    def _getSlabClass(self, style):
154        slabClass = None
155       
156        s = self._getActualStyle(style)
157       
158        for klass in DRGeoplotWmsLayer.slab_classes:
159            if klass.style == s:
160                slabClass = klass
161                break
162       
163        if slabClass == None:
164             Exception("No slab class found for style = %s"  % (style,))
165       
166        return slabClass
167
168    def getFeatureInfo(self, format, crs, point, dimValues):
169        """
170        Return a response string descibing the feature at a given
171        point in a given CRS.
172
173        Currently only "html" is supported as output format
174
175        @param format: One of self.featureInfoFormats.  Defines which
176            format the response will be in.
177        @param crs: One of self.crss
178        @param point: a tuple (x, y) in the supplied crs of the point
179            being selected.
180        @param dimValues: A mapping of dimension names to dimension values.
181        @return: A string containing the response.
182
183        """
184       
185#        #cached netcdf is indexed by a tuple of feature id and dimvalues - i.e. typically a particular time and Z value for that feature.
186#        #look in dictionary for cached copy, and if so use that as the file object.
187#        dictindex=str((self._feature.id, dimValues))
188#       
189#        if dictindex in self.featureinfofilecache:
190#            log.debug('calling cache')
191#            f=self.featureinfofilecache[dictindex]
192#        else: #else, use the csml api to subset the feature afresh
193#            log.debug('not calling cache')
194#            randomname= csml.csmllibs.csmlextra.getRandomID() + '.nc'
195#            result= self._feature.subsetToGridSeries(config['tmpdir'], ncname=randomname, **dimValues)
196#            #for now have to read netcdf back from disk (limitation of CSML api)
197#            f=cdms.open(result[1])
198#            #append to cache:
199#            self.featureinfofilecache[dictindex]=f
200#            #and then delete the temporary file
201#            os.system('rm %s'%result[1])
202#       
203#        netcdf = f(self.title)  #netcdf here is a cdms transient variable
204       
205        netcdf = self.dataReader.getNetcdfVar(self.name, dimValues)
206       
207        #Now grab the netCDF object for the point specified.
208        #The reason for the 'cob' option is so that if the grid the data
209        #is defined on does not have a grid point at the point specified,
210        #we should  still get the nearest location
211       
212        t_point = netcdf(latitude=(point[1], point[1], 'cob'), longitude=(point[0], point[0], 'cob'))
213        #now get the value recorded at this location
214        value = t_point.getValue().tolist()
215        log.debug(value)
216        log.debug(t_point.fill_value())
217        #and the fill_value too
218        fill_value = t_point.fill_value()
219        #value is actually embedded in a multi dimensional list,
220        #so we need to extract the actual value from the list
221        while type(value) is list:
222                value = value[0]
223
224        #now check if the value is actually the fill_value rather than
225        #a value recorded at the point specified
226        log.debug('%s %s' % (value, fill_value))
227        if (2*fill_value) == value:
228                value = "No value found at position: "+str(point[1])+", "+str(point[0])
229        else:
230                value = "Value found at position: "+str(point[1])+", "+str(point[0])+" is: "+str(value)
231               
232        # finally return the value
233        return value
234
235    def getLegendImage(self, dimValues, width=None, height=None, orientation='horizontal', renderOpts={}):
236        """
237        Create an image of the colourbar for this layer.
238        @param orientation: Either 'vertical' or 'horizontal'
239        @return: A PIL image with labels
240
241        """
242        if width == None:
243            width = self.legendSize[0]
244           
245        if height == None:
246            height = self.legendSize[1]
247               
248        variable = self.dataReader.getNetcdfVar(self.name, dimValues)
249       
250        klass = self._getSlabClass(None)
251        parser = SlabOptionsParser(klass.renderingOptions, renderOpts)
252       
253        minval = parser.getOption('cmap_min')
254        if minval == None:
255            minval = variable.min()
256           
257        maxval = parser.getOption('cmap_max')
258        if maxval == None:
259            maxval = variable.max()
260           
261        log.debug("dimValues = %s, minval = %s, maxval = %s" % (dimValues, minval , maxval,))
262
263        im = geoplot.colour_bar.getColourBarImage(width, height, 
264                                             label='Units of measure: %s' % str(self.units), 
265                                             cmap=parser.getOption('cmap'), 
266                                             cmapRange=(minval, maxval), 
267                                             orientation=orientation)
268       
269        return im
270   
271    def _buildStyles(self):
272        onlineRes = OnlineResource(url_for(qualified=True, action='index') + "?request=GetLegend&layers=%s" % self.name)
273       
274        legendURL = LegendURL(630, 80, format='img/png', onlineResource=onlineRes )
275       
276        styles = []
277        for klass in DRGeoplotWmsLayer.slab_classes:
278           
279            styleName = klass.style
280           
281            title = getattr(klass, 'title', None)
282           
283            if title is None:
284                title = styleName
285           
286            s = Style(styleName, title, legendURLs=[legendURL] )
287           
288            styles.append(s)
289       
290        return styles
291   
292    def _buildMetadataURL(self):
293       
294        if DRGeoplotWmsLayer.EnableDisplayOptions == True:
295            onlineRes = OnlineResource(url_for(qualified=True, action='index') +\
296                                        "?request=GetDisplayOptions&layers=%s" % self.name)
297           
298            displayMetadata = MetadataURL(metadataType='display_options', format='application/json', onlineResource=onlineRes)
299           
300            return [displayMetadata] 
301        else:
302            return []
Note: See TracBrowser for help on using the repository browser.