Esempio n. 1
0
def station_meta_to_json(by_type, val, el_list=None, time_range=None, constraints=None):
    '''
    Requests station meta data from ACIS and writes results to a json file
    This json file is read by the javascript function initialize_station_map
    which generates the station finder map
    Keyword arguments:
    by_type    -- station selection argument.
                  station selection is one of: county, climate_division, bounding box
                  county_warning_area, basin, state, states or custom shapes
    val        -- Value of station selection argument, e.g, AL if by_type = state
    el_list    -- List of var_majors of climate variables
                  (default None --> we look for for any of the 11 common variables)
    time_range -- User form start and end dates [start_date, end_date]
                  (default None --> we take valid_daterange of el_list)
    contraints -- specifies variable contsraints and date contsraints:
                  any_any, all_all, any_all, all_any

    If el_list and time_range are given, only stations that have variables
    for the given time range are listed.
    '''
    def stn_in_poly(by_type, shape_type, shape,stn_meta):
        #convert to floats
        s = [float(s) for s in shape]
        if shape_type == 'circle':
            poly = s
            stn_in = WRCCUtils.point_in_circle(stn_meta['ll'][0], stn_meta['ll'][1], poly)
        else:
            if shape_type in ['bbox','location']:
                poly = [(s[0],s[1]), (s[0],s[3]),(s[2],s[3]),(s[2],s[1])]
            else:
                poly = [(s[2*idx],s[2*idx+1]) for idx in range(len(s)/2)]
            stn_in = WRCCUtils.point_in_poly(stn_meta['ll'][0], stn_meta['ll'][1], poly)
        if not stn_in:return False
        else:return True

    def station_invalid(el_list, vX_list, time_range, stn, contraints):
        #Check if constraints are met for variable list and date range
        if constraints in ['any_any', 'any_all']:
            flag_invalid_station = True
        elif constraints in ['all_all', 'all_any']:
            flag_invalid_station = False
        for el_idx, el_vX in enumerate(el_list):
            #Find correct index in vX_list
            try:
                idx = vX_list.index(el_vX)
            except:
                if constraints in ['all_all', 'all_any']:
                    flag_invalid_station = True
                    break
                elif constraints in ['any_any', 'any_all']:
                    continue
            #Sanity Check
            if not stn['valid_daterange'][idx] and (constraints == 'all_all'  or constraints == 'all_any' or constraints is None):
                #data for this variable does not exist at station
                flag_invalid_station = True
                break
            elif not stn['valid_daterange'][idx] and (constraints == 'any_any' or constraints == 'any_all'):
                continue
            #Find period of record for this variable and station
            por_start = WRCCUtils.date_to_datetime(stn['valid_daterange'][idx][0])
            por_end = WRCCUtils.date_to_datetime(stn['valid_daterange'][idx][1])
            if time_range[0].lower() != 'por':
                user_start = WRCCUtils.date_to_datetime(time_range[0])
            else:
                user_start = por_start
            if time_range[1].lower() != 'por':
                user_end = WRCCUtils.date_to_datetime(time_range[1])
            else:
                user_end = por_end
            #Check constraints logic for this variable and station
            if constraints == 'all_all' or constraints is None:
                #all  variables have data records for all dates within start and end date given by user
                if user_start < por_start or user_end > por_end:
                    flag_invalid_station =  True
                    break
            elif constraints == 'any_any':
                #At least one variable has one data record within user given time_range
                if (user_end >= por_start and user_start <= por_end) or (user_start <= por_end and user_end >=por_start):
                    flag_invalid_station = False
                    break
            elif constraints == 'all_any':
                #All variables have at least one data record within user given time_range
                if (user_end >= por_start and user_start <= por_end) or (user_start <= por_end and user_end >=por_start):
                    continue
                else:
                    flag_invalid_station =  True
                    break
            elif constraints == 'any_all':
                #At least one variables has data records for all dates within given date_range
                if user_start >= por_start and user_end <= por_end:
                    flag_invalid_station = False
                    break
        return flag_invalid_station

    #Settings
    stn_list = []
    stn_json={
        'network_codes': WRCCData.KELLY_NETWORK_CODES,
        'network_icons': WRCCData.KELLY_NETWORK_ICONS,
        'overlay_type':by_type,
        'overlay_val':val
    }

    if el_list:
        vX_list = [str(el) for el in el_list]
        vX_tuple = ','.join(vX_list)
    else:
        vX_list= ['1','2','43','3','4','10','11','7','45','44','12']
        vX_tuple = '1,2,43,3,4,10,11,7,45,44,12'
    shape_type = None
    time_stamp = datetime.datetime.now().strftime('%Y_%m_%d_%H_%M_%S_')
    f_name = time_stamp + 'stn.json'
    f_dir = settings.TEMP_DIR
    #Set up metedata request
    params = {'meta':'name,state,sids,ll,elev,uid,valid_daterange','elems':vX_tuple}
    params[WRCCData.STN_AREA_FORM_TO_PARAM[by_type]] = val
    if by_type == 'sw_states':params['state'] = 'az,ca,co,nm,nv,ut'
    #Find bbox for custom shapes
    if by_type == 'shape':
        shape_type,bbox = WRCCUtils.get_bbox(val)
        params['bbox'] = bbox

    #Acis Metadata call and sanity checks on results
    try:
        request = StnMeta(params)
    except:
        stn_json['error'] = 'Metadata request failed. Please check your parameters!'
        WRCCUtils.load_data_to_json_file(f_dir + f_name, stn_json)
        return stn_json, f_name

    if request is None:
        stn_json['error'] = 'No metadata found.'
        WRCCUtils.load_data_to_json_file(f_dir + f_name, stn_json)
        return stn_json, f_name
    if not 'meta' in request.keys() or not request['meta'] or 'error' in request.keys():
        stn_json['error'] = 'No metadata found.'
        WRCCUtils.load_data_to_json_file(f_dir + f_name, stn_json)
        return stn_json, f_name
    stn_meta_list = []
    #For alphabetic ordering of station names
    sorted_list =[]
    #Keep track of duplicates
    unique_stations = []
    for i, stn in enumerate(request['meta']):
        #if custom shape, check if  stn lies within shape
        if by_type == 'shape':
            if shape_type in ['bbox','location']:shape = bbox.split(',')
            elif shape_type == 'polygon':shape = WRCCUtils.orient_shape_ccw(val).split(',')
            else:shape = val.split(',')
            if not stn_in_poly(by_type, shape_type, shape, stn):
                continue
        #sanity check
        if not stn['valid_daterange']:
            continue
        #check if we are looking for stations with particular variables
        if el_list is not None and time_range is not None:
            #Check if ACIS produced correct output, i.e. one valid_daterange per variable
            if len(stn['valid_daterange']) < len(el_list):
                continue
            #Check if station is valid, if not, proceed to next station
            flag_invalid_station = station_invalid(el_list, vX_list, time_range, stn, constraints)
            if flag_invalid_station:
                continue
        stn_sids = []
        stn_networks = []
        stn_network_codes = []
        sids = stn['sids'] if 'sids' in stn.keys() else []
        marker_icons = []
        for sid in sids:
            sid_split = sid.split(' ')
            '''
            #put coop id up front (for csc application metagraph  and possibly others)
            if str(sid_split[1]) == '2':
                #stn_sids.append(re.sub('[^a-zA-Z0-9\n\.]', ' ', str(sid_split[1])))
                stn_sids.insert(0,str(sid_split[0]).replace("\'"," "))
                stn_network_codes.insert(0, str(sid_split[1]))
                marker_icons.insert(0, WRCCData.NETWORK_ICONS[str(sid_split[1])])
                stn_networks.insert(0,WRCCData.NETWORK_CODES[str(sid_split[1])])
            else:
            '''
            #stn_sids.append(re.sub('[^a-zA-Z0-9\n\.]', ' ', str(sid_split[1])))
            stn_sids.append(str(sid_split[0]).replace("\'"," "))
            stn_network_codes.append(str(sid_split[1]))
            if int(sid_split[1]) <= 10:
                stn_networks.append(WRCCData.NETWORK_CODES[str(sid_split[1])])
                marker_icons.append(WRCCData.NETWORK_ICONS[str(sid_split[1])])
            else:
                stn_networks.append('Misc')
                marker_icons.append('red')
        #Sanity check : Some Acis records are incomplete, leading to key error
        if 'll' in stn.keys():
            lat = str(stn['ll'][1])
            lon = str(stn['ll'][0])
        else:
            continue
        try:
            #name = re.sub('[^a-zA-Z0-9\n\.]', ' ', str(stn['name'])) if 'name' in stn.keys() else 'Name not listed'
            name = str(stn['name']).replace("\'"," ").replace('#','') if 'name' in stn.keys() else 'Name not listed'
        except:
            name = 'Name not listed'

        uid = str(stn['uid']) if 'uid' in stn.keys() else 'Uid not listed'
        elev = str(stn['elev']) if 'elev' in stn.keys() else 'Elevation not listed'
        state_key = str(stn['state']).lower() if 'state' in stn.keys() else 'state not listed'
        #sort station networks so that coop is last
        #so that coop markers show on map
        stn_networks_sorted = []
        for n in stn_networks:
            if n !='COOP':
                stn_networks_sorted.append(n)
        if 'COOP' in stn_networks:
            stn_networks_sorted.append('COOP')
        #Generate one entry per network that the station belongs to
        for j, sid in enumerate(stn_networks_sorted):
            stn_dict = {
                'name':name,
                'uid':uid,
                'sid':stn_sids[j],
                'sids':stn_sids,
                'sids_str':','.join(stn_sids),
                'elevation':elev,
                'lat':lat,
                'lon':lon,
                'll':str(lon) + ', ' + str(lat),
                'state':state_key,
                'marker_icon':marker_icons[j],
                'marker_category':stn_networks[j],
                'stn_networks':stn_networks,
                'stn_network':','.join(stn_networks),
                'stn_network_codes': stn_network_codes
            }
            #check which variables are available at the stations[valid_daterange is not empty]
            valid_date_range_list = stn['valid_daterange']
            available_variables = []
            available_variables_str = ''
            for j,rnge in enumerate(valid_date_range_list):
                if rnge and len(rnge) >=2:
                    vd = [str(rnge[0]), str(rnge[1])]
                    vd_str = ' - '.join(vd)
                    if WRCCData.ACIS_ELEMENTS[vX_list[j]]['name'] == 'cdd':
                        el_name = WRCCData.ACIS_ELEMENTS['-44']['name_long']
                    else:
                        el_name = WRCCData.ACIS_ELEMENTS[vX_list[j]]['name_long']
                    available_variables.append([el_name,vd])
                    available_variables_str+=el_name + ': ' + vd_str + ', '
            if available_variables:
                stn_dict['available_variables'] = available_variables
                stn_dict['available_variables_str'] = available_variables_str[0:-2]
            #find index in alphabetically ordered list of station names
            sorted_list.append(name.split(' ')[0])
            try:
                sorted_list.sort()
                stn_idx = sorted_list.index(name.split(' ')[0])
            except ValueError:
                stn_idx = -1
            #Insert stn into alphabeticlly ordered list
            if stn_idx == -1:
                stn_meta_list.append(stn_dict)
            else:
                stn_meta_list.insert(stn_idx, stn_dict)
    stn_json['stations'] = stn_meta_list
    WRCCUtils.load_data_to_json_file(f_dir + f_name, stn_json)
    return stn_json, f_name