source: TI04-geosplat/trunk/pygss/VariableAnalyser.py @ 1660

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI04-geosplat/trunk/pygss/VariableAnalyser.py@6809
Revision 1660, 13.3 KB checked in by astephen, 14 years ago (diff)

Version with overlay of trajectories on top of model fields draft version working before any rigourous testing.

Line 
1#   Copyright (C) 2004 CCLRC & NERC( Natural Environment Research Council ).
2#   This software may be distributed under the terms of the
3#   Q Public License, version 1.0 or later. http://ndg.nerc.ac.uk/public_docs/QPublic_license.txt
4
5"""
6VariableAnalyser.py
7===================
8
9Contains the VariableAnalyser class that is used to determine the
10type of feature present and any other useful information related
11to plotting options.
12
13It analyses the dimensionality, type of axes and the name of the
14variable to do this.
15
16"""
17
18# Import library modules
19import os, sys
20
21# Import package modules
22from serverConfig import *
23from common import *
24from FeatureTypes import *
25from GSErrors import *
26
27# Import external modules
28import cdms, genutil
29
30class VariableAnalyser:
31    """
32    Class for analysing the nature of each variable.
33    """
34   
35    def __init__(self, filename=None, varID=None, graphicalOutputType=None, animationAxes=None, domainDict=None):
36        """
37        Takes a variable and analyses it to return a known Feature type.
38        The Feature types can then be mapped to known plotting operations.
39        """
40        self.filename=filename
41        self.varID=varID
42        self.domainDict=domainDict
43       
44        if (self.filename==None and self.varID==None) and self.domainDict==None:
45            raise GSOptionHandlingError, "VariableAnalyser needs either filename/varID or domainDict as valid arguments."
46       
47        if self.domainDict:
48            # Call the code to get
49            self._analyse(graphicalOutputType, animationAxes)
50        else:
51            cdmsfile=cdms.open(self.filename)
52            self.var=cdmsfile[varID]
53            self._analyse(graphicalOutputType, animationAxes)
54            cdmsfile.close()
55
56
57    def _analyse(self, graphicalOutputType, animationAxes):
58        """
59        Calls various analysing methods.
60        """
61        if graphicalOutputType==None:
62            fts=self._getFeatureTypes()
63            if type(fts)==type("string"): fts=[fts]
64            self.plotOpts=[]
65            for ft in fts:
66                self.plotOpts.append(self._getGraphicalOutputTypes(ft)[0])
67            # Add graphical output types to domainDict
68            self.domainDict["grots"]=self.plotOpts
69        else:
70            self.plotConfigurationDict=self._getPlotConfigurationDetails(graphicalOutputType, animationAxes)
71       
72       
73    def _getFeatureTypes(self):
74        """
75        Return Feature Type if can be identified, otherwise returns None.
76        """
77        axes=self.var.getAxisList()
78       
79        # Save axes to self.domainDict for use on next call
80        self.domainDict={}
81        orderedList=[]
82        for axis in axes:
83            id=axis.id
84            if axis.isTime(): 
85                known="time"
86            elif axis.isLevel():
87                known="level"
88            elif axis.isLatitude():
89                known="latitude"
90            elif axis.isLongitude():
91                known="longitude"
92            else:
93                known="unrecognised"
94            (low, high)=(axis[0], axis[-1])
95            self.domainDict[id]=[id, known, [low,high]]
96            orderedList.append(id)
97           
98        self.domainDict["ordered_axes"]=orderedList
99       
100        shape=self.var.shape
101        size=self.var.size()
102       
103        # Begin by squeezing out singleton axes
104        if size==1:
105            return "PointFeature"
106           
107        usefulAxes=[]
108        for axis in axes:
109            if len(axis)>1: usefulAxes.append(axis)
110           
111        ndims=len(usefulAxes)
112       
113        if ndims==1:
114            trajCheck=self._checkForTrajectoryFeature()
115            if trajCheck:
116                self.domainDict["bbox"]=trajCheck # which is (y1,x1,y2,x2)
117                return ["TrajectoryFeature", "ProfileFeature"]
118            else:
119                return "ProfileFeature"         
120        elif ndims==2:
121            trajCheck=self._checkForTrajectoryFeature()
122            if trajCheck:
123                self.domainDict["bbox"]=trajCheck # which is (y1,x1,y2,x2)
124                return ["TrajectoryFeature", "2DGridFeature"]
125            else:
126                if self._testLatLon(axes):
127                    return "2DLatLonGridFeature"
128                else:
129                    return "2DGridFeature"
130        elif ndims>2:
131            return "%sDGridFeature" % ndims
132        else:
133            raise  GSSelectionError, "Could not identify any useful data in this file."
134       
135       
136    def _getGraphicalOutputTypes(self, featureType):
137        """
138        Returns broad graphical output types available for a given
139        feature type.
140        """     
141        ft=featureType
142       
143        if ft=="PointFeature":
144            return [["PointValuetrueAndMetadata", "Display single value for variable '%s' from file: '%s'" % (self.varID, self.filename)]]
145           
146        elif ft=="ProfileFeature":
147            return [["YvsXGraph", "Y-vs-X Graph for variable '%s' from file: '%s'" % (self.varID, self.filename)]]
148           
149        elif ft=="2DGridFeature":
150            return [["2DPlot", "2D Plot for variable '%s' from file: '%s'" % (self.varID, self.filename)]]
151       
152        elif ft=="2DLatLonGridFeature":
153            return [["2DLatLonPlot", "2D Lat-Lon Plot for variable '%s' from file: '%s'" % (self.varID, self.filename)]]       
154       
155        elif ft=="TrajectoryFeature":
156            return [["TrajectoriesOverMap", "Trajectories plotted on map for variable '%s' from file: '%s'" % (self.varID, self.filename)]]
157
158        else:
159            return [["Animation", "Animated series if 2D plots for variable '%s' from file: '%s'" % (self.varID, self.filename)]]
160
161
162    def _getPlotConfigurationDetails(self, graphicalOutputType, animationAxes=None):
163        """
164        Returns plot configuration details in a dictionary of options
165        where each value is a list of lists holding the short name and long name
166        of the available options.
167        """
168        plotConfigDict={}       
169        grot=graphicalOutputType
170        print grot
171        if grot=="YvsXGraph":
172            plotConfigDict["plotType"]=[["YvsXGraph", "Y-vs-X Graph"]]
173           
174           
175        elif grot in ("2DPlot", "2DLatLonPlot", "Animation"):
176       
177            # Note that domainDict should hold axes as:
178            # id:[id, known_as, [low,high]]
179            if animationAxes!=None:
180           
181                (loopID, yID, xID)=animationAxes
182                axisList=[]
183           
184                for axID in (loopID, yID, xID):
185                    axis=self.domainDict[axID]
186                    axisList.append(axis)           
187           
188            else:
189                axisList=[]
190                print self.domainDict
191                orderedList=[self.domainDict[axisID] for axisID in self.domainDict["ordered_axes"]]
192                for axis in orderedList:
193                    if len(axis[2])>1:
194                        axisList.append(axis)
195       
196            if grot in ("2DLatLonPlot",): 
197              latLonAxesTest=self._testLatLon(axisList[-2:])
198              if latLonAxesTest:
199                plotConfigDict["continentsSwitch"]=[["on", "Show continents"], ["off", "Do not show continents"]]
200               
201                [[south, north], [west, east]]=latLonAxesTest
202               
203                projections=[["standard", "Standard"]]
204                if (east-west)>200: # Need 200+ degrees west-east to use projections safely
205                    projections.append(["mollweide", "Mollweide"])
206                    projections.append(["robinson", "Robinson"])                   
207                   
208                    if north>80 and south<10:
209                        projections.append(["northPolar", "Polar (Northern Hemisphere)"])
210                    if north>-10 and south<-80:
211                        projections.append(["southPolar", "Polar (Southern Hemisphere)"])
212       
213                plotConfigDict["projection"]=projections
214       
215            if grot in ("2DPlot", "2DLatLonPlot"):
216                plotTypes=[["boxfill", "Boxfill"],["isofill", "Isofill"],
217                       ["isoline", "Isoline"],["isolineAndFill", "Isoline and Isofill"]]
218            elif grot=="Animation":
219                plotTypes=[["boxfill", "Boxfill"],["isofill", "Isofill"],
220                           ["isoline", "Isoline"]]             
221               
222            plotConfigDict["plotType"]=plotTypes
223           
224        elif grot in ("TrajectoriesOverMap",):
225            plotConfigDict["plotType"]=[["MultipleTrajectory", "Multiple Trajectory Plot"]]     
226            plotConfigDict["projection"]=[["standard", "Standard"]]             
227            plotConfigDict["mapArea"]=[["surroundingArea","Surrounding Area"],["global","Global"]]     
228               
229        elif grot in ("MultipleTrajectoriesOver2DLatLonPlot",):
230            plotConfigDict["plotType"]=[["MultipleTrajectoryOverBoxfillLinear", "Multiple Trajectory Plot over Boxfill Lat-Lon Plot"]] 
231            plotConfigDict["projection"]=[["standard", "Standard"]]             
232            plotConfigDict["mapArea"]=[["surroundingArea","Surrounding Area"],["global","Global"]]             
233                                       
234        # Start with the easy one, image sizes
235        imageSizes=["800 x 600", "300 x 200", "600 x 400", "792 x 612", "1000 x 800"]
236        imageSizesLists=[[i.replace(" ",""), i] for i in imageSizes]
237       
238        plotConfigDict["imageSize"]=imageSizesLists
239       
240        # Then file format, also straightforward
241
242        if grot=="Animation":
243            fileFormats=["GIF"]
244        else:
245            fileFormats=["GIF", "Postscript"]
246        fileFormatsLists=[[i.lower(), i] for i in fileFormats]
247        plotConfigDict["fileFormat"]=fileFormatsLists
248
249        return plotConfigDict
250               
251
252    #def _getPlotConfigurationDetailsDEPRECATED(self, graphicalOutputType, animationAxes=None):
253        """
254        Returns plot configuration details in a dictionary of options
255        where each value is a list of lists holding the short name and long name
256        of the available options.
257        """
258        """plotConfigDict={}   
259        grot=graphicalOutputType
260        print grot
261        if grot=="YvsXGraph":
262            plotConfigDict["plotType"]=[["YvsXGraph", "Y-vs-X Graph"]]
263           
264           
265        elif grot in ("2DPlot", "2DLatLonPlot", "Animation"):
266       
267            if animationAxes!=None:
268           
269                (loopID, yID, xID)=animationAxes
270                axisList=[]
271           
272                for axID in (loopID, yID, xID):
273                    axis=self.var.getAxis(self.var.getAxisIds().index(axID))
274                    axisList.append(axis)           
275           
276            else:
277                axisList=[]
278                for axis in self.var.getAxisList():
279                    if len(axis)>1:
280                        axisList.append(axis)
281       
282            if grot in ("2DLatLonPlot",):
283              latLonAxesTest=self._testLatLon(axisList[-2:])
284              if latLonAxesTest:
285                plotConfigDict["continentsSwitch"]=[["on", "Show continents"], ["off", "Do not show continents"]]
286               
287                [[south, north], [west, east]]=latLonAxesTest
288               
289                projections=[["standard", "Standard"]]
290                if (east-west)>200: # Need 200+ degrees west-east to use projections safely
291                    projections.append(["mollweide", "Mollweide"])
292                    projections.append(["robinson", "Robinson"])                   
293                   
294                    if north>80 and south<10:
295                        projections.append(["northPolar", "Polar (Northern Hemisphere)"])
296                    if north>-10 and south<-80:
297                        projections.append(["southPolar", "Polar (Southern Hemisphere)"])
298       
299                plotConfigDict["projection"]=projections
300       
301            if grot in ("2DPlot", "2DLatLonPlot"):
302                plotTypes=[["boxfill", "Boxfill"],["isofill", "Isofill"],
303                       ["isoline", "Isoline"],["isolineAndFill", "Isoline and Isofill"]]
304            elif grot=="Animation":
305                plotTypes=[["boxfill", "Boxfill"],["isofill", "Isofill"],
306                           ["isoline", "Isoline"]]             
307               
308            plotConfigDict["plotType"]=plotTypes
309           
310        elif grot in ("TrajectoriesOverMap",):
311            plotConfigDict["plotType"]=[["MultipleTrajectory", "Multiple Trajectory Plot"]]     
312            plotConfigDict["projection"]=[["standard", "Standard"]]             
313            plotConfigDict["mapArea"]=[["surroundingArea","Surrounding Area"],["global","Global"]]     
314               
315        elif grot in ("MultipleTrajectoriesOver2DLatLonPlot",):
316            plotConfigDict["plotType"]=[["MultipleTrajectory", "Multiple Trajectory Plot"]]     
317            plotConfigDict["projection"]=[["standard", "Standard"]]             
318            plotConfigDict["mapArea"]=[["surroundingArea","Surrounding Area"],["global","Global"]]             
319                                       
320        # Start with the easy one, image sizes
321        imageSizes=["800 x 600", "300 x 200", "600 x 400", "792 x 612", "1000 x 800"]
322        imageSizesLists=[[i.replace(" ",""), i] for i in imageSizes]
323       
324        plotConfigDict["imageSize"]=imageSizesLists
325       
326        # Then file format, also straightforward
327
328        if grot=="Animation":
329            fileFormats=["GIF"]
330        else:
331            fileFormats=["GIF", "Postscript"]
332        fileFormatsLists=[[i.lower(), i] for i in fileFormats]
333        plotConfigDict["fileFormat"]=fileFormatsLists
334
335        return plotConfigDict"""
336
337
338
339    def _testLatLon(self, axes):
340        """
341        Returns ([northernExtent, southernExtent], westernExtent, easternExtent])
342        if axes are lat and lon.
343        """
344        latFound=None
345        lonFound=None
346       
347        if type(axes[0])==type([1,2]): # set up from domainDict
348            for ax in axes:
349                if len(ax[2])>1:
350                    if ax[1]=="latitude": latFound=ax[2]
351                    if ax[1]=="longitude": lonFound=ax[2]
352        else: # type is cdms.axis
353            for ax in axes:
354                if len(ax)>1:
355                    if ax.isLatitude(): latFound=minmax(ax)
356                    if ax.isLongitude(): lonFound=minmax(ax)
357                   
358        if latFound and lonFound:
359            return (latFound, lonFound)
360           
361           
362    def _checkForTrajectoryFeature(self):
363        """
364        Returns 1 if it is a trajectory feature.
365        """
366        axisList=self.var.getAxisList()
367        if not axisList[0].isTime():
368            return None
369       
370        if len(axisList)>1 and axisList[1].id!="parcel":
371            return None
372               
373        # If axes look right check that we have lat and lon defined
374        # against time as well
375        fname=self.filename     
376        cdmsFile=cdms.open(fname)
377        varNames=[i.lower() for i in cdmsFile.listvariables()]
378        latNames=["latitude","lat","lt"]
379        lonNames=["longitude","lon","lng"]
380        if overlap(varNames, latNames) and overlap(varNames, lonNames):
381            for lnm in latNames:
382                try:
383                    lat=cdmsFile(lnm)
384                except:
385                    pass   
386            for lom in lonNames:
387                try:
388                    lon=cdmsFile(lom)
389                except:
390                    pass
391            print "Calculating bounding box for traj data..."
392            (y1,y2)=genutil.minmax(lat) # south, north
393            (x1,x2)=genutil.minmax(lon)
394            return (y1,x1,y2,x2)
395        else:
396            return None 
397       
398                           
399                           
400if __name__=="__main__":
401    a=VariableAnalyser("/data/var2.nc", "var2")
402    print a.plotOpts
403    a=VariableAnalyser(graphicalOutputType="2DLatLonPlot", domainDict={"ordered_axes":["time","latitude","longitude"],
404                "time":["time","time",[0,4]],
405                "latitude":["latitude","latitude",[0,90]],
406                "longitude":["longitude","longitude",[0,359]]})   
407    print a.plotConfigurationDict
408    a=VariableAnalyser("/data/traj.nc", "theta")
409    print a.plotOpts
410    a=VariableAnalyser("/data/traj.nc", "theta", "TrajectoriesOverMap")
411    print a.plotConfigurationDict   
412    v=VariableAnalyser("/data/var1.nc", "pqn")
413    print v.plotOpts   
414    v=VariableAnalyser("/data/var1.nc", "pqn")
415    print v.plotOpts
416    #a=VariableAnalyser("/data/var1.nc", "pqn", "2DPlot")
417    #print a.plotConfigurationDict
418   
419   
Note: See TracBrowser for help on using the repository browser.