source: cows/branches/migrate-py26-pylons10/cows/service/imps/geoplot_wms_backend/geoplot_wms_layer.py @ 7342

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/cows/branches/migrate-py26-pylons10/cows/service/imps/geoplot_wms_backend/geoplot_wms_layer.py@7342
Revision 7342, 10.4 KB checked in by spascoe, 9 years ago (diff)

New branch for migration to Python-2.6 and Pylons-1.0.

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