Пример #1
0
    def plot_data(self, plot_no, plot, source):
        class Record(object):
            pass

        _ = pywws.localisation.translation.ugettext
        subplot_list = plot.get_children('subplot')
        subplot_count = len(subplot_list)
        if subplot_count < 1:
            return u''
        result = u''
        pressure_offset = self.pressure_offset
        # add some useful functions
        hour_diff = self.computations.hour_diff
        rain_hour = self.computations.rain_hour
        rain_day = self.computations.rain_day
        rain_24hr = self.computations.rain_24hr
        # label x axis of last plot
        if plot_no == self.plot_count - 1:
            x_lo = timezone.localize(self.x_lo)
            x_hi = timezone.localize(self.x_hi)
            if self.duration <= timedelta(hours=24):
                # TX_NOTE Keep the "(%Z)" formatting string
                xlabel = _('Time (%Z)')
            elif self.duration <= timedelta(days=7):
                xlabel = _('Day')
            else:
                xlabel = _('Date')
            xlabel = self.graph.get_value('xlabel', xlabel)
            if sys.version_info[0] < 3:
                xlabel = xlabel.encode(self.encoding[0])
            xlabel = x_hi.strftime(xlabel)
            if sys.version_info[0] < 3:
                xlabel = xlabel.decode(self.encoding[0])
            result += u'set xlabel "%s"\n' % xlabel
            dateformat = '%Y/%m/%d'
            dateformat = self.graph.get_value('dateformat', dateformat)
            if sys.version_info[0] < 3:
                dateformat = dateformat.encode(self.encoding[0])
            ldat = x_lo.strftime(dateformat)
            rdat = x_hi.strftime(dateformat)
            if sys.version_info[0] < 3:
                ldat = ldat.decode(self.encoding[0])
                rdat = rdat.decode(self.encoding[0])
            if ldat:
                result += u'set label "%s" at "%s", graph -0.3 left\n' % (
                    ldat, self.x_lo.isoformat())
            if rdat != ldat:
                result += u'set label "%s" at "%s", graph -0.3 right\n' % (
                    rdat, self.x_hi.isoformat())
        # set bottom margin
        bmargin = eval(plot.get_value('bmargin', '-1'))
        result += u'set bmargin %g\n' % (bmargin)
        # set y ranges and tics
        yrange = plot.get_value('yrange', None)
        y2range = plot.get_value('y2range', None)
        ytics = plot.get_value('ytics', 'autofreq')
        y2tics = plot.get_value('y2tics', '')
        if y2tics and not y2range:
            y2range = yrange
        elif y2range and not y2tics:
            y2tics = 'autofreq'
        if yrange:
            result += u'set yrange [%s]\n' % (yrange.replace(',', ':'))
        else:
            result += u'set yrange [*:*]\n'
        if y2range:
            result += u'set y2range [%s]\n' % (y2range.replace(',', ':'))
        if y2tics:
            result += u'set ytics nomirror %s; set y2tics %s\n' % (ytics,
                                                                   y2tics)
        else:
            result += u'unset y2tics; set ytics mirror %s\n' % (ytics)
        # set grid
        result += u'unset grid\n'
        grid = plot.get_value('grid', None)
        if grid is not None:
            result += u'set grid %s\n' % grid
        # 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
        cumu_start = start
        if source == self.calib_data:
            boxwidth = 240  # assume 5 minute data interval
            start = source.before(start)
        elif source == self.hourly_data:
            boxwidth = 2800
            start = source.before(start)
            interval = timedelta(minutes=90)
        elif source == self.monthly_data:
            boxwidth = 2800 * 24 * 30
            interval = timedelta(days=46)
        else:
            interval = timedelta(hours=36)
            boxwidth = 2800 * 24
        boxwidth = eval(plot.get_value('boxwidth', str(boxwidth)))
        result += u'set boxwidth %d\n' % boxwidth
        for command in plot.get_values('command'):
            result += u'%s\n' % command
        stop = source.after(stop)
        if stop:
            stop = stop + timedelta(minutes=1)
        # write data files
        subplots = []
        for subplot_no in range(subplot_count):
            subplot = Record()
            subplot.subplot = subplot_list[subplot_no]
            subplot.dat_file = os.path.join(
                self.work_dir, 'plot_%d_%d.dat' % (plot_no, subplot_no))
            self.tmp_files.append(subplot.dat_file)
            subplot.dat = open(subplot.dat_file, 'w')
            subplot.xcalc = subplot.subplot.get_value('xcalc', None)
            subplot.ycalc = subplot.subplot.get_value('ycalc', None)
            subplot.cummulative = 'last_ycalc' in subplot.ycalc
            if subplot.xcalc:
                subplot.xcalc = compile(subplot.xcalc, '<string>', 'eval')
            subplot.ycalc = compile(subplot.ycalc, '<string>', 'eval')
            subplot.last_ycalcs = 0.0
            subplot.last_idx = None
            subplot.using = '($2)'
            subplots.append(subplot)
        for data in source[start:stop]:
            for subplot in subplots:
                if subplot.xcalc:
                    idx = eval(subplot.xcalc)
                    if idx is None:
                        continue
                else:
                    idx = data['idx']
                idx += self.utcoffset
                if not subplot.cummulative and subplot.last_idx:
                    if source == self.calib_data:
                        interval = timedelta(
                            minutes=((data['delay'] * 3) + 1) // 2)
                    if idx - subplot.last_idx > interval:
                        # missing data
                        subplot.dat.write('%s ?\n' % (idx.isoformat()))
                subplot.last_idx = idx
                try:
                    if subplot.cummulative and data['idx'] <= cumu_start:
                        value = 0.0
                    else:
                        last_ycalc = subplot.last_ycalcs
                        value = eval(subplot.ycalc)
                    if not isinstance(value, tuple):
                        value = (value, )
                    values = (idx.isoformat(), ) + value
                    vformat = '%s' + (' %g' * len(value)) + '\n'
                    subplot.dat.write(vformat % values)
                    subplot.using = ':'.join(
                        '($%d)' % x for x in range(2,
                                                   len(values) + 1))
                    subplot.last_ycalcs = value[0]
                except TypeError:
                    if not subplot.cummulative:
                        subplot.dat.write('%s ?\n' % (idx.isoformat()))
                    subplot.last_ycalcs = 0.0
        for subplot in subplots:
            # ensure the data file isn't empty
            idx = self.x_hi + self.duration
            subplot.dat.write('%s ?\n' % (idx.isoformat()))
            subplot.dat.close()
        # plot data
        result += u'plot '
        colour_idx = 0
        for subplot_no in range(subplot_count):
            subplot = subplots[subplot_no]
            colour_idx += 1
            colour = subplot.subplot.get_value('colour', str(colour_idx))
            style = subplot.subplot.get_value(
                'style', 'smooth unique lc %s lw 1' % (colour))
            words = style.split()
            if len(words) > 1 and words[0] in ('+', 'x', 'line',
                                               'candlesticks',
                                               'candlesticksw'):
                width = float(words[1])
            else:
                width = 1
            if len(words) > 2 and words[0] in ('candlesticksw'):
                whiskerwidth = float(words[2])
            else:
                whiskerwidth = 1
            whiskerbars = ''
            if style == 'box':
                style = 'lc %s lw 0 with boxes' % (colour)
            elif words[0] == 'candlesticks':
                style = 'lc %s lw %g with candlesticks' % (colour, width)
            elif words[0] == 'candlesticksw':
                style = 'lc %s lw %g with candlesticks' % (colour, width)
                whiskerbars = ' whiskerbars %g' % (whiskerwidth)
            elif words[0] == '+':
                style = 'lc %s lw %g pt 1 with points' % (colour, width)
            elif words[0] == 'x':
                style = 'lc %s lw %g pt 2 with points' % (colour, width)
            elif words[0] == 'line':
                style = 'smooth unique lc %s lw %g' % (colour, width)
            axes = subplot.subplot.get_value('axes', 'x1y1')
            title = subplot.subplot.get_value('title', '')
            result += u' "%s" using 1:%s axes %s %s title "%s"%s' % (
                subplot.dat_file, subplot.using, axes, style, title,
                whiskerbars)
            if subplot_no != subplot_count - 1:
                result += u', \\'
            result += u'\n'
        return result
Пример #2
0
 def do_plot(self, input_file, output_file):
     if isinstance(input_file, GraphFileReader):
         self.graph = input_file
     else:
         # read XML graph description
         self.graph = GraphFileReader(input_file)
     # get list of plots
     plot_list = self.graph.get_children(self.plot_name)
     self.plot_count = len(plot_list)
     if self.plot_count < 1:
         # nothing to plot
         logger.info('%s has no %s nodes', self.graph.input_file,
                     self.plot_name)
         self.graph.close()
         return 1
     # get start and end datetimes
     self.x_lo = self.graph.get_value('start', None)
     self.x_hi = self.graph.get_value('stop', None)
     self.duration = self.graph.get_value('duration', None)
     if self.duration:
         self.duration = eval('timedelta(%s)' % self.duration)
     else:
         self.duration = timedelta(hours=24)
     if self.x_lo:
         self.x_lo = self._eval_time(self.x_lo)
         if self.x_hi:
             self.x_hi = self._eval_time(self.x_hi)
             self.duration = self.x_hi - self.x_lo
         else:
             self.x_hi = self.x_lo + self.duration
     elif self.x_hi:
         self.x_hi = self._eval_time(self.x_hi)
         self.x_lo = self.x_hi - self.duration
     else:
         self.x_hi = self.hourly_data.before(datetime.max)
         if not self.x_hi:
             self.x_hi = datetime.utcnow()  # only if no hourly data
         self.x_hi += timezone.utcoffset(self.x_hi)
         if self.duration < timedelta(hours=6):
             # set end of graph to start of the next minute after last item
             self.x_hi += timedelta(seconds=55)
             self.x_hi = self.x_hi.replace(second=0)
         else:
             # set end of graph to start of the next hour after last item
             self.x_hi += timedelta(minutes=55)
             self.x_hi = self.x_hi.replace(minute=0, second=0)
         self.x_lo = self.x_hi - self.duration
     self.utcoffset = timezone.utcoffset(self.x_hi)
     # open gnuplot command file
     self.tmp_files = []
     cmd_file = os.path.join(self.work_dir, 'plot.cmd')
     self.tmp_files.append(cmd_file)
     of = codecs.open(cmd_file, 'w', encoding=self.encoding[0])
     # write gnuplot set up
     of.write('set encoding %s\n' % (self.encoding[1]))
     lcl = locale.getlocale()
     if lcl[0]:
         of.write('set locale "%s.%s"\n' % lcl)
     self.rows = self.get_default_rows()
     self.cols = (self.plot_count + self.rows - 1) // self.rows
     self.rows, self.cols = eval(
         self.graph.get_value('layout', '%d, %d' % (self.rows, self.cols)))
     w, h = self.get_default_plot_size()
     w = w * self.cols
     h = h * self.rows
     w, h = eval(self.graph.get_value('size', '(%d, %d)' % (w, h)))
     fileformat = self.graph.get_value('fileformat', 'png')
     if fileformat == 'svg':
         terminal = 'svg enhanced font "arial,9" dynamic rounded'
     elif u' ' not in fileformat:
         terminal = '%s large' % (fileformat)
     else:
         terminal = fileformat
     if u'size' not in terminal:
         terminal += u' size %d,%d' % (w, h)
     terminal = self.graph.get_value('terminal', terminal)
     of.write('set terminal %s\n' % (terminal))
     of.write('set output "%s"\n' % (output_file))
     # set overall title
     title = self.graph.get_value('title', '')
     if title:
         if '%' in title:
             x_hi = timezone.localize(self.x_hi)
             if sys.version_info[0] < 3:
                 title = title.encode(self.encoding[0])
             title = x_hi.strftime(title)
             if sys.version_info[0] < 3:
                 title = title.decode(self.encoding[0])
         title = 'title "%s"' % title
     of.write('set multiplot layout %d, %d %s\n' %
              (self.rows, self.cols, title))
     # do actual plots
     of.write(self.get_preamble())
     for plot_no in range(self.plot_count):
         plot = plot_list[plot_no]
         # set key / title location
         title = plot.get_value('title', '')
         of.write('set key horizontal title "%s"\n' % title)
         # optional yaxis labels
         ylabel = plot.get_value('ylabel', '')
         if ylabel:
             ylabelangle = plot.get_value('ylabelangle', '')
             if ylabelangle:
                 ylabelangle = ' rotate by %s' % (ylabelangle)
             of.write('set ylabel "%s"%s\n' % (ylabel, ylabelangle))
         else:
             of.write('set ylabel\n')
         y2label = plot.get_value('y2label', '')
         if y2label:
             y2labelangle = plot.get_value('y2labelangle', '')
             if y2labelangle:
                 y2labelangle = ' rotate by %s' % (y2labelangle)
             of.write('set y2label "%s"%s\n' % (y2label, y2labelangle))
         else:
             of.write('set y2label\n')
         # set data source
         source = plot.get_value('source', 'raw')
         if source == 'raw':
             source = self.calib_data
         elif source == 'hourly':
             source = self.hourly_data
         elif source == 'monthly':
             source = self.monthly_data
         else:
             source = self.daily_data
         # do the plot
         of.write(self.plot_data(plot_no, plot, source))
     of.close()
     self.graph.close()
     # run gnuplot on file
     subprocess.check_call(['gnuplot', cmd_file])
     for file in self.tmp_files:
         os.unlink(file)
     return 0
Пример #3
0
    def plot_data(self, plot_no, plot, source):
        class Record(object):
            pass

        _ = pywws.localisation.translation.ugettext
        subplot_list = plot.get_children('subplot')
        subplot_count = len(subplot_list)
        if subplot_count < 1:
            return u''
        result = u''
        pressure_offset = self.pressure_offset
        # add some useful functions
        hour_diff = self.computations.hour_diff
        rain_hour = self.computations.rain_hour
        rain_day = self.computations.rain_day
        rain_24hr = self.computations.rain_24hr
        # label x axis of last plot
        if plot_no == self.plot_count - 1:
            x_lo = timezone.localize(self.x_lo)
            x_hi = timezone.localize(self.x_hi)
            if self.duration <= timedelta(hours=24):
                # TX_NOTE Keep the "(%Z)" formatting string
                xlabel = _('Time (%Z)')
            elif self.duration <= timedelta(days=7):
                xlabel = _('Day')
            else:
                xlabel = _('Date')
            xlabel = self.graph.get_value('xlabel', xlabel)
            if sys.version_info[0] < 3:
                xlabel = xlabel.encode(self.encoding[0])
            xlabel = x_hi.strftime(xlabel)
            if sys.version_info[0] < 3:
                xlabel = xlabel.decode(self.encoding[0])
            result += u'set xlabel "%s"\n' % xlabel
            dateformat = '%Y/%m/%d'
            dateformat = self.graph.get_value('dateformat', dateformat)
            if sys.version_info[0] < 3:
                dateformat = dateformat.encode(self.encoding[0])
            ldat = x_lo.strftime(dateformat)
            rdat = x_hi.strftime(dateformat)
            if sys.version_info[0] < 3:
                ldat = ldat.decode(self.encoding[0])
                rdat = rdat.decode(self.encoding[0])
            if ldat:
                result += u'set label "%s" at "%s", graph -0.3 left\n' % (
                    ldat, self.x_lo.isoformat())
            if rdat != ldat:
                result += u'set label "%s" at "%s", graph -0.3 right\n' % (
                    rdat, self.x_hi.isoformat())
        # set bottom margin
        bmargin = eval(plot.get_value('bmargin', '-1'))
        result += u'set bmargin %g\n' % (bmargin)
        # set y ranges and tics
        yrange = plot.get_value('yrange', None)
        y2range = plot.get_value('y2range', None)
        ytics = plot.get_value('ytics', 'autofreq')
        y2tics = plot.get_value('y2tics', '')
        if y2tics and not y2range:
            y2range = yrange
        elif y2range and not y2tics:
            y2tics = 'autofreq'
        if yrange:
            result += u'set yrange [%s]\n' % (yrange.replace(',', ':'))
        else:
            result += u'set yrange [*:*]\n'
        if y2range:
            result += u'set y2range [%s]\n' % (y2range.replace(',', ':'))
        if y2tics:
            result += u'set ytics nomirror %s; set y2tics %s\n' % (ytics, y2tics)
        else:
            result += u'unset y2tics; set ytics mirror %s\n' % (ytics)
        # set grid
        result += u'unset grid\n'
        grid = plot.get_value('grid', None)
        if grid is not None:
            result += u'set grid %s\n' % grid
        # 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
        cumu_start = start
        if source == self.calib_data:
            boxwidth = 240      # assume 5 minute data interval
            start = source.before(start)
        elif source == self.hourly_data:
            boxwidth = 2800
            start = source.before(start)
            interval = timedelta(minutes=90)
        elif source == self.monthly_data:
            boxwidth = 2800 * 24 * 30
            interval = timedelta(days=46)
        else:
            interval = timedelta(hours=36)
            boxwidth = 2800 * 24
        boxwidth = eval(plot.get_value('boxwidth', str(boxwidth)))
        result += u'set boxwidth %d\n' % boxwidth
        for command in plot.get_values('command'):
            result += u'%s\n' % command
        stop = source.after(stop)
        if stop:
            stop = stop + timedelta(minutes=1)
        # write data files
        subplots = []
        for subplot_no in range(subplot_count):
            subplot = Record()
            subplot.subplot = subplot_list[subplot_no]
            subplot.dat_file = os.path.join(self.work_dir, 'plot_%d_%d.dat' % (
                plot_no, subplot_no))
            self.tmp_files.append(subplot.dat_file)
            subplot.dat = open(subplot.dat_file, 'w')
            subplot.xcalc = subplot.subplot.get_value('xcalc', None)
            subplot.ycalc = subplot.subplot.get_value('ycalc', None)
            subplot.cummulative = 'last_ycalc' in subplot.ycalc
            if subplot.xcalc:
                subplot.xcalc = compile(subplot.xcalc, '<string>', 'eval')
            subplot.ycalc = compile(subplot.ycalc, '<string>', 'eval')
            subplot.last_ycalcs = 0.0
            subplot.last_idx = None
            subplot.using = '($2)'
            subplots.append(subplot)
        for data in source[start:stop]:
            for subplot in subplots:
                if subplot.xcalc:
                    idx = eval(subplot.xcalc)
                    if idx is None:
                        continue
                else:
                    idx = data['idx']
                idx += self.utcoffset
                if not subplot.cummulative and subplot.last_idx:
                    if source == self.calib_data:
                        interval = timedelta(minutes=((data['delay']*3)+1)//2)
                    if idx - subplot.last_idx > interval:
                        # missing data
                        subplot.dat.write('%s ?\n' % (idx.isoformat()))
                subplot.last_idx = idx
                try:
                    if subplot.cummulative and data['idx'] <= cumu_start:
                        value = 0.0
                    else:
                        last_ycalc = subplot.last_ycalcs
                        value = eval(subplot.ycalc)
                    if not isinstance(value, tuple):
                        value = (value,)
                    values = (idx.isoformat(),) + value
                    vformat = '%s' + (' %g' * len(value)) + '\n'
                    subplot.dat.write(vformat % values)
                    subplot.using = ':'.join(
                        '($%d)' % x for x in range(2, len(values)+1))
                    subplot.last_ycalcs = value[0]
                except TypeError:
                    if not subplot.cummulative:
                        subplot.dat.write('%s ?\n' % (idx.isoformat()))
                    subplot.last_ycalcs = 0.0
        for subplot in subplots:
            # ensure the data file isn't empty
            idx = self.x_hi + self.duration
            subplot.dat.write('%s ?\n' % (idx.isoformat()))
            subplot.dat.close()
        # plot data
        result += u'plot '
        colour_idx = 0
        for subplot_no in range(subplot_count):
            subplot = subplots[subplot_no]
            colour_idx += 1
            colour = subplot.subplot.get_value('colour', str(colour_idx))
            style = subplot.subplot.get_value(
                'style', 'smooth unique lc %s lw 1' % (colour))
            words = style.split()
            if len(words) > 1 and words[0] in ('+', 'x', 'line', 'candlesticks', 'candlesticksw'):
                width = float(words[1])
            else:
                width = 1
            if len(words) > 2 and words[0] in ('candlesticksw'):
                whiskerwidth = float(words[2])
            else:
                whiskerwidth = 1
            whiskerbars = ''
            if style == 'box':
                style = 'lc %s lw 0 with boxes' % (colour)
            elif words[0] == 'candlesticks':
                style = 'lc %s lw %g with candlesticks' % (colour, width)
            elif words[0] == 'candlesticksw':
                style = 'lc %s lw %g with candlesticks' % (colour, width)
                whiskerbars = ' whiskerbars %g' % (whiskerwidth)
            elif words[0] == '+':
                style = 'lc %s lw %g pt 1 with points' % (colour, width)
            elif words[0] == 'x':
                style = 'lc %s lw %g pt 2 with points' % (colour, width)
            elif words[0] == 'line':
                style = 'smooth unique lc %s lw %g' % (colour, width)
            axes = subplot.subplot.get_value('axes', 'x1y1')
            title = subplot.subplot.get_value('title', '')
            result += u' "%s" using 1:%s axes %s %s title "%s"%s' % (
                subplot.dat_file, subplot.using, axes, style, title, whiskerbars)
            if subplot_no != subplot_count - 1:
                result += u', \\'
            result += u'\n'
        return result
Пример #4
0
    def process(self, live_data, template_file):
        def jump(idx, count):
            while count > 0:
                new_idx = data_set.after(idx + SECOND)
                if new_idx == None:
                    break
                idx = new_idx
                count -= 1
            while count < 0:
                new_idx = data_set.before(idx)
                if new_idx == None:
                    break
                idx = new_idx
                count += 1
            return idx, count == 0

        params = self.params
        if not live_data:
            idx = self.calib_data.before(datetime.max)
            if not idx:
                logger.error("No calib data - run pywws.process first")
                return
            live_data = self.calib_data[idx]
        # get default character encoding of template input & output files
        self.encoding = params.get('config', 'template encoding', 'iso-8859-1')
        file_encoding = self.encoding
        if file_encoding == 'html':
            file_encoding = 'ascii'
        # get conversions module to create its 'private' wind dir text
        # array, then copy it to deprecated wind_dir_text variable
        winddir_text(0)
        wind_dir_text = conversions._winddir_text_array
        hour_diff = self.computations.hour_diff
        rain_hour = self.computations.rain_hour
        rain_day = self.computations.rain_day
        rain_24hr = self.computations.rain_24hr
        pressure_offset = float(self.params.get('config', 'pressure offset'))
        fixed_block = literal_eval(self.status.get('fixed', 'fixed block'))
        # start off with no time rounding
        round_time = None
        # start off in hourly data mode
        data_set = self.hourly_data
        # start off in utc
        local_time = False
        # start off with default use_locale setting
        use_locale = self.use_locale
        # jump to last item
        idx, valid_data = jump(datetime.max, -1)
        if not valid_data:
            logger.error("No summary data - run pywws.process first")
            return
        data = data_set[idx]
        # open template file, if not already a file(like) object
        if hasattr(template_file, 'readline'):
            tmplt = template_file
        else:
            tmplt = open(template_file, 'rb')
        # do the text processing
        line = ''
        while True:
            new_line = tmplt.readline()
            if not new_line:
                break
            if isinstance(new_line, bytes) or sys.version_info[0] < 3:
                new_line = new_line.decode(file_encoding)
            line += new_line
            parts = line.split('#')
            if len(parts) % 2 == 0:
                # odd number of '#'
                line = line.rstrip('\r\n')
                continue
            for i, part in enumerate(parts):
                if i % 2 == 0:
                    # not a processing directive
                    if i == 0 or part != '\n':
                        yield part
                    continue
                if part and part[0] == '!':
                    # comment
                    continue
                # Python 2 shlex can't handle unicode
                if sys.version_info[0] < 3:
                    part = part.encode(file_encoding)
                command = shlex.split(part)
                if sys.version_info[0] < 3:
                    command = map(lambda x: x.decode(file_encoding), command)
                if command == []:
                    # empty command == print a single '#'
                    yield u'#'
                elif command[0] in list(data.keys()) + ['calc']:
                    # output a value
                    if not valid_data:
                        continue
                    # format is: key fmt_string no_value_string conversion
                    # get value
                    if command[0] == 'calc':
                        x = eval(command[1])
                        del command[1]
                    else:
                        x = data[command[0]]
                    # adjust time
                    if isinstance(x, datetime):
                        if round_time:
                            x += round_time
                        if local_time:
                            x = timezone.to_local(x)
                        else:
                            x = timezone.to_utc(x)
                    # convert data
                    if x is not None and len(command) > 3:
                        x = eval(command[3])
                    # get format
                    fmt = u'%s'
                    if len(command) > 1:
                        fmt = command[1]
                    # write output
                    if x is None:
                        if len(command) > 2:
                            yield command[2]
                    elif isinstance(x, datetime):
                        if sys.version_info[0] < 3:
                            fmt = fmt.encode(file_encoding)
                        x = x.strftime(fmt)
                        if sys.version_info[0] < 3:
                            if self.encoding == 'html':
                                x = x.decode('ascii', errors='xmlcharrefreplace')
                            else:
                                x = x.decode(file_encoding)
                        yield x
                    elif not use_locale:
                        yield fmt % (x)
                    elif sys.version_info >= (2, 7) or '%%' not in fmt:
                        yield locale.format_string(fmt, x)
                    else:
                        yield locale.format_string(
                            fmt.replace('%%', '##'), x).replace('##', '%')
                elif command[0] == 'monthly':
                    data_set = self.monthly_data
                    idx, valid_data = jump(datetime.max, -1)
                    data = data_set[idx]
                elif command[0] == 'daily':
                    data_set = self.daily_data
                    idx, valid_data = jump(datetime.max, -1)
                    data = data_set[idx]
                elif command[0] == 'hourly':
                    data_set = self.hourly_data
                    idx, valid_data = jump(datetime.max, -1)
                    data = data_set[idx]
                elif command[0] == 'raw':
                    data_set = self.calib_data
                    idx, valid_data = jump(datetime.max, -1)
                    data = data_set[idx]
                elif command[0] == 'live':
                    data_set = self.calib_data
                    idx = live_data['idx']
                    valid_data = True
                    data = live_data
                elif command[0] == 'timezone':
                    if command[1] == 'utc':
                        local_time = False
                    elif command[1] == 'local':
                        local_time = True
                    else:
                        logger.error("Unknown time zone: %s", command[1])
                        return
                elif command[0] == 'locale':
                    use_locale = eval(command[1])
                elif command[0] == 'encoding':
                    self.encoding = command[1]
                    file_encoding = self.encoding
                    if file_encoding == 'html':
                        file_encoding = 'ascii'
                elif command[0] == 'roundtime':
                    if eval(command[1]):
                        round_time = timedelta(seconds=30)
                    else:
                        round_time = None
                elif command[0] == 'jump':
                    prevdata = data
                    idx, valid_data = jump(idx, int(command[1]))
                    data = data_set[idx]
                elif command[0] == 'goto':
                    prevdata = data
                    time_str = command[1]
                    if '%' in time_str:
                        if local_time:
                            lcl = timezone.to_local(idx)
                        else:
                            lcl = timezone.to_utc(idx)
                        time_str = lcl.strftime(time_str)
                    new_idx = pywws.weatherstation.WSDateTime.from_csv(time_str)
                    if local_time:
                        new_idx = timezone.to_naive(timezone.localize(new_idx))
                    new_idx = data_set.after(new_idx)
                    if new_idx:
                        idx = new_idx
                        data = data_set[idx]
                        valid_data = True
                    else:
                        valid_data = False
                elif command[0] == 'loop':
                    loop_count = int(command[1])
                    loop_start = tmplt.tell()
                elif command[0] == 'endloop':
                    loop_count -= 1
                    if valid_data and loop_count > 0:
                        tmplt.seek(loop_start, 0)
                else:
                    logger.error("Unknown processing directive: #%s#", part)
                    return
            line = ''
Пример #5
0
 def do_plot(self, input_file, output_file):
     if isinstance(input_file, GraphFileReader):
         self.graph = input_file
     else:
         # read XML graph description
         self.graph = GraphFileReader(input_file)
     # get list of plots
     plot_list = self.graph.get_children(self.plot_name)
     self.plot_count = len(plot_list)
     if self.plot_count < 1:
         # nothing to plot
         logger.info('%s has no %s nodes', self.graph.input_file, self.plot_name)
         self.graph.close()
         return 1
     # get start and end datetimes
     self.x_lo = self.graph.get_value('start', None)
     self.x_hi = self.graph.get_value('stop', None)
     self.duration = self.graph.get_value('duration', None)
     if self.duration:
         self.duration = eval('timedelta(%s)' % self.duration)
     else:
         self.duration = timedelta(hours=24)
     if self.x_lo:
         self.x_lo = self._eval_time(self.x_lo)
         if self.x_hi:
             self.x_hi = self._eval_time(self.x_hi)
             self.duration = self.x_hi - self.x_lo
         else:
             self.x_hi = self.x_lo + self.duration
     elif self.x_hi:
         self.x_hi = self._eval_time(self.x_hi)
         self.x_lo = self.x_hi - self.duration
     else:
         self.x_hi = self.hourly_data.before(datetime.max)
         if not self.x_hi:
             self.x_hi = datetime.utcnow()    # only if no hourly data
         self.x_hi += timezone.utcoffset(self.x_hi)
         if self.duration < timedelta(hours=6):
             # set end of graph to start of the next minute after last item
             self.x_hi += timedelta(seconds=55)
             self.x_hi = self.x_hi.replace(second=0)
         else:
             # set end of graph to start of the next hour after last item
             self.x_hi += timedelta(minutes=55)
             self.x_hi = self.x_hi.replace(minute=0, second=0)
         self.x_lo = self.x_hi - self.duration
     self.utcoffset = timezone.utcoffset(self.x_hi)
     # open gnuplot command file
     self.tmp_files = []
     cmd_file = os.path.join(self.work_dir, 'plot.cmd')
     self.tmp_files.append(cmd_file)
     of = codecs.open(cmd_file, 'w', encoding=self.encoding[0])
     # write gnuplot set up
     of.write('set encoding %s\n' % (self.encoding[1]))
     lcl = locale.getlocale()
     if lcl[0]:
         of.write('set locale "%s.%s"\n' % lcl)
     self.rows = self.get_default_rows()
     self.cols = (self.plot_count + self.rows - 1) // self.rows
     self.rows, self.cols = eval(self.graph.get_value(
         'layout', '%d, %d' % (self.rows, self.cols)))
     w, h = self.get_default_plot_size()
     w = w * self.cols
     h = h * self.rows
     w, h = eval(self.graph.get_value('size', '(%d, %d)' % (w, h)))
     fileformat = self.graph.get_value('fileformat', 'png')
     if fileformat == 'svg':
         terminal = 'svg enhanced font "arial,9" dynamic rounded'
     elif u' ' not in fileformat:
         terminal = '%s large' % (fileformat)
     else:
         terminal = fileformat
     if u'size' not in terminal:
         terminal += u' size %d,%d' % (w, h)
     terminal = self.graph.get_value('terminal', terminal)
     of.write('set terminal %s\n' % (terminal))
     of.write('set output "%s"\n' % (output_file))
     # set overall title
     title = self.graph.get_value('title', '')
     if title:
         if '%' in title:
             x_hi = timezone.localize(self.x_hi)
             if sys.version_info[0] < 3:
                 title = title.encode(self.encoding[0])
             title = x_hi.strftime(title)
             if sys.version_info[0] < 3:
                 title = title.decode(self.encoding[0])
         title = 'title "%s"' % title
     of.write('set multiplot layout %d, %d %s\n' % (self.rows, self.cols, title))
     # do actual plots
     of.write(self.get_preamble())
     for plot_no in range(self.plot_count):
         plot = plot_list[plot_no]
         # set key / title location
         title = plot.get_value('title', '')
         of.write('set key horizontal title "%s"\n' % title)
         # optional yaxis labels
         ylabel = plot.get_value('ylabel', '')
         if ylabel:
             ylabelangle = plot.get_value('ylabelangle', '')
             if ylabelangle:
                 ylabelangle = ' rotate by %s' % (ylabelangle)
             of.write('set ylabel "%s"%s\n' % (ylabel, ylabelangle))
         else:
             of.write('set ylabel\n')
         y2label = plot.get_value('y2label', '')
         if y2label:
             y2labelangle = plot.get_value('y2labelangle', '')
             if y2labelangle:
                 y2labelangle = ' rotate by %s' % (y2labelangle)
             of.write('set y2label "%s"%s\n' % (y2label, y2labelangle))
         else:
             of.write('set y2label\n')
         # set data source
         source = plot.get_value('source', 'raw')
         if source == 'raw':
             source = self.calib_data
         elif source == 'hourly':
             source = self.hourly_data
         elif source == 'monthly':
             source = self.monthly_data
         else:
             source = self.daily_data
         # do the plot
         of.write(self.plot_data(plot_no, plot, source))
     of.close()
     self.graph.close()
     # run gnuplot on file
     subprocess.check_call(['gnuplot', cmd_file])
     for file in self.tmp_files:
         os.unlink(file)
     return 0