Source code for pywws.WindRose

#!/usr/bin/env python

"""Plot a "wind rose"

::

%s

"""

__docformat__ = "restructuredtext en"
__usage__ = """
 usage: python RunModule.py WindRose [options] data_dir temp_dir xml_file output_file
 options are:
  -h or --help    display 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
"""
__doc__ %= __usage__
__usage__ = __doc__.split('\n')[0] + __usage__

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

from .conversions import (
    illuminance_wm2, pressure_inhg, rain_inch, temp_f,
    winddir_degrees, winddir_text, wind_kmph, wind_mph, wind_kn, wind_bft)
from . import DataStore
from . 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, __usage__.strip() return 1 # process options for o, a in opts: if o == '-h' or o == '--help': print __usage__.strip() return 0 # check arguments if len(args) != 4: print >>sys.stderr, 'Error: 4 arguments required\n' print >>sys.stderr, __usage__.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())