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

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI04-geosplat/trunk/pygss/PlotClasses.py@6809
Revision 1660, 14.7 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"""
6PlotClasses.py
7==============
8
9Holds classes used for each plot type.
10
11"""
12
13# Import standard libary modules
14import cdms, vcs
15
16# Import local modules
17from serverConfig import *
18from common import *
19
20
21class YvsXGraph:
22    """
23    Used for plotting 1D variables as graphs.
24    """
25   
26    def __init__(self, canvas, data):
27        """
28        Takes canvas and data and calls other relevant methods.
29        """
30        self.canvas=canvas
31        try:
32            self.plot_type=canvas.createyxvsx("new_yxvsx","default")
33        except:
34            self.plot_type=canvas.getyxvsx("new_yxvsx") 
35        self._extractData(data)
36        self._getTemplate()
37
38    def _extractData(self, data):
39        """
40        Used to extract the appropriate data object.
41        """
42        self.data=data(squeeze=1)
43
44    def _getTemplate(self):
45        """
46        Sets up the appropriate template for a plot type.
47        """
48        try:
49            self.template=self.canvas.gettemplate(VCS_TEMPLATES["no_levels"])
50        except:
51            self.template=self.canvas.gettemplate("AMIP")           
52
53    def createPlot(self):
54        """
55        Plots the output and saves to a file.
56        """
57        # The next line is a bug fix to stop part of the plot being chopped when background plot is set to 1 (on).
58        # self.canvas.open()
59        if hasattr(self.data, "title"):
60            fileComment="Dataset: "+self.data.title
61        else:
62            fileComment=""
63        self.canvas.plot(self.data, self.template, self.plot_type, bg=1, file_comment=fileComment, comment1=SOURCE_NAME)
64
65
66
67class SimplePlot:
68    """
69    SimplePlot class - used for non-XY plots.
70    """
71   
72    def __init__(self, canvas, data):
73        """
74        Takes canvas and data and calls other relevant methods.
75        """
76        self.canvas=canvas
77        self._extractData(data)
78        self._getTemplate()
79
80    def _extractData(self, data):
81        """
82        Used to extract the appropriate data object.
83        """
84        self.data=data(squeeze=1)
85
86    def _getTemplate(self):
87        """
88        Sets up the appropriate template for a plot type.
89        """
90        try:
91            self.template=self.canvas.gettemplate(VCS_TEMPLATES["no_levels"])
92        except:
93            self.template=self.canvas.gettemplate("AMIP")
94
95    def createPlot(self, animationArgs=None, continentsSwitch=0):
96        """
97        Plots the output and saves to a file.
98        """
99        # The next line is a bug fix to stop part of the plot being chopped when background plot is set to 1 (on).
100        # self.canvas.open()
101        if hasattr(self.data, "title"):
102            fileComment="Dataset: "+self.data.title
103        else:
104            fileComment=""
105        if animationArgs==None:
106            self.canvas.plot(self.data, self.template, bg=1, continents=continentsSwitch, file_comment=fileComment, comment1=SOURCE_NAME)
107        else: # animationArgs is the slice indices of the data to plot converted to a string
108            dataSlice=eval("self.data%s" % animationArgs)
109            dataSlice=dataSlice(squeeze=1)
110            #print dataSlice.shape, dataSlice.getAxisIds()
111            #print dataSlice
112            self.canvas.plot(dataSlice, self.template, self.plot_type, continents=continentsSwitch, bg=1, file_comment=fileComment, comment1=SOURCE_NAME)       
113
114
115class Boxfill(SimplePlot):
116    """
117    Boxfill class - base class for all Boxfill types.
118    """
119   
120    def __init__(self, canvas, data, bbox=None):
121        self.canvas=canvas
122        self.bbox=bbox
123        try:
124            self.plot_type=canvas.createboxfill("new_boxfill","default")
125        except:
126            self.plot_type=canvas.getboxfill("new_boxfill")
127        self._extractData(data)
128        self._getProjection()
129        self._getTemplate()
130
131    def _extractData(self, data):
132        """
133        _extractData method - used to extract the appropriate data object.
134        """
135        self.data=data
136
137    def _getTemplate(self):
138        """
139        _getTemplate method - sets up the appropriate template for a plot type.
140        """
141        try:
142            if not self.data.getLevel():
143                self.template=self.canvas.gettemplate(VCS_TEMPLATES["no_levels"])
144            else:
145                self.template=self.canvas.gettemplate(VCS_TEMPLATES["with_levels"])             
146        except:
147            self.template=self.canvas.gettemplate("AMIP")
148        if self.bbox:  # set up lat/lon limits
149            #d=self.template.data
150            #(d.y1,d.x1,d.y2,d.x2)=self.bbox
151           
152            pt=self.plot_type
153            pt.datawc_x1=self.bbox[1]
154            pt.datawc_x2=self.bbox[3]
155            pt.datawc_y1=self.bbox[0]
156            pt.datawc_y2=self.bbox[2]
157
158
159    def createPlot(self, animationArgs=None, continentsSwitch=1):
160        """
161        createPlot method - plots the output.
162        """
163        # The next line is a bug fix to stop part of the plot being chopped when background plot is set to 1 (on).
164        # self.canvas.open())
165        if hasattr(self.data, "title"):
166            fileComment="Dataset: "+self.data.title
167        else:
168            fileComment=""
169        if animationArgs==None:
170            self.canvas.plot(self.data, self.template, self.plot_type, bg=1, continents=continentsSwitch, file_comment=fileComment, comment1=SOURCE_NAME)
171        else: # animationArgs is the slice indices of the data to plot converted to a string
172            dataSlice=eval("self.data%s" % animationArgs)
173            dataSlice=dataSlice(squeeze=1)
174            #print dataSlice.shape, dataSlice.getAxisIds()
175            #print dataSlice
176            self.canvas.plot(dataSlice, self.template, self.plot_type, continents=continentsSwitch, bg=1, file_comment=fileComment, comment1=SOURCE_NAME) 
177
178
179        #elif animationArgs[0]=="time":
180        #    self.canvas.plot(self.data(time=slice(animationArgs[1][0],animationArgs[1][1])), self.template, self.plot_type, continents=continentsSwitch, bg=1, file_comment=fileComment, comment1=SOURCE_NAME)
181        #elif animationArgs[0]=="level":
182        #    self.canvas.plot(self.data(level=slice(animationArgs[1][0],animationArgs[1][1])), self.template, self.plot_type, continents=continentsSwitch, bg=1, file_comment=fileComment, comment1=SOURCE_NAME)               
183
184class BoxfillLinear(Boxfill):
185    def _getProjection(self):
186        self.plot_type.projection="linear"
187
188       
189class BoxfillMollweide(Boxfill):
190    def _getProjection(self):
191        self.plot_type.projection="mollweide"
192           
193
194class BoxfillPolarNorth(Boxfill):
195    def _extractData(self, data):
196        "Extracts only northern hemisphere."
197        self.data=data(latitude=(90,0))
198
199    def _getProjection(self):
200        self.plot_type.projection="polar"
201         
202       
203class BoxfillPolarSouth(BoxfillPolarNorth):
204    def _extractData(self, data):
205        "Extracts only southern hemisphere."
206        self.data=data(latitude=(-90,0))
207
208       
209class BoxfillRobinson(Boxfill):
210    def _getProjection(self):
211        self.plot_type.projection="robinson"
212
213
214class Isofill(Boxfill):
215    def __init__(self, canvas, data):
216        self.canvas=canvas
217        try:
218            self.plot_type=canvas.createisofill("new_isofill","default")
219        except:
220            self.plot_type=canvas.getisofill("new_isofill") 
221        self._extractData(data)
222        self._getProjection()
223        self._getTemplate()
224
225
226class IsofillLinear(Isofill):
227    def _getProjection(self):
228        self.plot_type.projection="linear"
229
230
231class IsofillMollweide(Isofill):
232    def _getProjection(self):
233        self.plot_type.projection="mollweide"
234
235
236class IsofillPolarNorth(Isofill):
237    def _extractData(self, data):
238        "Extracts only northern hemisphere."   
239        self.data=data(latitude=(90,0))
240
241    def _getProjection(self):
242        self.plot_type.projection="polar"
243
244       
245class IsofillPolarSouth(IsofillPolarNorth):
246    def _extractData(self, data):
247        "Extracts only southern hemisphere." 
248        self.data=data(latitude=(0,-90))
249
250       
251class IsofillRobinson(Isofill):
252    def _getProjection(self):
253        self.plot_type.projection="robinson"
254
255
256class Isoline(Isofill):
257    def __init__(self, canvas, data):
258        self.canvas=canvas
259        try:
260            self.plot_type=canvas.createisoline("new_isoline","default")
261        except:
262            self.plot_type=canvas.getisoline("new_isoline")     
263        self.plot_type.label="y"
264        self._extractData(data)
265        self._getProjection()
266        self._getTemplate()
267
268
269class IsolineLinear(Isoline):
270    def _getProjection(self):
271        self.plot_type.projection="linear"
272
273
274class IsolineMollweide(Isoline):
275    def _getProjection(self):
276        self.plot_type.projection="mollweide"
277
278
279class IsolinePolarNorth(Isoline):
280    def _extractData(self, data):
281        "Extracts only northern hemisphere."   
282        self.data=data(latitude=(90,0))
283
284    def _getProjection(self):
285        self.plot_type.projection="polar"
286
287       
288class IsolinePolarSouth(IsolinePolarNorth):
289    def _extractData(self, data):
290        "Extracts only southern hemisphere." 
291        self.data=data(latitude=(0,-90))
292
293       
294class IsolineRobinson(Isoline):
295    def _getProjection(self):
296        self.plot_type.projection="robinson"
297       
298       
299class MultipleTrajectory:
300    """
301    Plots multiple trajectories on the selected domain.
302    """ 
303    def __init__(self, canvas, filePath, varID, area, bbox=None):
304        """
305        Takes canvas and file and varID and calls other relevant methods.
306        """
307        self.canvas=canvas
308        self.area=area
309        self.bbox=bbox
310        self.filePath=filePath
311        self.cdmsFile=cdms.open(filePath)
312        self.varID=varID
313        self._extractData()
314        self.titleTemplate=self._getTemplate("titlet")
315        self.tboxTemplate=self._getTemplate("tboxt")
316       
317    def _extractData(self):
318        """
319        Used to extract the appropriate data object.
320        Returns a dictionary of {"parcelID":[[y,x],[y,x]...]]}
321        """
322        f=self.cdmsFile
323        self.data={}
324       
325        # Get var ids of lat and lon in file
326        [latID, lonID]=identifyLatLonVarIDs(f)
327        if latID==None or lonID==None:
328            raise GSPlottingError, "Could not identify and latitude and longitude variable to plot trajectory."
329       
330        # Now sort what needs plotting
331        lat=f[latID]
332        if lat.rank()==1:
333            lats=f(latID)[:].tolist()
334            lons=f(lonID)[:].tolist()
335            data=[[lats[i],lons[i]] for i in range(len(lats))]
336            self.data["single_traj"]=data[:]
337        else: # assume there is a parcel dimension as well
338            for parcel in range(len(lat[1])):
339                lats=f(latID)[:,parcel].tolist()
340                lons=f(lonID)[:,parcel].tolist()
341                data=[[lats[i],lons[i]] for i in range(len(lats))]
342                self.data[parcel]=data[:]
343           
344        if hasattr(f[self.varID], "title"):
345            self.title=f[self.varID].title
346        return self.data
347
348    def _getTemplate(self, name):
349        """
350        Sets up the appropriate template for a plot type.
351        """
352        try:
353            t=self.canvas.createtemplate(name, VCS_TEMPLATES["no_levels"])     
354        except:
355            try: 
356                t=self.canvas.createtemplate(name, "AMIP")     
357            except:
358                t=self.canvas.gettemplate(name)   
359        """try:
360            t=self.canvas.createtemplate(name, VCS_TEMPLATES["no_levels"])
361        except:
362            t=self.canvas.gettemplate(name)"""
363       
364        """box=t.box1
365        box.x1 = 0.0500000007451
366        box.y1 = 0.259999990463
367        box.x2 = 0.949999988079
368        box.y2 = 0.860000014305"""
369        data=t.data
370        #data.x1 = 0.0500000007451
371        #data.y1 = 0.263999560899
372        #data.x2 = 0.949999988079
373        #data.y2 = 0.856999927733       
374        #print t.name,"\n\n\n"
375        if name=="titlet":
376                t.max.priority=0
377                t.min.priority=0
378                t.mean.priority=0
379                t.crdate.priority=0
380                t.units.priority=0
381                t.crtime.priority=0
382                t.dataname.priority=0   
383                t.legend.priority=0
384                t.comment1.priority=1
385
386                try:
387                    title=self.canvas.createtexttable("title_stuff")
388                except:
389                    title=self.canvas.gettexttable("title_stuff")                       
390                title.font=1
391                t.title.texttable=title
392                try:
393                    titleto=self.canvas.createtextorientation("title_textorient")
394                except:
395                    titleto=self.canvas.gettextorientation("title_textorient")                 
396                titleto.height=30
397                print t.title.list()
398                t.title.x=0.13
399                t.title.y=0.99
400                t.title.textorientation=titleto
401        return t       
402
403    def _prepareContinents(self, bbox):
404        """
405        Prepares continents for plot.
406        """
407        try:
408            c=self.canvas.createcontinents("c1")
409        except:
410            c=self.canvas.getcontinents("c1")   
411
412        c.datawc_x1=bbox[1]
413        c.datawc_x2=bbox[3]
414        c.datawc_y1=bbox[0]
415        c.datawc_y2=bbox[2]
416        c.xticlabels1="*"
417        c.xticlabels2="*"
418        c.yticlabels1="*"
419        c.yticlabels2="*"                       
420        return c       
421
422    def _convertWC(self, i, xory, bbox, tbox):
423        """
424        Converts World Coordinates to pixel coordinates.
425        """
426        [y1,x1,y2,x2]=bbox 
427        [boty,botx,topy,topx]=tbox
428        if xory=="x":
429                return ((i-x1)/(x2-x1)*(topx-botx))+botx
430        elif xory=="y":
431                return ((i-y1)/(y2-y1)*(topy-boty))+boty
432
433    def _getExtent(self, datadict):
434        """
435        Returns the full extent of all trajectories.
436        """
437        maxLat=-91; 
438        maxLon=-361
439        minLat=91
440        minLon=361     
441        for key,data in datadict.items():
442            for (y,x) in data:
443                if y>maxLat:    maxLat=y
444                if y<minLat:    minLat=y
445                if x>maxLon:    maxLon=x
446                if x<minLon:    minLon=x
447        return (minLat,minLon,maxLat,maxLon)
448
449    def createPlot(self):
450        """
451        Plots the output and saves to a file.
452        """
453        if hasattr(self, "title"):
454            fileComment="Dataset: "+self.title
455        else:
456            fileComment=""
457       
458        datadict=self.data
459        if self.bbox:
460            bbox=self.bbox
461        else:
462            bbox=self._getExtent(datadict)
463            (y1,x1,y2,x2)=bbox
464
465            domain=self.area
466            if domain=="global":
467                bbox=[-90,(x1-20),90,(x1+340)]
468            elif domain=="northernHemisphere":
469                bbox=[0,(x1-20),90,(x1+340)]
470            elif domain=="southernHemisphere":
471                bbox=[-90,(x1-20),0,(x1+340)]
472            else:
473                bbox=[(y1-5),(x1-5),(y2+5),(x2+5)]
474       
475        c=self._prepareContinents(bbox)
476        t=self.tboxTemplate
477        d=t.data
478        tbox=(d.y1,d.x1,d.y2,d.x2)   
479       
480        self.canvas.plot(c, t, bg=1)
481       
482        parcels=datadict.keys()
483        parcels.sort()
484   
485        colourRange=range(30,180,10)*50
486        count=0
487       
488        for p in parcels:
489                data=datadict[p]
490                col=colourRange[count] 
491                try:
492                    marker=self.canvas.createmarker("markertest%s"%count)
493                except:
494                    marker=self.canvas.getmarker("markertest%s"%count)                 
495                marker.y=[self._convertWC(data[0][0],"y",bbox,tbox)]
496                marker.x=[self._convertWC(data[0][1],"x",bbox,tbox)]
497                marker.size=[4.0]
498                marker.type=["circle"]
499                marker.color=[col]
500                self.canvas.plot(marker,t,bg=1)
501       
502                try:
503                    line=self.canvas.createline("trajline%s"%count)
504                except:
505                    line=self.canvas.getline("trajline%s"%count)       
506                               
507                line.y=[self._convertWC(i[0],"y",bbox,tbox) for i in data]
508                line.x=[self._convertWC(i[1],"x",bbox,tbox) for i in data]
509                line.color=[col]
510                count+=1
511                self.canvas.plot(line, t, bg=1)
512   
513        # Now plot a title
514        self.canvas.plot([0,0], self.titleTemplate, bg=1, title="Plot of trajectory data from file: %s" % self.filePath)#, bg=1, file_comment=fileComment, comment1=SOURCE_NAME)
515
516
517
518if __name__=="__main__":
519    import vcs, cdms
520    vcsCanvas=vcs.init()
521    infile="/data/traj.nc"
522    varid="temp"
523    plotClass="MultipleTrajectory"
524    plotter=eval("%s(vcsCanvas, infile, varid, 'global')" % plotClass)
525    print "done"
526    plotter.createPlot()
527   
Note: See TracBrowser for help on using the repository browser.