source: qesdi/geoplot/trunk/lib/geoplot/layer_drawer.py @ 5980

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

Moved the getMatplotlibColour function from the base layer drawer to the utils module.

Line 
1"""
2An object to draw just the layer (map + grid) from the plot,
3can draw to a file, a string or create an Image object.
4"""
5
6
7import logging
8import time
9
10import matplotlib.colors
11from matplotlib.figure import Figure
12
13import geoplot.utils as geoplot_utils
14from geoplot.colour_bar import ColourBar
15from geoplot.grid_factory import GridFactory
16from geoplot.map_factory import MapFactory
17from geoplot.colour_scheme import ColourSchemeBuilder
18import geoplot.utils as utils
19
20log = logging.getLogger(__name__)
21
22VALID_GRID_TYPES = ['latlon', 'national', 'rotated']
23
24VALID_PROJECTIONS = ['latlon', 'national']
25
26class LayerDrawerBase(object):
27    "Draws only the layer section of the plot to create a PIL image object"
28   
29    def __init__(self, 
30                 gridType='latlon', 
31                 transparent=False,
32                 projection='latlon',
33                 resolution=None,
34                 cmap=None, 
35                 colourBarMin=None,
36                 colourBarMax=None, 
37                 colourBarScale='linear',
38                 intervals=None, 
39                 bgcolour='white'):
40       
41       
42        self._csBuilder = ColourSchemeBuilder()
43        self._bgcolour = 'white'
44       
45        self.colourBarScale = colourBarScale
46        self.transparent = transparent
47        self.cmap = cmap
48       
49        log.debug("bgcolour = %s" % (bgcolour,))
50        self.bgcolour = bgcolour
51       
52        self._gridFactory = GridFactory(dataType=gridType)
53        self._mapFactory = MapFactory(projection, drawCoast=True, drawRivers=False, resolution=resolution)
54       
55        self.colourBarMin = colourBarMin
56        self.colourBarMax = colourBarMax
57        self.intervals = intervals
58       
59    def makeImage(self, xLimits=None, yLimits=None, width=800, height=600, dpi=200):
60        """
61        Creates a PIL image of the selected area of the layer.
62        """
63        st = time.time()
64
65        fig = self._getFigure(width, height, dpi)
66        figTime = time.time() 
67
68        axes = self._addAxes(fig)
69        axTime = time.time() 
70
71        self._drawToAxes(axes, xLimits, yLimits)
72        drawAxTime = time.time() 
73       
74        self._resetAxes(axes, xLimits, yLimits)
75        resetTime = time.time() 
76       
77        im = geoplot_utils.figureToImage(fig)
78        figToImTime = time.time() 
79       
80        log.debug("drawn layer in %.4fs : fig=%.2f ax=%.2f draw=%.2f res=%.2f im=%.2f" % 
81                  (time.time() -st , figTime - st, axTime - figTime, drawAxTime - axTime, resetTime - drawAxTime, figToImTime - resetTime))
82       
83        return im
84   
85   
86    def _drawToAxes(self, *args, **kwargs):
87        """
88        Draw the layer onto the axis, should be overidden by all subclasses.
89        """
90       
91        raise NotImplementedError()
92   
93    def _getFigure(self, width, height, dpi):
94        """
95        Returns a new figure object that is ready to be drawn on.
96        """
97
98        figsize=(width / float(dpi), height / float(dpi))
99
100        fig = Figure(figsize=figsize, dpi=dpi, facecolor=self.bgcolour, edgecolor=self.bgcolour,
101                     frameon=(not self.transparent))
102       
103        return fig       
104   
105    def _addAxes(self, figure):
106        """
107        Adds an axis to the figure object provided. The axes has no border and takes
108        up all the area on the figure so that anything drawn on the axis will
109        completly cover the figure.
110       
111        The axis background is transparent, if self.transparency is set to false
112        then the Figure's frameon should be set to true not the axis.
113        """
114       
115        axes = matplotlib.axes.Axes(figure, [0.0, 0.0, 1.0, 1.0], 
116                                    xticks=[], yticks=[], frameon=False)
117       
118        figure.add_axes(axes)
119       
120        #axes = figure.add_axes([0.0, 0.0, 1.0, 1.0],
121        #                       xticks=[], yticks=[], frameon=False)
122       
123        if self.transparent:
124            axes.set_alpha(0.0)
125            axes.patch.set_alpha(0.0)
126           
127       
128        return axes
129   
130    def _buildGrid(self, cdmsVar, xLimits, yLimits):
131        """
132        Builds a new grid object using the data found in the cdmsVar.
133        """
134       
135        self._gridFactory.cdmsVar = cdmsVar
136       
137        grid = self._gridFactory.getGrid(xLimits, yLimits)
138       
139        return grid
140   
141    def _resetAxes(self, axes, xLimits=None, yLimits=None):
142        """
143        resets the axis to the original limis and aspect after they have
144        been drawn on, this is needed as some methods of drawing to the axis
145        (notably basemap) change these properties.
146        """
147       
148        axes.set_aspect('auto')
149       
150        axes.set_xticks([])
151        axes.set_yticks([])
152       
153        if self.projection == 'latlon':
154            xLimitsMapUnits, yLimitsMapUnits = xLimits, yLimits
155        else:
156            map = self._getMap(xLimits, yLimits)
157            xLimitsMapUnits, yLimitsMapUnits = map.basemap(xLimits, yLimits)
158       
159        #reset the limits after drawing the grid
160        if xLimits != None:
161            axes.set_xlim(float(xLimitsMapUnits[0]), float(xLimitsMapUnits[1]))
162       
163        if yLimits != None:
164            axes.set_ylim(float(yLimitsMapUnits[0]), float(yLimitsMapUnits[1]))   
165       
166    def _getMap(self, xLimits, yLimits, ):
167        """
168        Returns a map object that corresponds to the current projection,
169        map objects can be used for transformation or drawing data.
170        """
171       
172        self._mapFactory.xLimits = xLimits
173        self._mapFactory.yLimits = yLimits
174       
175        map = self._mapFactory.buildMap()
176           
177        return map       
178       
179    ### properties ###       
180   
181    def __set_gridType(self, value):
182        if value not in VALID_GRID_TYPES:
183           
184            raise Exception(\
185             "Invalid value of '%s' for LayerDrawer.gridType property, must be one of %s" 
186                % (value, VALID_GRID_TYPES,))
187           
188        self._gridFactory.dataType = value
189
190    def __get_gridType(self):
191        return self._gridFactory.dataType
192   
193    gridType = property(__get_gridType, __set_gridType, None, None)
194   
195    def __set_showGridLines(self, value):
196        self._gridDrawer.showGridLines = value
197   
198    def __get_showGridLines(self):
199        return self._gridDrawer.showGridLines
200   
201    showGridLines = property(__get_showGridLines, __set_showGridLines) 
202       
203    def __set_outline(self, value):
204        self._gridDrawer.outline = value
205       
206    def __get_outline(self):
207        return self._gridDrawer.outline
208   
209    outline = property(__get_outline, __set_outline)
210
211       
212    def __set_projection(self, value):
213        if value not in VALID_PROJECTIONS:
214           
215            raise Exception(\
216             "Invalid value of '%s' for projection property, must be one of %s" 
217                % (value, VALID_PROJECTIONS,))
218           
219        self._mapFactory.projection = value
220
221    def __get_projection(self):
222        return self._mapFactory.projection
223   
224    projection = property(__get_projection, __set_projection, None, None)
225
226    def __set_cmap(self, value):
227        self._csBuilder.cmap = value
228       
229    def __get_cmap(self):
230        return self._csBuilder.cmap
231   
232    cmap = property(__get_cmap, __set_cmap)
233
234
235    def __set_intervals(self, value):
236        self._csBuilder.intervals = value
237   
238    def __get_intervals(self):
239        return self._csBuilder.intervals
240   
241    intervals = property(__get_intervals, __set_intervals)
242   
243    def __set_colourBarMin(self, value):
244        self._csBuilder.colourBarMin = value
245   
246    def __get_colourBarMin(self):
247        return self._csBuilder.colourBarMin
248   
249    colourBarMin = property(__get_colourBarMin, __set_colourBarMin)
250   
251    def __set_colourBarMax(self, value):
252        self._csBuilder.colourBarMax = value
253   
254    def __get_colourBarMax(self):
255        return self._csBuilder.colourBarMax
256
257    colourBarMax = property(__get_colourBarMax, __set_colourBarMax)
258   
259    def __set_colourBarScale(self, value):
260        self._csBuilder.colourBarScale = value
261   
262    def __get_colourBarScale(self):
263        return self._csBuilder.colourBarScale
264
265    colourBarScale = property(__get_colourBarScale, __set_colourBarScale)
266           
267    def __set_bgcolour(self, value):
268       
269        try:
270            newVal = utils.getMatplotlibColour(value)
271        except ValueError, e:
272            log.warning("Error occurred getting matplotlib colour form %s, Exception:%s" % (value, e))
273        else:
274            self._bgcolour = newVal
275               
276    def __get_bgcolour(self):
277        return self._bgcolour
278   
279    bgcolour = property(__get_bgcolour, __set_bgcolour)   
280   
Note: See TracBrowser for help on using the repository browser.