source: cows/trunk/cows/service/imps/geoplot_wms_backend/geoplot_wms_layer.py @ 6394

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

Major refactoring of the wms code. the csml wms code is now based on the geoplot wms code. I've also increased the use of inheritance in the geoplot wms code to reduce duplication.

Line 
1'''
2Created on 9 Jun 2009
3
4@author: pnorton
5'''
6
7import logging
8
9import time
10import os
11import numpy
12
13from cows.service.imps.csmlbackend.config import config
14from cows.service.wms_iface import IwmsLayer
15
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.csmlbackend.wms.wms_csmllayer import CSMLwmsLayer
27
28from cows.service.imps.geoplot_wms_backend.slabs.slab_contour import SlabContour
29from cows.service.imps.geoplot_wms_backend.slabs.slab_grid import SlabGrid
30from cows.service.imps.geoplot_wms_backend.slabs.slab_interval import SlabInterval
31from cows.service.imps.geoplot_wms_backend.slab_options_parser import SlabOptionsParser
32
33
34class GeoplotWmsLayer(CSMLwmsLayer):
35
36    slab_classes = [SlabGrid, SlabContour, SlabInterval]
37    default_slab_class = SlabGrid
38   
39    EnableDisplayOptions = False
40    EnableXMLAxisConfig = False
41   
42    def __init__(self, title, abstract, name=None, dimensions=None, 
43                       units=None, crss=None, boundingBox=None, 
44                       dataReader=None, childLayers=None):
45       
46        CSMLwmsLayer.__init__(self, title, abstract, name=name, dimensions=dimensions,
47                     units=units, crss=crss, boundingBox=boundingBox,
48                     dataReader=dataReader, childLayers=childLayers)
49       
50        if name is not None:
51            self.styles = self._buildStyles()
52            self.metadataURLs = self._buildMetadataURL()
53       
54    def getSlab(self, crs, style, dimValues, transparent, bgcolor, 
55                    additionalParams={}):
56        """
57        Creates a slab of the layer in a particular CRS and set of
58        dimensions.
59
60        @param crs: The coordinate reference system.
61        @param dimValues: A mapping of dimension names to dimension values
62            as specified in the IDimension.extent
63        @param renderOpts: A generic mapping object for passing rendering
64            options
65        @return: An object implementing ILayerSlab
66        #create netcdf for whole lat/lon for given dimValues, use to init slab
67        """
68       
69        #make the colour compatable with matplotlib
70        if bgcolor.find('0x') == 0:
71            bgcolor = '#' + bgcolor[2:]
72       
73        netcdfVar = self.dataReader.getNetcdfVar(self.title, dimValues)
74       
75        slabClass = self._getSlabClass(style)
76       
77        bbox=self.getBBox(crs)
78       
79        slab = slabClass(netcdfVar, self.title, crs, dimValues, transparent, bgcolor, bbox, additionalParams)
80               
81        return slab
82
83    def _getActualStyle(self, style=None):
84        actualStyle = None
85       
86        if style == 'default' or style == '' or style is None:
87            actualStyle = GeoplotWmsLayer.default_slab_class.style
88        else:
89            actualStyle = style
90       
91        if actualStyle not in [x.style for x in GeoplotWmsLayer.slab_classes]:
92            Exception("No slab class found for style = %s"  % (style,))
93             
94        return actualStyle
95   
96    def _getSlabClass(self, style):
97        slabClass = None
98       
99        s = self._getActualStyle(style)
100       
101        for klass in GeoplotWmsLayer.slab_classes:
102            if klass.style == s:
103                slabClass = klass
104                break
105       
106        if slabClass == None:
107            Exception("No slab class found for style = %s"  % (style,))
108       
109        return slabClass
110
111    def getFeatureInfo(self, format, crs, point, dimValues):
112        """
113        Return a response string descibing the feature at a given
114        point in a given CRS.
115
116        Currently only "html" is supported as output format
117
118        @param format: One of self.featureInfoFormats.  Defines which
119            format the response will be in.
120        @param crs: One of self.crss
121        @param point: a tuple (x, y) in the supplied crs of the point
122            being selected.
123        @param dimValues: A mapping of dimension names to dimension values.
124        @return: A string containing the response.
125
126        """
127        netcdf = self.dataReader.getNetcdfVar(self.title, dimValues)
128       
129        #Now grab the netCDF object for the point specified.
130        #The reason for the 'cob' option is so that if the grid the data
131        #is defined on does not have a grid point at the point specified,
132        #we should  still get the nearest location
133       
134        t_point = netcdf(latitude=(point[1], point[1], 'cob'), longitude=(point[0], point[0], 'cob'))
135        #now get the value recorded at this location
136        value = t_point.getValue().tolist()
137        log.debug(value)
138        log.debug(t_point.fill_value())
139        #and the fill_value too
140        fill_value = t_point.fill_value()
141        #value is actually embedded in a multi dimensional list,
142        #so we need to extract the actual value from the list
143        while type(value) is list:
144                value = value[0]
145
146        #now check if the value is actually the fill_value rather than
147        #a value recorded at the point specified
148        log.debug('%s %s' % (value, fill_value))
149        if (2*fill_value) == value:
150                value = "No value found at position: "+str(point[1])+", "+str(point[0])
151        else:
152                value = "Value found at position: "+str(point[1])+", "+str(point[0])+" is: "+str(value)
153               
154        # finally return the value
155        return value
156
157    def getLegendImage(self, dimValues, width=None, height=None, 
158                       orientation='horizontal', 
159                       renderOpts={}, 
160                       style=None
161                       ):
162        """
163        Create an image of the colourbar for this layer.
164        @param orientation: Either 'vertical' or 'horizontal'
165        @return: A PIL image with labels
166
167        """
168        if width == None:
169            width = self.legendSize[0]
170           
171        if height == None:
172            height = self.legendSize[1]
173               
174        variable = self.dataReader.getNetcdfVar(self.title, dimValues)
175       
176        klass = self._getSlabClass(style)
177       
178        return klass.makeColourBar(width , height, orientation, self.units, renderOpts, variable)
179   
180       
181        parser = SlabOptionsParser(klass.renderingOptions, renderOpts)
182       
183        log.debug("klass.style = %s" % (klass.style,))
184       
185        minval = parser.getOption('cmap_min')
186        if minval == None:
187            minval = variable.min()
188           
189        maxval = parser.getOption('cmap_max')
190        if maxval == None:
191            maxval = variable.max()
192           
193            # can't have a colourbar with an infinite maximum, take the highest
194            # non-inf value.
195            if maxval == numpy.inf:
196                maxval = numpy.ma.masked_equal(variable, numpy.inf).max()
197       
198        log.debug("parser.getOption('intervals') = %s" % (parser.getOption('intervals'),))
199        log.debug("parser.getOption('intervalNames') = %s" % (parser.getOption('intervalNames'),))
200       
201        im = geoplot.colour_bar.getColourBarImage(width, height, 
202                                             label='Units of measure: %s' % str(self.units),
203                                             cmap=parser.getOption('cmap'), 
204                                             colourBarMin=minval,
205                                             colourBarMax=maxval,
206                                             colourBarScale=parser.getOption('cmap_scale'),
207                                             numIntervals=parser.getOption('num_intervals'), 
208                                             orientation=orientation,
209                                             intervals=parser.getOption('intervals'),
210                                             intervalNames=parser.getOption('intervalNames'),
211                                             colourBarStyle=parser.getOption('cbar_style'),
212                                             )
213       
214        return im
215   
216    def _buildStyles(self):
217        onlineRes = OnlineResource(self._getIndexActionURL() + "?request=GetLegend&layers=%s" % self.name)
218       
219        legendURL = LegendURL(630, 80, format='img/png', onlineResource=onlineRes )
220       
221        styles = []
222        for klass in GeoplotWmsLayer.slab_classes:
223           
224            styleName = klass.style
225           
226            title = getattr(klass, 'title', None)
227           
228            if title is None:
229                title = styleName
230           
231            s = Style(styleName, title, legendURLs=[legendURL] )
232           
233            styles.append(s)
234       
235        return styles
236   
237    def getAxisConfigFile(self):
238        xmlFile = None
239       
240        if hasattr(self.dataReader, 'getConfigAxisXMLFile'):
241           
242            xmlFile =  self.dataReader.getConfigAxisXMLFile()
243       
244        return xmlFile
245   
246    def _buildMetadataURL(self):
247       
248        metadataURLs = []
249       
250        if GeoplotWmsLayer.EnableDisplayOptions == True:
251            onlineRes = OnlineResource(self._getIndexActionURL() +\
252                       "?request=GetDisplayOptions&layers=%s" % self.name)
253           
254            metadataURLs.append( MetadataURL(metadataType='display_options', 
255                                          format='application/json',
256                                          onlineResource=onlineRes) )
257           
258        if GeoplotWmsLayer.EnableXMLAxisConfig:
259           
260            xmlFile =  self.getAxisConfigFile()
261           
262            if xmlFile != None:
263               
264                onlineRes = OnlineResource(self._getIndexActionURL() +\
265                                "?request=GetAxisConfig&layers=%s" % self.name)
266           
267                metadataURLs.append( MetadataURL(metadataType='axis_config', 
268                                                 format='text/xml',
269                                                 onlineResource=onlineRes) )     
270       
271        return metadataURLs
272   
273    def _getIndexActionURL(self):
274        """
275        Uses the pylons config to build a url for the index action of this contoller.
276        """
277               
278        indexURL = url_for(qualified=True, action='index')
279        return indexURL
Note: See TracBrowser for help on using the repository browser.