Source code for pywws.WindRose

#!/usr/bin/env python

"""
Plot a "wind rose".

usage: python WindRose.py [options] data_dir temp_dir xml_file output_file
options are:
\t-h or --help\t\tdisplay this help
data_dir is the root directory of the weather data
temp_dir is a workspace for temporary files e.g. /tmp
xml_file is the name of the source file that describes the plot
output_file is the name of the image file to be created e.g. 24hrs.png
"""

import codecs
from datetime import datetime, timedelta
import getopt
import math
import os
import sys
import xml.dom.minidom

from conversions import *
import DataStore
import Localisation
from Plot import BasePlotter
from TimeZone import Local
from WeatherStation import dew_point

[docs]class RosePlotter(BasePlotter):
[docs] def GetPlotList(self): return self.GetChildren(self.graph, 'windrose')
[docs] def GetDefaultRows(self): return int(math.sqrt(self.plot_count))
[docs] def GetDefaultPlotSize(self): return 600 / self.rows, 600 / self.rows
[docs] def GetPreamble(self): result = """set polar set angles degrees set xtics axis nomirror set ytics axis nomirror set zeroaxis set grid polar 22.5 set size square unset border """ lmargin = eval(self.GetValue(self.graph, 'lmargin', '-1')) result += 'set lmargin %g\n' % (lmargin) lmargin = eval(self.GetValue(self.graph, 'rmargin', '-1')) result += 'set rmargin %g\n' % (lmargin) lmargin = eval(self.GetValue(self.graph, 'tmargin', '-1')) result += 'set tmargin %g\n' % (lmargin) lmargin = eval(self.GetValue(self.graph, 'bmargin', '-1')) result += 'set bmargin %g\n' % (lmargin) return result
[docs] def PlotData(self, plot_no, plot, source): _ = Localisation.translation.ugettext # get statistics thresh = eval(self.GetValue( plot, 'threshold', '0.0, 1.54, 3.09, 5.14, 8.23, 10.8, 15.5')) thresh = thresh + (1000.0,) colour = eval(self.GetValue(plot, 'colour', str(range(len(thresh))))) xcalc = self.GetValue(plot, 'xcalc', 'True') xcalc = compile(xcalc, '<string>', 'eval') ycalc = self.GetValue(plot, 'ycalc', None) ycalc = compile(ycalc, '<string>', 'eval') histograms = [] for i in range(len(thresh)): hist = [] for n in range(16): hist.append(0) histograms.append(hist) # x_lo & x_hi are in local time, data is indexed in UTC start = self.x_lo - self.utcoffset stop = self.x_hi - self.utcoffset stop = stop + timedelta(minutes=1) for data in source[start:stop]: wind_dir = data['wind_dir'] if wind_dir == None or wind_dir >= 16: continue if not eval(xcalc): continue value = eval(ycalc) if value is None: continue for t in range(len(thresh)): if value <= thresh[t]: histograms[t][wind_dir] += 1 break # evenly distribute zero speed total = 0 for n in range(16): total += histograms[0][n] for n in range(16): histograms[0][n] = total / 16 # integrate histograms for i in range(1, len(thresh)): for n in range(16): histograms[i][n] += histograms[i-1][n] total = 0 for n in range(16): total += histograms[-1][n] result = '' yrange = self.GetValue(plot, 'yrange', '31') if yrange == '*': # auto-ranging if total > 0: max_petal = 100.0 * float(max(histograms[-1])) / float(total) else: max_petal = 0.0 if max_petal > 40.0: yrange = (int(max_petal / 20.0) * 20) + 21 elif max_petal > 30.0: yrange = 41 elif max_petal > 20.0: yrange = 31 else: yrange = 21 else: yrange = eval(yrange) result += 'set xrange [-%d:%d]\n' % (yrange, yrange) result += 'set yrange [-%d:%d]\n' % (yrange, yrange) points = [_('N'), _('S'), _('E'), _('W')] points = eval(self.GetValue(plot, 'points', str(points))) result += 'set label 1000 "%s" at 0, %d center front\n' % (points[0], yrange) result += 'set label 1001 "%s" at 0, -%d center front\n' % (points[1], yrange) result += 'set label 1002 "%s" at %d, 0 center front\n' % (points[2], yrange) result += 'set label 1003 "%s" at -%d, 0 center front\n' % (points[3], yrange) # plot segments for each speed-direction result += 'plot ' for i in reversed(range(len(thresh))): dat_file = os.path.join(self.work_dir, 'plot_%d_%d.dat' % (plot_no, i)) self.tmp_files.append(dat_file) dat = open(dat_file, 'w') sub_total = 0 for n in range(16): angle = 90.0 - (n * 22.5) sub_total += histograms[i][n] if i > 0: sub_total -= histograms[i-1][n] if total > 0: value = 100.0 * float(histograms[i][n]) / float(total) else: value = 0.0 if i == 0: dat.write('%g %g\n' % (angle - 11.24, value * 0.994)) else: dat.write('%g %g\n' % (angle - 8.1, 0)) dat.write('%g %g\n' % (angle - 8.0, value * 0.997)) dat.write('%g %g\n' % (angle, value)) dat.write('%g %g\n' % (angle + 8.0, value * 0.997)) if i == 0: dat.write('%g %g\n' % (angle + 11.24, value * 0.994)) dat.write('%g %g\n' % (angle + 11.25, 0)) else: dat.write('%g %g\n' % (angle + 8.1, 0)) dat.close() # plot data if total > 0: value = 100.0 * float(sub_total) / float(total) else: value = 0.0 if i == 0: title = '0 .. %g (%.3g%%)' % (thresh[i], value) elif i == len(thresh) - 1: title = '> %g (%.3g%%)' % (thresh[i-1], value) else: title = '%g .. %g (%.3g%%)' % (thresh[i-1], thresh[i], value) result += '"%s" using 1:2 title "%s" with filledcurve lt %d' % ( dat_file, title, colour[i % len(colour)]) if i > 0: result += ', \\' result += '\n' return result
[docs]def main(argv=None): if argv is None: argv = sys.argv try: opts, args = getopt.getopt(argv[1:], "h", ['help']) except getopt.error, msg: print >>sys.stderr, 'Error: %s\n' % msg print >>sys.stderr, __doc__.strip() return 1 # process options for o, a in opts: if o == '-h' or o == '--help': print __doc__.strip() return 0 # check arguments if len(args) != 4: print >>sys.stderr, 'Error: 4 arguments required\n' print >>sys.stderr, __doc__.strip() return 2 params = DataStore.params(args[0]) Localisation.SetApplicationLanguage(params) return RosePlotter( params, DataStore.calib_store(args[0]), DataStore.hourly_store(args[0]), DataStore.daily_store(args[0]), DataStore.monthly_store(args[0]), args[1] ).DoPlot(args[2], args[3])
if __name__ == "__main__": sys.exit(main())