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

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

Tidied up the datareader geoplot layer slabs so that there is only one class now, there was so little code in the style specific slabs that there seemed little point in keeping them.

Implemented a Modis file reader that reads and extracts a number of layers from a modis file on the filesystem. Currently the generated images appear to be the wrong way up but I can't find out why.

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