Beispiel #1
0
    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
Beispiel #2
0
    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