try this. You have to put skin.conf in your images directory. In imagegenerator you can find the code as "by Andrea" related to previous year and previous month of the year before. If you are able to modified the code you can get what you want.
Here is the webpage with the previous year graph. http://meteonibbio.altervista.org/station/Bootstrap/index.html bye Andrea Il giorno mercoledì 6 maggio 2020 19:49:44 UTC+2, Tomáš Filo ha scritto: > > And i would by nice to have this feature as part of ImageGenerator. > Configurable from skin. For now when I want to generate images for > historical records I use "wee_reports weewx.conf timestamp" and custom > weewx.conf and skin to generate just hostorical plots. It works but it is > workaround. > > Dňa streda, 6. mája 2020 18:14:55 UTC+2 Tomáš Filo napísal(a): >> >> Thank's for replay, where cat I find this implementation ? >> >> Dňa streda, 6. mája 2020 17:36:03 UTC+2 Andrea napísal(a): >>> >>> I have implemented report for an year before or the month of the year >>> before. Probably it can be simple adjust to have what you ask. >>> >>> Il giorno mercoledì 6 maggio 2020 17:17:18 UTC+2, Tomáš Filo ha scritto: >>>> >>>> Hello, Is it possible to force ImageGenerator to generate images not >>>> for only last day, week, month, year but for every month and year. I use >>>> instead of text NOAA html templates. And I would like to display plosts >>>> for >>>> every month and year possible. >>>> >>>> Now I have daytempdew.png, monthtempdew.png but I want to generate >>>> 2019-01-tempdew.png, 2019-02-tempdew.png etc. >>>> >>>> Thank you. >>>> >>>> >>>> -- You received this message because you are subscribed to the Google Groups "weewx-user" group. To unsubscribe from this group and stop receiving emails from it, send an email to weewx-user+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/weewx-user/d86e42ba-466c-49c2-930f-9d5a43c38acc%40googlegroups.com.
############################################################################################ ############################################################################################ # # # # # STANDARD SKIN CONFIGURATION FILE # # # # # ############################################################################################ # # # Copyright (c) 2010 Tom Keffer <tkef...@gmail.com> # # # # See the file LICENSE.txt for your full rights. # # # ############################################################################################ # # $Revision: 737 $ # $Author: tkeffer $ # $Date: 2012-11-04 09:05:51 -0800 (Sun, 04 Nov 2012) $ # ############################################################################################ [Extras] # # Put any extra tags here that you want to be available in the templates # ############################################################################################ [Units] # # This section is for managing the selection and formatting of units. # [[Groups]] # # For each group of measurements, this section sets what units to use for it. # NB: The unit is always in the singular. I.e., 'mile_per_hour', NOT 'miles_per_hour' # group_altitude = meter # Options are 'foot' or 'meter' group_degree_day = degree_C_day # Options are 'degree_F_day' or 'degree_C_day' group_direction = degree_compass group_moisture = centibar group_percent = percent group_pressure = mbar # Options are 'inHg', 'mmHg', 'mbar', or 'hPa' group_radiation = watt_per_meter_squared group_rain = mm # Options are 'inch', 'cm', or 'mm' group_rainrate = mm_per_hour # Options are 'inch_per_hour', 'cm_per_hour', or 'mm_per_hour' group_speed = knot # Options are 'mile_per_hour', 'km_per_hour', 'knot', or 'meter_per_second' group_speed2 = knot2 # Options are 'mile_per_hour2', 'km_per_hour2', 'knot2', or 'meter_per_second2' group_temperature = degree_C # Options are 'degree_F' or 'degree_C' group_uv = uv_index group_volt = volt # The following unit groups are used internally and should not be changed: group_count = count group_interval = minute group_time = unix_epoch [[StringFormats]] # # This section sets the string formatting for each type of unit. # centibar = %.0f cm = %.2f cm_per_hour = %.2f degree_C = %.1f degree_F = %.1f degree_compass = %.0f foot = %.0f hPa = %.1f inHg = %.3f inch = %.2f inch_per_hour = %.2f km_per_hour = %.0f km_per_hour2 = %.1f knot = %.0f knot2 = %.1f mbar = %.1f meter = %.0f meter_per_second = %.1f meter_per_second2 = %.1f mile_per_hour = %.0f mile_per_hour2 = %.1f mm = %.1f mmHg = %.1f mm_per_hour = %.1f percent = %.0f uv_index = %.1f volt = %.1f watt_per_meter_squared = %.0f NONE = " --" [[Labels]] # # This section sets a label to be used for each type of unit. # centibar = " cb" cm = " cm" cm_per_hour = " cm/hr" degree_C = " °C" degree_F = " °F" degree_compass = " °" foot = " feet" hPa = " hPa" inHg = " inHg" inch = " in" inch_per_hour = " in/hr" km_per_hour = " kph" km_per_hour2 = " kph" knot = " knots" knot2 = " knots" mbar = " mbar" meter = " meters" meter_per_second = " m/s" meter_per_second2 = " m/s" mile_per_hour = " mph" mile_per_hour2 = " mph" mm = " mm" mmHg = " mmHg" mm_per_hour = " mm/hr" percent = % volt = " V" watt_per_meter_squared = " W/m²" NONE = "" [[TimeFormats]] # # This section sets the string format to be used # each time scale. # day = %H:%M week = %H:%M on %A month = %d-%b-%Y %H:%M year = %d-%b-%Y %H:%M rainyear = %d-%b-%Y %H:%M current = %d-%b-%Y %H:%M ephem_day = %H:%M ephem_year = %d-%b-%Y %H:%M [[DegreeDays]] # # This section sets the base temperatures used for the calculation # of heating and cooling degree-days. # # Base temperature for heating days, with unit: heating_base = 15, degree_C # Base temperature for cooling days, with unit: cooling_base = 15, degree_C [[Trend]] time_delta = 7200 # 2 hours --10800 time_grace = 60 # 1 minutes --120 ############################################################################################ [Labels] # # Generic labels # # Set to hemisphere abbreviations suitable for your location: hemispheres = N, S, E, W [[Generic]] # # Generic labels, keyed by an observation type. # barometer = Barometer dewpoint = Dew Point heatindex = Heat Index inHumidity = In Humidity inTemp = In Temp outHumidity = Out Humidity outTemp = Out Temp radiation = Radiation rain = Rain rainRate = Rain Rate rxCheckPercent = ISS Signal Quality windDir = Wind Direction windGust = Gust Speed windGustDir = Gust Direction windSpeed = Wind Speed windchill = Wind Chill windgustvec = Gust Vector windvec = Wind Vector # This one is probably specific to my station! # extraTemp1 = Pond Temperature ############################################################### [Language] # # Set a language below and labels will be overridden with any that are specified in # skins/languages/[language].conf # # Choices are: espanol # language = italian [ImageGenerator] # # This section lists all the images to be generated, what SQL types are to # be included in them, along with many plotting options, such as color or # font. There's a default for almost everything, if not specified # below. Nevertheless, I've explicitly put in values, to make it easy to see # and understand the options. # # Fonts can be anything accepted by the Python Imaging Library (PIL), which # is currently truetype (.ttf), or PIL's own font format (.pil). See # http://www.pythonware.com/library/pil/handbook/imagefont.htm for more # details. Note that "font size" is only used with truetype (.ttf) # fonts. For others, font size is determined by the bit-mapped size, usually # encoded in the file name (e.g., courB010.pil). If a font can't be found, # then a default font will be used. # # Anti-aliasing # anti_alias = 3 show_daynight = true # These control the appearance of the bands if they are shown. # Here's a monochrome scheme: # daynight_day_color = 0xdfdfdf # daynight_night_color = 0xffff00 # daynight_edge_color = 0xd0d0d0 # Here's an alternative, using a blue/yellow tint: # daynight_day_color = 0xf8ffff # daynight_night_color = 0xfff8f8 # daynight_edge_color = 0xf8f8ff # Richie's day-night colors # daynight_day_color = 0xf8ffff # daynight_night_color = 0xbcffde # daynight_edge_color = 0xd9ffd1 # Nick's values - frankly monocrhome is best daynight_day_color = 0xdfdfdf daynight_night_color = 0xbbbbbb daynight_edge_color = 0xd0d0d0 image_width = 920 #550 image_height = 275 #350 image_background_color = 0xffffff chart_background_color = 0xffffff chart_gridline_color = 0xa0a0a0 top_label_font_path = /usr/share/fonts/truetype/freefont/FreeMonoBold.ttf top_label_font_size = 18 unit_label_font_path = /usr/share/fonts/truetype/freefont/FreeMonoBold.ttf unit_label_font_size = 14 unit_label_font_color = 0x000000 bottom_label_font_path = /usr/share/fonts/truetype/freefont/FreeMonoBold.ttf bottom_label_font_size = 14 bottom_label_font_color = 0x000000 axis_label_font_path = /usr/share/fonts/truetype/freefont/FreeMonoBold.ttf axis_label_font_size = 14 axis_label_font_color = 0x000000 # Options for the compass rose, used for progressive vector plots rose_label = N rose_label_font_path = /usr/share/fonts/truetype/freefont/FreeMonoBold.ttf rose_label_font_size = 12 rose_label_font_color = 0x000000 # Default colors for the plot lines. These can be overridden for # individual lines using option 'color' chart_line_colors = 0xb48242, 0x4242b4, 0x42b442 # Type of line. Only 'solid' or 'none' is offered now line_type = 'solid' # Size of marker in pixels marker_size = 8 # Type of marker. Pick one of 'cross', 'x', 'circle', 'box', or 'none' marker_type ='none' ## ## What follows is a list of subsections, each specifying a time span, such ## as a day, week, month, or year. There's nothing special about them or ## their names: it's just a convenient way to group plots with a time span ## in common. You could add a time span [[biweek_images]] and add the ## appropriate time length, aggregation strategy, etc., without changing any ## code. ## ## Within each time span, each sub-subsection is the name of a plot to be ## generated for that time span. The generated plot will be stored using ## that name, in whatever directory was specified by option 'HTML_ROOT' ## in weewx.conf. ## ## With one final nesting (four brackets!) is the sql type of each line to ## be included within that plot. ## ## Unless overridden, leaf nodes inherit options from their parent ## # Default plot and aggregation. Can get overridden at any level. plot_type = line aggregate_type = none width = 1 time_length = 86400 # == 24 hours # line_gap_fraction = 0.01 ################# ### DAY Images [[day_images]] x_label_format = %H # x_label_format = %H:%M width = 2 # bottom_label_format = %x %X bottom_label_format = %d/%m/%y %X time_length = 97200 # == 27 hours # time_length = 129600 # == 36 hours [[[daybarometer-Bootstrap]]] [[[[barometer]]]] x_label_format = %d/%m time_length = 172800 # == 48 hours aggregate_type = avg aggregate_interval = 21600 # 6 hours [[[daytempdew-Bootstrap]]] [[[[outTemp]]]] [[[[extraTemp2]]]] label = HeatDegDays [[[[extraTemp3]]]] label = CoolDegDays [[[dayrain-Bootstrap]]] # Make sure the y-axis increment is at least 0.02 for the rain plot yscale = None, None, 0.02 plot_type = bar [[[[rain]]]] aggregate_type = sum aggregate_interval = 900 # 15 min # label = Rain (hourly total) [[[dayinside-Bootstrap]]] [[[[inTemp]]]] [[[dayhumid-Bootstrap]]] # x_label_format = %d aggregate_interval = 600 # == 10 min [[[[outHumidity]]]] [[[[inHumidity]]]] [[[daywind-Bootstrap]]] [[[[windSpeed]]]] [[[[windGust]]]] [[[daywinddir-Bootstrap]]] # Hardwire in the y-axis scale for wind direction: yscale = 0.0, 360.0, 45.0 # Don't join lines # Type of line. Only 'solid' or 'none' is offered now line_type = 'none' # Size of marker in pixels marker_size = 6 # Type of marker. Pick one of 'cross', 'x', 'circle', 'box', or 'none' marker_type ='cross' [[[[windDir]]]] ############# ### WEEK Images [[week_images]] x_label_format = %d # bottom_label_format = %x %X bottom_label_format = %d/%m/%y %X time_length = 604800 # == 7 days aggregate_type = avg aggregate_interval = 7200 # 2 hh width = 2 [[[weekbarometer-Bootstrap]]] [[[[barometer]]]] [[[weektempdew-Bootstrap]]] [[[[outTemp]]]] [[[[extraTemp2]]]] label = HeatDegDays [[[[extraTemp3]]]] label = CoolDegDays [[[weekrain-Bootstrap]]] yscale = None, None, 0.02 plot_type = bar [[[[rain]]]] aggregate_type = sum aggregate_interval = 86400 label = Rain (daily total) [[[weekinside-Bootstrap]]] [[[[inTemp]]]] [[[weekwind-Bootstrap]]] [[[[windSpeed]]]] [[[[windGust]]]] [[[weekwinddir-Bootstrap]]] # Hardwire in the y-axis scale for wind direction: yscale = 0.0, 360.0, 45.0 # Don't join lines # Type of line. Only 'solid' or 'none' is offered now line_type = 'none' # Size of marker in pixels marker_size = 6 # Type of marker. Pick one of 'cross', 'x', 'circle', 'box', or 'none' marker_type ='cross' [[[[windDir]]]] ############# ### MONTH Images [[month_images]] x_label_format = %d # bottom_label_format = %x %X bottom_label_format = %d/%m/%y %X time_length = 2678400 # == 31 days aggregate_type = avg aggregate_interval = 86400 # == 1 giorno show_daynight = false width = 2 [[[monthbarometer-Bootstrap]]] [[[[barometer]]]] [[[monthtempdew-Bootstrap]]] yscale = 0.0, 35.0, 5.0 label = Monthly Out Temp [[[[outTemp]]]] [[[[extraTemp2]]]] label = HeatDegDays [[[[extraTemp3]]]] label = CoolDegDays [[[monthrain-Bootstrap]]] yscale = None, None, 0.02 plot_type = bar [[[[rain]]]] aggregate_type = sum aggregate_interval = 86400 label = Rain (daily total) [[[monthinside-Bootstrap]]] yscale = 0.0, 35.0, 5.0 [[[[inTemp]]]] [[[monthwind-Bootstrap]]] [[[[windSpeed]]]] [[[[windGust]]]] [[[monthwinddir-Bootstrap]]] # Hardwire in the y-axis scale for wind direction: yscale = 0.0, 360.0, 45.0 # Don't join lines # Type of line. Only 'solid' or 'none' is offered now line_type = 'none' # Size of marker in pixels marker_size = 6 # Type of marker. Pick one of 'cross', 'x', 'circle', 'box', or 'none' marker_type = 'cross' [[[[windDir]]]] ############# ### YEAR Images [[year_images]] x_label_format = %b/%y ####x_label_format = %d/%m # bottom_label_format = %x %X bottom_label_format = %d/%m/%y %X time_length = 34128000 # == 365 days +30gg aggregate_type = avg aggregate_interval = 432000 # -- 5 gg show_daynight = false width = 2 [[[yearbarometer-Bootstrap]]] # aggregate_interval = 604800 # 1 week [[[[barometer]]]] [[[yeartempdew-Bootstrap]]] yscale = 0.0, 35.0, 5.0 label = Yearly Out Temp [[[[outTemp]]]] [[[yearinside-Bootstrap]]] [[[[inTemp]]]] # Daily high/lows: [[[yearhilow-Bootstrap]]] [[[[hi]]]] data_type = outTemp aggregate_type = max label = High [[[[low]]]] data_type = outTemp aggregate_type = min label = Low Temp [[[yearrain-Bootstrap]]] yscale = None, None, 0.02 plot_type = bar [[[[rain]]]] aggregate_type = sum aggregate_interval = 2629800 # Magic number: the length of a nominal month label = Rain (weekly total) [[[yearwind-Bootstrap]]] [[[[windSpeed]]]] [[[[windGust]]]] [[[yearwinddir-Bootstrap]]] # Hardwire in the y-axis scale for wind direction: yscale = 0.0, 360.0, 45.0 # Don't join lines # Type of line. Only 'solid' or 'none' is offered now line_type = 'none' # Size of marker in pixels marker_size = 6 # Type of marker. Pick one of 'cross', 'x', 'circle', 'box', or 'none' marker_type = 'cross' [[[[windDir]]]] aggregate_type = avg # aggregate_interval = 1209600 # 2 sett ############################# ### Last Year / Month Images [[[lastyeartempdew-Bootstrap]]] x_label_format = %b/%y ####x_label_format = %d/%m # bottom_label_format = %x %X bottom_label_format = %d/%m/%y %X time_length = 31622400 # == 366 days aggregate_type = avg aggregate_interval = 432000 # 5 gg show_daynight = false width = 2 yscale = 0.0, 35.0, 5.0 label = Out Temp Year Before color = 0x42b442 previous_year = -1 report_timing = @yearly [[[[outTemp]]]] [[[lastmonthtempdew-Bootstrap]]] x_label_format = %d/%m ###### %d/%b bottom_label_format = %x %X time_length = 2678400 # == 31 days aggregate_type = avg aggregate_interval = 86400 # == 1 giorno show_daynight = false width = 2 yscale = 0.0, 35.0, 5.0 label = Monthly Out Temp Year Before color = 0x42b442 previous_month = -12 report_timing = @monthly [[[[outTemp]]]] ############################################################################################ # # The list of generators that are to be run: # [Generators] generator_list = user.translategenerator.ImageGeneratorTranslated # generator_list = weewx.imagegenerator.ImageGenerator
# # Copyright (c) 2009-2015 Tom Keffer <tkef...@gmail.com> # # See the file LICENSE.txt for your full rights. # """Generate images for up to an effective date. Needs to be refactored into smaller functions.""" from __future__ import with_statement import time import datetime import syslog import os.path import weeplot.genplot import weeplot.utilities import weeutil.weeutil import weewx.reportengine import weewx.units from weeutil.config import search_up from weeutil.weeutil import to_bool, to_int, to_float from weewx.units import ValueTuple # ============================================================================= # Class ImageGenerator # ============================================================================= class ImageGenerator(weewx.reportengine.ReportGenerator): """Class for managing the image generator.""" def run(self): self.setup() self.genImages(self.gen_ts) def setup(self): try: d = self.skin_dict['Labels']['Generic'] except KeyError: d = {} self.title_dict = weeutil.weeutil.KeyDict(d) self.image_dict = self.skin_dict['ImageGenerator'] self.formatter = weewx.units.Formatter.fromSkinDict(self.skin_dict) self.converter = weewx.units.Converter.fromSkinDict(self.skin_dict) # ensure that the skin_dir is in the image_dict self.image_dict['skin_dir'] = os.path.join( self.config_dict['WEEWX_ROOT'], self.skin_dict['SKIN_ROOT'], self.skin_dict['skin']) # ensure that we are in a consistent right location os.chdir(self.image_dict['skin_dir']) def genImages(self, gen_ts): """Generate the images. The time scales will be chosen to include the given timestamp, with nice beginning and ending times. gen_ts: The time around which plots are to be generated. This will also be used as the bottom label in the plots. [optional. Default is to use the time of the last record in the database.] """ t1 = time.time() ngen = 0 # determine how much logging is desired log_success = to_bool(search_up(self.image_dict, 'log_success', True)) # Loop over each time span class (day, week, month, etc.): for timespan in self.image_dict.sections: # Now, loop over all plot names in this time span class: for plotname in self.image_dict[timespan].sections: # Accumulate all options from parent nodes: plot_options = weeutil.weeutil.accumulateLeaves( self.image_dict[timespan][plotname]) plotgen_ts = gen_ts if not plotgen_ts: binding = plot_options['data_binding'] archive = self.db_binder.get_manager(binding) plotgen_ts = archive.lastGoodStamp() if not plotgen_ts: plotgen_ts = time.time() ## @Andrea __START _last year last month_____________________________________________________________________ # If previous year or month is set, get the setting and use it to calculate the time span. year = datetime.date.today().year month = datetime.date.today().month day = datetime.date.today().day previous_month = 0 previous_year = 0 try: previous_year = int(plot_options.get('previous_year', 0)) except: raise ValueError("Invalid field value 'previous_year', previous_year can only be a negative integer") if previous_year > 0: raise ValueError("Invalid field value 'previous_year' in '%s', previous_year can only be a negative integer" % str(previous_year)) if previous_year < 0: ## plotgen_ts = time.mktime((year + previous_year, 12, 31, 23, 59, 59, 999, 999, 999)) plotgen_ts = time.mktime((year + previous_year, month, day, 23, 59, 59, 999, 999, 999)) ## Modified by @Andrea 2018 if previous_year == 0: try: previous_month = int(plot_options.get('previous_month', 0)) except: raise ValueError("Invalid field value 'previous_month', previous_month can only be a negative integer") if previous_month > 0: raise ValueError("Invalid field value 'previous_month' in '%s', previous_month can only be a negative integer" % str(previous_month)) if previous_month < 0: ## plotgen_ts = time.mktime((year, month + previous_month + 1, 1, 0, 0, 0, 0, 0, 0)) - 1 ## Modified by @Andrea 2018 plotgen_ts = time.mktime((year, month + previous_month, day, 0, 0, 0, 0, 0, 0)) - 1 ##__END______________________________________________________________________ image_root = os.path.join(self.config_dict['WEEWX_ROOT'], plot_options['HTML_ROOT']) # Get the path that the image is going to be saved to: img_file = os.path.join(image_root, '%s.png' % plotname) ai = to_int(plot_options.get('aggregate_interval')) # Check whether this plot needs to be done at all: if skipThisPlot(plotgen_ts, ai, img_file): continue # skip image files that are fresh, but only if staleness is defined stale = to_int(plot_options.get('stale_age')) if stale is not None: t_now = time.time() try: last_mod = os.path.getmtime(img_file) if t_now - last_mod < stale: continue except os.error: pass # Create the subdirectory that the image is to be put in. # Wrap in a try block in case it already exists. try: os.makedirs(os.path.dirname(img_file)) except OSError: pass # Create a new instance of a time plot and start adding to it plot = weeplot.genplot.TimePlot(plot_options) ##START plot last Year last Month_______________________________________________________________________ @Andrea # If previous_year is less than 0 generate graph for specified calendar year or month if previous_year < 0: minstamp = time.mktime((year + previous_year, 1, 1, 0, 0, 0, 0, 0, 0)) maxstamp = time.mktime((year + previous_year, 12, 31, 23, 59, 59, 999, 999, 999)) + 1 elif previous_year == 0 and previous_month < 0: minstamp = time.mktime((year, month + previous_month, 1, 0, 0, 0, 0, 0, 0)) maxstamp = time.mktime((year, month + previous_month + 1, 1, 0, 0, 0, 0, 0, 0)) ##__End_______________________________________________________________________ # Calculate a suitable min, max time for the requested time. (minstamp, maxstamp, timeinc) = weeplot.utilities.scaletime(plotgen_ts - int(plot_options.get('time_length', 86400)), plotgen_ts) # Override the x interval if the user has given an explicit interval: timeinc_user = to_int(plot_options.get('x_interval')) if timeinc_user is not None: timeinc = timeinc_user plot.setXScaling((minstamp, maxstamp, timeinc)) # Set the y-scaling, using any user-supplied hints: plot.setYScaling(weeutil.weeutil.convertToFloat(plot_options.get('yscale', ['None', 'None', 'None']))) # Get a suitable bottom label: bottom_label_format = plot_options.get('bottom_label_format', '%m/%d/%y %H:%M') bottom_label = time.strftime(bottom_label_format, time.localtime(plotgen_ts)) plot.setBottomLabel(bottom_label) # Set day/night display plot.setLocation(self.stn_info.latitude_f, self.stn_info.longitude_f) plot.setDayNight(to_bool(plot_options.get('show_daynight', False)), weeplot.utilities.tobgr(plot_options.get('daynight_day_color', '0xffffff')), weeplot.utilities.tobgr(plot_options.get('daynight_night_color', '0xf0f0f0')), weeplot.utilities.tobgr(plot_options.get('daynight_edge_color', '0xefefef'))) # Loop over each line to be added to the plot. for line_name in self.image_dict[timespan][plotname].sections: # Accumulate options from parent nodes. line_options = weeutil.weeutil.accumulateLeaves(self.image_dict[timespan][plotname][line_name]) # See what SQL variable type to use for this line. By # default, use the section name. var_type = line_options.get('data_type', line_name) # Look for aggregation type: aggregate_type = line_options.get('aggregate_type') if aggregate_type in (None, '', 'None', 'none'): # No aggregation specified. aggregate_type = aggregate_interval = None else: try: # Aggregation specified. Get the interval. aggregate_interval = line_options.as_int('aggregate_interval') except KeyError: syslog.syslog(syslog.LOG_ERR, "imagegenerator: aggregate interval required for aggregate type %s" % aggregate_type) syslog.syslog(syslog.LOG_ERR, "imagegenerator: line type %s skipped" % var_type) continue # Now its time to find and hit the database: binding = line_options['data_binding'] archive = self.db_binder.get_manager(binding) (start_vec_t, stop_vec_t, data_vec_t) = \ archive.getSqlVectors((minstamp, maxstamp), var_type, aggregate_type=aggregate_type, aggregate_interval=aggregate_interval) if weewx.debug: assert(len(start_vec_t) == len(stop_vec_t)) # Get the type of plot ("bar', 'line', or 'vector') plot_type = line_options.get('plot_type', 'line') if aggregate_type and aggregate_type.lower() in ('avg', 'max', 'min') and plot_type != 'bar': # Put the point in the middle of the aggregate_interval for these aggregation types start_vec_t = ValueTuple([x - aggregate_interval / 2.0 for x in start_vec_t[0]], start_vec_t[1], start_vec_t[2]) stop_vec_t = ValueTuple([x - aggregate_interval / 2.0 for x in stop_vec_t[0]], stop_vec_t[1], stop_vec_t[2]) # Do any necessary unit conversions: new_start_vec_t = self.converter.convert(start_vec_t) new_stop_vec_t = self.converter.convert(stop_vec_t) new_data_vec_t = self.converter.convert(data_vec_t) # Add a unit label. NB: all will get overwritten except the # last. Get the label from the configuration dictionary. unit_label = line_options.get('y_label', weewx.units.get_label_string(self.formatter, self.converter, var_type)) # Strip off any leading and trailing whitespace so it's # easy to center plot.setUnitLabel(unit_label.strip()) # See if a line label has been explicitly requested: label = line_options.get('label') if not label: # No explicit label. Look up a generic one. NB: title_dict is a KeyDict which # will substitute the key if the value is not in the dictionary. label = self.title_dict[var_type] # See if a color has been explicitly requested. color = line_options.get('color') if color is not None: color = weeplot.utilities.tobgr(color) fill_color = line_options.get('fill_color') if fill_color is not None: fill_color = weeplot.utilities.tobgr(fill_color) # Get the line width, if explicitly requested. width = to_int(line_options.get('width')) interval_vec = None gap_fraction = None # Some plot types require special treatments: if plot_type == 'vector': vector_rotate_str = line_options.get('vector_rotate') vector_rotate = -float(vector_rotate_str) if vector_rotate_str is not None else None else: vector_rotate = None if plot_type == 'bar': interval_vec = [x[1] - x[0]for x in zip(new_start_vec_t.value, new_stop_vec_t.value)] elif plot_type == 'line': gap_fraction = to_float(line_options.get('line_gap_fraction')) if gap_fraction is not None: if not 0 < gap_fraction < 1: syslog.syslog(syslog.LOG_ERR, "imagegenerator: Gap fraction %5.3f outside range 0 to 1. Ignored." % gap_fraction) gap_fraction = None # Get the type of line (only 'solid' or 'none' for now) line_type = line_options.get('line_type', 'solid') if line_type.strip().lower() in ['', 'none']: line_type = None marker_type = line_options.get('marker_type') marker_size = to_int(line_options.get('marker_size', 8)) # Add the line to the emerging plot: plot.addLine(weeplot.genplot.PlotLine( new_stop_vec_t[0], new_data_vec_t[0], label = label, color = color, fill_color = fill_color, width = width, plot_type = plot_type, line_type = line_type, marker_type = marker_type, marker_size = marker_size, bar_width = interval_vec, vector_rotate = vector_rotate, gap_fraction = gap_fraction)) # OK, the plot is ready. Render it onto an image image = plot.render() try: # Now save the image image.save(img_file) ngen += 1 except IOError as e: syslog.syslog(syslog.LOG_CRIT, "imagegenerator: Unable to save to file '%s' %s:" % (img_file, e)) t2 = time.time() if log_success: syslog.syslog(syslog.LOG_INFO, "imagegenerator: Generated %d images for %s in %.2f seconds" % (ngen, self.skin_dict['REPORT_NAME'], t2 - t1)) def skipThisPlot(time_ts, aggregate_interval, img_file): """A plot can be skipped if it was generated recently and has not changed. This happens if the time since the plot was generated is less than the aggregation interval.""" # Images without an aggregation interval have to be plotted every time. # Also, the image definitely has to be generated if it doesn't exist. if aggregate_interval is None or not os.path.exists(img_file): return False # If its a very old image, then it has to be regenerated if time_ts - os.stat(img_file).st_mtime >= aggregate_interval: return False # Finally, if we're on an aggregation boundary, regenerate. time_dt = datetime.datetime.fromtimestamp(time_ts) tdiff = time_dt - time_dt.replace(hour=0, minute=0, second=0, microsecond=0) ret = abs(tdiff.seconds % aggregate_interval) > 1 return ret