def _finalizeProduct(self, plot_time, is_forecast, plot_names=[]): """ _finalizeProduct() [protected] Purpose: Add final things to the product, such as the title, valid time, and border, and then save. Parameters: forecast_hour [type=int] Forecast hour for model products (pass in None for an observed product). Returns: [nothing] """ plot_names = uniquify(plot_names) # Modify the last plot name for joining for the title string if len(plot_names) > 1: plot_names[-1] = "and " + plot_names[-1] # Create the forecast hour string according to whether or not we're passed a forecast hour. plot_time_delta = plot_time - self._valid_time hour = Units.convert(plot_time_delta.microseconds, 'us', 'hr') + Units.convert(plot_time_delta.seconds, 's', 'hr') + Units.convert(plot_time_delta.days, 'dy', 'hr') file_name = self._image_file_name % { 'plot_time':hour } if is_forecast: fh_string = " (F%03d)" % hour else: fh_string = "" if self._vertical_level in ['surface', 'sfc', "None"]: vert_level_str = "" else: vert_level_str = " %s" % self._vertical_level # Create the valid time string and assemble the title string valid_time_string = plot_time.strftime(self._product_time_format) title_string = "%s%s %s Valid: %s%s" % (self._product_title, vert_level_str, ", ".join(plot_names), valid_time_string, fh_string) # Put the title on the image pylab.title(title_string, weight="bold", size="x-small", bbox=dict(facecolor="#ffffff", alpha=0.7),x=0.5,y=0.95) # Save the figure try: pylab.savefig(file_name) except IOError: fatalError("Couldn't save image to %s" % file_name) print "Saved product '%s', valid at %s%s, to file %s" % (self._product_title, valid_time_string, fh_string, file_name) pylab.close() return
def _loadFunctionString(self, nc, plot_dict, data_scheme, data_index=None, scratch=False): """ _loadFunctionString() [protected] Purpose: Parses a function string from the input file, loads the data from the file, and converts the data to the proper units for plotting. Parameters: nc [type=DataIO] DataIO object that loads in the data. plot_dict [type=dictionary] Dictionary containing the plot attributes and their values. data_scheme [type=dictionary] Dictionary containing the mapping of internal variable names to the variable names in the data file. data_index [type=np.array] An array containing the indexes into the data array to return [not yet implemented]. Returns: [nothing] """ if type(plot_dict['function']) not in [ list, tuple ]: plot_dict['function'] = [ plot_dict['function'] ] plot_dict['data'] = {} for function in plot_dict['function']: parse_function = False try: default_units = data_scheme[self._unit_map[function]] except KeyError: parse_function = True if parse_function or default_units is not None: units_function = function var_list, const_list = self._parseFunctionConstituents(function) parsed_function = function for const in const_list: # Replace each constant in the function and units function with the proper source code to get the value parsed_function = re.sub("(?:^|(?<=[\\W]))(%s)(?:(?=[\\W])|$)" % const, "derived.\\1", parsed_function) for nc_variable in var_list: if scratch: plot_dict['scratch'] = nc.get_variable(data_scheme[self._var_map[nc_variable]], data_index) return if self._inCache(nc_variable): # Check the cache to make sure the units in the cache are what we think they are (they might have been converted before putting them in). file_units = data_scheme[self._unit_map[nc_variable]] cache_units = self._getFromCache(nc_variable, 'units') if file_units != cache_units: nc_data = self._getFromCache(nc_variable) self._updateCache(nc_variable, Units.convert(nc_data, cache_units, file_units), file_units) else: # Put data in the global namespace for easy access (will be deleted later) self._updateCache(nc_variable, nc.get_variable(data_scheme[self._var_map[nc_variable]], data_index), data_scheme[self._unit_map[nc_variable]]) for const in const_list: # Find each constant and HootPy function in the string match = re.search("(?:^|(?<=[\\W]))%s\\(([\\w\\, ]+)\\)?(?:(?=[\\W])|$)" % const, units_function) # Parse out the arguments to each function. If it's not a function (and really a constant, such as g) give it an empty list for arguments. if match is not None and match.group(1) is not None: args = re.split("\,[\s]*", match.group(1)) else: args = [] # Determine what the units of the data for the arguments are. If the argument's variable name is not in the cache, # then that probably means it's the units being output from another HootPy function that's already been subbed # into the string. Put None in its place. arg_units = [ self._getFromCache(a, 'units') if self._inCache(a) else None for a in args ] # Determine what the function is expecting func_units = derived._units(const, *arg_units) # A bit of idiot-proofing on the arguments if len(arg_units) != len(func_units['args']): fatalError("Incorrect number of arguments for function %s." % const) for idx in xrange(len(args)): # Convert all argument data to the units the function is expecting (only do it if we actually have units there, and they don't need to be converted. if arg_units[idx] is not None and arg_units[idx] != func_units['args'][idx]: self._updateCache(args[idx], Units.convert(self._getFromCache(args[idx], 'value'), arg_units[idx], func_units['args'][idx]), func_units['args'][idx]) # Substitute the units output from this function back into the units string units_function = re.sub("(?:^|(?<=[\\W]))((?:%s)(?:\\([\w\\, ]+\\))?)(?:(?=[\\W])|$)" % const, func_units['return'], units_function) for nc_variable in var_list: # Sub individual variables' units into the units string if units_function.find(nc_variable) > -1: units_function = re.sub("(?:^|(?<=[\\W]))(%s)(?:(?=[\\W])|$)" % nc_variable, data_scheme[self._unit_map[nc_variable]], units_function) plot_dict['default_units'] = Units.evaluateFunction(units_function) else: parsed_function = function self._updateCache(parsed_function, nc.get_variable(data_scheme[self._var_map[parsed_function]], data_index), None) plot_dict['default_units'] = None # Load data if len(plot_dict['function']) == 1: if not scratch: if type(plot_dict['plot_name']) == dict: print "Loading/computing data for %s ..." % plot_dict['plot_name'][function] else: print "Loading/computing data for %s ..." % plot_dict['plot_name'] exec "plot_dict['data'] = %s " % parsed_function in globals(), locals() # Do units conversion if plot_dict['element_config']['units'] is not None: if type(plot_dict['data']) in [ list, tuple ]: plot_dict['data'] = tuple([ Units.convert(d, plot_dict['default_units'], plot_dict['element_config']['units']) for d in plot_dict['data'] ]) else: plot_dict['data'] = Units.convert(plot_dict['data'], plot_dict['default_units'], plot_dict['element_config']['units']) else: if not scratch: if type(plot_dict['plot_name']) == dict: print "Loading/computing data for %s (%s) ..." % (plot_dict['plot_name'][function], function) else: print "Loading/computing data for %s (%s) ..." % (plot_dict['plot_name'], function) exec "plot_dict['data']['%s'] = %s " % (function, parsed_function) in globals(), locals() # Do units conversion if plot_dict['element_config']['units'][function] is not None: if type(plot_dict['data'][function]) in [ list, tuple ]: plot_dict['data'][function] = tuple([ Units.convert(d, plot_dict['default_units'], plot_dict['element_config']['units'][function]) for d in plot_dict['data'][function] ]) else: plot_dict['data'][function] = Units.convert(plot_dict['data'][function], plot_dict['default_units'], plot_dict['element_config']['units'][function]) if scratch: for nc_variable in var_list: self._clearCache(nc_variable) return