source: qesdi/geoplot/trunk/lib/geoplot/plot_base.py @ 6089

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/qesdi/geoplot/trunk/lib/geoplot/plot_base.py@6089
Revision 6089, 9.6 KB checked in by pnorton, 11 years ago (diff)

Imroved the colour bar code so that a legend colour bar can be used without specifying any intervals.

Line 
1import logging
2
3from geoplot.colour_bar import ColourBar
4from geoplot.map_factory import MapFactory
5from geoplot.grid_factory import GridFactory
6from geoplot.plotarea import PlotArea
7from geoplot.plot_writer import PlotWriter
8from geoplot.metadata_box import MetadataBox
9from geoplot.colour_scheme import ColourSchemeBuilder
10
11from geoplot.config import getConfig
12import geoplot.utils as geoplot_utils 
13
14config = getConfig()
15log = logging.getLogger(__name__)
16
17_construtorDocString = """
18Constructor for the abstract class PlotBase, should be called by any class inheriting
19from PlotBase.
20
21@param cdmsVar:the CDMS variable being plotted
22@type cdmsVar:
23@keyword format:the format of the output file
24@type format: a string , one of ('jpg','pdf','ps','png')
25@keyword width:the width of the drawn image in pixels, the actual width of 'pdf' and 'ps'
26    files will be altered by the dpi.
27@type width: integer
28@keyword height:the height of the drawn map in pixels, the actual width of 'pdf' and 'ps'
29    files will be altered by the dpi.
30@type height: integer
31@keyword xLimits:a tuple representing the (longitude) limits of the map
32@type xLimits: a tuple of 2 floats, corresponding to (min, max)
33@keyword yLimits:a tuple representing the (latitude) limits of the map
34@type yLimits: a tuple of 2 floats , corresponding to (min, max)
35@keyword dip: the resolution of the produced image
36@type dpi: integer
37@keyword cmap: the colour map to be used to draw the grid
38@type cmap: an instance of matplotlib.colors.LinearSegmentedColormap
39
40@keyword drawColourBar: indicates if the colour bar should be drawn
41@type drawColourBar: boolean
42@keyword colourBarLabel: the label for the colour bar
43@type colourBarLabel: string
44@keyword colourBarPosition: the orientation and position the colour bar is drawn on
45    the plot. The default is chosen based on the lat-lon limits of the plot.
46@type colourBarPosition: string, one of ['horizontal', 'vertical']
47@keyword colourBarMax: the minimum value for the colour bar
48@type colourBarMax: float
49@keyword colourBarMin: the maximum value for the colour bar
50@type colourBarMin: float
51@keyword drawLogo: indicates wheather to draw the UKCIP08 logo
52@type drawLogo: boolean
53@keyword drawCoast: indicates if coaslines should be drawn
54@type drawCoast: boolean
55@keyword drawRivers: indicates if rivers should be drawn
56@type drawRivers: boolean
57@keyword plotTitle: the title of the plot
58@type plotTitle: string
59@keyword units: the units of the value being plotted
60@type units: string
61@keyword metadataList: the metadata to be displayed along with the plot, if None no
62    metadata box will be drawn
63@type metadataList: a list of (key, value) tuples. The keys and values should both be
64    strings.
65@keyword fontSize: a general indication of the size of the fonts used on the plot
66@type fontSize: a string, one of ["small","medium" ,"large", 'xl', 'xxl']
67@keyword units: the units the cdmsVar data is in, if no colourBarLabel is specified
68    the units will be used instead.
69@type units: string
70
71@keyword addShapefile: location of shapefile to overlay
72@type addShapefile: string
73"""
74
75class PlotBase(object):
76    '''
77    Creates a contour plot form the data stored in a netCDF file
78    '''
79   
80    _accessableObjects = ['_colourBar', '_plotArea', '_metadataBox', 
81                          '_plotWriter', '_mapFactory', '_gridFactory']
82   
83    def __init__(self, **kwargs):
84        # doc string a top of file
85       
86        self.units = kwargs.pop('units', None)
87       
88        self._schemeBuilder = ColourSchemeBuilder(**self._getArgs(kwargs, ColourSchemeBuilder.__name__))
89       
90        self._colourBar   = ColourBar  (**self._getArgs(kwargs, ColourBar.__name__))
91       
92        self._plotArea    = PlotArea   (**self._getArgs(kwargs, PlotArea.__name__))
93       
94        self._metadataBox = MetadataBox(**self._getArgs(kwargs, MetadataBox.__name__))
95       
96        self._plotWriter  = PlotWriter (**self._getArgs(kwargs, PlotWriter.__name__))
97       
98        self._mapFactory  = MapFactory (**self._getArgs(kwargs, MapFactory.__name__))
99       
100        self._gridFactory = GridFactory(**self._getArgs(kwargs, GridFactory.__name__))
101       
102        if len(kwargs.keys()) > 0:
103            log.warning("Unused keyword arguments = %s" % (kwargs,))
104   
105    __init__.__doc__ = _construtorDocString
106     
107    def _getArgs(self, kwargs, className):
108        args = {}
109       
110        # all of the keyword arguments will have a value (even if it is None).
111        for k, defaultValue in config['Defaults'][className].items():
112           
113            # use the value from the keywords if one is there, otherwise use the
114            # default value
115            args[k] = kwargs.pop(k, defaultValue)
116               
117        return args
118
119    def drawMap(self, filename):
120        """
121        Outputs the map to the filename.
122
123        @param filename: the name of the file the image should be written to,
124            the extension of the filename given should match the intended format
125            of the image, i.e. 'test.jpg' for an image with format 'jpg'.
126        @type filename: string
127        """
128
129        log.info("Drawing map to " + filename)
130
131        self._plotWriter.checkFileExtension(filename)
132
133        self._drawToPlotArea()
134
135        self._plotWriter.writeFile(self._plotArea.figure, filename, self.drawLogo, self._plotArea.logoAxes)
136   
137    def _drawToPlotArea(self):
138       
139        self._setDynamicArgs()
140       
141        self._plotArea.setupArea(self.colourBarPosition)
142
143        map = self._mapFactory.buildMap()
144       
145        grid = self._gridFactory.getGrid(self.xLimits, self.yLimits)
146       
147        log.debug("self._colourBar.colourBarStyle = %s" % (self._colourBar.colourBarStyle,))
148       
149        colourScheme = self._schemeBuilder.buildScheme(self._colourBar.colourBarStyle, grid)
150       
151        log.debug("colourScheme.__class__ = %s" % (colourScheme.__class__,))
152       
153        self._drawDiagram(map, grid, self._plotArea.axes, colourScheme)
154       
155        #the map has to be drawn after the grid, otherwise it distorts the axis
156        map.drawMap(self._plotArea.axes)
157       
158        if self.drawMetadata:
159            self._metadataBox.draw(self._plotArea.metadataAxes, self.fontSize, self.height)
160
161        if self.drawColourBar:
162            self._colourBar.draw(self._plotArea.cbAxes, colourScheme, self.fontSize)
163
164    def drawToImage(self):
165        if self.format not in 'png':
166            raise Exception("format %s not yet supported for image retrieval" % (self.format,))
167       
168        self._drawToPlotArea()
169       
170        im = geoplot_utils.figureToImage(self._plotArea.figure)
171       
172        return im       
173   
174    def drawToBuffer(self):
175        self._drawToPlotArea()
176        return self._plotWriter.printFigureToBuffer(self._plotArea.figure)
177       
178       
179       
180    def _drawDiagram(self, *args, **kwargs):
181        raise NotImplementedError()
182
183
184    def __getattr__(self, name):
185        """
186        If this object dosen't have the desired attribute check the public attributes
187        of some of the interal objects. This allows properties (e.g. colourBarMin) to
188        be accesed without having to care about exactly where it is stored.
189        """
190
191        if name[0] == '_':
192            raise AttributeError("Attribute %s not found on %s" % (name, self))
193       
194        obj = self._findPrivateObjWithAttribute(name)
195           
196        if obj != None:
197            return getattr(obj, name)
198       
199        raise AttributeError("Attribute %s not found on %s" % (name, self))
200           
201    def __setattr__(self, name, value):
202        """
203        Allow the setting of some attributes on internal objects, these
204        are the attributes set in the defaults section of the config file
205        """
206               
207        if name[0] == '_':
208            object.__setattr__(self, name, value)
209            return
210       
211        obj = self._findPrivateObjWithAttribute(name)
212       
213        if obj != None:
214            #if obj found set it on that object
215            setattr(obj, name, value)
216        else:
217            #set it on self instead
218            object.__setattr__(self, name, value)
219
220    def _findPrivateObjWithAttribute(self, name):
221       
222        objFoundIn = None
223        for objName in self.__class__._accessableObjects:
224           
225   
226            #just in case this is called during initialisation
227            if objName not in self.__dict__.keys():
228                continue
229
230            obj = self.__dict__[objName]
231           
232            #use the defaults as a guide to what can be set
233            if name in config['Defaults'][obj.__class__.__name__].keys():
234                if objFoundIn != None:
235                    raise Exception("Attribute %s found in both %s and %s" % (name, objFoundIn, obj))
236                else:
237                    objFoundIn = obj
238                   
239        return objFoundIn
240   
241    def _setDynamicArgs(self):
242       
243        self._setColourBarPosition()
244        self._setColourBarLabel()
245   
246    def _setColourBarPosition(self):
247       
248        #if the colourbar position isn't already set, use the limits to work out
249        #the best fit
250        if self.colourBarPosition == None:
251            xRange = self.xLimits[1] - self.xLimits[0]
252            yRange = self.yLimits[1] - self.yLimits[0]
253            #log.debug("xRange:" + str(xRange) + "yRange:" + str(yRange))
254            if xRange > yRange:
255                self.colourBarPosition = 'horizontal'
256            else:
257                self.colourBarPosition = 'vertical'
258#            log.debug('new colour bar position:' + kwargs['colourBarPosition'])
259
260    def _setColourBarLabel(self):
261        #if no colourBarLabel is provided use the units insted
262        if self.colourBarLabel==None : 
263            self.colourBarLabel = self.units
264               
Note: See TracBrowser for help on using the repository browser.