source: TI03-DataExtractor/branches/titania_install/pygss/OutputManager.py @ 1520

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI03-DataExtractor/branches/titania_install/pygss/OutputManager.py@1610
Revision 1520, 12.2 KB checked in by astephen, 14 years ago (diff)

This is the live version on titania - changes have been made so safest to SVN it.

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"""
6OutputManager.py
7================
8
9Contains the class OutputManager class that controls all generation of
10graphical outputs.
11
12""" 
13
14# Import library modules
15import os, sys, re,time
16
17# Import package modules
18from serverConfig import *
19from common import *
20from localRules import *
21from GSErrors import *
22from PlotClasses import *
23from Animator import * 
24
25# Import external packages
26import cdms
27import vcs
28
29
30class OutputManager:
31    """
32    Manages generation of visual outputs.
33    """             
34       
35    def __init__(self, sessionObject):
36        """
37        Sets up instance variables and gets things ready to plot.
38        """
39        self.bag=sessionObject
40        self.textOnly=None
41        self._prepareData()
42        if self.textOnly:
43            # This should be checked by external caller
44            pass
45        else:
46            self._decidePlotClass()
47
48
49    def _prepareData(self):
50        """
51        Sets up variables to be worked with.
52        """
53        # Start with list of fileURIs - sorted
54        fileURIs=self.bag["fileURIList"]
55        fileURIs.sort()
56
57        gpattern=re.compile(r"(PointValueAndMetadata|YvsXGraph|2DPlot|Animation)_(\d+)\.?(\d+)?-?(\d+)?\.?(\d+)?")
58       
59        match=gpattern.match(self.bag["graphicalOutputType"])
60        if not match:
61            raise GSOptionHandlingError, "Cannot find a match for graphical output type."
62         
63        (self.graphicalOutputType, fileIndex1, varIndex1, fileIndex2, varIndex2)=match.groups()
64
65        if fileIndex2: 
66            raise GSOptionHandlingError, "Cannot yet handle multiple feature graphical outputs, sorry!"
67       
68        fileIndex1=int(fileIndex1)
69        varIndex1=int(varIndex1)
70        varID=self.bag["fileVariable_%s.%s" % (fileIndex1, varIndex1)]
71       
72        infile=cdms.open(fileURIs[fileIndex1-1])
73        self.var=infile(varID)
74       
75        self.suffix="%s.%s" % (fileIndex1, varIndex1)
76       
77        if self.graphicalOutputType=="PointValueAndMetadata":
78            self.textOnly=self._createTextOutputString(infile) 
79
80        infile.close()
81
82    def _createTextOutputString(self, cdmsFile):
83        """
84        Returns a text string including the variable value and suitable
85        metadata.
86        """
87        axisinfo="<B>Axis Information:</B>"
88        for ax in self.var.getAxisList():
89            axisinfo="""%s
90
91<B>ID:</B> %s
92<B>Units:</B> %s
93<B>Start:</B> %s
94<B>End:</B> %s""" % (axisinfo, ax.id, ax.units, ax[0], ax[-1])
95
96            if "bounds_"+ax.id in cdmsFile.listvariables():
97                bounds=cdmsFile('bounds_'+ax.id)
98                axisinfo="""%s
99<B>Bounds:</B> %s""" % (axisinfo, bounds.tolist())
100                   
101        textOutput="""
102
103<B>Your data contains only a single value</B>
104
105<B>Variable name:</B> %s
106
107<B>Variable value:</B> %s
108<B>Variable units:</B> %s
109
110%s""" % (getBestName(self.var), self.var.flat[0], getattr(self.var, "units", "-"), axisinfo)   
111       
112        print textOutput
113        return textOutput
114       
115
116    def _decidePlotClass(self):
117        """
118        Decides on plot class to use.
119        infile=cdms.open(fileURIs[fileIndex1-1])
120        self.var=infile(varID)
121        infile.close()
122       
123        """
124        plotType=self.bag["plotType"]   
125       
126        if self.bag.has_key("continentsSwitch"):
127            continentsSwitch=self.bag["continentsSwitch"]
128        else:
129            continentsSwitch="off"
130       
131        if self.bag.has_key("projection"):   
132            projection=self.bag["projection"]
133        else: 
134            projection="standard"
135       
136        projMap={"standard":"Linear",
137            "mollweide":"Mollweide",
138            "northPolar":"PolarNorth",
139            "southPolar":"PolarSouth",
140            "robinson":"Robinson"}         
141       
142        if plotType in ["YvsXGraph"]:
143            self.plotClass=plotType   
144        elif plotType=="isolineAndFill":
145            self.plotClass="IsolineAndFill"+projMap[projection] 
146        else:
147            self.plotClass=plotType.title()+projMap[projection] 
148       
149        self.contSwitch={"off":0, "on":1}[continentsSwitch]
150       
151       
152    def createOutputs(self):
153        """
154        Creates the visualisations and writes them to a file.
155        """
156        self.fileFormat=self.bag["fileFormat"] 
157        formatMap={"postscript":"ps", "gif":"gif"}
158        ext=formatMap[self.fileFormat]
159       
160        timestamp= time.strftime("%Y%m%d%H%M%S", time.gmtime(time.time()))
161        fileName="output_%s.%s" % (timestamp, ext)
162
163        outputDir=checkSubDirectory(self.bag["username"])
164
165        self.localPath=os.path.join(outputDir, fileName)
166        self.URLPath=translateURI(self.localPath)       
167
168        # Delete output file if already there
169        if os.path.isfile(self.localPath): os.unlink(self.localPath)
170
171        self.imageSize=self.bag["imageSize"]
172       
173        print "Creating plot using class: ", self.plotClass
174       
175        vcsCanvas=vcs.init()
176       
177        if self.graphicalOutputType=="Animation":
178            self._createAnimation(vcsCanvas)               
179        else:
180            self._createPlot(vcsCanvas)
181
182        fixFilePermissions(self.localPath)
183        print "Plot produced successfully:", self.localPath,"\n\n"   
184        return
185
186
187    def _createPlot(self, vcsCanvas):
188        """
189        Creates a single frame plot - optionally including overlays.
190        """
191        try:
192            if self.plotClass.find("IsolineAndFill")>-1:
193                proj=self.plotClass[14:]
194                plotClassList=["Isofill"+proj, "Isoline"+proj]     
195            else:
196                plotClassList=[self.plotClass] 
197       
198            # Loop through (note only relevant really for isoline and fill
199            for plotClass in plotClassList:
200                plotter=eval("%s(vcsCanvas, self.var(squeeze=1))" % plotClass)
201               
202                if plotClass in ["YvsXGraph"]:
203                    plotter.createPlot()
204                else:
205                    plotter.createPlot(continentsSwitch=self.contSwitch)
206
207            # Plot appropriate output format
208            if self.fileFormat=="gif": 
209                vcsCanvas.gif(self.localPath, geometry=self.imageSize) 
210                # Brand output if GIF
211                print "<P>Branding switched off for now...<P>"
212
213            elif self.fileFormat=="postscript": 
214                vcsCanvas.postscript(self.localPath) 
215                       
216        except Exception, error:
217            raise GSPlottingError, error
218
219
220    def _createAnimation(self, vcsCanvas):
221        """
222        If animation is selected then control it here.
223        """
224
225        plotter=eval("%s(vcsCanvas, self.var)" % self.plotClass)       
226               
227        plotType=plotter.plot_type   
228       
229        if self.plotClass.find("Boxfill")>-1:
230            plotType.boxfill_type="custom"
231
232        (valueList, colourList)=self._setUpColourRange()
233        plotType.levels=valueList
234       
235        if self.plotClass.find("Isoline")>-1 and self.plotClass.find("AndFill")<0:
236            plotType.label="y"
237        else:   
238            plotType.fillareacolors=colourList
239        print (valueList, colourList)
240       
241        print plotType.list()
242                       
243        #(loopAxisID, nLoops)=self._getAnimationAxesInfo()
244        (loopAxisIndex, axisSelectionIndices, nLoops)=self._getAnimationAxesInfo()
245
246        indexSelectionString=""
247        for indxTuple in axisSelectionIndices:
248            indexSelectionString=indexSelectionString+("%s:%s," % indxTuple)
249           
250        indexSelectionString="[%s]" % indexSelectionString[:-1]
251        print indexSelectionString
252                       
253        for i in range(nLoops): 
254             vcsCanvas.clear() 
255             indexString=indexSelectionString.replace("LOWER:HIGHER", "%s:%s" % (i, i+1))
256             print "indexString:", indexString
257             plotter.createPlot(animationArgs=indexString, continentsSwitch=self.contSwitch)
258             #plotter.createPlot(animationArgs=(loopAxisID, (i,i+1)), continentsSwitch=self.contSwitch)
259             print "Plotted:", (i,i+1)
260             vcsCanvas.gif(self.localPath, merge="a", geometry=self.imageSize) 
261       
262        print "Animation complete!"
263       
264       
265    def _getAnimationAxesInfo(self):
266        """
267        Works out and returns the index of the axis for looping over,
268        the start and end indices of each axis selection and the number
269        of loops.
270        """
271        axes=self.var.getAxisList()   
272        (xID, yID, loopID)=(self.bag["axisXForAnimation"], self.bag["axisYForAnimation"], self.bag["axisLoopForAnimation"])
273
274        axisSelectionIndices=[]
275           
276        counter=0 
277         
278        for axis in axes:
279            if axis.id==loopID:
280                loopAxisIndex=counter
281                nLoops=len(axis)
282                axisSelectionIndices.append(("LOWER", "HIGHER"))
283            elif axis.id==yID:
284                axisSelectionIndices.append((0, len(axis)))
285                yIndex=counter
286            elif axis.id==xID:
287                axisSelectionIndices.append((0, len(axis)))
288                xIndex=counter
289            else:
290                axisSelectionIndices.append((0, 1)) # only the first value
291       
292            counter=counter+1
293       
294        # Reorder x and y axes if needed
295        if yIndex>xIndex:
296            print "Reordering x and y axes..."
297            axisOrder=range(len(axes))
298            axisOrder[yIndex]=xIndex
299            axisOrder[xIndex]=yIndex
300            axisOrderString="".join([str(i) for i in axisOrder])
301            self.var.reorder(axisOrderString)
302       
303        return (loopAxisIndex, axisSelectionIndices, nLoops)
304       
305        #return (axes[0].id, len(axes[0]))
306       
307       
308        time_axis = self.data.getTime() 
309        lev_axis = self.data.getLevel() 
310        lat_axis = self.data.getLatitude() 
311        lon_axis = self.data.getLongitude()
312 
313        loop_num=1 
314        if time_axis!=None: 
315            loop_flag = 'time' 
316            loop_num = len(time_axis) 
317        if loop_num==1 and lev_axis!=None: 
318            loop_num = len(lev_axis) 
319            loop_flag = 'level' 
320        if loop_num==1 and lat_axis!=None: 
321            loop_num=len(lat_axis) 
322            loop_flag='lat' 
323        if loop_num==1 and lon_axis!=None: 
324            loop_num=len(lon_axis) 
325            loop_flag='lon' 
326       
327        self.loop_num=loop_num
328        self.loop_flag=loop_flag
329       
330         
331    def _setUpColourRange(self):
332        """
333        Creates the appropriate colour range for multiple frames to
334        share a common legend/scale.
335        """
336        # Get the colour range for the legend
337        (mn,mx)=vcs.minmax(self.var)
338        scaleValues=vcs.mkscale(mn, mx, 16)
339        valueList=[] 
340        colourList=[] 
341       
342        try: 
343            d=int(222/(len(scaleValues)-1)) 
344        except: 
345            d=1 
346                   
347        for a in range(len(scaleValues)):
348            colourList.append(16 + a*d)
349            valueList.append(scaleValues[a])
350       
351        return (valueList, colourList)
352
353 
354       
355                               
356                       
357if __name__=="__main__":
358
359    b=OutputManager({'fileVariable_1.1':'t', 'status': 'constructing', 'username': 'jane', 'accessTime': 1142557842.2275701, 'fileURIList': ['/data/dx/0d.nc'], 'userRoles': [], 'sessionID': 'session_20060317011041792', 'graphicalOutputType': 'PointValueAndMetadata_1.1', 'getOutput': 'getOutput'})
360    sys.exit()
361    b=OutputManager({'status': 'constructing', 'username': None, 'outputURLPath': 'http://localhost/output/test.gif', 'fileURIList': ['/srv/www/htdocs/output/jane/dx_output/output_20060316232539.nc'], 'imageSize': '300x200', 'confirm': 'Confirm', 'accessTime': 1142551623.3794341, 'userRoles': [], 'sessionID': 'session_20060316232622350', 'graphicalOutputType': 'YvsXGraph_1.1', 'plotType': 'YvsXGraph', 'proceed': 'Proceed', 'action': 'createOutput', 'outputFilePath': '/srv/www/htdocs/output/test.gif', 'fileFormat': 'postscript', 'getOutput': 'getOutput', 'fileVariable_1.1': 'var1'})
362    b.createOutputs()
363    sys.exit()
364
365    a=OutputManager({'status': 'constructing', 'username': 'jane', 'accessTime': 1142325307.7825251, 'imageSize': '800x600', 'fileVariable_1.3': 'pqn', 'fileURIList': ['/tmp/ani.nc'], 'userRoles': [], 'sessionID': 'session_20060314083506222', 'graphicalOutputType': 'Animation_1.3', 'plotType': 'isofill', 'continentsSwitch': 'on', 'fileFormat': 'gif', 'getOutput': 'getOutput', 'projection': 'standard'})
366    a.createOutputs()
367    sys.exit()
368    a=OutputManager({'status': 'constructing', 'username': 'jane', 'accessTime': 1142325307.7825251, 'imageSize': '800x600', 'fileVariable_1.2': 'var1', 'fileURIList': ['/tmp/tmp.nc'], 'userRoles': [], 'sessionID': 'session_20060314083506222', 'graphicalOutputType': '2DPlot_1.2', 'plotType': 'boxfill', 'continentsSwitch': 'on', 'fileFormat': 'gif', 'getOutput': 'getOutput', 'projection': 'standard'})
369    a.createOutputs()   
370    sys.exit()
371
372    o=OutputManager({"plotType":"isolineAndFill", "projection":"standard",
373                     "continentsSwitch":"on", "imageSize":"800x600",
374                     "fileFormat":"postscript", "fileURIList":["/tmp/tmp.nc"],
375                     "fileVariable_1.1":"var1", "graphicalOutputType":"2DPlot_1.1"})
376
377    o.createOutputs()
378    print o.__dict__   
379    if o.localPath.split(".")[-1]=="gif":
380        util="gifview"
381    else:
382        util="gv"
383    os.system("%s %s&" % (util, o.localPath))
384    import sys; sys.exit()
385    o=OutputManager({"plotType":"isofill", "projection":"standard",
386                     "continentsSwitch":"off", "imageSize":"600x400",
387                     "fileFormat":"gif", "fileURIList":["/tmp/tmp2.nc"],
388                     "fileVariable_1.1":"myway", "graphicalOutputType":"2DPlot_1.1"})
389    o.createOutputs()
390    print o.__dict__   
391    os.system("gifview %s&" % o.localPath)   
Note: See TracBrowser for help on using the repository browser.