source: TI04-geosplat/trunk/pygss/OutputManager.py @ 798

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

Latest working version with install method.
Can accept more than one file but doesn't combine variables yet.

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        self.localPath=os.path.join(OUTPUT_DIR, fileName)
164        self.URLPath=os.path.join(OUTPUT_DIR_URL, fileName)     
165
166        # Delete output file if already there
167        if os.path.isfile(self.localPath): os.unlink(self.localPath)
168
169        self.imageSize=self.bag["imageSize"]
170       
171        print "Creating plot using class: ", self.plotClass
172       
173        vcsCanvas=vcs.init()
174       
175        if self.graphicalOutputType=="Animation":
176            self._createAnimation(vcsCanvas)               
177        else:
178            self._createPlot(vcsCanvas)
179
180        print "Plot produced successfully:", self.localPath,"\n\n"   
181        return
182
183
184    def _createPlot(self, vcsCanvas):
185        """
186        Creates a single frame plot - optionally including overlays.
187        """
188        try:
189            if self.plotClass.find("IsolineAndFill")>-1:
190                proj=self.plotClass[14:]
191                plotClassList=["Isofill"+proj, "Isoline"+proj]     
192            else:
193                plotClassList=[self.plotClass] 
194       
195            # Loop through (note only relevant really for isoline and fill
196            for plotClass in plotClassList:
197                plotter=eval("%s(vcsCanvas, self.var(squeeze=1))" % plotClass)
198               
199                if plotClass in ["YvsXGraph"]:
200                    plotter.createPlot()
201                else:
202                    plotter.createPlot(continentsSwitch=self.contSwitch)
203
204            # Plot appropriate output format
205            if self.fileFormat=="gif": 
206                vcsCanvas.gif(self.localPath, geometry=self.imageSize) 
207                # Brand output if GIF
208                print "<P>Branding switched off for now...<P>"
209
210            elif self.fileFormat=="postscript": 
211                vcsCanvas.postscript(self.localPath) 
212                       
213        except Exception, error:
214            raise GSPlottingError, error
215
216
217    def _createAnimation(self, vcsCanvas):
218        """
219        If animation is selected then control it here.
220        """
221
222        plotter=eval("%s(vcsCanvas, self.var)" % self.plotClass)       
223               
224        plotType=plotter.plot_type   
225       
226        if self.plotClass.find("Boxfill")>-1:
227            plotType.boxfill_type="custom"
228
229        (valueList, colourList)=self._setUpColourRange()
230        plotType.levels=valueList
231       
232        if self.plotClass.find("Isoline")>-1 and self.plotClass.find("AndFill")<0:
233            plotType.label="y"
234        else:   
235            plotType.fillareacolors=colourList
236        print (valueList, colourList)
237       
238        print plotType.list()
239                       
240        #(loopAxisID, nLoops)=self._getAnimationAxesInfo()
241        (loopAxisIndex, axisSelectionIndices, nLoops)=self._getAnimationAxesInfo()
242
243        indexSelectionString=""
244        for indxTuple in axisSelectionIndices:
245            indexSelectionString=indexSelectionString+("%s:%s," % indxTuple)
246           
247        indexSelectionString="[%s]" % indexSelectionString[:-1]
248        print indexSelectionString
249                       
250        for i in range(nLoops): 
251             vcsCanvas.clear() 
252             indexString=indexSelectionString.replace("LOWER:HIGHER", "%s:%s" % (i, i+1))
253             print "indexString:", indexString
254             plotter.createPlot(animationArgs=indexString, continentsSwitch=self.contSwitch)
255             #plotter.createPlot(animationArgs=(loopAxisID, (i,i+1)), continentsSwitch=self.contSwitch)
256             print "Plotted:", (i,i+1)
257             vcsCanvas.gif(self.localPath, merge="a", geometry=self.imageSize) 
258       
259        print "Animation complete!"
260       
261       
262    def _getAnimationAxesInfo(self):
263        """
264        Works out and returns the index of the axis for looping over,
265        the start and end indices of each axis selection and the number
266        of loops.
267        """
268        axes=self.var.getAxisList()   
269        (xID, yID, loopID)=(self.bag["axisXForAnimation"], self.bag["axisYForAnimation"], self.bag["axisLoopForAnimation"])
270
271        axisSelectionIndices=[]
272           
273        counter=0 
274         
275        for axis in axes:
276            if axis.id==loopID:
277                loopAxisIndex=counter
278                nLoops=len(axis)
279                axisSelectionIndices.append(("LOWER", "HIGHER"))
280            elif axis.id==yID:
281                axisSelectionIndices.append((0, len(axis)))
282                yIndex=counter
283            elif axis.id==xID:
284                axisSelectionIndices.append((0, len(axis)))
285                xIndex=counter
286            else:
287                axisSelectionIndices.append((0, 1)) # only the first value
288       
289            counter=counter+1
290       
291        # Reorder x and y axes if needed
292        if yIndex>xIndex:
293            print "Reordering x and y axes..."
294            axisOrder=range(len(axes))
295            axisOrder[yIndex]=xIndex
296            axisOrder[xIndex]=yIndex
297            axisOrderString="".join([str(i) for i in axisOrder])
298            self.var.reorder(axisOrderString)
299       
300        return (loopAxisIndex, axisSelectionIndices, nLoops)
301       
302        #return (axes[0].id, len(axes[0]))
303       
304       
305        time_axis = self.data.getTime() 
306        lev_axis = self.data.getLevel() 
307        lat_axis = self.data.getLatitude() 
308        lon_axis = self.data.getLongitude()
309 
310        loop_num=1 
311        if time_axis!=None: 
312            loop_flag = 'time' 
313            loop_num = len(time_axis) 
314        if loop_num==1 and lev_axis!=None: 
315            loop_num = len(lev_axis) 
316            loop_flag = 'level' 
317        if loop_num==1 and lat_axis!=None: 
318            loop_num=len(lat_axis) 
319            loop_flag='lat' 
320        if loop_num==1 and lon_axis!=None: 
321            loop_num=len(lon_axis) 
322            loop_flag='lon' 
323       
324        self.loop_num=loop_num
325        self.loop_flag=loop_flag
326       
327         
328    def _setUpColourRange(self):
329        """
330        Creates the appropriate colour range for multiple frames to
331        share a common legend/scale.
332        """
333        # Get the colour range for the legend
334        (mn,mx)=vcs.minmax(self.var)
335        scaleValues=vcs.mkscale(mn, mx, 16)
336        valueList=[] 
337        colourList=[] 
338       
339        try: 
340            d=int(222/(len(scaleValues)-1)) 
341        except: 
342            d=1 
343                   
344        for a in range(len(scaleValues)):
345            colourList.append(16 + a*d)
346            valueList.append(scaleValues[a])
347       
348        return (valueList, colourList)
349
350 
351       
352                               
353                       
354if __name__=="__main__":
355
356    b=OutputManager({'fileVariable_1.1':'t', 'status': 'constructing', 'username': 'jane', 'accessTime': 1142557842.2275701, 'fileURIList': ['/dxd/0d.nc'], 'userRoles': [], 'sessionID': 'session_20060317011041792', 'graphicalOutputType': 'PointValueAndMetadata_1.1', 'getOutput': 'getOutput'})
357    sys.exit()
358    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'})
359    b.createOutputs()
360    sys.exit()
361
362    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'})
363    a.createOutputs()
364    sys.exit()
365    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'})
366    a.createOutputs()   
367    sys.exit()
368
369    o=OutputManager({"plotType":"isolineAndFill", "projection":"standard",
370                     "continentsSwitch":"on", "imageSize":"800x600",
371                     "fileFormat":"postscript", "fileURIList":["/tmp/tmp.nc"],
372                     "fileVariable_1.1":"var1", "graphicalOutputType":"2DPlot_1.1"})
373
374    o.createOutputs()
375    print o.__dict__   
376    if o.localPath.split(".")[-1]=="gif":
377        util="gifview"
378    else:
379        util="gv"
380    os.system("%s %s&" % (util, o.localPath))
381    import sys; sys.exit()
382    o=OutputManager({"plotType":"isofill", "projection":"standard",
383                     "continentsSwitch":"off", "imageSize":"600x400",
384                     "fileFormat":"gif", "fileURIList":["/tmp/tmp2.nc"],
385                     "fileVariable_1.1":"myway", "graphicalOutputType":"2DPlot_1.1"})
386    o.createOutputs()
387    print o.__dict__   
388    os.system("gifview %s&" % o.localPath)   
Note: See TracBrowser for help on using the repository browser.