source: DPPP/kml/csml2kml/python/pylonsstack/pylonsstack/controllers/csmlGrapher.py @ 3316

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/DPPP/kml/csml2kml/python/pylonsstack/pylonsstack/controllers/csmlGrapher.py@3316
Revision 3316, 6.6 KB checked in by mkochan, 12 years ago (diff)

Changed x-axis labelling in point series graphing to show times.

Line 
1# Pylons-specific imports
2import logging
3from pylonsstack.lib.base import *
4
5# Other imports
6import csml
7import Image
8import pylab
9from pylab import *
10from datetime import datetime, timedelta
11import re
12import urllib
13from cStringIO import StringIO
14from tempfile import NamedTemporaryFile
15from cElementTree import Element, ElementTree, XML
16
17log = logging.getLogger(__name__)
18
19# [TODO] . Add correct labeling of time axis
20#        . Comments
21#        . Add security (especially checking of input parameters).
22#        . Add configurable URL for the data source web service (preferably explicitly on localhost)
23class CsmlgrapherController(BaseController):
24
25    def plot(self):
26        '''
27        Handler for plotting a specific PointSeries feature given by URL parameter "feature_id".
28        Retrieves the data from a web service, which should preferably run on the same machine.
29
30        Request parameters:    EITHER "feature_id" OR "station_id"
31        where:
32                               feature_id    Unique identifier of a requested CSML PointSeries feature.
33                               station_id    Unique identifier of a requested station.
34
35        Response:              If feature_id is supplied, an image/png of the time series for the CSML PointSeries feature;
36                               if station_id is supplied, nothing.
37        '''
38        def _plot_feature(feature):
39            '''
40            Plot a PointSeries feature using matplotlib, into a temporary file
41            '''
42            (lon, lat) = map(float, feature.location.CONTENT.split())
43            print 'Feature "%s" (%s) at: (%f,%f)' % (feature.id, feature.description.CONTENT, lon, lat)
44
45            times=feature.value.pointSeriesDomain.timePositionList.CONTENT.split()
46            print 'All times (%s of them): '% len(times)
47            print times
48           
49            start_date = dates.dateutil.parser.parse(times[0])
50            end_date = dates.dateutil.parser.parse(times[-1])
51            span = datestr2num(times[-1]) - datestr2num(times[0])
52            print 'The span is ' + str(span) + ' days.'
53
54            elapsed_times = map(datestr2num, times)
55
56            (tickLocator, tickFormatter) = dates.date_ticker_factory(span, numticks=8)
57            print 'tickLocator:%s\ntickFormatter:%s' % (tickLocator, tickFormatter)
58
59            print 'All times (%s of them) as days since 01-01-0001 UTC: '% len(elapsed_times)
60            print elapsed_times
61
62            # We may need to do this for bodc data (i.e. not inline data)
63            # vals=feature.value.rangeSet.valueArray.valueComponent.insertedExtract.components.getDataFromChunks(0,19)
64
65            # We use this for inline data:
66            ql = feature.value.rangeSet.quantityList
67            vals = map(float, ql.CONTENT.split())
68            print 'Measurement values (%s of them):\n%s' % (len(vals), repr(vals))
69
70            # Determine the units of measurement
71            uom=ql.uom.title()
72            if ql.uom.islower():
73                uom = uom.lower()
74            if ql.uom.isupper():
75                uom = uom.upper()
76            print 'Units of measurement: %s' % uom
77
78            # Plot the figure
79            fig = figure()
80            plot_date(elapsed_times, vals, '-', xdate=True, lw=2)
81            ax = gca()
82            ml = ax.xaxis.get_major_locator()
83            ax.xaxis.set_major_locator(tickLocator)
84            ax.xaxis.set_major_formatter(tickFormatter)
85            fig.autofmt_xdate()
86            time_format = '%d-%b-%Y, %H:%M:%S'
87            xlabel('Times between %s and %s' % (start_date.strftime(time_format), end_date.strftime(time_format)))
88            ylabel('Values [%s]' % uom)
89            title('"%s" (%s)' % (feature.id, feature.description.CONTENT))
90            grid(True)
91
92            # Save the figure to a temporary file
93            tempFile = NamedTemporaryFile(suffix='.png')
94            savefig(tempFile.name)
95           
96            return tempFile
97
98        def _set_response(tempFile):
99            '''
100            Set the WSGI response to an image, containing image read from a temporary location.
101            '''
102            img = Image.open(tempFile.name)
103            buf = StringIO()
104            img.save(buf, 'PNG')
105            response.content_type = 'image/png'
106            response.content = buf.getvalue()
107           
108        def _wget(url):
109            '''Auxiliary function, returns data read from an URL'''
110            content = None
111            try:
112                socket = urllib.urlopen(url)               # open a socket (actually a file-like object)
113                content = socket.read()                    # read the text in
114            finally:
115                try:
116                    socket.close()
117                except NameError:
118                    pass  # socket undefined -- no need to close
119            return content
120
121        #-------------------------------------------------------------------------------------------------------------------
122
123        # get feature ID from HTTP request
124        feature_id = None; station_id = None
125        try:
126            feature_id = request.params['feature_id']
127            gml_id = feature_id
128        except KeyError:
129            try:
130                station_id = request.params['station_id']
131                gml_id = station_id
132            except KeyError:
133                raise HTTPBadRequest('exactly one of the parameters "feature_id" and "station_id" must be supplied.')
134
135        # Get response from GeoServer and parse it into an ElementTree
136        geoServerURL = 'http://bond.badc.rl.ac.uk:8089/dummyGeoServer/GetStationCSMLFeatures?gml_id=' + gml_id
137        geoSrResponse = _wget(geoServerURL)
138        tree = ElementTree(XML(geoSrResponse))
139
140        if station_id:
141
142            # --- [NOTE] Keeping until ruled as obsolete ---
143
144            # Parse in the feature collection
145            fc = csml.parser.CSMLFeatureCollection()
146            fc.fromXML(tree.getroot())
147
148        else:
149           
150            # Parse in the feature directly
151            feature = csml.parser.PointSeriesFeature()
152            feature.fromXML(tree.getroot())
153
154        if not feature:
155            raise HTTPNotFound('Feature not found')
156           
157        # Try to plot the feature into a temporary file, and put the contents of that file into the WSGI response
158        try:
159            tempFile = _plot_feature(feature)              # plot the feature into a temporary file
160            _set_response(tempFile)                        # set WSGI response as an image containing the plot
161        finally:
162            try:
163                tempFile.close()
164            except NameError:
165                pass  # tempFile undefined -- no need to close
Note: See TracBrowser for help on using the repository browser.